/**
© Florian Joncour, 2013-2018 florian@zetta-sys.com

Ce logiciel est un programme informatique faisant interface à la bibliothèque
Perspective3D, un outil de modélisation 3D à partir de vues orthographiques 2D.

Ce logiciel est régi par la licence CeCILL-C soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL-C telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".

En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme,  le
titulaire des droits patrimoniaux et les concédants successifs.

A cet égard  l'attention de l'utilisateur est attirée sur les risques
associés au chargement,  à l'utilisation,  à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant  des  connaissances  informatiques approfondies.  Les
utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.

Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL-C, et que vous en avez accepté les
termes.
**/

#include <cmath>
#include <iostream>
#include <stack>

#include <cstdlib>
#include "eval_exp.h"

#include <cerrno>

//#define tr(x) std::string(x)

using namespace Evaluateur;

namespace EvalFcts DLL_LOCAL
{
    class DLL_LOCAL rand1024
    /* Référence : http://xoroshiro.di.unimi.it/xorshift1024star.c */
    {
        typedef puint64 ru64;

        public:
            inline rand1024(ru64 seed=9305640792670ULL)
            {
                this->srand(seed);
            }

            inline void srand(ru64 seed)
            {
                for(pint i=0; i<16; ++i)
                {
                    seed = splitmix64(seed);
                    s[i] = seed;
                }
                p=0;
            }

            inline ru64 rand()
            {
                const ru64 s0 = s[p];
                ru64 s1 = s[p = (p + 1) & 15];
                s1 ^= s1 << 31; // a
                s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30); // b,c
                return s[p] * ru64(0x9e3779b97f4a7c13ULL);
            }

            inline double rand_double()
            {
                const union { ru64 i; double d; } u = { ru64(0x3FF) << 52 | this->rand() >> 12 };
                return u.d - 1.0;
            }

            inline void jump(void)
            {
                static const uint64_t JUMP[] = { 0x84242f96eca9c41d,
                                               0xa3c65b8776f96855, 0x5b34a39f070b5837, 0x4489affce4f31a1e,
                                               0x2ffeeb0a48316f40, 0xdc2d9891fe68c022, 0x3659132bb12fea70,
                                               0xaac17d8efa43cab8, 0xc4cb815590989b13, 0x5ee975283d71c93b,
                                               0x691548c86c1bd540, 0x7910c41d10a1e6a5, 0x0b5fc64563b3e2a8,
                                               0x047f7684e9fc949d, 0xb99181f2d8f685ca, 0x284600e3f30e38c3 };

                uint64_t t[16] = { 0 };
                for(puint i = 0; i < sizeof(JUMP) / sizeof(*JUMP); ++i)
                {
                    for(pint b=0; b<64; b++)
                    {
                        if (JUMP[i] & 1ULL << b)
                        {
                            for(pint j=0; j<16; ++j)
                            {
                                t[j] ^= s[(j + p) & 15];
                            }
                        }
                        this->rand();
                    }
                }

                for(pint j=0; j<16; ++j)
                {
                    s[(j + p) & 15] = t[j];
                }
            }

        private:
            inline ru64 splitmix64(ru64 seed) const
            /* Source : http://xoroshiro.di.unimi.it/splitmix64.c */
            {
                seed += 0x9e3779b97f4a7c15ULL;
                seed = (seed ^ (seed >> 30)) * ru64(0xbf58476d1ce4e5b9ULL);
                seed = (seed ^ (seed >> 27)) * ru64(0x94d049bb133111ebULL);
                return seed ^ (seed >> 31);
            }

            ru64 s[16];
            pint p;
    };
    static EvalFcts::rand1024 RAND_1024;

    inline DLL_LOCAL Evaluateur::eval_float StoD(const std::string &s)
    {
    //    return std::stod(s);

        eval_float f(0);
        std::locale locale("C");
        std::istringstream convert(s);
        convert.imbue(locale);
        if (!(convert >> f)) // Erreur
        {
    #ifdef DEBUG
            std::cout << "StoD :: Erreur conversion (StoD) " << s << std::endl;
    #endif // DEBUG
            return 0.0;
        }
        return f;
    }

    inline DLL_LOCAL Evaluateur::eval_int StoI(const std::string &s)
    {
        return std::stoi(s);
    }

    inline DLL_LOCAL std::string Itos(long n)
    /* Conversion long -> std::string en base 10. */
    {
    //    return std::to_string(n);

        /* Fonction optimisée: */
        char *tail = nullptr;
        char buffer[(sizeof(long) * 8 + 1)];

        std::string str;

        tail = &buffer[(sizeof(long) * 8 - 1)];
        *(tail+1) = '\0';

        long uarg = n;
        if (n < 0L)
        {
            str += '-';
            uarg = -uarg;
        }

        if (uarg)
        {
            while (uarg)
            {
                ldiv_t r = ldiv(uarg, 10);
                *tail-- = (char)(r.rem + ((9L < r.rem) ? ('A' - 10L) : '0'));
                uarg = r.quot;
            }
        }
        else
        {
            *tail-- = '0';
        }

        str += (++tail);
        return str;
    }
} // namespace EvalFcts

inline std::string tr_exp(const char *s)
/* Gère les traductions de chaîne de l'interpréteur, à implémenter... */
{
    return std::string(s);
}

/* Opérateurs (les noms ne doivent pas être modifiés !) */
static const def_fonction OperateursCalcEval[] = {
    { "+", Evaluateur::OPERATEUR_1, 2, 0 },
    { "-", Evaluateur::OPERATEUR_1, 2, 1 },
    { "*", Evaluateur::OPERATEUR_0, 2, 2 },
    { "/", Evaluateur::OPERATEUR_0, 2, 3 },
    { "%", Evaluateur::OPERATEUR_0, 2, 4 }, /* Reste de division (modulo) */
    { "^", Evaluateur::OPERATEUR_0, 2, 5 }, /* Puissance */
};
static const puint n_OperateursCalcEval = sizeof(OperateursCalcEval) / sizeof(def_fonction);

/* Opérateurs booléens (les noms ne doivent pas être modifiés !) */
static const def_fonction OperateursBoolEval[] = {
    { "==",     Evaluateur::OPERATEUR_2, 2, 0 },
    { "!=",     Evaluateur::OPERATEUR_2, 2, 1 },
    { "<",      Evaluateur::OPERATEUR_2, 2, 2 },
    { ">",      Evaluateur::OPERATEUR_2, 2, 3 },
    { "<=",     Evaluateur::OPERATEUR_2, 2, 4 },
    { ">=",     Evaluateur::OPERATEUR_2, 2, 5 },
    { "&",      Evaluateur::OPERATEUR_2, 2, 6 },
    { "|",      Evaluateur::OPERATEUR_2, 2, 7 }
};
const puint n_OperateursBoolEval = sizeof(OperateursBoolEval) / sizeof(def_fonction);

/* Fonctions (On peut donner les noms de fonction de son choix à condition de les faires commencer par un caractère a-Z, et sans caractères spéciaux. */
static const def_fonction FonctionsEval[] = {
    { "print",      Evaluateur::FONCTION, -1, 0  }, /* Nombre dynamique de paramètres. */
    { "if",         Evaluateur::FONCTION,  1, 1  },
    { "sqrt",       Evaluateur::FONCTION,  1, 2  },
    { "pow",        Evaluateur::FONCTION,  2, 3  },
    { "min",        Evaluateur::FONCTION,  2, 4  },
    { "max",        Evaluateur::FONCTION,  2, 5  },
    { "hypot",      Evaluateur::FONCTION,  2, 6  },
    { "sin",        Evaluateur::FONCTION,  1, 7  },
    { "cos",        Evaluateur::FONCTION,  1, 8  },
    { "tan",        Evaluateur::FONCTION,  1, 9  },
    { "asin",       Evaluateur::FONCTION,  1, 10 },
    { "acos",       Evaluateur::FONCTION,  1, 11 },
    { "atan",       Evaluateur::FONCTION,  1, 12 },
    { "deg_rad",    Evaluateur::FONCTION,  1, 13 },
    { "rad_deg",    Evaluateur::FONCTION,  1, 14 },
    { "abs",        Evaluateur::FONCTION,  1, 15 },
    { "diff",       Evaluateur::FONCTION,  2, 16 },
    { "srand",      Evaluateur::FONCTION,  1, 17 },
    { "clamp",      Evaluateur::FONCTION,  3, 18 },
    { "round",      Evaluateur::FONCTION,  1, 19 },
    { "round0",     Evaluateur::FONCTION,  1, 20 },
    { "round1",     Evaluateur::FONCTION,  1, 21 },
    { "exp",        Evaluateur::FONCTION,  1, 22 },
    { "ln",         Evaluateur::FONCTION,  1, 23 },
    { "log10",      Evaluateur::FONCTION,  1, 24 },
};
static const puint n_FonctionsEval = sizeof(FonctionsEval) / sizeof(Evaluateur::def_fonction);

static const def_fonction ConstantesEval[] = {
    { "pi",      Evaluateur::FONCTION, 1, 0 },
    { "phi",     Evaluateur::FONCTION, 1, 1 },
    { "e",       Evaluateur::FONCTION, 1, 2 },
    { "rand",    Evaluateur::FONCTION, 1, 3 }, /* Dans la doc, c'est décrit comme une fonction, mais en réalité c'est utilisé comme une constante! */
    { "true",    Evaluateur::FONCTION, 1, 4 },
    { "false",   Evaluateur::FONCTION, 1, 5 },
    { "x",       Evaluateur::FONCTION, 1, 6 },
    { "y",       Evaluateur::FONCTION, 1, 7 },
    { "z",       Evaluateur::FONCTION, 1, 8 },
    { "w",       Evaluateur::FONCTION, 1, 9 },
};
static const puint n_ConstantesEval = sizeof(ConstantesEval) / sizeof(Evaluateur::def_fonction);

bool DerefConstante(pint fonction, val_tok &resultat)
{
    switch (fonction)
    {
        case 0: /* pi */
            resultat.var.f = 3.141592653589793;
            resultat.type_var = Evaluateur::TYPE_FLOAT;
            return true;

        case 1: /* phi */
            resultat.var.f = 1.618033988749895;
            resultat.type_var = Evaluateur::TYPE_FLOAT;
            return true;

        case 2: /* e */
            resultat.var.f = 2.718281828459045;
            resultat.type_var = Evaluateur::TYPE_FLOAT;
            return true;

        case 3: /* rand */
            resultat.var.f = EvalFcts::RAND_1024.rand_double();
            resultat.type_var = Evaluateur::TYPE_FLOAT;
            return true;

        case 4: /* true */
            resultat.var.b = true;
            resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;

        case 5: /* false */
            resultat.var.b = false;
            resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;

        case 6: /* x */
            resultat.var.i = 0;
            resultat.type_var = Evaluateur::TYPE_INT;
            return true;

        case 7: /* y */
            resultat.var.i = 1;
            resultat.type_var = Evaluateur::TYPE_INT;
            return true;

        case 8: /* z */
            resultat.var.i = 2;
            resultat.type_var = Evaluateur::TYPE_INT;
            return true;

        case 9: /* w */
            resultat.var.i = 3;
            resultat.type_var = Evaluateur::TYPE_INT;
            return true;

        default:
            return false;
    }
    return false;
}

class DLL_LOCAL LangageInterne : public DictionnaireLangage
{
    public:
        inline LangageInterne() : DictionnaireLangage()
        {
        }

        inline ~LangageInterne()
        {
        }

        inline bool Exec(puint id_fonction, Evaluateur::operation_tok *args, puint n_args) const
        {
            if (ExecInterne(id_fonction, args, n_args))
            {
                args[n_args-1].id_fonction = ID_FCT_ASSIGNATION;
                args[n_args-1].resultat.valide = true;
                return true;
            }
            else
            {
                args[n_args-1].resultat.valide = false;
                return false;
            }
        }

        inline bool ExecInterne(puint id_fonction, Evaluateur::operation_tok *args, puint n_args) const
        /* Exécute une fonction sur son id, un contrôle du nombre de paramètre sera effectué. */
        {
            const puint domaine_fonction = DOMAINE_FCT(id_fonction);
            const puint fonction = ID_FCT(id_fonction);
//            pint type_fonction = TypeFonction(id_fonction);

            if (domaine_fonction == DOM_FONCTION_EXTERNE)
                return false;

            if (domaine_fonction == DOM_CONSTANTE)
            {
                if (n_args != 1)
                    return false;

                return DerefConstante(fonction, args[0].resultat);
            }
            else if (domaine_fonction == DOM_OPERATEUR)
            {
                if (n_args != 2)
                    return false;

                switch (fonction)
                {
                    case 0:
                        return op_plus(args[0], args[1]);
                    case 1:
                        return op_moins(args[0], args[1]);
                    case 2:
                        return op_mult(args[0], args[1]);
                    case 3:
                        return op_divis(args[0], args[1]);
                    case 4:
                        return op_modulo(args[0], args[1]);
                    case 5:
                        return fct_pow(args[0], args[1]);
                    default:
                        return false;
                }
            }
            else if (domaine_fonction == DOM_OPERATEUR_BOOL)
            {
                if (n_args != 2)
                    return false;

                switch (fonction)
                {
                    case 0:
                        return op_eq(args[0], args[1]);
                    case 1:
                        return op_neq(args[0], args[1]);
                    case 2:
                        return op_inf(args[0], args[1]);
                    case 3:
                        return op_sup(args[0], args[1]);
                    case 4:
                        return op_inf_eq(args[0], args[1]);
                    case 5:
                        return op_sup_eq(args[0], args[1]);
                    case 6:
                        return op_and(args[0], args[1]);
                    case 7:
                        return op_or(args[0], args[1]);
                    default:
                        return false;
                }
            }
            else if (domaine_fonction == DOM_FONCTION_INTERNE)
            {
                switch (fonction)
                {
                    case 0:
                        return (n_args == 0) ? false : fct_print(args, n_args); /* Nombre dynamique d'arguments. */
                    case 1:
                        return (n_args != 1) ? false : fct_if(args[0]);
                    case 2:
                        return (n_args != 1) ? false : fct_sqrt(args[0]);
                    case 3:
                        return (n_args != 2) ? false : fct_pow(args[0], args[1]);
                    case 4:
                        return (n_args != 2) ? false : fct_min(args[0], args[1]);
                    case 5:
                        return (n_args != 2) ? false : fct_max(args[0], args[1]);
                    case 6:
                        return (n_args != 2) ? false : fct_hypot(args[0], args[1]);
                    case 7:
                        return (n_args != 1) ? false : fct_sin(args[0]);
                    case 8:
                        return (n_args != 1) ? false : fct_cos(args[0]);
                    case 9:
                        return (n_args != 1) ? false : fct_tan(args[0]);
                    case 10:
                        return (n_args != 1) ? false : fct_asin(args[0]);
                    case 11:
                        return (n_args != 1) ? false : fct_acos(args[0]);
                    case 12:
                        return (n_args != 1) ? false : fct_atan(args[0]);
                    case 13:
                        return (n_args != 1) ? false : fct_deg_rad(args[0]);
                    case 14:
                        return (n_args != 1) ? false : fct_rad_deg(args[0]);
                    case 15:
                        return (n_args != 1) ? false : fct_abs(args[0]);
                    case 16:
                        return (n_args != 2) ? false : fct_diff(args[0], args[1]);
                    case 17:
                        return (n_args != 1) ? false : fct_srand(args[0]);
                    case 18:
                        return (n_args != 3) ? false : fct_clamp(args[0], args[1], args[2]);
                    case 19:
                        return (n_args != 1) ? false : fct_round(args[0]);
                    case 20:
                        return (n_args != 1) ? false : fct_round0(args[0]);
                    case 21:
                        return (n_args != 1) ? false : fct_round1(args[0]);
                    case 22:
                        return (n_args != 1) ? false : fct_exp(args[0]);
                    case 23:
                        return (n_args != 1) ? false : fct_ln(args[0]);
                    case 24:
                        return (n_args != 1) ? false : fct_log10(args[0]);
                    default:
                        return false;
                }
                return false;
            }
            else
            {
                return false;
            }
            return true;
        }

        inline pint IdFonctionDom(const std::string &s, puint domaine) const
        {
            if (domaine == DOM_CONSTANTE) /* Recherche parmis les constantes. */
            {
                for(puint i=0; i<n_ConstantesEval; ++i)
                {
                    if (Evaluateur::CompareStrEval(s, ConstantesEval[i].nom_fonction))
                    {
                        return CONCAT_INT_FCT(DOM_CONSTANTE, i);
                    }
                }
            }
            else if (domaine == DOM_OPERATEUR) /* Recherche uniquement parmis les opérateurs décimaux */
            {
                for(puint i=0; i<n_OperateursCalcEval; ++i)
                {
                    if (Evaluateur::CompareStrEval(s, OperateursCalcEval[i].nom_fonction))
                    {
                        return CONCAT_INT_FCT(DOM_OPERATEUR, i);
                    }
                }
            }
            else if (domaine == DOM_OPERATEUR_BOOL) /* Recherche parmis les opérateurs booléens. */
            {
                for(puint i=0; i<n_OperateursBoolEval; ++i)
                {
                    if (Evaluateur::CompareStrEval(s, OperateursBoolEval[i].nom_fonction))
                    {
                        return CONCAT_INT_FCT(DOM_OPERATEUR_BOOL, i);
                    }
                }
            }
            else /* Recherche parmis les fonctions. */
            {
                for(puint i=0; i<n_FonctionsEval; ++i)
                {
                    if (Evaluateur::CompareStrEval(s, FonctionsEval[i].nom_fonction))
                    {
                        return CONCAT_INT_FCT(DOM_FONCTION_INTERNE, i);
                    }
                }
            }
            return -1;
        }

        inline pint IdFonction(const std::string &s) const
        {
            return IdFonctionDom(s, DOM_FONCTION_INTERNE);
        }

        inline const def_fonction &ReferenceFonction(puint id) const
        /* Renvoi la référence vers une fonction. */
        {
            puint id_domaine = DOMAINE_FCT(id);
            puint id_fct = ID_FCT(id);

            if (id_domaine == DOM_CONSTANTE)
            {
                if (id_fct < n_ConstantesEval)
                {
                    return ConstantesEval[id_fct];
                }
            }
            else if (id_domaine == DOM_OPERATEUR)
            {
                if (id_fct < n_OperateursCalcEval)
                {
                    return OperateursCalcEval[id_fct];
                }
            }
            else if (id_domaine == DOM_OPERATEUR_BOOL)
            {
                if (id_fct < n_OperateursBoolEval)
                {
                    return OperateursBoolEval[id_fct];
                }
            }
            else if (id_domaine == DOM_FONCTION_INTERNE)
            {
                if (id_fct < n_FonctionsEval)
                {
                    return FonctionsEval[id_fct];
                }
            }
            return FonctionNulle;
        }

    private:

        /* *** Liste des fonctions appelées pour la manipulation des données du langage *** */

        static inline bool valide_resultat(const Evaluateur::operation_tok &n)
        {
            if (n.resultat.type_var == Evaluateur::TYPE_FLOAT)
            {
                if (errno == EDOM)
                {
                    return false;
                }
                else if (errno == ERANGE)
                {
                    return false;
                }
                return !(std::isnan(DEREF_VAR_EVAL(n.resultat)));
            }
            return true;
        }

        static inline bool fct_sqrt(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            const eval_float vn = DEREF_VAR_EVAL(n.resultat);
            if (vn >= 0)
            {
                n.resultat.var.f = std::sqrt(vn);
                n.resultat.type_var = Evaluateur::TYPE_FLOAT;
                return valide_resultat(n);
            }
            return false;
        }

        static inline bool fct_pow(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n2.resultat.var.f = std::pow(DEREF_VAR_EVAL(n1.resultat), DEREF_VAR_EVAL(n2.resultat));
            n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n2);
        }

        static inline bool fct_min(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT))
            {
                n2.resultat.var.f = std::fmin(DEREF_VAR_EVAL(n1.resultat), DEREF_VAR_EVAL(n2.resultat));
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var = ((DEREF_VAR_EVAL(n1.resultat)) < (DEREF_VAR_EVAL(n2.resultat)) ? n1.resultat.var : n2.resultat.var);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool fct_max(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT))
            {
                n2.resultat.var.f = fmax(DEREF_VAR_EVAL(n1.resultat), DEREF_VAR_EVAL(n2.resultat));
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var = ((DEREF_VAR_EVAL(n1.resultat)) > (DEREF_VAR_EVAL(n2.resultat)) ? n1.resultat.var : n2.resultat.var);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool fct_hypot(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n2.resultat.var.f = std::hypot(DEREF_VAR_EVAL(n1.resultat), DEREF_VAR_EVAL(n2.resultat));
            n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n2);
        }

        static inline bool fct_sin(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::sin(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_cos(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::cos(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_tan(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::tan(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_asin(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::asin(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_acos(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::acos(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_atan(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = std::atan(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_deg_rad(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = eval_float(DEREF_VAR_EVAL(n.resultat)) * 0.017453292519943295;
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_rad_deg(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.f = eval_float(DEREF_VAR_EVAL(n.resultat)) * 57.29577951308232;
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_abs(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            if ((n.resultat.type_var) == Evaluateur::TYPE_FLOAT)
            {
                n.resultat.var.f = std::fabs(DEREF_VAR_EVAL(n.resultat));
                n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n.resultat.var.i = std::abs(DEREF_VAR_EVAL(n.resultat));
                n.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n);
        }

        static inline bool fct_diff(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT))
            {
                n2.resultat.var.f = std::fabs(DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat));
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var.i = std::abs(DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat));
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool fct_srand(Evaluateur::operation_tok &n)
        {
            EvalFcts::RAND_1024.srand(DEREF_VAR_EVAL(n.resultat));
            n.resultat.var.b = true;
            n.resultat.type_var = Evaluateur::TYPE_BOOL;
            return valide_resultat(n);
        }

        static inline bool fct_clamp(const Evaluateur::operation_tok &n1, const Evaluateur::operation_tok &n2, Evaluateur::operation_tok &n3)
        {
            if (n1.resultat.type_var == Evaluateur::TYPE_FLOAT)
            {
                const eval_float val = DEREF_VAR_EVAL(n1.resultat);
                const eval_float min = DEREF_VAR_EVAL(n2.resultat);
                const eval_float max = DEREF_VAR_EVAL(n3.resultat);
                n3.resultat.var.f = ((val < min) ? min : (val > max ? max : val));
            }
            else
            {
                const eval_int val = DEREF_VAR_EVAL(n1.resultat);
                const eval_int min = DEREF_VAR_EVAL(n2.resultat);
                const eval_int max = DEREF_VAR_EVAL(n3.resultat);
                n3.resultat.var.i = ((val < min) ? min : (val > max ? max : val));
                n3.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n3);
        }

        static inline bool fct_round(Evaluateur::operation_tok &n)
        {
            if (n.resultat.type_var == Evaluateur::TYPE_FLOAT)
            {
                n.resultat.var.i = static_cast<eval_int>(round(n.resultat.var.f));
                n.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n);
        }

        static inline bool fct_round0(Evaluateur::operation_tok &n)
        {
            if (n.resultat.type_var == Evaluateur::TYPE_FLOAT)
            {
                n.resultat.var.i = static_cast<eval_int>(floor(n.resultat.var.f));
                n.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n);
        }

        static inline bool fct_round1(Evaluateur::operation_tok &n)
        {
            if (n.resultat.type_var == Evaluateur::TYPE_FLOAT)
            {
                n.resultat.var.i = static_cast<eval_int>(ceil(n.resultat.var.f));
                n.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n);
        }

        static inline bool fct_exp(Evaluateur::operation_tok &n)
        {
            n.resultat.var.f = std::exp(DEREF_VAR_EVAL(n.resultat));
            n.resultat.type_var = Evaluateur::TYPE_FLOAT;
            return valide_resultat(n);
        }

        static inline bool fct_ln(Evaluateur::operation_tok &n)
        {
            const eval_float vn = DEREF_VAR_EVAL(n.resultat);
            if (vn > 0)
            {
                n.resultat.var.f = std::log(vn);
                n.resultat.type_var = Evaluateur::TYPE_FLOAT;
                return valide_resultat(n);
            }
            return false;
        }

        static inline bool fct_log10(Evaluateur::operation_tok &n)
        {
            const eval_float vn = DEREF_VAR_EVAL(n.resultat);
            if (vn > 0)
            {
                n.resultat.var.f = std::log10(DEREF_VAR_EVAL(n.resultat));
                n.resultat.type_var = Evaluateur::TYPE_FLOAT;
                return valide_resultat(n);
            }
            return false;
        }

        static inline bool fct_if(Evaluateur::operation_tok &n)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n.resultat.var.b = !(n.resultat.Nul());
            n.resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;
        }

        static inline bool fct_print(Evaluateur::operation_tok *args, const puint n_args)
        {
#ifdef DEBUG_EVAL
            const bool affiche_type = true;
#else
            const bool affiche_type = false;
#endif // DEBUG_EVAL
            std::cout << "> ";
            for(puint i=0; i<n_args; ++i)
            {
                if (i)
                    std::cout << ", ";
                if (affiche_type)
                    std::cout << args[i].resultat.encodeType() << " ";
                std::cout << args[i].resultat.encode();
            }
            std::cout << std::endl;
            return true;
        }

        /* *** Définition des mots du langage *** */

        static inline bool op_plus(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.f = DEREF_VAR_EVAL(n1.resultat) + DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var.i = DEREF_VAR_EVAL(n1.resultat) + DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool op_moins(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.f = DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var.i = DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool op_mult(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.f = DEREF_VAR_EVAL(n1.resultat) * DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
                return valide_resultat(n2);
            }
            else
            {
                n2.resultat.var.i = DEREF_VAR_EVAL(n1.resultat) * DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool op_divis(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if (n2.resultat.Nul()) /* Evite la division par 0 */
            {
                if (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)
                {
                    n2.resultat.var.f = 0.f;
                }
                else
                {
                    n2.resultat.var.i = 0;
                }
                return false;
            }

            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.f = DEREF_VAR_EVAL(n1.resultat) / DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var.i = DEREF_VAR_EVAL(n1.resultat) / DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool op_modulo(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if (n2.resultat.Nul()) /* Evite la division par 0 */
            {
                if (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)
                {
                    n2.resultat.var.f = 0.f;
                }
                else
                {
                    n2.resultat.var.i = 0;
                }
                return false;
            }

            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.f = std::fmod(DEREF_VAR_EVAL(n1.resultat), DEREF_VAR_EVAL(n2.resultat));
                n2.resultat.type_var = Evaluateur::TYPE_FLOAT;
            }
            else
            {
                n2.resultat.var.i = (static_cast<eval_int>(DEREF_VAR_EVAL(n1.resultat))) % (static_cast<eval_int>(DEREF_VAR_EVAL(n2.resultat)));
                n2.resultat.type_var = Evaluateur::TYPE_INT;
            }
            return valide_resultat(n2);
        }

        static inline bool op_eq(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.b = ( std::fabs(DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat)) < 0.00001f );
                n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            }
            else
            {
                n2.resultat.var.b = DEREF_VAR_EVAL(n1.resultat) == DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            }
            return true;
        }

        static inline bool op_neq(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            if ((n1.resultat.type_var == Evaluateur::TYPE_FLOAT) || (n2.resultat.type_var == Evaluateur::TYPE_FLOAT)) /* Calcul type float */
            {
                n2.resultat.var.b = !( std::fabs(DEREF_VAR_EVAL(n1.resultat) - DEREF_VAR_EVAL(n2.resultat)) < 0.00001f );
                n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            }
            else
            {
                n2.resultat.var.b = DEREF_VAR_EVAL(n1.resultat) != DEREF_VAR_EVAL(n2.resultat);
                n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            }
            return true;
        }

        static inline bool op_inf(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            n2.resultat.var.b = DEREF_VAR_EVAL(n1.resultat) < DEREF_VAR_EVAL(n2.resultat);
            n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;
        }

        static inline bool op_sup(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            n2.resultat.var.b = DEREF_VAR_EVAL(n1.resultat) > DEREF_VAR_EVAL(n2.resultat);
            n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;
        }

        static inline bool op_and(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n2.resultat.var.b = (!(n1.resultat.Nul())) && (!(n2.resultat.Nul()));
            n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;
        }

        static inline bool op_or(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        /* Exemple de fonction personalisée, assigne "1" si valeur non nulle. */
        {
            n2.resultat.var.b = (!(n1.resultat.Nul())) || (!(n2.resultat.Nul()));
            n2.resultat.type_var = Evaluateur::TYPE_BOOL;
            return true;
        }

        static inline bool op_inf_eq(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            operation_tok copie_args2 = n2;

            if (!op_inf(n1, n2))
            {
                return false;
            }

            if (!n2.resultat.var.b)
            {
                n2 = copie_args2;
                if (!op_eq(n1, n2))
                {
                    return false;
                }
            }
            return true;
        }

        static inline bool op_sup_eq(const Evaluateur::operation_tok &n1, Evaluateur::operation_tok &n2)
        {
            operation_tok copie_args2 = n2;

            if (!op_sup(n1, n2))
            {
                return false;
            }

            if (!n2.resultat.var.b)
            {
                n2 = copie_args2;
                if (!op_eq(n1, n2))
                {
                    return false;
                }
            }
            return true;
        }

};

inline bool est_decoration(const eval_char c)
{
//    return (c == '(') || (c == ')' || (c == ',') || (c == ';'));
    return (c == '(') || (c == ')' || (c == ';'));
}

inline bool est_commentaire(const eval_char c)
{
    return c == '#';
}

inline bool est_lettre(const eval_char c)
{
    return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ;
}

inline bool est_signe(const eval_char c)
{
    return (c == '-');
}

inline bool est_operateur(const eval_char c)
{
    return (c == '+') || (c == '-') || (c == '*') || (c == '/') || (c == '%') || (c=='^');
}

inline bool est_operateur_bool(const eval_char c)
{
    return (c == '!') || (c == '=') || (c == '<') || (c == '>') || (c == '&') || (c == '|');
}

inline bool est_chiffre(const eval_char c, bool debut=false)
{
    if (!debut && c=='.') /* Cas particulier, accepte les points si l'ont est au milieu d'un chiffre (pour les points décimaux) */
    {
        return true;
    }
//    else /* Cas particulier, accepte les signes si l'on est au début d'un chiffre */
//    {
//        if (est_signe(c))
//        {
//            return true;
//        }
//    }
    return (c >= '0') && (c <= '9');
}

inline bool est_char_deref(const eval_char c)
{
    return (c == '$');
}

inline bool est_char_tableau_ouverture(const eval_char c)
{
    return (c == '[');
}

inline bool est_char_tableau_fermeture(const eval_char c)
{
    return (c == ']');
}

inline bool est_char_tableau(const eval_char c)
{
    return (est_char_tableau_ouverture(c) || est_char_tableau_fermeture(c));
}

inline bool est_char_noms(const eval_char c, bool debut=false)
{
    if (debut) /* On refuse les chiffres en début de chaine */
    {
        return (est_lettre(c) || (c == '_'));
    }
    return (est_lettre(c) || est_chiffre(c, false) || (c == '_') || est_char_tableau(c));
}

inline string_list_t split_str(const std::string &str, eval_char separateur)
{
    string_list_t toks;
    std::size_t debut = 0, fin_mot = 0;
    while ((fin_mot = str.find(separateur, debut)) != std::string::npos)
    {
        toks.push_back(str.substr(debut, fin_mot - debut));
        debut = fin_mot + 1;
    }
    toks.push_back(str.substr(debut));
    return toks;
}

inline string_list_t split_str(const std::string &str, const char separateurs[], const pint n_separateurs)
{
    string_list_t toks;
    std::size_t debut = 0, fin_mot = 0;

    for(puint i1=0; i1<str.size(); ++i1)
    {
        bool trouve = false;
        for(pint i2=0; i2<n_separateurs; ++i2)
        {
            if (str[i1] == separateurs[i2])
            {
                trouve = true;
                fin_mot = i1;
                break;
            }
        }

        if (trouve)
        {
            toks.push_back(str.substr(debut, fin_mot - debut));
            debut = fin_mot + 1;
        }
    }
    toks.push_back(str.substr(debut));
    return toks;
}

inline std::string &remplace_str(std::string &str, const std::string &lex, const std::string &repl)
/* Remplace lex par repl dans str. */
{
    std::size_t pos = 0;
    while((pos = str.find(lex, pos)) != std::string::npos)
    {
        str.replace(pos, lex.length(), repl);
        pos += repl.length();
    }
    return str;
}

template<typename T> bool vect_remove(T &vect, pint pos, puint n=1)
{
    if ( (pos < 0) || ((pos+n) > vect.size()) )
    {
        return false;
    }

    for(pint i=(n-1); i>=0; --i)
    {
        vect.erase(vect.begin()+pos);
    }

    return true;
}

std::string EvaluateurExp::StrOperation(const operation_tok &op) const
{
    const puint domaine = DOMAINE_FCT(op.id_fonction);
    pint type_operation = TypeOperation(op.id_fonction);

    if (domaine == DOM_ASSIGNATION)
    {
        return std::string("'") + op.resultat.encodeType() + " " + op.resultat.encode(true) + "'";
    }
    else if (domaine == DOM_DEPILE)
    {
        return std::string("$") + op.resultat.encodeType() + " " + op.resultat.encode(true);
    }
    else if (type_operation != TYPE_FCT_NUL)
    {
        if (domaine == DOM_FONCTION_EXTERNE)
        {
            if (Lang_Extension)
            {
                const char *nom = Lang_Extension->NomFonction(op.id_fonction);
                if (nom)
                {
                    return std::string("'") + nom + "'";
                }
            }
            return std::string("(fct externe ?)");
        }
        else if (domaine == DOM_CONSTANTE)
        {
            const char *nom = Lang_Interne->NomFonction(op.id_fonction);
            if (nom)
            {
                return std::string(":") + nom + "";
            }
            return std::string("(const ?)");
        }
        else
        {
            const char *nom = Lang_Interne->NomFonction(op.id_fonction);
            if (nom)
            {
                return std::string("'") + nom + "'";
            }
            return std::string("(fct ?)");
        }
    }
    return std::string("?:") + EvalFcts::Itos(domaine) + ":" + EvalFcts::Itos(ID_FCT(op.id_fonction));
}

#ifdef DEBUG

void EvaluateurExp::AfficheOperations(const std::string &txt, const operations_list_t &operations) const
{
    const pint n = operations.size();

    std::string sortie(txt + "Operations( ");

    for(pint i=0; i<n; ++i)
    {
        const operation_tok &op = operations[i];
        if (i>0)
            sortie += ", ";
        sortie += StrOperation(op);
    }

    sortie += " )";
    std::cout << sortie << std::endl;
}

void EvaluateurExp::AfficheOperations(const std::string &txt, const operations_arbre_t &operations) const
{
    std::string sortie(txt + "Arbre Operations( ");

    for (operations_arbre_t::const_iterator it0=operations.begin(); it0 != operations.end(); ++it0)
    {
        const operations_list_t &liste_ops = *it0;
        const pint n2 = liste_ops.size();

        sortie += "[ ";

        for(pint i2=0; i2<n2; ++i2)
        {
            const operation_tok &op = liste_ops[i2];

            if (i2>0)
            {
                sortie += ", ";
            }

            sortie += StrOperation(op);
        }

        sortie += " ] ";
    }

    sortie += " )";
    std::cout << sortie << std::endl;
}

void EvaluateurExp::AffichePile() const
{
    std::cout << "Pile Evaluateur( ";
    for (puint i=0; i<Pile_Variables.size(); ++i)
    {
        if (i)
        {
            std::cout << ", ";
        }
        std::cout << Pile_Variables[i].encodeType() << " " << Pile_Variables[i].encode();
    }
    std::cout << " )" << std::endl;
}

void EvaluateurExp::AfficheTas() const
{
    std::cout <<"Tas Evaluateur( ";
    for (std::unordered_map<std::string, variable_tok>::const_iterator it = Tas_Variables.begin(); it != Tas_Variables.end(); ++it)
    {
        if (it != Tas_Variables.begin())
            std::cout << ",\n";
       std::cout << "[" << it->first << ":" << it->second.encode() << "]";
    }
    std::cout << " )" << std::endl;
}

#endif // DEBUG

EvaluateurExp::EvaluateurExp(DictionnaireLangage *ext) :
    CompteurErreurs(0), var_def_0()
{
    Lang_Interne = new LangageInterne;
    Lang_Extension = ext;
    CompteurErreurs = 0;
    Pile_Variables.reserve(128);
}

EvaluateurExp::~EvaluateurExp()
{
    delete Lang_Interne;
}

void EvaluateurExp::Reinit()
/* Réinitialise l'évaluateur. Toutes les variables seront supprimées. */
{
    ReinitPile();
    CompteurErreurs = 0;
    Tas_Variables.clear();
}

void EvaluateurExp::ReinitPile()
/* Réinitialise la pile des variables. */
{
    Pile_Variables.clear();
}

bool EvaluateurExp::AjoutVariable(const std::string &code)
/* Ajoute une variable de type "i=42" ou "f=0.42" */
{
    string_list_t lexs = split_str(code, '=');
    if (lexs.size() == 2)
    {
        return AssigneVal(lexs[0], lexs[1]);
    }
    return false;
}

bool EvaluateurExp::AjoutVariableBool(const std::string &variable, bool valeur)
/* Ajoute une variable de type bool */
{
    std::string copie_var = TraiteNomVariable(variable);

#ifdef DEBUG_EVAL
    std::cout << "  AjoutVariableBool(" << copie_var << ", " << valeur << ")" << std::endl;
#endif // DEBUG_EVAL

    variable_tok &var_m = Variable(copie_var, false, false);
    variable_tok var_tmp(copie_var, TYPE_BOOL, valeur);
    var_tmp.valeur.valide = true;

    if (var_m.Nul()) /* Nouvelle variable */
    {
#ifdef DEBUG_EVAL
        std::cout << "Ajout de la variable (bool) " << copie_var << " = " << valeur << std::endl;
#endif // DEBUG_EVAL

        Tas_Variables[copie_var] = var_tmp;
        return true;
    }
#ifdef DEBUG_EVAL
    std::cout << "Assignation de la variable (bool) " << " (" << var_m.encode() << ")" << " = " << valeur << std::endl;
#endif // DEBUG_EVAL
    var_m = var_tmp; /* Simple mise à jour. */
    return true;
}

bool EvaluateurExp::AjoutVariableInt(const std::string &variable, eval_int valeur)
/* Ajoute une variable de type int */
{
    std::string copie_var = TraiteNomVariable(variable);

#ifdef DEBUG_EVAL
    std::cout << "  AjoutVariableInt(" << copie_var << ", " << valeur << ")" << std::endl;
#endif // DEBUG_EVAL

    variable_tok &var_m = Variable(copie_var, false, false);
    variable_tok var_tmp(copie_var, TYPE_INT, valeur);
    var_tmp.valeur.valide = true;

    if (var_m.Nul()) /* Nouvelle variable */
    {
#ifdef DEBUG_EVAL
        std::cout << "Ajout de la variable (int) " << copie_var << " = " << valeur << std::endl;
#endif // DEBUG_EVAL

        Tas_Variables[copie_var] = var_tmp;
        return true;
    }
#ifdef DEBUG_EVAL
    std::cout << "Assignation de la variable (int) " << " (" << var_m.encode() << ")" << " = " << valeur << std::endl;
#endif // DEBUG_EVAL
    var_m = var_tmp; /* Simple mise à jour. */
    return true;
}

bool EvaluateurExp::AjoutVariableFloat(const std::string &variable, eval_float valeur)
/* Ajoute une variable de type float */
{
    std::string copie_var = TraiteNomVariable(variable);

#ifdef DEBUG_EVAL
    std::cout << "  AjoutVariableFloat(" << copie_var << ", " << valeur << ")" << std::endl;
#endif // DEBUG_EVAL

    variable_tok &var_m = Variable(copie_var, false, false);
    variable_tok var_tmp(copie_var, TYPE_FLOAT, valeur);
    var_tmp.valeur.valide = true;

    if (var_m.Nul()) /* Nouvelle variable */
    {
#ifdef DEBUG_EVAL
        std::cout << "Ajout de la variable (float) " << copie_var << " = " << valeur << std::endl;
#endif // DEBUG_EVAL

        Tas_Variables[copie_var] = var_tmp;
        return true;
    }
#ifdef DEBUG_EVAL
    std::cout << "Assignation de la variable (float) " << " (" << var_m.encode() << ")" << " = " << valeur << std::endl;
#endif // DEBUG_EVAL
    var_m = var_tmp; /* Simple mise à jour. */
    return true;
}

bool EvaluateurExp::AssigneTableau(const std::string &var, const std::string &code)
/* Assigne (si la synthaxe est valide) les valeurs du tableau pour le nom donné en argument. */
{
    const puint pos_debut_tableau = PositionCharSuivant(code, 0);
    const pint pos_fin_tableau = PositionCharPrecedent(code, code.size()-1);

    if (est_char_tableau_ouverture(code[pos_debut_tableau]) && est_char_tableau_fermeture(code[pos_fin_tableau]))
    {
#ifdef DEBUG_EVAL
        std::cout << "Ajout de tableau pour la variable " << var << " = '" << code << "'" << std::endl;
#endif // DEBUG_EVAL

        pint iter_affectations = 0;
        pint pos_affectations = pos_debut_tableau+1;

        while (true)
        {
            pint pos_affectations2 = PositionSeparateurSuivant(code, pos_affectations, true);
            if (pos_affectations2 == -1)
            {
                break;
            }

            const pint taille_affectation = pos_affectations2-pos_affectations;
            if (taille_affectation)
            {
                std::ostringstream out;
                out << iter_affectations;
                const std::string s_var = var + "[" + out.str() + "]";
                const std::string s_val = code.substr(pos_affectations, taille_affectation);

                if (AssigneVal(s_var, s_val, true))
                {
#ifdef DEBUG_EVAL
                    std::cout << "    Ajout élement tableau " << s_var << " = '" << s_val << "'" << std::endl;
#endif // DEBUG_EVAL
                    ++iter_affectations;
                }
                else
                {
#ifdef DEBUG
                    std::cout << "    AssigneTableau :: Erreur d'affectation tableau " << s_var << " = '" << s_val << "'" << std::endl;
#endif // DEBUG
                    break;
                }
            }

            pos_affectations = pos_affectations2+1;
            if (pos_affectations >= pos_fin_tableau)
            {
                break;
            }
        }
        return (iter_affectations > 0);
    }
    return false;
}

bool EvaluateurExp::AssigneVal(variable_tok &var, const std::string &code)
{
    std::string copie_code = code;

    if (!EvalLigne(copie_code, true))
    {
        return false;
    }

    var.valeur = etat_machine;

#ifdef DEBUG_EVAL
    std::cout << "Après évaluation :: " << copie_code << " :: " << var.valeur.encode() << std::endl;
#endif // DEBUG_EVAL
    return var.valeur.valide;
}

bool EvaluateurExp::AssigneVal(const std::string &var, const std::string &code, bool ignore_affectation_tableaux)
/* Assigne une variable en évaluant le code. Si elle n'existe pas, elle sera ajoutée. */
{
    std::string copie_var = TraiteNomVariable(var);

#ifdef DEBUG_EVAL
        std::cout << "  AssigneVal(" << copie_var << ", " << code << ")" << std::endl;
#endif // DEBUG_EVAL

    if (!ignore_affectation_tableaux && AssigneTableau(copie_var, code)) /* Contrôle en premier lieu si il s'agit d'un tableau... */
    {
        return true;
    }

    variable_tok &var_m = Variable(copie_var, false);

    if (var_m.Nul()) /* Nouvelle variable */
    {
#ifdef DEBUG_EVAL
        std::cout << "Ajout de la variable " << copie_var << " = " << code << std::endl;
#endif // DEBUG_EVAL

        variable_tok var_tmp(copie_var, TYPE_NUL, false);

        if (AssigneVal(var_tmp, code))
        {
//            std::cout << "Nouvelle variable : " << var_tmp.encode() << std::endl;
            Tas_Variables[copie_var] = var_tmp;
            return true;
        }
        return false;
    }
#ifdef DEBUG_EVAL
    std::cout << "Assignation de la variable " << " (" << var_m.encode() << ")" << " = " << code << std::endl;
#endif // DEBUG_EVAL
    return AssigneVal(Tas_Variables[copie_var], code);
}

bool EvaluateurExp::PermuteVals(const std::string &var1, const std::string &var2)
{
//    std::cout << "(TEST) Permutation des variables : " << var1 << " : " << var2 << std::endl;
    std::string copie_var1 = TraiteNomVariable(var1);
    std::string copie_var2 = TraiteNomVariable(var2);

    variable_tok &var_m1 = Variable(copie_var1, false, false);

    if (var_m1.Nul()) /* Variable inconnue */
    {
        return false;
    }

    variable_tok &var_m2 = Variable(copie_var2, false, false);
    if (var_m2.Nul()) /* Variable inconnue */
    {
        return false;
    }

    variable_tok copie = var_m1;
    var_m1 = var_m2;
    var_m2 = copie;

    return true;
}

bool EvaluateurExp::ValeurFloat(const std::string &var, bool evaluation_tableau, eval_float &n)
{
    const variable_tok &v = VariableConst(var, evaluation_tableau);

    if (!v.valeur.valide)
    {
        return false;
    }
    if (v.valeur.type_var == Evaluateur::TYPE_FLOAT || v.valeur.type_var == Evaluateur::TYPE_INT)
    {
        n = static_cast<eval_float>(DEREF_VAR_EVAL(v.valeur));
        return true;
    }
    return false;
}

bool EvaluateurExp::ValeurInt(const std::string &var, bool evaluation_tableau, pint &n)
{
    const variable_tok &v = VariableConst(var, evaluation_tableau);

    if (!v.valeur.valide)
    {
        return false;
    }
    if (v.valeur.type_var == Evaluateur::TYPE_FLOAT || v.valeur.type_var == Evaluateur::TYPE_INT)
    {
        n = static_cast<pint>(DEREF_VAR_EVAL(v.valeur));
        return true;
    }
    return false;
}

bool EvaluateurExp::ValeurShort(const std::string &var, bool evaluation_tableau, pshort &n)
{
    const variable_tok &v = VariableConst(var, evaluation_tableau);

    if (!v.valeur.valide)
    {
        return false;
    }
    if (v.valeur.type_var == Evaluateur::TYPE_FLOAT || v.valeur.type_var == Evaluateur::TYPE_INT)
    {
        n = static_cast<pshort>(DEREF_VAR_EVAL(v.valeur));
        return true;
    }
    return false;
}

bool EvaluateurExp::ValeurBool(const std::string &var, bool evaluation_tableau, bool &n)
{
    const variable_tok &v = VariableConst(var, evaluation_tableau);

    if (!v.valeur.valide)
    {
        return false;
    }

    if (v.valeur.type_var == Evaluateur::TYPE_BOOL || v.valeur.type_var == Evaluateur::TYPE_INT)
    {
        n = DEREF_VAR_EVAL(v.valeur) != 0;
        return true;
    }
    return false;
}

std::string EvaluateurExp::TraiteNomVariable(const std::string &nom)
/* Traite le nom d'une variable pour renvoyer le nom d'une variable d'après une expression. Par exemple (avec x=1) "tableau[ x+1 ]" -> "tableau[2]" */
{
    std::string var = nom;
    remplace_str(var, " ", "");

//    return var;

    if (PreTraiteLigne(var))
    {
#ifdef DEBUG_EVAL
        std::cout << "TraiteNomVariable :: Dé-Indexation :: " << nom << " :: " << var << std::endl;
#endif // DEBUG_EVAL
    }
    return var;
}

variable_tok &EvaluateurExp::Variable(const std::string &var, bool evaluation_tableau, bool recherche_constantes)
/* Renvoi une variable sur le tas ou une constante du langage d'après son nom. */
{
    if (!Tas_Variables.size())
    {
        var_def_0 = variable_tok();
        return var_def_0;
    }

    if (recherche_constantes)
    {
        /* Tente de voir si la variable est une constante du langage: */
        const pint id_constante = EvalFonction(var, DOM_CONSTANTE);
        if (id_constante != TYPE_FCT_NUL)
        {
//            std::cout << "Variable constante ?! " << var << " : " << ID_FCT(id_constante) << std::endl;
            if (DerefConstante(ID_FCT(id_constante), var_def_temp.valeur))
            {
                var_def_temp.valeur.valide = true;
                return var_def_temp;
            }
        }
    }

    /* Tente avec le tas... */

//    try
//    {
//        return Tas_Variables.at(evaluation_tableau ? TraiteNomVariable(var) : var);
//    }
//    catch (std::out_of_range)
//    {
//#ifdef DEBUG_EVAL
//        std::cout << "  Variable inconnue : \"" << var << "\" : taille_tas=" << Tas_Variables.size() << ", nul=" << var_def_0.Nul() << std::endl;
//        AfficheTas();
//#endif // DEBUG_EVAL
//        return var_def_0;
//    }

    type_tas::iterator it = Tas_Variables.find(evaluation_tableau ? TraiteNomVariable(var) : var);
    if (it != Tas_Variables.end())
    {
        return it->second;
    }
    var_def_0 = variable_tok();
#ifdef DEBUG_EVAL
    std::cout << "  Variable inconnue : \"" << var << "\" : taille_tas=" << Tas_Variables.size() << ", nul=" << var_def_0.Nul() << std::endl;
    AfficheTas();
#endif // DEBUG_EVAL
    return var_def_0;
}

const variable_tok &EvaluateurExp::VariableConst(const std::string &var, bool evaluation_tableau, bool recherche_constantes)
/* Renvoi une variable sur le tas ou une constante du langage d'après son nom. */
{
//    std::cout << "Variable ?! : " << var << " : evaluation_tableau=" << evaluation_tableau << " : recherche_constantes=" << recherche_constantes << std::endl;

    if (recherche_constantes)
    {
        /* Tente de voir si la variable est une constante du langage: */
        const pint id_constante = EvalFonction(var, DOM_CONSTANTE);
        if (id_constante != TYPE_FCT_NUL)
        {
//            std::cout << "Variable constante ?! " << var << " : " << ID_FCT(id_constante) << std::endl;
            if (DerefConstante(ID_FCT(id_constante), var_def_temp.valeur))
            {
                var_def_temp.valeur.valide = true;
                return var_def_temp;
            }
        }
    }

    /* Tente avec le tas... */

//    try
//    {
//        return Tas_Variables.at(evaluation_tableau ? TraiteNomVariable(var) : var);
//    }
//    catch (std::out_of_range)
//    {
//#ifdef DEBUG_EVAL
//        std::cout << "  Variable inconnue : \"" << var << "\" : taille_tas=" << Tas_Variables.size() << ", nul=" << var_def_0.Nul() << std::endl;
//        AfficheTas();
//#endif // DEBUG_EVAL
//        return var_def_0;
//    }

    type_tas::iterator it = Tas_Variables.find(evaluation_tableau ? TraiteNomVariable(var) : var);
    if (it != Tas_Variables.end())
    {
        return it->second;
    }
    var_def_0 = variable_tok();
#ifdef DEBUG_EVAL
    std::cout << "  Variable inconnue : \"" << var << "\" : taille_tas=" << Tas_Variables.size() << ", nul=" << var_def_0.Nul() << std::endl;
    AfficheTas();
#endif // DEBUG_EVAL
    return var_def_0;
}

bool EvaluateurExp::VariableExiste(const std::string &var)
{
    return !(VariableConst(var).Nul());
}

bool EvaluateurExp::Exec(const std::string &code)
/* Exécute un segment de code (peut contenir plusieurs lignes) */
{
    std::string copie_code = code;
    remplace_str(copie_code, "\t", " ");

    /* Séparation du code et création de l'arbre: */
    string_list_t lexs = split_str(code, ";\r\n", 3);

    for(puint i = 0; i<lexs.size(); ++i)
    {
        if (PreTraiteLigne(lexs[i])) /* Analyse de l'indexation des tableaux si il y en a... */
        {
        }
#ifdef DEBUG_EVAL
        std::cout << "EvalLigne :: Après pré-traitement :: " << lexs[i] << std::endl;
#endif // DEBUG_EVAL

        if (!EvalLigne(lexs[i], true))
        {
            break;
        }
    }
    return (CompteurErreurs == 0);
}

void EvaluateurExp::MessageErreur(const std::string &s)
{
    std::cerr << "Erreur Evaluation : " << s << std::endl;
    ++CompteurErreurs;
}

int EvaluateurExp::PositionCharPrecedent(const std::string &code, pint pos) const
/* Renvoi la position du caractère précédent par rapport à la position donnée en argument, tout en ignorant les espaces. Renvoi -1 en cas de résultat invalide. */
{
    if ((puint(pos) >= code.size()) || (pos < 0))
    {
        return -1;
    }
    pint iter = pos;
    for(; iter>=0; --iter)
    {
        if (code[iter] != ' ')
        {
            return iter;
        }
    }
    return -1;
}

int EvaluateurExp::PositionCharSuivant(const std::string &code, pint pos) const
/* Renvoi la position du caractère suivant par rapport à la position donnée en argument, tout en ignorant les espaces. Renvoi -1 en cas de résultat invalide. */
{
    const puint n = code.size();
    if ((puint(pos) >= n) || (pos < 0))
    {
        return -1;
    }
    puint iter = pos;
    for(; iter<n; ++iter)
    {
        if (code[iter] != ' ')
        {
            return iter;
        }
    }
    return -1;
}

int EvaluateurExp::PositionSeparateurSuivant(const std::string &code, pint pos, bool passe_interieur) const
/* Renvoi la position du caractère de séparation (espace) suivant. Renvoi -1 en cas de résultat invalide. */
{
    const puint n = code.size();
    if ((puint(pos) >= n) || (pos < 0))
    {
        return -1;
    }

    puint iter = pos;
    if (passe_interieur) // On ne prend que le contour (ignore les charactères intérieurs, même si ce sont des séparateurs).
    {
        pint compteur_ouverture_expression = 0;
        pint compteur_ouverture_tableau = 0;

        for(; iter<n; ++iter)
        {
            if (code[iter] == ' ')
            {
                if (compteur_ouverture_expression || compteur_ouverture_tableau)
                {
                    ;
                }
                else
                {
                    return iter;
                }
            }
            else if (est_char_tableau_ouverture(code[iter]))
            {
                ++compteur_ouverture_tableau;
            }
            else if (est_char_tableau_fermeture(code[iter]))
            {
                if (compteur_ouverture_tableau == 0)
                {
                    return iter;
                }
                else
                {
                    --compteur_ouverture_tableau;
                }
            }
            else if (code[iter] == '(')
            {
                ++compteur_ouverture_expression;
            }
            else if (code[iter] == ')')
            {
                if (compteur_ouverture_expression == 0)
                {
                    return iter;
                }
                else
                {
                    --compteur_ouverture_expression;
                }
            }
        }
    }
    else
    {
        for(; iter<n; ++iter)
        {
            if (code[iter] == ' ' || est_char_tableau(code[iter]))
            {
                return iter;
            }
        }
    }
    return -1;
}

int EvaluateurExp::PositionOpAffectation(const std::string &code) const
/* Renvoi la position du caractère d'affectation dans le code donné en argument, avec contrôle de la validité du code. */
{
    const puint n = code.size();
    for(puint i=1; i<n; ++i)
    {
        if (code[i] == '=')
        {
            pint pos_prec = PositionCharPrecedent(code, i-1);
            if (pos_prec != -1)
            {
                if (est_char_noms(code[pos_prec]) || est_chiffre(code[pos_prec]))
                {
                    if (i < code.size()-1)
                    {
                        pint pos_suiv = PositionCharSuivant(code, i+1);
                        if (pos_suiv != -1)
                        {
                            if ( est_char_noms(code[pos_suiv]) || est_chiffre(code[pos_suiv]) || est_decoration(code[pos_suiv]) || est_signe(code[pos_suiv]) )
                            {
                                return i;
                            }
                        }
                    }
                }
            }
        }
    }
    return -1;
}

int EvaluateurExp::PositionOpPermutation(const std::string &code) const
/* Renvoi la position de l'opération de permutation dans le code donné en argument, avec contrôle de la validité du code. */
{
    const puint n = code.size();
//    for(puint i=2; i<n; ++i)
    for(puint i=1; i<n; ++i)
    {
//        if ((code[i] == '>') && (code[i-1] == '<'))
        if ((code[i] == ':'))
        {
//            pint pos_prec = PositionCharPrecedent(code, i-2);
            pint pos_prec = PositionCharPrecedent(code, i-1);
            if (pos_prec != -1)
            {
                if (est_char_noms(code[pos_prec])) /* N'accepte la permutation qu'avec une autre variable déjà affectée. */
                {
                    if (i < code.size()-1)
                    {
                        pint pos_suiv = PositionCharSuivant(code, i+1);
                        if (pos_suiv != -1)
                        {
                            if ( est_char_noms(code[pos_suiv]) ) /* N'accepte la permutation qu'avec une autre variable déjà affectée. */
                            {
//                                return i-1;
                                return i;
                            }
                        }
                    }
                }
            }
        }
    }
    return -1;
}

bool EvaluateurExp::PreTraiteLigne(std::string &code)
/* Traitement de la ligne pour récupérer les indices de tableau. Change les expression entre [] par des entiers. */
{
//    return true;

    pint pos_depart = 0;
    pint cpt_modifs = 0;

    while (true)
    {
        bool trouve = false;
        pint pos_char_ouverture_0 = -1;
        pint pos_char_ouverture = -1;
        pint pos_char_fermeture = -1;

        const pint lg = code.size();
        for(pint i1=pos_depart; i1<lg; ++i1) /* Recherche des positions des caractères '[' et ']' dans le code. */
        {
            if (pos_char_ouverture == -1)
            {
                if (est_char_tableau_ouverture(code[i1]))
                {
                    pos_char_ouverture_0 = i1;
                    pos_char_ouverture = i1;
                }
            }
            else if (pos_char_fermeture == -1)
            {
                if (est_char_tableau_ouverture(code[i1])) /* Nouvelle ouverture ?! */
                {
                    pos_char_ouverture = i1;
                }
                else if (est_char_tableau_fermeture(code[i1]))
                {
                    pos_char_fermeture = i1;
                    trouve = true;
                    break;
                }
            }
            else /* Impossible en principe, ça break avant, mais bon... */
            {
                trouve = true;
                break;
            }
        }

        if (!trouve)
        {
            break;
        }

        /* Remplace à l'intérieur des '[' et ']' le résultat de l'évaluation. */
        std::string exp = code.substr(pos_char_ouverture+1, pos_char_fermeture-pos_char_ouverture-1);

        if (exp.size())
        {
            if (EvalLigne(exp, true))
            {
#ifdef DEBUG_EVAL
//                std::cout << "PreTraiteLigne :: Expression pour le code " << code << " :: " << exp << " :: " << etat_machine.encode() << std::endl;
#endif // DEBUG_EVAL
                code.replace(pos_char_ouverture+1, pos_char_fermeture-pos_char_ouverture-1, etat_machine.encode());
#ifdef DEBUG_EVAL
//                std::cout << "PreTraiteLigne :: Après remplacement : " << code << std::endl;
#endif // DEBUG_EVAL
                ++cpt_modifs;
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }

        if (pos_depart>=lg)
        {
            break;
        }
        pos_depart = pos_char_ouverture_0 + 1;
    }
    return cpt_modifs>0;
}

bool EvaluateurExp::EvalLigne(std::string &code, bool reinit_pile)
/* Exécute la ligne de code donnée en argument */
{
#ifdef DEBUG_EVAL
    std::cout << "EvalLigne :: Avant évaluation :: " << code << std::endl;
#endif // DEBUG_EVAL

    if (!code.size())
    {
        return true;
    }

    CompteurErreurs = 0;

    if (reinit_pile)
    {
        ReinitPile();
    }

    if (est_commentaire(code[0]))
    {
#ifdef AFFICHE_EXEC_EVAL
        std::cout << "Commentaire : " << code << std::endl;
#endif // AFFICHE_EXEC_EVAL
        return true;
    }

    pint pos_affectation = -1;
    pint pos_permutation = -1;

    if ((pos_affectation = PositionOpAffectation(code)) != -1) /* Si l'on repère un opération d'affectation... */
    {
        std::string nom_var = code.substr(0, pos_affectation);
        std::string code_aff = code.substr(pos_affectation+1, code.size());

        if (nom_var.size() && code_aff.size())
        {
            if (!AssigneVal(nom_var, code_aff))
            {
                MessageErreur(tr_exp("Problème lors de l'affectation de la variable") + " : " + nom_var);
                return false;
            }
            else
            {
                return true;
            }
        }
        else
        {
            MessageErreur(tr_exp("Erreur : Erreur affectation"));
        }
    }
    else if ((pos_permutation = PositionOpPermutation(code)) != -1) /* Si l'on repère un opération de permutation... */
    {
        std::string nom_var1 = code.substr(0, pos_permutation);
//        std::string nom_var2 = code.substr(pos_permutation+2, code.size());
        std::string nom_var2 = code.substr(pos_permutation+1, code.size());

        if (nom_var1.size() && nom_var2.size())
        {
            if (!PermuteVals(nom_var1, nom_var2))
            {
                MessageErreur(tr_exp("Problème lors de la permutation des variables") + " : " + nom_var1 + " <> " + nom_var2);
                return false;
            }
            else
            {
                return true;
            }
        }
        else
        {
            MessageErreur(tr_exp("Erreur : Erreur permutation"));
        }
    }
    else /* Aucune affectation */
    {
        operations_arbre_t arbre_operations;

        pint pos_premier_char = PositionCharSuivant(code, 0);

        /* Insertion des parenthèses englobant le bloc si elles ont été *oubliées* ... */
        if (code[pos_premier_char] != '(')
        {
            if (pos_premier_char == 0)
            {
                code.insert(code.begin(), '(');
            }
            else
            {
                code[0] = '(';
            }
            code.push_back(')');
//            std::cout << "  Modification du code : " << code << " (" << pos_premier_char << std::endl;
        }

        if (Evalcode(code, arbre_operations))
        {
#if defined(DEBUG_EVAL) && defined(AFFICHE_EXEC_EVAL)
            std::cout << "Code après évaluation :: " << code << std::endl;
            AfficheOperations("#", arbre_operations);
#endif // DEBUG_EVAL && AFFICHE_EXEC_EVAL
            if (!ExecOperations(arbre_operations))
            {
                etat_machine = val_tok();
                return false;
            }
        }
        else
        {
            etat_machine = val_tok();
            return false;
        }
    }

    if (Pile_Variables.size() == 1 && reinit_pile)
    {
        if (!DepileVal(etat_machine))
        {
            return false;
        }
    }

#ifdef DEBUG_EVAL
    std::cout << "Etat après évaluation ligne : " << etat_machine.encode(false) << ", pile=" << Pile_Variables.size() << std::endl;
#endif // DEBUG_EVAL

    return ((CompteurErreurs == 0) && (Pile_Variables.size() == 0));
}

bool EvaluateurExp::Evalcode(std::string &code, operations_arbre_t &arbre_operations)
/* Genère les opérations et les ajoutes dans l'arbre à partir du code donné en argument. */
{
    std::stack<puint> pile_blocks_ouvrant;

    operations_list_t liste_operations;

    pint profondeur_blocs = 0;

#ifdef AFFICHE_EXEC_EVAL
    std::cout << "Evalcode :: '" << code << "'" << std::endl;
#endif // AFFICHE_EXEC_EVAL

    /* Division du code en fonction des parenthèses. */
    for(puint i=0; i<code.size(); ++i)
    {
        if (code[i] == ' ')
            continue;
        if (code[i] == '(')
        {
            pile_blocks_ouvrant.push(i);
//            std::cout << "Empile ouverture du bloc : " << pile_blocks_ouvrant.top() << std::endl;
        }
        else if (code[i] == ')')
        {
            if (!pile_blocks_ouvrant.size())
            {
                MessageErreur(tr_exp("Erreur, fermeture de bloc sans ouverture."));
                return false;
            }
//            std::cout << "Fermeture de bloc !" << std::endl;

            const pint pos_parenthese_ouvrante = pile_blocks_ouvrant.top();
            const pint pos_parenthese_fermante = i;

            if (GenOperations(code, pos_parenthese_ouvrante, ((pos_parenthese_fermante-pos_parenthese_ouvrante)+1), liste_operations))
            {
                if (liste_operations.size())
                {
                    std::string remplacement_ref("$");
                    remplacement_ref += EvalFcts::Itos(Pile_Variables.size());

                    code.replace(pos_parenthese_ouvrante, ((pos_parenthese_fermante-pos_parenthese_ouvrante)+1), remplacement_ref);
                    i = pos_parenthese_ouvrante + (remplacement_ref.size() - 1);

                    if (!EmpileVal(val_tok(), true)) /* Reserve l'emplacement mémoire, la valeur sera assignée à l'exécution. */
                    {
                        return false;
                    }

#ifdef DEBUG_EVAL
                    std::cout << "Empilement ! (" << Pile_Variables.size() << ")" << std::endl;
#endif // DEBUG_EVAL

                    arbre_operations.push_back(liste_operations); /* Nouvelle branche dans l'arbre */
#ifdef DEBUG_EVAL
                    std::cout << "Code après remplacement : " << code << ", Taille pile : (" << Pile_Variables.size() << ")" << std::endl;
#endif // DEBUG_EVAL
                    liste_operations.clear();
                }
                else
                {
                    code.erase(pos_parenthese_ouvrante, ((pos_parenthese_fermante-pos_parenthese_ouvrante)+1));
                }

//                std::cout << "Depile ouverture du bloc : " << pile_blocks_ouvrant.top() << std::endl;
                pile_blocks_ouvrant.pop();
                ++profondeur_blocs;
            }
            else
            {
                return false;
            }
        }
//        else if (!pile_blocks_ouvrant.size())
//        {
//            std::string mot_suivant = MotSuivant(code, i);
//            if (GenOperations(mot_suivant, 0, mot_suivant.size(), liste_operations))
//            {
//                code.erase(i, mot_suivant.size());
////                i += 1;
////                ++profondeur_blocs;
//            }
//            else
//            {
//                return false;
//            }
//        }
    }

    if (!profondeur_blocs) /* Aucune parenthèse, on exécute le bloc entier. */
    {
        if (GenOperations(code, 0, code.size(), liste_operations))
        {
            if (liste_operations.size())
            {
                arbre_operations.push_back(liste_operations); /* Nouvelle branche dans l'arbre */
            }
            return true;
        }
        else
        {
            return false;
        }
    }
    else if (pile_blocks_ouvrant.size())
    {
        MessageErreur(tr_exp("Erreur, il y a un nombre impaire de parenthèses ouvrante/fermante") + " (" + val_tok(TYPE_INT, (eval_int) pile_blocks_ouvrant.size(), true).encode() + ")");
        return false;
    }
    return true;
}

puint EvaluateurExp::EvalFonction(const std::string &s, puint type_op) const
/* Renvoi l'identifiant de fonction pour la chaine donnée en argument. */
{
    if (Lang_Interne)
    {
        pint id_fct = Lang_Interne->IdFonctionDom(s, type_op);
        if (id_fct != -1)
        {
            return id_fct;
        }
    }

    if (Lang_Extension)
    {
        pint id_ext = Lang_Extension->IdFonction(s);
        if (id_ext != -1)
        {
            return CONCAT_INT_FCT(DOM_FONCTION_EXTERNE, id_ext);
        }
    }
    return TYPE_FCT_NUL;
}

val_tok EvaluateurExp::EvalNombre(const std::string &s) const
/* Evalue un nombre, place la valeur dans t et renvoi le type. */
{
#ifdef AFFICHE_EXEC_EVAL
    std::cout << "Conversion de nombre : " << s << std::endl;
#endif // AFFICHE_EXEC_EVAL

    val_tok t;

    std::string str = s;

    std::size_t pos_virgule = s.find('.');
    if (pos_virgule == std::string::npos)
    {
        pos_virgule = s.find(',');
    }

    if (str.find('.') != std::string::npos)
    {
        str[pos_virgule] = '.';

        try
        {
            t.var.f = EvalFcts::StoD(str);
            t.valide = true;
            t.type_var = TYPE_FLOAT;
        }
        catch (const std::invalid_argument& xc)
        {
#ifdef DEBUG_EVAL
            std::cout << "Erreur de conversion décimale : " << xc.what() << std::endl;
#endif // DEBUG_EVAL
            t.type_var = TYPE_NUL;
            t.valide = false;
            return t;
        }
#ifdef DEBUG_EVAL
        std::cout << str << " >> Après conversion (float) : " << t.encodeType() << " " << t.encode() << std::endl;
#endif // DEBUG_EVAL
    }
    else
    {
        try
        {
            t.var.i = EvalFcts::StoI(str);
            t.valide = true;
            t.type_var = TYPE_INT;
        }
        catch (const std::invalid_argument& xc)
        {
#ifdef DEBUG_EVAL
            std::cout << "Erreur de conversion entière : " << xc.what() << std::endl;
#endif // DEBUG_EVAL
            t.type_var = TYPE_NUL;
            t.valide = false;
            return t;
        }

#ifdef DEBUG_EVAL
        std::cout << str << " >> Après conversion (pint) : " << t.encodeType() << " " << t.encode() << std::endl;
#endif // DEBUG_EVAL
    }
    return t;
}

bool EvaluateurExp::DepileVal(val_tok &v)
/* Assigne dans v la dernière variable de la pile et la retire.*/
{
    if (!Pile_Variables.size())
    {
        MessageErreur("Erreur retrait de la pile.");
        return false;
    }
    v = Pile_Variables.back();
    return vect_remove(Pile_Variables, Pile_Variables.size()-1, 1);
}

bool EvaluateurExp::EmpileVal(const val_tok &v, bool init)
/* Dans le cas où il ne s'agit pas d'une initialisation, trouve le dernier emplacement mémoire non initialisé et assigne une variable dans la pile,
    sinon ajoute simplement la variable dans la pile */
{
    if (Pile_Variables.size() && !init)
    {
        for(pint i=Pile_Variables.size()-1; i>=0; --i)
        {
            val_tok &vx = Pile_Variables[i];
            if (!vx.valide)
            {
                vx = v;
                return true;
            }
        }
        MessageErreur("Erreur empilement.");
        return false;
    }

    Pile_Variables.push_back(v);
    return true;
}

std::string EvaluateurExp::MotSuivant(const std::string &code, puint position) const
/* Renvoi une référence vers le mot suivant dans le code depuis la position dans le code donné en argument,
    que ça soit une fonction, une variable ou un nombre, etc... */
{
    if (!code.size() || position >= code.size())
        return std::string();

    const eval_char c_init = code.at(position);

    if (est_decoration(c_init))
    {
        return std::string();
    }

    pint pos_suivant = PositionCharSuivant(code, position);
    if (pos_suivant == -1)
    {
        return code.substr(position, 1);
    }


//    std::cout << "Mot suivant : " << code << " (" << c_init << ")" << std::endl;

//    if (pos_prec != -1)
//        std::cout << "Position du caractère précédent : " << code.at(pos_prec) << std::endl;
//    else
//        std::cout << "Position du caractère précédent : " << pos_prec << std::endl;

    /* Cas particulier, expression -x */
    bool signe = false;
    if (est_signe(c_init) && (puint(pos_suivant) < code.size()))
    {
        if (est_char_noms(code.at(position+1), true) || est_chiffre(code.at(position+1), true))
        {
//            const pint pos_prec = PositionCharPrecedent(code, position-1);
//            if (position > 0 && pos_prec > 0)
//            {

//                std::cout << "Signe ?: " << " : " << code.substr(position, code.size()-position) << " :: " << code.at(pos_prec) << std::endl;
//                if (!est_chiffre(code.at(pos_prec), false) && !est_char_noms(code.at(pos_prec), false))
//                {
//                    signe = true;
//                }
//            }
            if (position > 0)
            {
//                std::cout << "Signe ?: " << " : " << code.substr(position, code.size()-position) << std::endl;

                if (!est_chiffre(code.at(position-1), false) && !est_char_noms(code.at(position-1), false))
                {
                    signe = true;
                }
            }
            else
            {
                signe = true;
            }
        }
    }

    if (est_operateur_bool(c_init))
    {
        if ((position+1 < code.size()) && (code.at(position+1) == '=')) /* Cas particulier '==', '!=', etc... */
        {
            return code.substr(position, 2);
        }
        return code.substr(position, 1);
    }

    if (est_operateur(c_init) && !signe)
    {
        return code.substr(position, 1);
    }

    pint type = -1;
    if (est_chiffre(c_init, true) || signe)
    {
        type = 0;
    }
    else if (est_char_noms(c_init, true))
    {
        type = 1;
    }
    else if (est_char_deref(c_init)) /* Un déréférencement sur la pile commence par un caractère $ et est suivie d'un nombre */
    {
        type = 0;
    }
    else
    {
        return std::string(); /* Tous les caractères ne pouvant définir un mot ou une valeur seront ignorés. */
    }

    puint fin_s = -1;
    for(fin_s = position+1; fin_s<code.size(); ++fin_s)
    {
        const eval_char c = code.at(fin_s);

        if (type == 1)
        {
            if (!est_char_noms(c))
            {
                break;
            }
        }
        else if (type == 0)
        {
            if (!est_chiffre(c))
            {
                break;
            }
        }
    }

    if (fin_s > position)
    {
//        return fin_s + 1;
        return code.substr(position, (fin_s-position));
    }

//    MessageErreur(tr("Erreurs lors de la récupération d'un mot : ") + code);
    return std::string();
}

bool EvaluateurExp::OperationTok(puint id_op, operations_list_t &operations)
/* Effectue l'opération d'après la source. Le coeur du langage est ici. */
{
    if (id_op >= operations.size())
    {
        MessageErreur("Erreur, Exécution d'opération en dehors du flot !");
        return false;
    }

    const pint n_parametres_max = 24;
    operation_tok arguments[n_parametres_max];
    operation_tok &op = operations[id_op];

    const puint domaine_fonction = DOMAINE_FCT(op.id_fonction);
    const bool externe = (domaine_fonction == DOM_FONCTION_EXTERNE);

    if (externe && !Lang_Extension)
    {
        MessageErreur("Appel d'une fonction externe sans instance pour gérer l'appel.");
        return false;
    }

    const puint type_operation = TypeOperation(op.id_fonction);

    if ((domaine_fonction == DOM_NUL) || (type_operation == TYPE_FCT_NUL)) /* Fonction indéfinie ?! */
    {
        MessageErreur("Fonction indéfinie.");
        return false;
    }

    if (domaine_fonction == DOM_DEPILE)
    {
        MessageErreur("Exécution d'une opération de dépilement à la place d'une expression, il y a sans doute un décalage dans le flot d'exécution.");
        return false;
    }

    if (domaine_fonction == DOM_CONSTANTE) /* Assignation d'une constante */
    {
        MessageErreur("Exécution d'une constante à la place d'une expression, il y a sans doute un décalage dans le flot d'exécution.");
        return false;
    }

    if (type_operation == OPERATEUR_0 || type_operation == OPERATEUR_1 || type_operation == OPERATEUR_2) /* Exécution d'un opérateur. */
    {
        if (domaine_fonction == DOM_ASSIGNATION)
        {
            ; /* On touche à rien dans ce cas (toutefois cette fonction ne devrait pas avoir été appelée dans ce cas) ! */
        }
        else
        {
            if (((id_op == 0) || id_op == (operations.size()-1))) /* Contrôle le débordement dans le cas particulier des opérateurs */
            {
#if defined(DEBUG_EVAL) && defined(AFFICHE_EXEC_EVAL)
                std::cout << "Tentative d'utilisation d'un opérateur sur un bord !" << " :: " << id_op << "/" << operations.size()-1 << " : " << StrOperation(op) << std::endl;
                AfficheOperations("OperationTok", operations);
#endif // DEBUG_EVAL && AFFICHE_EXEC_EVAL

                MessageErreur("Tentative d'utilisation d'un opérateur sur un bord.");
                return false;
            }

            if ((DOMAINE_FCT_OP(operations[id_op-1]) == DOM_ASSIGNATION) && (DOMAINE_FCT_OP(operations[id_op+1]) == DOM_ASSIGNATION))
            {
                arguments[0] = operations[id_op-1];
                arguments[1] = operations[id_op+1];

                //std::cout << "Arguments : " << DEREF_VAR_EVAL(arguments[0].resultat) << " : " << DEREF_VAR_EVAL(arguments[1].resultat) << std::endl;

                if (externe)
                {
                    if (!Lang_Extension->Exec(op.id_fonction, arguments, 2))
                    {
                        MessageErreur(tr_exp("Erreur lors de l'exécution de l'opérateur") + " " + StrOperation(op));
                        return false;
                    }
                }
                else
                {
                    if (!Lang_Interne->Exec(op.id_fonction, arguments, 2)) /* Exécute la fonction */
                    {
                        MessageErreur(tr_exp("Erreur lors de l'exécution de l'opérateur interne") + " " + StrOperation(op));
                        return false;
                    }
                }

                /* Le résultat devient une assignation. */
                operations[id_op+1] = arguments[1];
                etat_machine = operations[id_op+1].resultat;

//                std::cout << "  Nouvel état après opération : " << etat_machine.encode() << std::endl;

                /* On supprime les références aux opérandes utilisée, l'opérande de fin a pris la valeur du résultat. */
                vect_remove(operations, id_op);
                vect_remove(operations, id_op-1);
                return true;
            }
            else
            {
                MessageErreur(tr_exp("Erreur lors de l'analyse des arguments") + " " + tr_exp("(opérateur)") + " " + StrOperation(operations[id_op-1]) + " : " + StrOperation(operations[id_op+1]) + ")");
                return false;
            }
        }
    }
    else if (type_operation == FONCTION)
    {
        pint nb_params = NombreOperandes(op.id_fonction);
        pint nombre_parametres = -1; /* Nombre de paramètres après contrôle, si vaut toujours -1, on a une erreur. */

        if (nb_params == -1) /* Fonction avec un nombre dynamique de paramètres. */
        {
            pint n_params_tmp = -1;
            const pint n_ops = operations.size();
            for(pint i=(id_op+1); i<n_ops; ++i)
            {
                const puint dom = DOMAINE_FCT(operations[i].id_fonction);
//                std::cout << "  Test domaine fonction dynamique : " << StrOperation(operations[i]) << " (" << dom << ")" << std::endl;
                if (dom != DOM_ASSIGNATION && dom != DOM_DEPILE && dom != DOM_CONSTANTE)
                    break;
                n_params_tmp = i;
            }

            if (n_params_tmp != -1)
            {
                nombre_parametres = n_params_tmp;
            }
            else
            {
                ;
            }

#ifdef DEBUG_EVAL
            std::cout << "FCT_X_PARAMS " << StrOperation(operations[id_op]) << " : " << nombre_parametres << std::endl;
#endif // DEBUG_EVAL
        }
        else /* Nombre déterminé de paramètres */
        {
            if (nb_params == 0)
            {
                nombre_parametres = 0;
            }
            else /* Contrôle des paramètres, ils doivent tous être des assignations. */
            {
                if (signed(operations.size()-1-id_op) < (nb_params))
                {
                    MessageErreur(tr_exp("Erreur, pas assez d'arguments dans l'appel de fonction") + " (" + EvalFcts::Itos(operations.size()-id_op-1) + "/" + EvalFcts::Itos(nb_params) + ").");
                    return false;
                }

                const pint iter_op = id_op + 1;
                for(pint i=0; i<nb_params; ++i)
                {
                    if (DOMAINE_FCT_OP(operations[iter_op+i]) != DOM_ASSIGNATION)
                    {
                        MessageErreur(tr_exp("Erreur lors de l'analyse des arguments") + " (" + EvalFcts::Itos(i) + "/" + EvalFcts::Itos(nb_params) + ")." );
                        return false;
                    }
                }
                /* Tous les paramètres sont des assignations, on peut exécuter la fonction ! */
                nombre_parametres = nb_params;
            }
        }

        /* Lance l'exécution */
        if (nombre_parametres == -1)
        {
            MessageErreur(tr_exp("Erreur lors de l'analyse des arguments (indéfini)."));
            return false;
        }

        if (nombre_parametres == 0)
        {
            /* Exécution */
            if (externe)
            {
                if (!Lang_Extension->Exec(op.id_fonction, arguments, nombre_parametres))
                {
                    MessageErreur(tr_exp("Erreur lors de l'exécution de la fonction (extension)") + " " + StrOperation(op));
                    etat_machine = val_tok(TYPE_BOOL, eval_types_t(false), false);
                    return false;
                }
            }
            else
            {
                if (!Lang_Interne->Exec(op.id_fonction, arguments, nombre_parametres))
                {
                    MessageErreur(tr_exp("Erreur lors de l'exécution de la fonction") + " " + StrOperation(op));
                    etat_machine = val_tok(TYPE_BOOL, eval_types_t(false), false);
                    return false;
                }
            }

            etat_machine = val_tok(TYPE_BOOL, eval_types_t(true), true);
            vect_remove(operations, id_op, 1);
            return true;
        }
        else
        {
            if (nombre_parametres >= n_parametres_max)
            {
                MessageErreur(tr_exp("Dépassement du nombre de paramètres pour l'appel de fonction") + " " + StrOperation(op));
                return false;
            }

            for(pint i_p=0; i_p<nombre_parametres; ++i_p) /* Récupération des paramètres. */
            {
                arguments[i_p] = operations[id_op+i_p+1];
            }

            /* Exécution */
            if (externe)
            {
                if (!Lang_Extension->Exec(op.id_fonction, arguments, nombre_parametres))
                {
                    MessageErreur(tr_exp("Erreur lors de l'exécution de la fonction") + " " + StrOperation(op));
                    return false;
                }
            }
            else
            {
                if (!Lang_Interne->Exec(op.id_fonction, arguments, nombre_parametres))
                {
                    MessageErreur(tr_exp("Erreur lors de l'exécution de la fonction") + " " + StrOperation(op));
                    return false;
                }
            }

            /* Assignation de la valeur dans le paramètre de fin, les autres seront supprimés de la chaine d'opération. */
            operations[id_op+nombre_parametres] = arguments[nombre_parametres-1];
            etat_machine = operations[id_op+nombre_parametres].resultat;
            vect_remove(operations, id_op, nombre_parametres);
            return true;
        }
    }

    MessageErreur(tr_exp("Erreur indéfinie"));
    return false;
}

bool EvaluateurExp::ExecOperations(operations_arbre_t &arbre_operations)
/* Exécute l'arbre des opérations générés par EvalCode() */
{
    etat_machine = val_tok();

    for (operations_arbre_t::iterator it=arbre_operations.begin(); it != arbre_operations.end(); ++it)
    {
        operations_list_t &operations = *it;

        /* Exécute les opérations (prioritée opératoire haute): */
        if (!ExecOperationsTok(operations, OPERATEUR_0))
        {
            return false;
        }

        if (operations.size() == 0) /* Plus rien à exécuter. */
        {
            continue;
        }

        if (operations.size() == 1 && DOMAINE_FCT(operations[0].id_fonction) == DOM_ASSIGNATION)
        {
            if (!EmpileVal(operations[0].resultat))
                return false;
        }
        else
        {
            /* Effectue les opérations (prioritée moyenne): */
            if (!ExecOperationsTok(operations, OPERATEUR_1))
            {
                return false;
            }

            if (operations.size() == 0) /* Plus rien à exécuter. */
            {
                continue;
            }

            if (operations.size() == 1 && DOMAINE_FCT(operations[0].id_fonction) == DOM_ASSIGNATION)
            {
                if (!EmpileVal(operations[0].resultat))
                    return false;
            }
            else
            {
                /* Effectue les opérations (prioritée basse): */
                if (!ExecOperationsTok(operations, OPERATEUR_2))
                {
                    return false;
                }

                if (operations.size() == 0) /* Plus rien à exécuter. */
                {
                    continue;
                }

                if (operations.size() == 1 && DOMAINE_FCT(operations[0].id_fonction) == DOM_ASSIGNATION)
                {
                    if (!EmpileVal(operations[0].resultat))
                        return false;
                }
                else /* Au moins une des opérations n'a pas été exécutée... */
                {
                    return false;
                }
            }
        }
    }
    return true;
}

puint EvaluateurExp::TypeOperation(puint id_fonction) const
{
    return (DOMAINE_FCT(id_fonction) == DOM_FONCTION_EXTERNE) ?
                (Lang_Extension ? Lang_Extension->TypeFonction(id_fonction) : TYPE_FCT_NUL) :
                Lang_Interne->TypeFonction(id_fonction);
}


int EvaluateurExp::NombreOperandes(puint id_fonction) const
/* Renvoi le nombre d'opérandes nécessaires pour la fonction donnée en argument. */
{
    return (DOMAINE_FCT(id_fonction) == DOM_FONCTION_EXTERNE) ?
                (Lang_Extension ? Lang_Extension->NombreParametresFonction(id_fonction) : TYPE_FCT_NUL) :
                Lang_Interne->NombreParametresFonction(id_fonction);
}

bool EvaluateurExp::ExecOperationsTok(operations_list_t &operations, pint niveau_priorite_operatoire)
/* Exécute les opérations, le vecteur d'opérations sera vidé au fur et à mesure de l'exécution */
{
#if defined(DEBUG_EVAL) && defined(AFFICHE_EXEC_EVAL)
    std::cout << "Exécution des opérations :: ";
    AfficheOperations("#", operations);
#endif // DEBUG_EVAL && AFFICHE_EXEC_EVAL

    /* Converti les opérations de dépilement et constantes en assignation */
    const puint n_ops_init = operations.size();
    for(puint i1=0; i1<n_ops_init; ++i1)
    {
        operation_tok &op = operations[i1];

        const puint domaine_operation = DOMAINE_FCT(op.id_fonction);

        if (domaine_operation == DOM_DEPILE) /* Converti une opération de dépilement en assignation et dépile la valeur. */
        {
            if (!DepileVal(op.resultat))
            {
                MessageErreur(tr_exp("Erreur lors du retrait d'une valeur de la pile."));
                return false;
            }
#ifdef DEBUG_EVAL
            std::cout << "Dépilement : " << op.resultat.encode() << std::endl;
#endif // DEBUG_EVAL

            op.id_fonction = ID_FCT_ASSIGNATION;
//            etat_machine = op.resultat;
        }
        else if (domaine_operation == DOM_CONSTANTE)
        {
#ifdef DEBUG_EVAL
            std::string copie_op = StrOperation(op);
#endif // DEBUG_EVAL
            if (!Lang_Interne->Exec(op.id_fonction, &op, 1))
            {
                MessageErreur(tr_exp("Erreur lors de l'assignation de la constante") + " " + StrOperation(op));
                return false;
            }

//            etat_machine = op.resultat;

#ifdef DEBUG_EVAL
            std::cout << "Assignation de la constante : " << copie_op << " -> " << op.resultat.encode() << std::endl;
#endif // DEBUG_EVAL
        }
    }

    /* Exécution des opérations: */
    while (true)
    {
        bool trouve_op = false;

        for(pint i1=operations.size()-1; i1>=0; --i1)
        {
            const operation_tok &op = operations[i1];
            const puint domaine_operation = DOMAINE_FCT(op.id_fonction);

            if (domaine_operation == DOM_ASSIGNATION || domaine_operation == DOM_DEPILE)
            {
                etat_machine = op.resultat;
                continue;
            }

            const pint type_operation = TypeOperation(op.id_fonction);
            if (type_operation == TYPE_FCT_NUL)
                return false;

            if (niveau_priorite_operatoire == OPERATEUR_0)
            {
                if (type_operation == OPERATEUR_2 || type_operation == OPERATEUR_1) /* Passe les fonctions de prioritée basse */
                {
                    continue;
                }
            }
            else if (niveau_priorite_operatoire == OPERATEUR_1)
            {

                if (type_operation == OPERATEUR_2) /* Passe les fonctions de prioritée basse */
                {
                    continue;
                }
            }

            /* La fonction supprimera au fur et à mesure les opérations après leur exécution, donc le vecteur se videra, ce qui arrêtera la boucle ! */
            if (!OperationTok(i1, operations))
            {
#ifdef DEBUG_EVAL
                std::cout << "Erreur OperationTok :: " << i1 << " (" << StrOperation(op) << ")" << std::endl;
#endif // DEBUG_EVAL
                MessageErreur("Erreur lors de l'exécution de l'opération : " + StrOperation(op));
                return false;
            }
            trouve_op = true;
        }

        if (!trouve_op) /* Plus rien à exécuter... */
            break;
    }

#ifdef DEBUG_EVAL
    std::cout << "Etat après exécution : " << etat_machine.encodeType() << " " << etat_machine.encode() << std::endl;
#endif // DEBUG_EVAL
    return true;
}

bool EvaluateurExp::GenOperations(std::string &code, puint pos1, puint lg_tok, operations_list_t &operations)
/* Ajoute les opérations du fragments de code donné en argument. */
{
    if (pos1+lg_tok > code.size())
        return false;

//    puint taille_op_debut = operations.size();
    std::string tok = code.substr(pos1, lg_tok);

    /* Division du sous-élement en mots et recherche des opérations (opérateurs et appels de fonction): */
    for(puint i=0; i<tok.size(); )
    {
        std::string mot = MotSuivant(tok, i);

//        std::cout << "Mot : " << mot << std::endl;

        if (mot.size())
        {
            i += mot.size();

            const eval_char char_mot_debut = mot[0];

            if (est_decoration(char_mot_debut))
            {
                continue;
            }
            else if (est_char_deref(char_mot_debut) && mot.size() > 1)
            {
                std::string addr = mot.substr(1, mot.size()-1);
                val_tok n_addr = EvalNombre(addr);

                if (!(n_addr.type_var == TYPE_INT))
                {
                    MessageErreur(tr_exp("Erreur analyse de l'identifiant de pile") + " : " + mot);
                    return false;
                }

                if (n_addr.var.i >= eval_int(Pile_Variables.size()))
                {
                    MessageErreur(tr_exp("Erreur analyse de l'identifiant de pile (débordement)") + " : "  + mot  + " (" + EvalFcts::Itos(n_addr.var.i) + "/" + EvalFcts::Itos(Pile_Variables.size()) + ")");
                    return false;
                }

                operations.push_back(operation_tok(ID_FCT_DEPILE));
                operations.back().resultat = val_tok(TYPE_REF, static_cast<eval_int>(Pile_Variables.size()-1), true);
            }
            else if (est_char_noms(char_mot_debut, true))
            {
                puint fct = EvalFonction(mot, DOM_FONCTION_INTERNE);
                if (fct == TYPE_FCT_NUL)
                {
                    fct = EvalFonction(mot, DOM_FONCTION_EXTERNE);
                }
                if (fct == TYPE_FCT_NUL)
                {
                    fct = EvalFonction(mot, DOM_CONSTANTE);
                }

                if (fct != TYPE_FCT_NUL)
                {
                    operations.push_back(operation_tok(fct));
                }
                else /* Ca ne correspond pas à une fonction, on cherche parmis les variables. */
                {
                    const variable_tok &var_m = Variable(mot, false);

                    if (var_m.Nul())
                    {
                        /* Erreur, ça n'est ni une fonction, ni une variable */
                        MessageErreur(tr_exp("Erreur, aucune fonction ou variable avec un tel nom") + " : '" + mot + "'");
//#ifdef DEBUG
//                        AfficheTas();
//#endif // DEBUG
                        return false;
                    }
                    else /* On assigne la valeur de la variable. */
                    {
                        operations.push_back( operation_tok(ID_FCT_ASSIGNATION) );
                        operations.back().resultat = var_m.valeur;
                    }
                }
            }
            else if (est_operateur(char_mot_debut) && (mot.size() == 1))
                /* Obligatoirement avant le contrôle des chiffres pour éviter les de confondre un opérateur et le symbole négatif ! */
            {
                puint fct = EvalFonction(mot, DOM_OPERATEUR);

                if (fct != TYPE_FCT_NUL)
                {
                    operations.push_back(operation_tok(fct));
                }
                else
                {
                    MessageErreur(tr_exp("Expression inconnue (opérateur)") + " : " + mot);
                    return false;
                }
            }
            else if (est_operateur_bool(char_mot_debut) && (mot.size() == 2 || mot.size() == 1))
            {
                puint fct = EvalFonction(mot, DOM_OPERATEUR_BOOL);

                if (fct != TYPE_FCT_NUL)
                {
                    operations.push_back(operation_tok(fct));
                }
                else
                {
                    MessageErreur(tr_exp("Opérateur booléen inconnu") + " : " + mot);
                    return false;
                }
            }
            else if (est_chiffre(char_mot_debut, true) || est_signe(char_mot_debut))
            {
                /* On ne se soucie pas des chiffres ici, ce sont les opérateurs et fonctions qui les utiliseront. */
//                continue;

                val_tok val = EvalNombre(mot);

//                std::cout << "Chiffre val(" << mot << ") = " << val.encodeType() << " " << val.encode() << std::endl;

                if (val.valide)
                {
                    operations.push_back( operation_tok(ID_FCT_ASSIGNATION) );
                    operations.back().resultat = val;
                }
                else
                {
                    MessageErreur(tr_exp("Erreur lors de l'analyse du nombre") + " : '" + mot + "'");
                    return false;
                }
            }
            else
            {
                MessageErreur(tr_exp("Expression inconnue") + " : '" + mot + "'");
            }
        }
        else
        {
            ++i;
        }
    }

#ifdef AFFICHE_EXEC_EVAL
    std::cout << "Opérations pour le code " << code << " :\n";
    AfficheOperations("     Operations> ", operations);
#endif // AFFICHE_EXEC_EVAL

    return true;
}
