/* Chrysalide - Outil d'analyse de fichiers binaires
 * abi.c - décodage des noms d'éléments selon l'ABI C++ Itanium
 *
 * Copyright (C) 2013-2017 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide 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.
 *
 *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "abi.h"


#include <ctype.h>
#include <stdlib.h>



#include "../../analysis/types/basic.h"
#include "../../common/cpp.h"



/* Liste des opérateurs reconnus */

#define IDT_NL(s) s, sizeof(s) - 1

const itanium_operator_info itanium_demangle_operators[] = {

    { "aN", IDT_NL("&="),               2 },
    { "aS", IDT_NL("="),                2 },
    { "aa", IDT_NL("&&"),               2 },
    { "ad", IDT_NL("&"),                1 },
    { "an", IDT_NL("&"),                2 },
    { "at", IDT_NL("alignof "),         1 },
    { "az", IDT_NL("alignof "),         1 },
    { "cc", IDT_NL("const_cast"),       2 },
    { "cl", IDT_NL("()"),               2 },
    { "cm", IDT_NL(","),                2 },
    { "co", IDT_NL("~"),                1 },
    { "dV", IDT_NL("/="),               2 },
    { "da", IDT_NL("delete[] "),        1 },
    { "dc", IDT_NL("dynamic_cast"),     2 },
    { "de", IDT_NL("*"),                1 },
    { "dl", IDT_NL("delete "),          1 },
    { "ds", IDT_NL(".*"),               2 },
    { "dt", IDT_NL("."),                2 },
    { "dv", IDT_NL("/"),                2 },
    { "eO", IDT_NL("^="),               2 },
    { "eo", IDT_NL("^"),                2 },
    { "eq", IDT_NL("=="),               2 },
    { "ge", IDT_NL(">="),               2 },
    { "gs", IDT_NL("::"),	            1 },
    { "gt", IDT_NL(">"),                2 },
    { "ix", IDT_NL("[]"),               2 },
    { "lS", IDT_NL("<<="),              2 },
    { "le", IDT_NL("<="),               2 },
    { "li", IDT_NL("operator\"\" "),    1 },
    { "ls", IDT_NL("<<"),               2 },
    { "lt", IDT_NL("<"),                2 },
    { "mI", IDT_NL("-="),               2 },
    { "mL", IDT_NL("*="),               2 },
    { "mi", IDT_NL("-"),                2 },
    { "ml", IDT_NL("*"),                2 },
    { "mm", IDT_NL("--"),               1 },
    { "na", IDT_NL("new[]"),            3 },
    { "ne", IDT_NL("!="),               2 },
    { "ng", IDT_NL("-"),                1 },
    { "nt", IDT_NL("!"),                1 },
    { "nw", IDT_NL("new"),              3 },
    { "oR", IDT_NL("|="),               2 },
    { "oo", IDT_NL("||"),               2 },
    { "or", IDT_NL("|"),                2 },
    { "pL", IDT_NL("+="),               2 },
    { "pl", IDT_NL("+"),                2 },
    { "pm", IDT_NL("->*"),              2 },
    { "pp", IDT_NL("++"),               1 },
    { "ps", IDT_NL("+"),                1 },
    { "pt", IDT_NL("->"),               2 },
    { "qu", IDT_NL("?"),                3 },
    { "rM", IDT_NL("%="),               2 },
    { "rS", IDT_NL(">>="),              2 },
    { "rc", IDT_NL("reinterpret_cast"), 2 },
    { "rm", IDT_NL("%"),                2 },
    { "rs", IDT_NL(">>"),               2 },
    { "sc", IDT_NL("static_cast"),      2 },
    { "st", IDT_NL("sizeof "),          1 },
    { "sz", IDT_NL("sizeof "),          1 },
    { "tr", IDT_NL("throw"),            0 },
    { "tw", IDT_NL("throw "),           1 }
};

/* Substitutions standards */

typedef struct _itanium_std_subst_info
{
    char code;                              /* Identifiant associé         */

    const char *simple;                     /* Représentation simple       */
    size_t simple_len;                      /* Taille de cette représentat°*/

    const char *full;                       /* Représentation complète     */
    size_t full_len;                        /* Taille de cette représentat°*/

    const char *last_name;                  /* Pour les (con|de)structeurs */
    size_t last_name_len;                   /* Taille de cette indication  */

} itanium_std_subst_info;

const itanium_std_subst_info itanium_standard_substitutions[] = {

    {
        't',
        IDT_NL("std"),
        IDT_NL("std"),
        NULL,
        0
    },
    {
        'a',
        IDT_NL("std::allocator"),
        IDT_NL("std::allocator"),
        IDT_NL("allocator")
    },
    {
        'b',
        IDT_NL("std::basic_string"),
        IDT_NL("std::basic_string"),
        IDT_NL("basic_string")
    },
    {
        's',
        IDT_NL("std::string"),
        IDT_NL("std::basic_string<char, std::char_traits<char>, std::allocator<char>>"),
        IDT_NL("basic_string")
    },
    {
        'i',
        IDT_NL("std::istream"),
        IDT_NL("std::basic_istream<char, std::char_traits<char>>"),
        IDT_NL("basic_istream")
    },
    {
        'o',
        IDT_NL("std::ostream"),
        IDT_NL("std::basic_ostream<char, std::char_traits<char>>"),
        IDT_NL("basic_ostream")
    },
    {
        'd',
        IDT_NL("std::iostream"),
        IDT_NL("std::basic_iostream<char, std::char_traits<char>>"),
        IDT_NL("basic_iostream")
    }

};



/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_encoding(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unscoped_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unscoped_template_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_nested_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_prefix(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_prefix(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unqualified_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_source_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static bool itd_number(GItaniumDContext *, ssize_t *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_identifier(GItaniumDContext *, size_t);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_operator_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_special_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_call_offset(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_nv_offset(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_v_offset(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_ctor_dtor_name(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_type(GItaniumDContext *);

/* Extrait une propriété de composant pour un contexte Itanium. */
static TypeQualifier itd_cv_qualifiers(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_builtin_type(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_bare_function_type(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_class_enum_type(GItaniumDContext *);



/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_args(GItaniumDContext *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_arg(GItaniumDContext *);



/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_value_to_string(GItaniumDContext *, bool);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_expr_primary(GItaniumDContext *);




/* Extrait un composant dans un contexte Itanium. */
static bool itd_seq_id(GItaniumDContext *, char, size_t *);

/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_substitution(GItaniumDContext *);






#define itd_template_param(ctx) NULL


#define itd_local_name(ctx) NULL




#define itd_expression(ctx) NULL




/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

itanium_component *itd_mangled_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */

    /**
     * La règle traitée ici est la suivante :
     *
     * <mangled-name> ::= _Z <encoding>
     *
     */

    if (!g_itanium_dcontext_check_char(context, '_'))
        return NULL;

    if (!g_itanium_dcontext_check_char(context, 'Z'))
        return NULL;

    result = itd_encoding(context);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_encoding(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *func;                /* Composant 'function name'   */
    itanium_component *types;               /* Composant 'bare-function...'*/

    /**
     * La règle traitée ici est la suivante :
     *
     * <encoding> ::= <function name> <bare-function-type>
     *            ::= <data name>
     *            ::= <special-name>
     *
     */

    result = NULL;
    g_itanium_dcontext_push_state(context, &saved);

    func = itd_name(context);

    if (func != NULL)
    {
        types = itd_bare_function_type(context);

        if (types != NULL)
            result = itd_make_binary(context, ICT_FUNCTION_ENCODING, func, types);
        else
            itd_unref_comp(func);

    }
    /*
    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_name(context);
    }
    */
    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_special_name(context);
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *tname;               /* Composant '...template-name'*/
    itanium_component *targs;               /* Composant 'template-args'   */

    /**
     * La règle traitée ici est la suivante :
     *
     * <name> ::= <nested-name>
     *        ::= <unscoped-name>
     *        ::= <unscoped-template-name> <template-args>
     *        ::= <local-name>
     *
     */

    g_itanium_dcontext_push_state(context, &saved);

    result = itd_nested_name(context);

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);

        tname = itd_unscoped_template_name(context);

        if (tname != NULL)
        {
            targs = itd_template_args(context);

            if (targs != NULL)
            {
                g_itanium_dcontext_add_substitution(context, tname);
                result = itd_make_binary(context, ICT_TEMPLATE_NAME_ARGS, tname, targs);
            }

            else
                itd_unref_comp(tname);

        }

    }

    /**
     * La règle <unscoped-name> doit être traitée après <unscoped-template-name>,
     * car ces deux dernières ont une base commune et la seconde peut avoir besoin
     * d'aller plus loin avec la règle <template-args>.
     *
     * On termine donc par moins gourmand si la règle la plus complexe n'a pas abouti.
     */

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_unscoped_name(context);
    }

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_local_name(context);
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_unscoped_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */

    /**
     * La règle traitée ici est la suivante :
     *
     * <unscoped-name> ::= <unqualified-name>
     *                 ::= St <unqualified-name>   # ::std::
     *
     */


    /* TODO : 'St' */


    result = itd_unqualified_name(context);


    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_unscoped_template_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <unscoped-template-name> ::= <unscoped-name>
     *                          ::= <substitution>
     *
     */

    g_itanium_dcontext_push_state(context, &saved);

    result = itd_unscoped_name(context);

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_substitution(context);
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_nested_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    TypeQualifier qualifier;                /* Propriétés supplémentaires  */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *left;                /* Première partie             */
    itanium_component *right;               /* Seconde partie              */

    static int inner = 0;

    int val = inner++;

    printf("\n ### (%d) NESTED>> '%s'\n", val,
           g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

    /**
     * La règle traitée ici est la suivante :
     *
     * <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
     *               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
     *
     */

    if (!g_itanium_dcontext_check_char(context, 'N'))
        return NULL;

    qualifier = itd_cv_qualifiers(context);

    result = NULL;

    g_itanium_dcontext_push_state(context, &saved);


    printf("\n ----- (%d) nested prefix '%s'\n", val, g_itanium_dcontext_get_string(context, (size_t []){ 0 }));



    left = itd_prefix(context);

    if (left != NULL)
    {
        if (itd_get_component_type(left) != ICT_EMPTY)
            g_itanium_dcontext_add_substitution(context, left);

        right = itd_unqualified_name(context);

        if (right != NULL)
        {
            if (g_itanium_dcontext_check_char(context, 'E'))
                result = itd_make_binary(context, ICT_NESTED_NAME, left, right);
            else
                printf("=== (%d) nested/prefix : BAD E\n\n", val);

            //result = itd_make_binary(context, ICT_NESTED_NAME, left, right);

        }
        else
            itd_unref_comp(left);

        printf(" ---- (%d) nested prefix --> %p\n\n", val, result);

    }


    if (result == NULL)
    {
        printf("\n ----- (%d) nested template_arg '%s'\n", val, g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

        g_itanium_dcontext_pop_state(context, &saved);

        left = itd_template_prefix(context);

        if (left != NULL)
        {
            g_itanium_dcontext_add_substitution(context, left);

            right = itd_template_args(context);

            if (right != NULL)
            {
                if (g_itanium_dcontext_check_char(context, 'E'))
                    result = itd_make_binary(context, ICT_NESTED_NAME, left, right);
                else
                    printf("=== (%d) nested/prefix : BAD E\n\n", val);
            }
            else
                itd_unref_comp(left);

        }

        printf(" ---- (%d) nested template_arg --> %p\n\n", val, result);

    }



    printf("(%d)   nested/E >> '%s'\n", val, g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

    /*
    if (!g_itanium_dcontext_check_char(context, 'E'))
    {
        printf("=== (%d) NESTED : BAD E\n\n", val);

        if (result != NULL)
            itd_unref_comp(result);
        return NULL;
    }
    */

    if (result != NULL)
    printf("=== (%d) NESTED OK (%p)\n\n", val, result);

    inner--;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_prefix(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itanium_component *looping_rule;        /* Extraction d'une boucle     */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *left;                /* Première partie             */
    itanium_component *right;               /* Seconde partie              */

    itd_state next_name_saved;              /* Position d'analyse courante */
    itanium_component *next_name;           /* Eventuel complément #1      */
    itd_state next_targs_saved;             /* Position d'analyse courante */
    itanium_component *next_targs;          /* Eventuel complément #2      */



    itd_state expected_saved;               /* Position d'analyse suivante */
    itanium_component *expected;            /* Nom non-qualifié en réserve */



    /**
     * Les deux règles traitées ici sont les suivantes :
     *
     * <prefix> ::= <prefix> <unqualified-name>
     *          ::= <template-prefix> <template-args>
     *          ::= <template-param>
     *          ::= # empty
     *          ::= <substitution>
     *
     * <template-prefix> ::= <prefix> <template unqualified-name>
     *                   ::= <template-param>
     *                   ::= <substitution>
     *
     * Pour éviter une récursivité qui ferait exploser la pile, on les fusionne
     * en une nouvelle règle <prefix> étendue :
     *
     * <prefix> ::= <prefix> <unqualified-name>
     *          ::= <prefix> <unqualified-name> <template-args>
     *          ::= <template-param> <template-args>
     *          ::= <substitution> <template-args>
     *          ::= <template-param>
     *          ::= # empty
     *          ::= <substitution>
     *
     * On découpe ainsi les traitements en deux parties :
     *  - extraction du socle non récursif.
     *  - extraction éventuelle d'un complément <unqualified-name> [<template-args>]
     */

    result = NULL;

    while (1)
    {
        printf("loop....\n");

        looping_rule = NULL;

        /**
         * Première partie.
         */

        g_itanium_dcontext_push_state(context, &saved);

        /* <template-param> <template-args> */

        left = itd_template_param(context);

        if (left != NULL)
        {
            g_itanium_dcontext_add_substitution(context, left);

            right = itd_template_args(context);

            if (right != NULL)
                looping_rule = itd_make_binary(context, ICT_PREFIX_BINARY, left, right);
            else
                itd_unref_comp(left);

        }

        /* <substitution> <template-args> */

        if (looping_rule != NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved);

            left = itd_substitution(context);

            if (left != NULL)
            {
                right = itd_template_args(context);

                if (right != NULL)
                    looping_rule = itd_make_binary(context, ICT_PREFIX_BINARY, left, right);
                else
                    itd_unref_comp(left);

            }

        }

        /* <template-param> */

        if (looping_rule == NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved);
            looping_rule = itd_template_param(context);
        }

        /* <substitution> */

        if (looping_rule == NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved);
            looping_rule = itd_substitution(context);
        }

        printf("looping_rule = %p\n", looping_rule);

        if (looping_rule != NULL)
        {
            if (result == NULL)
                result = looping_rule;
            else
                result = itd_make_binary(context, ICT_PREFIX_BINARY, result, looping_rule);
        }

        /**
         * Seconde partie (1/3) : recherche d'un éventuel complément.
         */

        if (looping_rule == NULL)
            g_itanium_dcontext_pop_state(context, &saved);

        /* <unqualified-name> */

        g_itanium_dcontext_push_state(context, &next_name_saved);

        next_name = itd_unqualified_name(context);

        if (next_name == NULL)
        {
            /**
             * Si on n'obtient pas de <unqualified-name> ici, rien ne sert de
             * continuer. On se dirige donc vers la sortie avec ce que l'on a.
             */

            return NULL;

            break;

        }

        /* <template-args> */

        g_itanium_dcontext_push_state(context, &next_targs_saved);

        next_targs = itd_template_args(context);

        g_itanium_dcontext_pop_state(context, &next_targs_saved);

        /**
         * Seconde partie (2/3) : validation de la présence d'un jeton
         * <unqualified-name> en réserve pour la règle <nested-name> parente.
         */

        g_itanium_dcontext_push_state(context, &expected_saved);

        expected = itd_unqualified_name(context);

        if (expected == NULL)
        {
            /**
             * La lecture a été trop loin ici.
             *
             * Le dernier <unqualified-name> valide pour la règle parente est
             * donc celui lu à une fin de recherche de complément.
             *
             * On revient donc à ce stade avant de se diriger vers la sortie.
             */

            itd_unref_comp(next_name);

            if (next_targs != NULL)
                itd_unref_comp(next_targs);

            g_itanium_dcontext_pop_state(context, &next_name_saved);

            break;

        }

        g_itanium_dcontext_pop_state(context, &expected_saved);

        /**
         * Seconde partie (3/3) : pleine inscription des composants extraits.
         *
         * On s'est manifestement retrouvé dans un des deux cas suivants :
         * - <prefix> ::= <prefix> <unqualified-name>
         * - <prefix> ::= <prefix> <template unqualified-name> <template-args>
         *
         * Or <prefix> est un candidat pour des substitutions futures, donc on
         * procède à son enregistrement, s'il n'est pas nul.
         */

        if (result != NULL)
            g_itanium_dcontext_add_substitution(context, result);

        printf("result = %p  -  next_name = %p\n", result, next_name);


        if (result == NULL)
            result = next_name;
        else
            result = itd_make_binary(context, ICT_PREFIX_BINARY, result, next_name);

        if (next_targs != NULL)
            result = itd_make_binary(context, ICT_PREFIX_BINARY, result, next_targs);


        printf(" > result = %p\n", result);

    }

    if (result == NULL)
        result = itd_make_empty(context);
    /*
    if (itd_get_component_type(result) != ICT_PREFIX_BINARY)
        result = itd_make_unary(context, ICT_PREFIX_UNARY, result);
    */
    //printf("<prefix> : %p\n", result);

    printf("### FIN DE PREFIX ### '%s'\n",
           g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_template_prefix(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *prefix;              /* Premier d'un couple de comp.*/
    itanium_component *name;                /* Second d'un couple de comp. */

    /**
     * La règle traitée ici est la suivante :
     *
     * <template-prefix> ::= <prefix> <template unqualified-name>
     *                   ::= <template-param>
     *                   ::= <substitution>
     *
     */

    result = NULL;
    g_itanium_dcontext_push_state(context, &saved);

    prefix = itd_prefix(context);

    if (prefix != NULL)
    {
        name = itd_unqualified_name(context);

        if (name != NULL)
            result = itd_make_binary(context, ICT_TPREFIX_BINARY, prefix, name);
        else
            itd_unref_comp(prefix);

    }

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_template_param(context);
    }

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_substitution(context);
    }

    if (result != NULL && itd_get_component_type(result) != ICT_TPREFIX_BINARY)
        result = itd_make_unary(context, ICT_TPREFIX_UNARY, result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_unqualified_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <unqualified-name> ::= <operator-name>
     *                    ::= <ctor-dtor-name>
     *                    ::= <source-name>
     *
     */

    g_itanium_dcontext_push_state(context, &saved);

    result = itd_operator_name(context);

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_ctor_dtor_name(context);
    }

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_source_name(context);
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_source_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    ssize_t number;                         /* Taille positive             */

    /**
     * La règle traitée ici est la suivante :
     *
     * <source-name> ::= <positive length number> <identifier>
     *
     */

    if (!itd_number(context, &number))
        return NULL;

    if (number <= 0)
        return NULL;

    result = itd_identifier(context, number);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                size    = taille positive ou non lue. [OUT]                  *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Bilan de l'opération (un chifre lu au moins).                *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool itd_number(GItaniumDContext *context, ssize_t *size)
{
    bool result;                            /* Validité à renvoyer         */
    bool negative;                          /* Taille négative ?           */
    char peek;                              /* Prochain caractère lu       */

    /**
     * La règle traitée ici est la suivante :
     *
     * <number> ::= [n] <non-negative decimal integer>
     *
     */

    result = false;

    negative = false;

    peek = g_itanium_dcontext_peek_char(context);

    if (peek == 'n')
    {
        negative = true;
        g_itanium_dcontext_advance(context, 1);
        peek = g_itanium_dcontext_peek_char(context);
    }

    *size = 0;

    while (isdigit(peek))
    {
        result = true;
        *size = *size * 10 + peek - '0';
        g_itanium_dcontext_advance(context, 1);
        peek = g_itanium_dcontext_peek_char(context);
    }

    if (negative)
        *size *= -1;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                length  = taille de l'identifiant à retrouver.               *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_identifier(GItaniumDContext *context, size_t length)
{
    itanium_component *result;              /* Construction à retourner    */
    const char *data;                       /* Données restantes           */
    size_t remaining;                       /* Quantité d'octets           */

    /**
     * La règle traitée ici est la suivante :
     *
     * <identifier> ::= <unqualified source code identifier>
     *
     */

    data = g_itanium_dcontext_get_string(context, &remaining);

    if (length > remaining)
        return NULL;

    result = itd_make_name(context, data, length);

    if (result != NULL)
        g_itanium_dcontext_advance(context, length);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_operator_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    char code[2];                           /* Code à venir lire           */
    itanium_operator_info info;             /* Clef des informations       */
    itanium_operator_info *found;           /* Informations complètes      */

    /**
     * La règle traitée ici est la suivante :
     *
     * <operator-name> ::= nw    # new           
     *                 ::= na    # new[]
     *                 ::= dl    # delete        
     *                 ::= da    # delete[]      
     *                 ::= ps    # + (unary)
     *                 ::= ng    # - (unary)     
     *                 ::= ad    # & (unary)     
     *                 ::= de    # * (unary)     
     *                 ::= co    # ~             
     *                 ::= pl    # +             
     *                 ::= mi    # -             
     *                 ::= ml    # *             
     *                 ::= dv    # /             
     *                 ::= rm    # %             
     *                 ::= an    # &             
     *                 ::= or    # |             
     *                 ::= eo    # ^             
     *                 ::= aS    # =             
     *                 ::= pL    # +=            
     *                 ::= mI    # -=            
     *                 ::= mL    # *=            
     *                 ::= dV    # /=            
     *                 ::= rM    # %=            
     *                 ::= aN    # &=            
     *                 ::= oR    # |=            
     *                 ::= eO    # ^=            
     *                 ::= ls    # <<            
     *                 ::= rs    # >>            
     *                 ::= lS    # <<=           
     *                 ::= rS    # >>=           
     *                 ::= eq    # ==            
     *                 ::= ne    # !=            
     *                 ::= lt    # <             
     *                 ::= gt    # >             
     *                 ::= le    # <=            
     *                 ::= ge    # >=            
     *                 ::= nt    # !             
     *                 ::= aa    # &&            
     *                 ::= oo    # ||            
     *                 ::= pp    # ++            
     *                 ::= mm    # --            
     *                 ::= cm    # ,             
     *                 ::= pm    # ->*           
     *                 ::= pt    # ->            
     *                 ::= cl    # ()            
     *                 ::= ix    # []            
     *                 ::= qu    # ?             
     *                 ::= st    # sizeof (a type)
     *                 ::= sz    # sizeof (an expression)
     *                 ::= cv <type> # (cast)        
     *                 ::= v <digit> <source-name>   # vendor extended operator
     *
     */

    result = NULL;

    code[0] = g_itanium_dcontext_next_char(context);

    if (code[0] == 'v')
    {

        result = NULL;  /* TODO */

        goto itd_operator_name_exit;


    }

    code[1] = g_itanium_dcontext_next_char(context);

    if (code[0] == 'c' && code[1] == 'v')
    {

        result = NULL;  /* TODO */

        goto itd_operator_name_exit;


    }

    /* Recherche dans la liste des opérateurs reconnus */

    info.code = code;

    int comp_itanium_operators(const itanium_operator_info *a, const itanium_operator_info *b)
    {
        int result;                         /* Bilan à renvoyer            */

        if (a->code[0] < b->code[0])
            result = -1;
        else if (a->code[0] > b->code[0])
            result = 1;
        else
        {
            if (a->code[1] < b->code[1])
                result = -1;
            else if (a->code[1] > b->code[1])
                result = 1;
            else
                result = 0;
        }

        return result;

    }

    found = bsearch(&info, itanium_demangle_operators,
                    ARRAY_SIZE(itanium_demangle_operators),
                    sizeof(itanium_operator_info), (__compar_fn_t)comp_itanium_operators);

    if (found != NULL)
        result = itd_make_operator(context, found);

 itd_operator_name_exit:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_special_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    char next;                              /* Caractère suivant           */
    char peek;                              /* Prochain caractère lu       */
    itanium_component *offset1;             /* Décalage extrait #1         */
    itanium_component *encoding;            /* Encodage suivant            */

    /**
     * La règle traitée ici est la suivante :
     *
     * <special-name> ::= T <call-offset> <base encoding>
     *                   # base is the nominal target function of thunk
     */

    result = NULL;

    next = g_itanium_dcontext_next_char(context);

    if (next == 'T')
    {
        peek = g_itanium_dcontext_peek_char(context);

        switch (peek)
        {
            case 'V':
                result = NULL; /* TODO */
                break;

            case 'T':
                result = NULL; /* TODO */
                break;

            case 'I':
                result = NULL; /* TODO */
                break;

            case 'S':
                result = NULL; /* TODO */
                break;

            case 'c':
                result = NULL; /* TODO */
                break;


            default:

                offset1 = itd_call_offset(context);
                if (offset1 == NULL) break;

                encoding = itd_encoding(context);

                if (encoding == NULL)
                    itd_unref_comp(offset1);
                else
                    result = itd_make_binary(context, ICT_FUNCTION_THUNK, offset1, encoding);

                break;

        }

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_call_offset(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    char next;                              /* Caractère suivant           */

    /**
     * La règle traitée ici est la suivante :
     *
     * <call-offset> ::= h <nv-offset> _
     *               ::= v <v-offset> _
     */

    next = g_itanium_dcontext_next_char(context);

    switch (next)
    {
        case 'h':
            result = itd_nv_offset(context);
            break;

        case 'v':
            result = itd_v_offset(context);
            break;

        default:
            result = NULL;
            break;

    }

    if (result != NULL && !g_itanium_dcontext_check_char(context, '_'))
    {
        itd_unref_comp(result);
        result = NULL;
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_nv_offset(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    ssize_t offset;                         /* Décalage obtenu             */

    /**
     * La règle traitée ici est la suivante :
     *
     * <nv-offset> ::= <offset number>
     *                     # non-virtual base override
     */

    if (!itd_number(context, &offset))
        return NULL;

    result = itd_make_offset(context, ICT_NON_VIRTUAL_OFFSET, offset);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_v_offset(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    ssize_t offset;                         /* Décalage obtenu #1          */
    ssize_t voffset;                        /* Décalage obtenu #2          */

    /**
     * La règle traitée ici est la suivante :
     *
     * <v-offset>  ::= <offset number> _ <virtual offset number>
     *                     # virtual base override, with vcall offset
     */

    if (!itd_number(context, &offset))
        return NULL;

    if (!g_itanium_dcontext_check_char(context, '_'))
        return NULL;

    if (!itd_number(context, &voffset))
        return NULL;

    result = itd_make_binary(context, ICT_VIRTUAL_OFFSET,
                             itd_make_offset(context, ICT_NON_VIRTUAL_OFFSET, offset),
                             itd_make_offset(context, ICT_VIRTUAL_OFFSET, voffset));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_ctor_dtor_name(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    char next;                              /* Caractère suivant           */
    ItaniumComponentType type;              /* Type de composant           */

    /**
     * La règle traitée ici est la suivante :
     *
     * <ctor-dtor-name> ::= C1   # complete object constructor
     *                  ::= C2   # base object constructor
     *                  ::= C3   # complete object allocating constructor
     *                  ::= D0   # deleting destructor
     *                  ::= D1   # complete object destructor
     *                  ::= D2   # base object destructor
     */

    next = g_itanium_dcontext_peek_char(context);

    if (next == 'C')
        type = ICT_CONSTRUCTOR;
    else if (next == 'D')
        type = ICT_DESSTRUCTOR;
    else
        return NULL;

    g_itanium_dcontext_advance(context, 1);

    next = g_itanium_dcontext_peek_char(context);

    if (next != '0' && next != '1' && next != '2')
        return NULL;

    g_itanium_dcontext_advance(context, 1);

    result = itd_make_empty(context);
    itd_set_type(result, type);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_type(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    TypeQualifier qualifier;                /* Propriétés supplémentaires  */
    itanium_component *sub;                 /* Sous-type lié à associer    */
    itd_state saved;                        /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <type> ::= <builtin-type>
     *        ::= <function-type>
     *        ::= <class-enum-type>
     *        ::= <array-type>
     *        ::= <pointer-to-member-type>
     *        ::= <template-param>
     *        ::= <template-template-param> <template-args>
     *        ::= <substitution> # See Compression below
     *        ::= <CV-qualifiers> <type>
     *        ::= P <type>   # pointer-to
     *        ::= R <type>   # reference-to
     *        ::= O <type>   # rvalue reference-to (C++0x)
     *        ::= C <type>   # complex pair (C 2000)
     *        ::= G <type>   # imaginary (C 2000)
     *        ::= U <source-name> <type> # vendor extended type qualifier
     *
     */

    result = NULL;

    qualifier = itd_cv_qualifiers(context);

    switch (g_itanium_dcontext_peek_char(context))
    {
        case 'P':

            g_itanium_dcontext_advance(context, 1);

            sub = itd_type(context);
            if (sub == NULL) return NULL;

            result = itd_make_unary(context, ICT_POINTER_TO, sub);
            break;

        case 'R':

            g_itanium_dcontext_advance(context, 1);

            sub = itd_type(context);
            if (sub == NULL) return NULL;

            result = itd_make_unary(context, ICT_REFERENCE_TO, sub);
            break;

        case 'O':

            g_itanium_dcontext_advance(context, 1);

            sub = itd_type(context);
            if (sub == NULL) return NULL;

            result = itd_make_unary(context, ICT_RVALUE_REFERENCE_TO, sub);
            break;

        case 'C':

            g_itanium_dcontext_advance(context, 1);

            sub = itd_type(context);
            if (sub == NULL) return NULL;

            result = itd_make_unary(context, ICT_COMPLEX_PAIR, sub);
            break;

        case 'G':

            g_itanium_dcontext_advance(context, 1);

            sub = itd_type(context);
            if (sub == NULL) return NULL;

            result = itd_make_unary(context, ICT_IMAGINARY, sub);
            break;

        case 'U':

            g_itanium_dcontext_advance(context, 1);
            /* TODO */
            return NULL;
            break;

        }

    if (result != NULL) goto itd_type_end;

    g_itanium_dcontext_push_state(context, &saved);

    result = itd_builtin_type(context);
    if (result != NULL) goto itd_type_end;

    g_itanium_dcontext_pop_state(context, &saved);

    result = itd_class_enum_type(context);
    if (result != NULL) goto itd_type_end;


    g_itanium_dcontext_pop_state(context, &saved);

    result = itd_substitution(context);
    if (result != NULL) goto itd_type_end;




 itd_type_end:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait une propriété de composant pour un contexte Itanium. *
*                                                                             *
*  Retour      : Indication extraite.                                         *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static TypeQualifier itd_cv_qualifiers(GItaniumDContext *context)
{
    TypeQualifier result;                   /* Valeur à remonter           */

    /**
     * La règle traitée ici est la suivante :
     *
     * <CV-qualifiers> ::= [r] [V] [K] 	# restrict (C99), volatile, const
     *
     */

    result = TQF_NONE;

    while (1)
        switch (g_itanium_dcontext_peek_char(context))
        {
            case 'r':
                result = TQF_RESTRICT;
                g_itanium_dcontext_advance(context, 1);
                break;

            case 'V':
                result = TQF_VOLATILE;
                g_itanium_dcontext_advance(context, 1);
                break;

            case 'K':
                result = TQF_CONST;
                g_itanium_dcontext_advance(context, 1);
                break;

            default:
                goto itd_cv_qualifiers_exit;
                break;

        }

 itd_cv_qualifiers_exit:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_builtin_type(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    BaseType type;                          /* Type reconnu ou BTP_INVALID */
    GDataType *builtin;                     /* Type construit              */

    /**
     * La règle traitée ici est la suivante :
     *
     * <builtin-type> ::= v  # void
     *                ::= w  # wchar_t
     *                ::= b  # bool
     *                ::= c  # char
     *                ::= a  # signed char
     *                ::= h  # unsigned char
     *                ::= s  # short
     *                ::= t  # unsigned short
     *                ::= i  # int
     *                ::= j  # unsigned int
     *                ::= l  # long
     *                ::= m  # unsigned long
     *                ::= x  # long long, __int64
     *                ::= y  # unsigned long long, __int64
     *                ::= n  # __int128
     *                ::= o  # unsigned __int128
     *                ::= f  # float
     *                ::= d  # double
     *                ::= e  # long double, __float80
     *                ::= g  # __float128
     *                ::= z  # ellipsis
     *                ::= u <source-name>    # vendor extended type
     *
     */

    switch (g_itanium_dcontext_peek_char(context))
    {
        case 'v':
            type = BTP_VOID;
            break;
        case 'w':
            type = BTP_WCHAR_T;
            break;
        case 'b':
            type = BTP_BOOL;
            break;
        case 'c':
            type = BTP_CHAR;
            break;
        case 'a':
            type = BTP_SCHAR;
            break;
        case 'h':
            type = BTP_UCHAR;
            break;
        case 's':
            type = BTP_SHORT;
            break;
        case 't':
            type = BTP_USHORT;
            break;
        case 'i':
            type = BTP_INT;
            break;
        case 'j':
            type = BTP_UINT;
            break;
        case 'l':
            type = BTP_LONG;
            break;
        case 'm':
            type = BTP_ULONG;
            break;
        case 'x':
            type = BTP_LONG_LONG;
            break;
        case 'y':
            type = BTP_ULONG_LONG;
            break;
        case 'n':
            type = BTP_INT128;
            break;
        case 'o':
            type = BTP_UINT128;
            break;
        case 'f':
            type = BTP_FLOAT;
            break;
        case 'd':
            type = BTP_DOUBLE;
            break;
        case 'e':
            type = BTP_LONG_DOUBLE;
            break;
        case 'g':
            type = BTP_FLOAT128;
            break;
        case 'z':
            type = BTP_ELLIPSIS;
            break;
        case 'u':
            type = BTP_OTHER;
            /* FIXME */
            /*  <source-name>    # vendor extended type */
            break;
        default:
            type = BTP_INVALID;
            break;
    }

    if (type != BTP_INVALID)
    {
        builtin = g_basic_type_new(type);
        result = itd_make_type(context, builtin);
        g_itanium_dcontext_advance(context, 1);
    }
    else
        result = NULL;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_bare_function_type(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itanium_component *type;                /* Nouvel élément à intégrer   */
    itd_state saved;                        /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <bare-function-type> ::= <signature type>+
     *       # types are possible return type, then parameter types
     *
     */

    type = itd_type(context);
    if (type == NULL) return NULL;

    result = itd_append_right_to_binary(context, ICT_TYPES_LIST, NULL, type);

    while (1)
    {
        g_itanium_dcontext_push_state(context, &saved);

        type = itd_type(context);
        if (type == NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved);
            break;
        }

        result = itd_append_right_to_binary(context, ICT_TYPES_LIST, result, type);

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_class_enum_type(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */

    /**
     * La règle traitée ici est la suivante :
     *
     * <class-enum-type> ::= <name>
     *
     */

    result = itd_name(context);

    return result;

}








/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_template_args(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itanium_component *arg;                 /* Nouvel argument extrait     */
    itd_state saved;                        /* Position d'analyse courante */

    printf(">>> TA>> '%s'\n", g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

    /**
     * La règle traitée ici est la suivante :
     *
     * <template-args> ::= I <template-arg>+ E
     *
     */

    if (!g_itanium_dcontext_check_char(context, 'I'))
        return NULL;

    arg = itd_template_arg(context);
    if (arg == NULL) return NULL;

    result = itd_append_right_to_binary(context, ICT_TYPES_LIST, NULL, arg);

    while (1)
    {
        g_itanium_dcontext_push_state(context, &saved);

        arg = itd_template_arg(context);
        if (arg == NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved);
            break;
        }

        result = itd_append_right_to_binary(context, ICT_TYPES_LIST, result, arg);

    }

    //printf("  ta/E >> '%s'\n", g_itanium_dcontext_get_string(context, (size_t []){ 0 }));

    if (!g_itanium_dcontext_check_char(context, 'E'))
    {
        //printf("=== TA : BAD E\n\n");

        if (result != NULL)
            itd_unref_comp(result);
        return NULL;
    }

    //printf("=== TA >> %p\n\n", result);

    result = itd_make_unary(context, ICT_TEMPLATE_ARGS, result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_template_arg(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <template-arg> ::= <type>                     # type or template
     *                ::= X <expression> E           # expression
     *                ::= <expr-primary>             # simple expressions
     *
     */

    g_itanium_dcontext_push_state(context, &saved);

    result = itd_type(context);

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);

        if (g_itanium_dcontext_check_char(context, 'X'))
        {
            result = itd_expression(context);

            if (result != NULL && !g_itanium_dcontext_check_char(context, 'E'))
            {
                itd_unref_comp(result);
                result = NULL;
            }

        }

    }

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_expr_primary(context);
    }

    return result;

}
















/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                hex     = prise en compte des caractères hexadécimaux ?      *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_value_to_string(GItaniumDContext *context, bool hex)
{
    itanium_component *result;              /* Construction à retourner    */
    const char *data;                       /* Données restantes           */
    itd_state saved;                        /* Position d'analyse initiale */
    itd_state cur;                          /* Position d'analyse courante */
    char peek;                              /* Prochain caractère lu       */

    /**
     * Les règles traitées ici sont les suivantes :
     *
     * <value number>  # integer literal
     * <value float>   # floating literal
     *
     */

    result = NULL;

    data = g_itanium_dcontext_get_string(context, (size_t []) { 0 });

    g_itanium_dcontext_push_state(context, &saved);

    while (1)
    {
        peek = g_itanium_dcontext_peek_char(context);

        switch (peek)
        {
            case '0' ... '9':
                g_itanium_dcontext_advance(context, 1);
                break;

            case 'a' ... 'f':
                if (hex)
                    g_itanium_dcontext_advance(context, 1);
                else
                    goto exit_iits;
                break;

            case 'E':
                goto exit_loop;
                break;

            default:
                goto exit_iits;

        }

    }

 exit_loop:

    g_itanium_dcontext_push_state(context, &cur);

    if ((cur.pos - saved.pos) > 0)
        result = itd_make_name(context, data, cur.pos - saved.pos);

 exit_iits:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_expr_primary(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    itd_state saved;                        /* Position d'analyse courante */
    itanium_component *type;                /* Type de valeur extrait      */
    itd_state saved_value;                  /* Position d'analyse courante */

    /**
     * La règle traitée ici est la suivante :
     *
     * <expr-primary> ::= L <type> <value number> E  # integer literal
     *                ::= L <type> <value float> E   # floating literal
     *                ::= L <mangled-name> E         # external name
     *
     */

    printf("PRIMARY :: no L\n");

    if (!g_itanium_dcontext_check_char(context, 'L'))
        return NULL;

    g_itanium_dcontext_push_state(context, &saved);

    type = itd_type(context);

    if (type != NULL)
    {
        g_itanium_dcontext_push_state(context, &saved_value);

        /* Règle <type> <value number> */

        result = itd_value_to_string(context, false);

        if (result != NULL && !g_itanium_dcontext_check_char(context, 'E'))
        {
            itd_unref_comp(result);
            result = NULL;
        }

        /* Règle <type> <value float> */

        if (result == NULL)
        {
            g_itanium_dcontext_pop_state(context, &saved_value);

            result = itd_value_to_string(context, true);

            if (result != NULL && !g_itanium_dcontext_check_char(context, 'E'))
            {
                itd_unref_comp(result);
                result = NULL;
            }

        }

        itd_unref_comp(type);

    }
    else
        result = NULL;

    /* Règle <mangled-name> */

    if (result == NULL)
    {
        g_itanium_dcontext_pop_state(context, &saved);
        result = itd_mangled_name(context);

        if (result != NULL && !g_itanium_dcontext_check_char(context, 'E'))
        {
            itd_unref_comp(result);
            result = NULL;
        }

    }

    printf("PRIMARY :: %p\n", result);

    return result;

}








/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                cur     = caractère courant.                                 *
*                id      = identifiant lu en cas de succès. [OUT]             *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool itd_seq_id(GItaniumDContext *context, char cur, size_t *id)
{
    /**
     * La règle traitée ici est la suivante :
     *
     * <seq-id>
     *
     */

    *id = 0;

    /**
     * La fonction n'est appelée que si un début de séquence est détecté.
     * (ie, cur == '_' || isdigit(cur) || isupper(cur)).
     */

    if (cur != '_')
    {
        do
        {
            if (isdigit(cur))
                *id = *id * 36 + cur - '0';
            else if (isupper(cur))
                *id = *id * 36 + cur - 'A' + 10;
            else
                return false;

            cur = g_itanium_dcontext_next_char(context);

        }
        while (cur != '_');

        (*id)++;

    }

    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : context = contexte de décodage à utiliser.                   *
*                                                                             *
*  Description : Extrait un composant dans un contexte Itanium.               *
*                                                                             *
*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static itanium_component *itd_substitution(GItaniumDContext *context)
{
    itanium_component *result;              /* Construction à retourner    */
    char cur;                               /* Caractère analysé           */
    size_t id;                              /* Identifiant de substitution */
    char peek;                              /* Prochain caractère lu       */
    bool verbose;                           /* Sélection du rendu idéal    */
    size_t i;                               /* Boucle de parcours          */

    /**
     * La règle traitée ici est la suivante :
     *
     * <substitution> ::= S <seq-id> _
     *                ::= S_
     *                ::= St # ::std::
     *                ::= Sa # ::std::allocator
     *                ::= Sb # ::std::basic_string
     *                ::= Ss # ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
     *                ::= Si # ::std::basic_istream<char, std::char_traits<char>>
     *                ::= So # ::std::basic_ostream<char, std::char_traits<char>>
     *                ::= Sd # ::std::basic_iostream<char, std::char_traits<char>>
     *
     */

    peek = g_itanium_dcontext_peek_char(context);

    if (!g_itanium_dcontext_check_char(context, 'S'))
        return NULL;

    cur = g_itanium_dcontext_next_char(context);

    if (cur == '_' || isdigit(cur) || isupper(cur))
    {
        if (!itd_seq_id(context, cur, &id))
            return NULL;

        printf("requesting... %zu\n", id);

        result = g_itanium_dcontext_get_substitution(context, id);

    }
    else
    {
        result = NULL;

        peek = g_itanium_dcontext_peek_char(context);
        verbose = (peek == 'C' || peek == 'D'); /* TODO : prefixe ? */

        for (i = 0; i < ARRAY_SIZE(itanium_standard_substitutions); i++)
            if (itanium_standard_substitutions[i].code == cur)
            {
                /* TODO : constructeur... */

                if (verbose)
                    result = itd_make_name(context,
                                           itanium_standard_substitutions[i].full,
                                           itanium_standard_substitutions[i].full_len);
                else
                    result = itd_make_name(context,
                                           itanium_standard_substitutions[i].simple,
                                           itanium_standard_substitutions[i].simple_len);

                itd_set_type(result, ICT_STD_SUBST);

                break;

            }

    }

    return result;

}