/* Chrysalide - Outil d'analyse de fichiers binaires
 * args.c - gestion des arguments dans leur ensemble
 *
 * Copyright (C) 2015 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  OpenIDA is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  OpenIDA is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "args.h"


#include <assert.h>
#include <malloc.h>
#include <string.h>


#include "conv.h"
#include "helpers.h"



/*
#include <assert.h>
#include <ctype.h>

#include <regex.h>
#include <stdbool.h>
#include <sys/param.h>


*/




/* Types d'expressions représentés */
typedef enum _ConvExprType
{
    CET_NAME,                               /* Désignation de variable     */
    CET_NUMBER,                             /* Valeur codée en dur         */
    CET_COMPOSED,                           /* Agrégat de champs divers    */
    CET_UNARY,                              /* Opération unaire            */
    CET_BINARY,                             /* Opération binaire           */

    CET_COUNT

} ConvExprType;


/* Représentation d'une expression de conversion */
struct _arg_expr_t
{
    ConvExprType type;

    bool declared;                          /* Expression déjà déclarée ?  */
    bool defined;                           /* Expression déjà définie ?   */

    union
    {
        /* CET_NAME */
        char *name;                         /* Désignation de variable     */

        /* CET_NUMBER */
        unsigned long number;               /* Valeur durablement définie  */

        /* CET_COMPOSED */
        struct
        {
            char **comp_items;              /* Elements à agréger          */
            size_t comp_count;              /* Quantité de ces éléments    */
        };

        /* CET_UNARY */
        struct
        {
            arg_expr_t *un_expr;            /* Expression à traiter        */
            ConvUnaryOperation un_op;       /* Type d'opération à mener    */

        };

        /* CET_BINARY */
        struct
        {
            arg_expr_t *bin_expr1;          /* Expression à traiter        */
            arg_expr_t *bin_expr2;          /* Expression à traiter        */
            ConvBinaryOperation bin_op;     /* Type d'opération à mener    */

        };

    };

};


/* Visite une expression en traitant en premier ses composantes. */
typedef bool (* visit_expr_fc) (arg_expr_t *, int, const coding_bits *, const conv_list *, void *);

/* Visite une expression en traitant en premier ses composantes. */
static bool visit_arg_expr(arg_expr_t *, visit_expr_fc, int, const coding_bits *, const conv_list *, void *);

/* Retrouve si elle existe une variable manipulée. */
static bool find_var_by_name(const coding_bits *, const conv_list *, const char *, raw_bitfield **, conv_func **);



/* ----------------------- MANIPULATION DE LISTES D'ARGUMENTS ----------------------- */


/* Liste d'expressions utilisées en arguments de conversion */
struct _arg_list_t
{
    arg_expr_t **items;                     /* Liste d'expressions         */
    size_t count;                           /* Taille de cette liste       */

};



/* ---------------------------------------------------------------------------------- */
/*                            REPRESENTATION D'UN ARGUMENT                            */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : name = désignation d'une variable quelconque.                *
*                                                                             *
*  Description : Référence une variable en tant qu'expression de conversion.  *
*                                                                             *
*  Retour      : Nouvelle expression mise en place.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *build_arg_expr_from_name(char *name)
{
    arg_expr_t *result;                     /* Structure à retourner       */

    result = (arg_expr_t *)calloc(1, sizeof(arg_expr_t));

    result->type = CET_NAME;

    result->name = make_string_lower(name);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : number = valeur à conserver dans sa forme brute.             *
*                                                                             *
*  Description : Conserve une valeur en tant qu'expression de conversion.     *
*                                                                             *
*  Retour      : Nouvelle expression mise en place.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *build_arg_expr_from_number(unsigned long number)
{
    arg_expr_t *result;                     /* Structure à retourner       */

    result = (arg_expr_t *)calloc(1, sizeof(arg_expr_t));

    result->type = CET_NUMBER;

    result->number = number;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : item1 = premier élément à agréger.                           *
*                item2 = second élément à agréger.                            *
*                                                                             *
*  Description : Construit une base d'expression de conversion composée.      *
*                                                                             *
*  Retour      : Nouvelle expression mise en place.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *build_composed_arg_expr(char *item1, char *item2)
{
    arg_expr_t *result;                     /* Structure à retourner       */

    result = (arg_expr_t *)calloc(1, sizeof(arg_expr_t));

    result->type = CET_COMPOSED;

    result->comp_items = (char **)calloc(2, sizeof(char *));
    result->comp_count = 2;

    result->comp_items[0] = make_string_lower(item1);
    result->comp_items[1] = make_string_lower(item2);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = expression déjà en place à compléter.                 *
*                item = nouvel élément à agréger.                             *
*                                                                             *
*  Description : Etend une base d'expression de conversion composée.          *
*                                                                             *
*  Retour      : Expression en place et mise à jour.                          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *extend_composed_arg_expr(arg_expr_t *expr, char *item)
{
    assert(expr->type == CET_COMPOSED);

    expr->comp_items = (char **)realloc(expr->comp_items, ++expr->comp_count * sizeof(char *));

    expr->comp_items[expr->comp_count - 1] = make_string_lower(item);

    return expr;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = expression à encapsuler.                              *
*                op   = opération unaire à associer à l'opération.            *
*                                                                             *
*  Description : Traduit une opération unaire sur expression de conversion.   *
*                                                                             *
*  Retour      : Nouvelle expression mise en place.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *build_unary_arg_expr(arg_expr_t *expr, ConvUnaryOperation op)
{
    arg_expr_t *result;                     /* Structure à retourner       */

    result = (arg_expr_t *)calloc(1, sizeof(arg_expr_t));

    result->type = CET_UNARY;

    result->un_expr = expr;
    result->un_op = op;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr1 = première expression à encapsuler.                    *
*                expr2 = seconde expression à encapsuler.                     *
*                op    = opération binaire à associer à l'opération.          *
*                                                                             *
*  Description : Traduit une opération binaire sur expression de conversion.  *
*                                                                             *
*  Retour      : Nouvelle expression mise en place.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_expr_t *build_binary_arg_expr(arg_expr_t *expr1, arg_expr_t *expr2, ConvBinaryOperation op)
{
    arg_expr_t *result;                    /* Structure à retourner       */

    result = (arg_expr_t *)calloc(1, sizeof(arg_expr_t));

    result->type = CET_BINARY;

    result->bin_expr1 = expr1;
    result->bin_expr2 = expr2;
    result->bin_op = op;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = expression à libérer de la mémoire.                   *
*                                                                             *
*  Description : Supprime tous les éléments mis en place pour un argument.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void delete_arg_expr(arg_expr_t *expr)
{
    size_t i;                               /* Boucle de parcours          */

    switch (expr->type)
    {
        case CET_NAME:
            free(expr->name);
            break;

        case CET_COMPOSED:
            for (i = 0; i < expr->comp_count; i++)
                free(expr->comp_items[i]);
            free(expr->comp_items);
            break;

        case CET_UNARY:
            delete_arg_expr(expr->un_expr);
            break;

        case CET_BINARY:
            delete_arg_expr(expr->bin_expr1);
            delete_arg_expr(expr->bin_expr2);
            break;

        default:
            break;

    }

    free(expr);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à consulter.                      *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                size = taille déterminée avec précision. [OUT]               *
*                                                                             *
*  Description : Détermine la taille en bits d'une expression donnée.         *
*                                                                             *
*  Retour      : true si la taille a pu être déterminée, false sinon.         *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool compute_arg_expr_size(const arg_expr_t *expr, const coding_bits *bits, const conv_list *list, unsigned int *size)
{
    bool result;                            /* Bilan à retourner           */
    raw_bitfield *field;                    /* Eventuel champ brut associé */
    conv_func *func;                        /* Eventuelle fonction liée    */
    size_t i;                               /* Boucle de parcours          */
    unsigned int tmp;                       /* Stockage temporaire         */

    switch (expr->type)
    {
        case CET_NAME:

            result = find_var_by_name(bits, list, expr->name, &field, &func);

            if (result)
            {
                if (field != NULL)
                    *size = get_raw_bitfield_length(field);
                else
                    result = compute_conv_func_size(func, bits, list, size);
            }

            break;

        case CET_COMPOSED:

            result = true;
            *size = 0;

            for (i = 0; i < expr->comp_count && result; i++)
            {
                if (isdigit(expr->comp_items[i][0]))
                    *size += strlen(expr->comp_items[i]);

                else
                {
                    if (!find_var_by_name(bits, list, expr->comp_items[i], &field, &func))
                        result = false;

                    else
                    {
                        if (field != NULL)
                            *size += get_raw_bitfield_length(field);
                        else
                        {
                            result = compute_conv_func_size(func, bits, list, &tmp);
                            *size += tmp;
                        }
                    }

                }

            }

            break;

        case CET_UNARY:
            result = compute_arg_expr_size(expr->un_expr, bits, list, size);
            break;

        case CET_BINARY:

            result = compute_arg_expr_size(expr->bin_expr1, bits, list, &tmp);

            if (result)
                result = compute_arg_expr_size(expr->bin_expr1, bits, list, size);

            if (tmp > *size) *size = tmp;

            break;

        default:
            result = false;
            break;

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à encapsuler.                     *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                data = éventuelle donnée à transmettre à chaque visite.      *
*                                                                             *
*  Description : Visite une expression en traitant en premier ses composantes.*
*                                                                             *
*  Retour      : Bilan des traitements effectués.                             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit, int fd, const coding_bits *bits, const conv_list *list, void *data)
{
    bool result;                            /* Bilan à retourner           */

    switch (expr->type)
    {
        case CET_UNARY:
            result = visit_arg_expr(expr->un_expr, visit, fd, bits, list, data);
            break;

        case CET_BINARY:
            result = visit_arg_expr(expr->bin_expr1, visit, fd, bits, list, data);
            result = visit_arg_expr(expr->bin_expr2, visit, fd, bits, list, data);
            break;

        default:
            result = true;
            break;

    }

    result &= visit(expr, fd, bits, list, data);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : bits  = gestionnaire des bits d'encodage.                    *
*                list  = liste de l'ensemble des fonctions de conversion.     *
*                name  = déssignation de la variable recherchée.              *
*                field = éventuel élement brut de décodage.                   *
*                func  = éventuelle fonction de conversion pour intermédiaire.*
*                                                                             *
*  Description : Retrouve si elle existe une variable manipulée.              *
*                                                                             *
*  Retour      : Bilan des recherches : trouvaille ou non ?                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool find_var_by_name(const coding_bits *bits, const conv_list *list, const char *name, raw_bitfield **field, conv_func **func)
{
    bool result;                            /* Bilan à retourner           */
    raw_bitfield *cached_field;             /* Champ, version cachée       */
    conv_func *cached_func;                 /* Fonction, version cachée    */

    cached_field = find_named_field_in_bits(bits, name);
    result = (cached_field != NULL);

    if (!result)
    {
        cached_func = find_named_conv_in_list(list, name);
        result = (cached_func != NULL);
    }
    else
        cached_func = NULL;

    if (field != NULL) *field = cached_field;
    if (func != NULL) *func = cached_func;

    if (!result)
        fprintf(stderr, "Variable '%s' not found!\n", name);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à encapsuler.                     *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                                                                             *
*  Description : S'assure du marquage des expressions pre-requises.           *
*                                                                             *
*  Retour      : Bilan des traitements effectués.                             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *bits, const conv_list *list)
{
    bool mark_sub_expr(arg_expr_t *sub, int dummy, const coding_bits *bts, const conv_list *lst, void *unused)
    {
        bool result;                        /* Bilan à retourner           */
        size_t i;                           /* Boucle de parcours          */

        bool mark_by_name(const coding_bits *_bts, const conv_list *_lst, const char *name)
        {
            bool found;                     /* Bilan d'opération à renvoyer*/
            raw_bitfield *field;            /* Eventuel champ brut associé */
            conv_func *func;                /* Eventuelle fonction liée    */

            found = find_var_by_name(bts, lst, name, &field, &func);

            if (found)
            {
                if (field != NULL)
                    mark_raw_bitfield_as_used(field);
                else /*if (func != NULL) */
                    mark_conv_func(func, bts, lst);

                printf(" VAR '%s' found (bf=%d  fc=%d)\n", name, !!field, !!func);


            }
            else printf(" VAR '%s' not found...\n", name);

            return found;

        }

        /* Il est uniquement nécessaire de s'attacher aux références */
        switch (sub->type)
        {
            case CET_NAME:
                result = mark_by_name(bits, lst, sub->name);
                break;

            case CET_COMPOSED:
                result = true;
                for (i = 0; i < sub->comp_count && result; i++)
                    if (!isdigit(sub->comp_items[i][0]))
                        result = mark_by_name(bits, lst, sub->comp_items[i]);
                break;

            default:
                result = true;
                break;

        }

        return result;

    }

    return visit_arg_expr(expr, (visit_expr_fc)mark_sub_expr, -1, bits, list, NULL);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à encapsuler.                     *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                arch = architecture visée par l'opération globale.           *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                wide = taille des mots décodés.                              *
*                                                                             *
*  Description : S'assure de la déclaration des expressions pre-requises.     *
*                                                                             *
*  Retour      : Bilan des traitements effectués.                             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide)
{
    bool declare_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, unsigned int *wide)
    {
        bool result;                        /* Bilan à retourner           */
        size_t i;                           /* Boucle de parcours          */

        /* Si l'expression a déjà été définie lors d'un précédent besoin... */
        printf("  sub declared ? %d  --  type = %d\n", sub->declared, sub->type);
        if (sub->declared) return true;

        bool declare_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, unsigned int _wide, const char *name)
        {
            bool found;                     /* Bilan d'opération à renvoyer*/
            conv_func *func;                /* Eventuelle fonction liée    */

            found = find_var_by_name(bts, lst, name, NULL, &func);

            if (found && func != NULL)
            {
                printf("========= DECLARE for '%s'\n", name);
                found = declare_conv_func(func, _f, _bts, _lst, _wide);
                printf("========= END DECLARE for '%s'\n", name);

                /**
                 * Si on déclare les variables suivantes dans declare_conv_func(),
                 * elles seront également déclarées pour les fonctions de conversion
                 * racine à partir de declare_syntax_items(), ce qui ne convient pas
                 * car les appels racine servent directement d'arguments.
                 */

                if (is_conv_func_expression(func))
                    dprintf(_f, "\t\tuint%u_t val_%s; // Ho\n", _wide, name);
                else
                    dprintf(_f, "\t\tGArchOperand *val_%s;;;;;\n", name);

            }

            return found;

        }

        /* Il est uniquement nécessaire de s'attacher aux références */
        switch (sub->type)
        {
            case CET_NAME:
                result = declare_by_name(f, bits, lst, *wide, sub->name);
                break;

            case CET_COMPOSED:
                result = true;
                for (i = 0; i < sub->comp_count && result; i++)
                    if (!isdigit(sub->comp_items[i][0]))
                        printf("... trying to declare... '%s'\n", sub->comp_items[i]);
                for (i = 0; i < sub->comp_count && result; i++)
                    if (!isdigit(sub->comp_items[i][0]))
                        result = declare_by_name(f, bits, lst, *wide, sub->comp_items[i]);
                break;

            default:
                result = true;
                break;

        }

        sub->declared = result;

        return result;

    }

    return visit_arg_expr(expr, (visit_expr_fc)declare_sub_expr, fd, bits, list, &wide);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à encapsuler.                     *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                arch = architecture visée par l'opération globale.           *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                pp   = pré-processeur pour les échanges de chaînes.          *
*                                                                             *
*  Description : S'assure de la définition des expressions pre-requises.      *
*                                                                             *
*  Retour      : Bilan des traitements effectués.                             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp)
{
    typedef struct _def_info
    {
        const char *arch;
        const pre_processor *pp;

    } def_info;

    def_info info;                          /* Transmissions au visiteur   */

    bool define_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, def_info *info)
    {
        bool result;                        /* Bilan à retourner           */
        size_t i;                           /* Boucle de parcours          */

        /* Si l'expression a déjà été définie lors d'un précédent besoin... */
        if (sub->defined) return true;

        bool define_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, def_info *_info, const char *name)
        {
            bool found;                     /* Bilan d'opération à renvoyer*/
            conv_func *func;                /* Eventuelle fonction liée    */

            found = find_var_by_name(bts, lst, name, NULL, &func);

            if (found && func != NULL)
                found = define_conv_func(func, false, false, _f, _info->arch, _bts, _lst, _info->pp);

            return found;

        }

        /* Il est uniquement nécessaire de s'attacher aux références */
        switch (sub->type)
        {
            case CET_NAME:
                result = define_by_name(f, bits, lst, info, sub->name);
                break;

            case CET_COMPOSED:
                result = true;
                for (i = 0; i < sub->comp_count && result; i++)
                    if (!isdigit(sub->comp_items[i][0]))
                        result = define_by_name(f, bits, lst, info, sub->comp_items[i]);
                break;

            default:
                result = true;
                break;

        }

        sub->defined = result;

        return result;

    }

    info.arch = arch;
    info.pp = pp;

    return visit_arg_expr(expr, (visit_expr_fc)define_sub_expr, fd, bits, list, &info);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = première expression à encapsuler.                     *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                                                                             *
*  Description : Définit une expression utilisée dans une conversion.         *
*                                                                             *
*  Retour      : Bilan des traitements effectués.                             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list)
{
    bool result;                            /* Bilan à retourner           */
    raw_bitfield *field;                    /* Eventuel champ brut associé */
    conv_func *func;                        /* Eventuelle fonction liée    */
    unsigned int max_size;                  /* Quantité de bits totale     */
    size_t i;                               /* Boucle de parcours          */
    const char *cname;                      /* Raccourci de confort        */
    unsigned int used_size;                 /* Quantité de bits utilisée   */

    result = true;

    switch (expr->type)
    {
        case CET_NAME:

            if (!find_var_by_name(bits, list, expr->name, &field, &func))
                result = false;

            else
            {
                if (field != NULL)
                    dprintf(fd, "raw_%s", expr->name);
                else
                    dprintf(fd, "val_%s", expr->name);
            }

            break;

        case CET_NUMBER:
            dprintf(fd, "%lu", expr->number);
            break;

        case CET_COMPOSED:

            result = compute_arg_expr_size(expr, bits, list, &max_size);

            printf("MAX SIZE :: %u\n", max_size);

            for (i = 0; i < expr->comp_count && result; i++)
            {
                cname = expr->comp_items[i];

                if (i > 0)
                    dprintf(fd, " | ");

                /* Constante binaire ? */
                if (isdigit(cname[0]))
                {
                    max_size -= strlen(cname);

                    if (max_size == 0)
                        dprintf(fd, "b%s", cname);
                    else
                        dprintf(fd, "b%s << %u", cname, max_size);

                }

                /* Ou variable définie ? */
                else
                {
                    result = find_var_by_name(bits, list, cname, &field, &func);

                    if (result)
                    {
                        if (field != NULL)
                            used_size = get_raw_bitfield_length(field);
                        else
                            /*result = */compute_conv_func_size(func, bits, list, &used_size);

                        max_size -= used_size;

                        if (field != NULL)
                        {
                            if (max_size == 0)
                                dprintf(fd, "raw_%s", cname);
                            else
                                dprintf(fd, "raw_%s << %u", cname, max_size);
                        }
                        else
                        {
                            if (max_size == 0)
                                dprintf(fd, "val_%s", cname);
                            else
                                dprintf(fd, "val_%s << %u", cname, max_size);
                        }

                    }

                }

            }

            break;

        case CET_UNARY:

            switch (expr->un_op)
            {
                case CUO_NOT:
                    dprintf(fd, "!");
                    break;
                default:
                    result = false;
                    break;
            }

            result &= define_arg_expr(expr->un_expr, fd, bits, list);

            break;

        case CET_BINARY:

            dprintf(fd, "(");

            result = define_arg_expr(expr->bin_expr1, fd, bits, list);

            switch (expr->bin_op)
            {
                case CBO_EOR:
                    dprintf(fd, " ^ ");
                    break;
                default:
                    result = false;
                    break;
            }

            result &= define_arg_expr(expr->bin_expr2, fd, bits, list);

            dprintf(fd, ")");

            break;

        default:
            result = false;
            break;

    }

    return result;

}



/* ---------------------------------------------------------------------------------- */
/*                         MANIPULATION DE LISTES D'ARGUMENTS                         */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : expr = expression initial pour constituer une liste.         *
*                                                                             *
*  Description : Crée une liste d'arguments de conversion.                    *
*                                                                             *
*  Retour      : Nouvelle structure mise en place.                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_list_t *build_arg_list(arg_expr_t *expr)
{
    arg_list_t *result;                     /* Structure à retourner       */

    result = (arg_list_t *)calloc(1, sizeof(arg_list_t));

    result->items = (arg_expr_t **)calloc(1, sizeof(arg_expr_t *));
    result->count = 1;

    result->items[0] = expr;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : list = liste d'expressions à supprimer de la mémoire.        *
*                                                                             *
*  Description : Libère la mémoire occupée par une liste d'expressions.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void delete_arg_list(arg_list_t *list)
{
    size_t i;                               /* Boucle de parcours          */

    for (i = 0; i < list->count; i++)
        delete_arg_expr(list->items[i]);

    if (list->items != NULL)
        free(list->items);

    free(list);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : list = liste d'expressions à supprimer de la mémoire. [OUT]  *
*                expr = expression à ajouter à la liste courante.             *
*                                                                             *
*  Description : Ajoute un élément à une liste d'arguments de conversion.     *
*                                                                             *
*  Retour      : Structure en place mise à jour.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

arg_list_t *extend_arg_list(arg_list_t *list, arg_expr_t *expr)
{
    list->items = (arg_expr_t **)realloc(list->items, ++list->count * sizeof(arg_expr_t *));

    list->items[list->count - 1] = expr;

    return list;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : args = liste d'expressions à supprimer de la mémoire.        *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                                                                             *
*  Description : S'assure du marquage des expressions pre-requises.           *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_list_content_fully_marked(arg_list_t *args, const coding_bits *bits, const conv_list *list)
{
    bool result;                            /* Bilan à remonter            */
    size_t i;                               /* Boucle de parcours          */

    result = true;

    for (i = 0; i < args->count && result; i++)
        result = ensure_arg_expr_content_fully_marked(args->items[i], bits, list);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : args = liste d'expressions à supprimer de la mémoire.        *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                wide = taille des mots décodés.                              *
*                                                                             *
*  Description : S'assure de la déclaration des expressions pre-requises.     *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide)
{
    bool result;                            /* Bilan à remonter            */
    size_t i;                               /* Boucle de parcours          */

    result = true;

    for (i = 0; i < args->count && result; i++)
        result = ensure_arg_expr_content_fully_declared(args->items[i], fd, bits, list, wide);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : args = liste d'expressions à supprimer de la mémoire.        *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                arch = architecture visée par l'opération globale.           *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                pp   = pré-processeur pour les échanges de chaînes.          *
*                                                                             *
*  Description : S'assure de la définition des expressions pre-requises.      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp)
{
    bool result;                            /* Bilan à remonter            */
    size_t i;                               /* Boucle de parcours          */

    result = true;

    for (i = 0; i < args->count && result; i++)
        result = ensure_arg_expr_content_fully_defined(args->items[i], fd, arch, bits, list, pp);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : args = liste d'expressions à supprimer de la mémoire.        *
*                fd   = descripteur d'un flux ouvert en écriture.             *
*                bits = gestionnaire des bits d'encodage.                     *
*                list = liste de l'ensemble des fonctions de conversion.      *
*                                                                             *
*  Description : Définit les variables associées à un appel de fonction.      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool define_arg_list(const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list)
{
    bool result;                            /* Bilan à remonter            */
    size_t i;                               /* Boucle de parcours          */

    result = true;

    for (i = 0; i < args->count && result; i++)
    {
        if (i > 0) dprintf(fd, ", ");
        result = define_arg_expr(args->items[i], fd, bits, list);
    }

    return result;

}