/* Chrysalide - Outil d'analyse de fichiers binaires
* abi.c - décodage des noms d'éléments selon l'ABI C++ Itanium
*
* Copyright (C) 2018 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 .
*/
#include "abi.h"
#include
#include
#include
#include
#include
#include
#include
/* 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 }
};
/* Substitutions standards */
typedef struct _itanium_std_subst_info
{
char code; /* Identifiant associé */
const char *class; /* Classe visée dans l'espace */
} itanium_std_subst_info;
const itanium_std_subst_info itanium_standard_substitutions[] = {
{ 't', NULL },
{ 'a', "allocator" },
{ 'b', "basic_string" },
{ 's', "string" },
{ 'i', "istream" },
{ 'o', "ostream" },
{ 'd', "iostream" }
};
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_encoding(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_name(GItaniumDemangling *);
/* Détermine si le composant suivant correspond à un type donné. */
static bool is_itd_unscoped_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unscoped_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unscoped_template_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_nested_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_prefix(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_prefix(GItaniumDemangling *);
/* Détermine si le composant suivant correspond à un type donné. */
static bool is_itd_unqualified_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_unqualified_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_source_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static bool itd_number(GItaniumDemangling *, ssize_t *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_identifier(GItaniumDemangling *, size_t);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_operator_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_special_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_call_offset(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_nv_offset(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_v_offset(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_ctor_dtor_name(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_type(GItaniumDemangling *);
/* Extrait une propriété de composant pour un contexte Itanium. */
static TypeQualifier itd_cv_qualifiers(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_builtin_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_function_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_bare_function_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_class_enum_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_array_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_pointer_to_member_type(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_param(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_template_param(GItaniumDemangling *);
/* Détermine si le composant suivant correspond à un type donné. */
static bool is_itd_template_args(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_args(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_template_arg(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_expression(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_value_to_string(GItaniumDemangling *, bool);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_expr_primary(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_data_member_prefix(GItaniumDemangling *);
/* Extrait un composant dans un contexte Itanium. */
static bool itd_seq_id(GItaniumDemangling *, char, size_t *);
/* Extrait un composant dans un contexte Itanium. */
static itanium_component *itd_substitution(GItaniumDemangling *);
#define itd_local_name(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
/**
* La règle traitée ici est la suivante :
*
* ::= _Z
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, '_'))
return NULL;
if (!check_input_buffer_char(ibuf, '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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
itanium_component *types; /* Composant 'bare-function...'*/
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'T' || peek == 'G')
result = itd_special_name(context);
else
{
result = itd_name(context);
if (result != NULL)
{
types = itd_bare_function_type(context);
if (types != NULL)
result = itd_make_binary(ICT_FUNCTION_ENCODING, result, types);
/**
* Si le chargement des types échoue, il peut y avoir deux explications :
* - on ne chargeait qu'un simple nom.
* - il y a eu une erreur de décodage pour les types.
*
* Le tampon aura été vidé dans le premier cas uniquement,
* donc on laisse le contexte détecter une éventuelle erreur.
*/
}
}
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(GItaniumDemangling *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 :
*
* ::=
* ::=
* ::=
* ::=
*
*/
g_itanium_demangling_push_state(context, &saved);
result = itd_nested_name(context);
if (result == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
tname = itd_unscoped_template_name(context);
if (tname != NULL)
{
targs = itd_template_args(context);
if (targs != NULL)
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, tname, targs);
else
itd_unref_comp(tname);
}
}
/**
* La règle doit être traitée après ,
* car ces deux dernières ont une base commune et la seconde peut avoir besoin
* d'aller plus loin avec la règle .
*
* On termine donc par moins gourmand si la règle la plus complexe n'a pas abouti.
*/
if (result == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
result = itd_unscoped_name(context);
}
if (result == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
result = itd_local_name(context);
}
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Détermine si le composant suivant correspond à un type donné.*
* *
* Retour : true si le décodage va à priori réussir, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool is_itd_unscoped_name(GItaniumDemangling *context)
{
bool result; /* Bilan à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
char next_peek; /* Caractère après le prochain */
/**
* La règle anticipée ici est la suivante :
*
* ::=
* ::= St # ::std::
*
*/
result = is_itd_unqualified_name(context);
if (!result)
{
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'S')
{
next_peek = peek_input_buffer_next_char(ibuf);
result = (next_peek == 't');
}
}
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
char next_peek; /* Caractère après le prochain */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::= St # ::std::
*
*/
if (is_itd_unqualified_name(context))
result = itd_unqualified_name(context);
else
{
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'S')
{
next_peek = peek_input_buffer_next_char(ibuf);
if (next_peek == 't')
{
advance_input_buffer(ibuf, 2);
result = itd_unqualified_name(context);
if (result != NULL)
result = itd_make_unary(ICT_STD_UNSCOPED_NAME, result);
}
else
result = NULL;
}
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_unscoped_template_name(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
*
*/
if (is_itd_unscoped_name(context))
{
result = itd_unscoped_name(context);
if (result != NULL)
g_itanium_demangling_add_substitution(context, result);
}
else
{
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'S')
result = itd_substitution(context);
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_nested_name(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
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 */
/**
* La règle traitée ici est la suivante :
*
* ::= N [] E
* ::= N [] E
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'N'))
return NULL;
qualifier = itd_cv_qualifiers(context);
result = NULL;
g_itanium_demangling_push_state(context, &saved);
/**
* Comme peut aussi être ,
* on commence par traiter la seconde règle.
*/
left = itd_template_prefix(context);
if (left != NULL)
{
/**
* Quand son traitement est un succès, doit toujours
* se terminer par .
*/
assert(is_itd_template_args(context));
right = itd_template_args(context);
if (right != NULL)
{
if (check_input_buffer_char(ibuf, 'E'))
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, left, right);
else
{
itd_unref_comp(left);
itd_unref_comp(right);
}
}
else
itd_unref_comp(left);
}
if (result == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
left = itd_prefix(context);
/**
* Quand son traitement est un succès, doit toujours
* se terminer par .
*/
assert(left == NULL || (left != NULL && is_itd_unqualified_name(context)));
/**
* La règle peut être vide, donc on se doit de tenter un
* dans tous les cas.
*/
right = itd_unqualified_name(context);
if (right != NULL)
{
if (check_input_buffer_char(ibuf, 'E'))
result = itd_make_binary(ICT_NESTED_NAME, left, right);
else
{
if (left != NULL)
itd_unref_comp(left);
itd_unref_comp(right);
}
}
else if (left != NULL)
itd_unref_comp(left);
}
if (result != NULL)
itd_make_qualified_type(result, qualifier);
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
itanium_component *targs; /* Composant 'template-args' */
itd_state saved; /* Position d'analyse courante */
itanium_component *further; /* Tentative de progression */
itanium_component *backup; /* Solution de repli existante */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
* ::=
* ::=
* ::=
* ::=
*
* Réorganisée, cette règle a pour définition :
*
* ::=
* ::=
* ::=
* ::=
* ::=
*
* ::=
* ::=
*
* Il existe cependant une boucle infinie avec une règle de :
*
* ::=
*
* On déplie donc les règles afin de casser la boucle, quitte à gérer ici
* une partie de la règle :
*
* ::=
* ::=
* ::=
* ::=
*
* ::=
* ::=
* ::=
*
* ::=
* ::=
* ::=
*/
result = NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'S')
result = itd_substitution(context);
else if (peek == 'T')
result = itd_template_param(context);
else if (is_itd_unqualified_name(context))
result = itd_unqualified_name(context);
/**
* Si le traitement débouche sur une règle , c'est qu'il
* était en fait potentiellement dans une voie .
*
* Cette voie est vérifiée après coup en analysant la suite.
*/
if (is_itd_template_args(context))
{
g_itanium_demangling_push_state(context, &saved);
/* Ajout de la substitution tirée de */
g_itanium_demangling_add_substitution(context, result);
targs = itd_template_args(context);
if (targs != NULL)
{
if (!is_itd_unqualified_name(context))
{
g_itanium_demangling_pop_state(context, &saved);
itd_unref_comp(targs);
}
else
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs);
}
else
{
itd_unref_comp(result);
result = NULL;
goto done;
}
}
if (result == NULL)
goto done;
g_itanium_demangling_add_substitution(context, result);
/* Tentative de rebouclage sur la règle */
while (count_input_buffer_remaining(ibuf) > 0)
{
g_itanium_demangling_push_state(context, &saved);
/**
* Comme commence par une régle et
* complète ensuite sa définition et comme contient
* également cette même règle sans l'étendre, on commence
* par traiter la règle .
*/
further = itd_data_member_prefix(context);
if (further == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
further = itd_unqualified_name(context);
}
if (further == NULL)
break;
backup = result;
itd_ref_comp(backup);
result = itd_make_binary(ICT_PREFIX_BINARY, result, further);
/* Ajout de la substitution tirée de <[template-]prefix> */
g_itanium_demangling_add_substitution(context, result);
if (is_itd_template_args(context))
{
targs = itd_template_args(context);
if (targs == NULL)
{
itd_unref_comp(backup);
itd_unref_comp(result);
result = NULL;
goto done;
}
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs);
g_itanium_demangling_add_substitution(context, result);
}
/* Si l'ensemble ne se termine pas par la règle finale attendue, on rétropédale */
if (!is_itd_unqualified_name(context))
{
itd_unref_comp(result);
result = backup;
g_itanium_demangling_pop_state(context, &saved);
break;
}
itd_unref_comp(backup);
}
done:
/**
* Quand son traitement est un succès, doit toujours
* se terminer par .
*/
if (result != NULL)
{
if (!is_itd_unqualified_name(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_template_prefix(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
bool new_subst; /* Ajoute d'une substitution ? */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
itd_state saved; /* Position d'analyse courante */
itanium_component *name; /* Second d'un couple de comp. */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
* ::=
*
* Il existe cependant une boucle infinie avec une règle de :
*
* ::=
*
* On traite donc cette règle de en dernier, quand les autres
* options ont été épuisées.
*/
result = NULL;
new_subst = true;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
g_itanium_demangling_push_state(context, &saved);
if (peek == 'S')
{
result = itd_substitution(context);
new_subst = false;
}
else if (peek == 'T')
result = itd_template_param(context);
else if (is_itd_unqualified_name(context))
result = itd_unqualified_name(context);
/* Vérification : a-t-on empiété sur une règle ? */
if (result != NULL)
{
if (is_itd_template_args(context))
goto done;
else
{
new_subst = true;
itd_unref_comp(result);
result = NULL;
g_itanium_demangling_pop_state(context, &saved);
}
}
/* Tentative avec en dernier recours */
result = itd_prefix(context);
if (result != NULL)
{
/**
* Quand son traitement est un succès, doit toujours
* se terminer par .
*
* De même, toutes les règles se poursuivent avec une
* règle ; la procédure n'est donc un succès que dans ce cas.
*/
assert(is_itd_unqualified_name(context));
name = itd_unqualified_name(context);
if (name != NULL)
result = itd_make_binary(ICT_TPREFIX_BINARY, result, name);
else
{
itd_unref_comp(result);
result = NULL;
}
}
done:
if (result != NULL)
{
if (!is_itd_template_args(context))
{
itd_unref_comp(result);
result = NULL;
}
else if (new_subst)
g_itanium_demangling_add_substitution(context, result);
}
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Détermine si le composant suivant correspond à un type donné.*
* *
* Retour : true si le décodage va à priori réussir, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool is_itd_unqualified_name(GItaniumDemangling *context)
{
bool result; /* Bilan à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
/**
* La règle anticipée ici est la suivante :
*
* ::=
* ::=
* ::=
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
result = islower(peek) /* */
|| (peek == 'C' || peek == 'D') /* */
|| isdigit(peek); /* */
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (islower(peek))
result = itd_operator_name(context);
else if (peek == 'C' || peek == 'D')
result = itd_ctor_dtor_name(context);
else if (isdigit(peek))
result = itd_source_name(context);
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_source_name(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
ssize_t number; /* Taille positive */
/**
* La règle traitée ici est la suivante :
*
* ::=
*
*/
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(GItaniumDemangling *context, ssize_t *size)
{
bool result; /* Validité à renvoyer */
bool negative; /* Taille négative ? */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
/**
* La règle traitée ici est la suivante :
*
* ::= [n]
*
*/
result = false;
negative = false;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'n')
{
negative = true;
advance_input_buffer(ibuf, 1);
peek = peek_input_buffer_char(ibuf);
}
*size = 0;
while (isdigit(peek))
{
result = true;
*size = *size * 10 + peek - '0';
advance_input_buffer(ibuf, 1);
peek = peek_input_buffer_char(ibuf);
}
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(GItaniumDemangling *context, size_t length)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
const char *data; /* Données restantes */
size_t remaining; /* Quantité d'octets */
/**
* La règle traitée ici est la suivante :
*
* ::=
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
data = get_input_buffer_string(ibuf, &remaining);
if (length > remaining)
return NULL;
result = itd_make_name(data, length);
if (result != NULL)
advance_input_buffer(ibuf, 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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char code[2]; /* Code à venir lire */
itanium_component *type; /* Type transtypé */
itanium_operator_info info; /* Clef des informations */
itanium_operator_info *found; /* Informations complètes */
/**
* La règle traitée ici est la suivante :
*
* ::= 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 # (cast)
* ::= v # vendor extended operator
*
*/
result = NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!get_input_buffer_next_char_carefully(ibuf, &code[0]))
goto itd_operator_name_exit;
if (code[0] == 'v')
{
type = itd_type(context);
if (type != NULL)
result = itd_make_cast_operator(type);
else
result = NULL;
goto itd_operator_name_exit;
}
if (!get_input_buffer_next_char_carefully(ibuf, &code[1]))
goto itd_operator_name_exit;
if (code[0] == 'c' && code[1] == 'v')
{
result = NULL;
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(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char next; /* Caractère suivant */
char peek; /* Prochain caractère lu */
itanium_component *offset1; /* Décalage extrait #1 */
itanium_component *offset2; /* Décalage extrait #2 */
itanium_component *encoding; /* Encodage suivant */
/**
* La règle traitée ici est la suivante :
*
* ::= TV # virtual table
* ::= TT # VTT structure (construction vtable index)
* ::= TI # typeinfo structure
* ::= TS # typeinfo name (null-terminated byte string)
* ::= Tc
* # base is the nominal target function of thunk
* # first call-offset is 'this' adjustment
* # second call-offset is result adjustment
* ::= T
* # base is the nominal target function of thunk
*/
result = NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!get_input_buffer_next_char_carefully(ibuf, &next))
goto exit_eof;
if (next == 'T')
{
peek = peek_input_buffer_char(ibuf);
switch (peek)
{
case 'V':
advance_input_buffer(ibuf, 1);
result = itd_type(context);
if (result != NULL)
result = itd_make_unary(ICT_SPECIAL_NAME_VTABLE, result);
break;
case 'T':
advance_input_buffer(ibuf, 1);
result = itd_type(context);
if (result != NULL)
result = itd_make_unary(ICT_SPECIAL_NAME_VSTRUCT, result);
break;
case 'I':
advance_input_buffer(ibuf, 1);
result = itd_type(context);
break;
case 'S':
advance_input_buffer(ibuf, 1);
result = itd_type(context);
break;
case 'c':
advance_input_buffer(ibuf, 1);
offset1 = itd_call_offset(context);
if (offset1 == NULL) break;
offset2 = itd_call_offset(context);
if (offset2 == NULL)
{
itd_unref_comp(offset1);
break;
}
encoding = itd_encoding(context);
if (encoding == NULL)
{
itd_unref_comp(offset1);
itd_unref_comp(offset2);
}
else
result = itd_make_ternary(ICT_FUNCTION_COVARIANT_THUNK, encoding, offset1, offset2);
break;
case '\0':
/**
* Si on se trouve à la fin du tampon, on n'avance pas aveuglément !
*/
result = NULL;
break;
default:
advance_input_buffer(ibuf, 1);
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(ICT_FUNCTION_THUNK, encoding, offset1);
break;
}
}
exit_eof:
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char next; /* Caractère suivant */
/**
* La règle traitée ici est la suivante :
*
* ::= h _
* ::= v _
*/
result = NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (get_input_buffer_next_char_carefully(ibuf, &next))
goto exit_eof;
switch (next)
{
case 'h':
result = itd_nv_offset(context);
break;
case 'v':
result = itd_v_offset(context);
break;
}
if (result != NULL && !check_input_buffer_char(ibuf, '_'))
{
itd_unref_comp(result);
result = NULL;
}
exit_eof:
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
ssize_t offset; /* Décalage obtenu */
/**
* La règle traitée ici est la suivante :
*
* ::=
* # non-virtual base override
*/
if (!itd_number(context, &offset))
return NULL;
result = itd_make_offset(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
ssize_t offset; /* Décalage obtenu #1 */
input_buffer *ibuf; /* Tampon de texte manipulé */
ssize_t voffset; /* Décalage obtenu #2 */
/**
* La règle traitée ici est la suivante :
*
* ::= _
* # virtual base override, with vcall offset
*/
if (!itd_number(context, &offset))
return NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, '_'))
return NULL;
if (!itd_number(context, &voffset))
return NULL;
result = itd_make_binary(ICT_DOUBLE_OFFSET,
itd_make_offset(ICT_NON_VIRTUAL_OFFSET, offset),
itd_make_offset(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char next; /* Caractère suivant */
ItaniumComponentType type; /* Type de composant */
/**
* La règle traitée ici est la suivante :
*
* ::= C1 # complete object constructor
* ::= C2 # base object constructor
* ::= C3 # complete object allocating constructor
* ::= D0 # deleting destructor
* ::= D1 # complete object destructor
* ::= D2 # base object destructor
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
next = peek_input_buffer_char(ibuf);
if (next == 'C')
type = ICT_CONSTRUCTOR;
else if (next == 'D')
type = ICT_DESTRUCTOR;
else
return NULL;
advance_input_buffer(ibuf, 1);
next = peek_input_buffer_char(ibuf);
if (next != '0' && next != '1' && next != '2')
return NULL;
advance_input_buffer(ibuf, 1);
result = itd_make_with_type(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
TypeQualifier qualifier; /* Propriétés supplémentaires */
input_buffer *ibuf; /* Tampon de texte manipulé */
bool handled; /* Prise en compte effectuée ? */
itanium_component *sub; /* Sous-type lié à associer */
itanium_component *vendor; /* Extension propriétaire */
GDataType *builtin; /* Type construit */
itd_state saved; /* Position d'analyse courante */
itanium_component *targs; /* Composant 'template-args' */
ItaniumComponentType comp_type; /* Type de composant final */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
* ::=
* ::=
* ::=
* ::=
* ::= # See Compression below
* ::=
* ::= P # pointer-to
* ::= R # reference-to
* ::= O # rvalue reference-to (C++0x)
* ::= C # complex pair (C 2000)
* ::= G # imaginary (C 2000)
* ::= U # vendor extended type qualifier
* ::= Dp # pack expansion (C++0x)
*
*/
result = NULL;
qualifier = itd_cv_qualifiers(context);
if (qualifier != TQF_NONE)
{
result = itd_type(context);
if (result != NULL)
result = itd_make_qualified_type(result, qualifier);
goto itd_type_end;
}
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
handled = false;
switch (peek_input_buffer_char(ibuf))
{
case 'F':
result = itd_function_type(context);
handled = true;
break;
case 'A':
result = itd_array_type(context);
handled = true;
break;
case 'M':
result = itd_pointer_to_member_type(context);
handled = true;
break;
case 'P':
advance_input_buffer(ibuf, 1);
sub = itd_type(context);
if (sub == NULL) return NULL;
result = itd_make_unary(ICT_POINTER_TO, sub);
handled = true;
break;
case 'R':
advance_input_buffer(ibuf, 1);
sub = itd_type(context);
if (sub == NULL) return NULL;
result = itd_make_unary(ICT_REFERENCE_TO, sub);
handled = true;
break;
case 'O':
advance_input_buffer(ibuf, 1);
sub = itd_type(context);
if (sub == NULL) return NULL;
result = itd_make_unary(ICT_RVALUE_REFERENCE_TO, sub);
handled = true;
break;
case 'C':
advance_input_buffer(ibuf, 1);
sub = itd_type(context);
if (sub == NULL) return NULL;
result = itd_make_unary(ICT_COMPLEX_PAIR, sub);
handled = true;
break;
case 'G':
advance_input_buffer(ibuf, 1);
sub = itd_type(context);
if (sub == NULL) return NULL;
result = itd_make_unary(ICT_IMAGINARY, sub);
handled = true;
break;
case 'U':
advance_input_buffer(ibuf, 1);
result = NULL;
vendor = itd_source_name(context);
if (vendor == NULL)
result = NULL;
else
{
builtin = g_class_enum_type_new(CEK_UNKNOWN, itd_translate_component(vendor, NULL));
result = itd_make_type(builtin);
itd_set_type(result, ICT_VENDOR_TYPE);
itd_unref_comp(vendor);
sub = itd_type(context);
if (sub != NULL)
itd_unref_comp(sub);
else
{
itd_unref_comp(result);
result = NULL;
}
}
handled = true;
break;
case 'D':
if (peek_input_buffer_next_char(ibuf) == 'p')
{
advance_input_buffer(ibuf, 2);
result = itd_type(context);
handled = true;
}
break;
case 'T':
/**
* Comme on a la définition suivante :
*
* ::=
* ::=
*
* On ne sait pas laquelle de ces deux directions prendre :
*
* ::=
* ::=
*
* Comme commence toujour par un I, on teste
* le caractère courant après et on revient
* un poil en arrière au besoin.
*
* Le cas est traité de façon similaire après.
*/
g_itanium_demangling_push_state(context, &saved);
result = itd_template_param(context);
if (result != NULL)
{
if (peek_input_buffer_char(ibuf) == 'I')
{
itd_unref_comp(result);
g_itanium_demangling_pop_state(context, &saved);
result = itd_template_template_param(context);
if (result != NULL)
{
targs = itd_template_args(context);
if (targs != NULL)
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs);
else
{
itd_unref_comp(result);
result = NULL;
}
}
}
}
handled = true;
break;
}
if (handled) goto itd_type_end;
g_itanium_demangling_push_state(context, &saved);
result = itd_builtin_type(context);
if (result != NULL) goto itd_type_end;
g_itanium_demangling_pop_state(context, &saved);
result = itd_class_enum_type(context);
if (result != NULL) goto itd_type_end;
g_itanium_demangling_pop_state(context, &saved);
/**
* De façon similaire au cas traité au dessus,
* on guette un usage de via :
*
* ::=
* ::=
*
* La distinction se réalise via une liste d'argument, et on tranche
* cette fois entre les deux directions suivantes :
*
* ::=
* ::= # See Compression below
*/
g_itanium_demangling_push_state(context, &saved);
result = itd_substitution(context);
if (result != NULL && peek_input_buffer_char(ibuf) == 'I')
{
itd_unref_comp(result);
g_itanium_demangling_pop_state(context, &saved);
result = itd_template_template_param(context);
if (result != NULL)
{
targs = itd_template_args(context);
if (targs != NULL)
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs);
else
{
itd_unref_comp(result);
result = NULL;
}
}
}
itd_type_end:
if (result != NULL)
{
/**
* Les spécifications (§ 5.1.9) précisent:
*
* There are two exceptions that appear to be substitution candidates
* from the grammar, but are explicitly excluded:
*
* other than vendor extended types, and
* function and operator names other than extern "C" functions.
*
* On saute donc éventuelleement certains résultats.
*
* Par ailleurs, il existe quelques restrictions à propos des qualificatifs :
*
* For purposes of substitution, given a CV-qualified type, the base
* type is substitutible, and the type with all the C, V, and r qualifiers
* plus any vendor extended types in the same order-insensitive set is
* substitutible; any type with a subset of those qualifiers is not.
*
* Le code courant englobe tous les qualificatifs, donc il n'y a pas de
* mesure particulière à prendre ici.
*/
comp_type = itd_get_component_type(result);
if (comp_type != ICT_TYPE
&& (comp_type != ICT_FUNCTION_TYPE || itd_is_external_function(result)))
{
g_itanium_demangling_add_substitution(context, result);
}
}
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(GItaniumDemangling *context)
{
TypeQualifier result; /* Valeur à remonter */
input_buffer *ibuf; /* Tampon de texte manipulé */
/**
* La règle traitée ici est la suivante :
*
* ::= [r] [V] [K] # restrict (C99), volatile, const
*
*/
result = TQF_NONE;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
while (1)
switch (peek_input_buffer_char(ibuf))
{
case 'r':
result = TQF_RESTRICT;
advance_input_buffer(ibuf, 1);
break;
case 'V':
result = TQF_VOLATILE;
advance_input_buffer(ibuf, 1);
break;
case 'K':
result = TQF_CONST;
advance_input_buffer(ibuf, 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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
size_t consumed; /* Nombre de consommations */
BaseType type; /* Type reconnu ou BTP_INVALID */
GDataType *std; /* Espace de noms */
itanium_component *vendor; /* Extension propriétaire */
GDataType *builtin; /* Type construit */
/**
* La règle traitée ici est la suivante :
*
* ::= 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
* ::= Dd # IEEE 754r decimal floating point (64 bits)
* ::= De # IEEE 754r decimal floating point (128 bits)
* ::= Df # IEEE 754r decimal floating point (32 bits)
* ::= Dh # IEEE 754r half-precision floating point (16 bits)
* ::= DF _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
* ::= Di # char32_t
* ::= Ds # char16_t
* ::= Da # auto
* ::= Dc # decltype(auto)
* ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
* ::= u # vendor extended type
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
consumed = 1;
switch (peek_input_buffer_char(ibuf))
{
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 'D':
consumed = 2;
switch (peek_input_buffer_next_char(ibuf))
{
case 'd':
type = BTP_754R_64;
break;
case 'e':
type = BTP_754R_128;
break;
case 'f':
type = BTP_754R_32;
break;
case 'h':
type = BTP_754R_16;
break;
case 'F':
advance_input_buffer(ibuf, 2);
if (itd_number(context, (ssize_t []) { 0 }) && check_input_buffer_char(ibuf, '_'))
type = BTP_754R_N;
else
type = BTP_INVALID;
consumed = 0;
break;
case 'i':
type = BTP_CHAR32_T;
break;
case 's':
type = BTP_CHAR16_T;
break;
case 'a':
type = BTP_AUTO;
break;
case 'c':
type = BTP_DECL_AUTO;
break;
case 'n':
std = g_class_enum_type_new(CEK_NAMESPACE, strdup("std"));
builtin = g_class_enum_type_new(CEK_CLASS, strdup("nullptr_t"));
g_data_type_set_namespace(builtin, std, strdup("::"));
result = itd_make_type(builtin);
itd_set_type(result, ICT_STD_SUBST);
goto done;
break;
default:
type = BTP_INVALID;
break;
}
break;
case 'u':
advance_input_buffer(ibuf, 1);
vendor = itd_source_name(context);
if (vendor == NULL)
result = NULL;
else
{
builtin = g_class_enum_type_new(CEK_UNKNOWN, itd_translate_component(vendor, NULL));
result = itd_make_type(builtin);
itd_unref_comp(vendor);
}
goto done;
break;
default:
type = BTP_INVALID;
break;
}
if (type != BTP_INVALID)
{
builtin = g_basic_type_new(type);
result = itd_make_type(builtin);
advance_input_buffer(ibuf, consumed);
}
else
result = NULL;
done:
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_function_type(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère dispo. */
itanium_component *args; /* Liste des arguments */
/**
* La règle traitée ici est la suivante :
*
* ::= F [Y] E
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'F'))
return NULL;
peek = peek_input_buffer_char(ibuf);
if (peek == 'Y')
advance_input_buffer(ibuf, 1);
args = itd_bare_function_type(context);
if (args == NULL)
result = NULL;
else
{
result = itd_make_function_type(peek == 'Y', args);
if (!check_input_buffer_char(ibuf, 'E'))
{
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_bare_function_type(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
itanium_component *type; /* Nouvel élément à intégrer */
input_buffer *ibuf; /* Tampon de texte manipulé */
itd_state saved; /* Position d'analyse courante */
/**
* La règle traitée ici est la suivante :
*
* ::= +
* # types are possible return type, then parameter types
*
*/
type = itd_type(context);
if (type == NULL) return NULL;
result = itd_append_right_to_binary(ICT_TYPES_LIST, NULL, type);
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
while (count_input_buffer_remaining(ibuf) > 0)
{
g_itanium_demangling_push_state(context, &saved);
type = itd_type(context);
if (type == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
break;
}
result = itd_append_right_to_binary(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
/**
* La règle traitée ici est la suivante :
*
* ::=
*
*/
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_array_type(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
ssize_t dim_number; /* Dimension par un nombre */
itanium_component *type; /* Type du tableau */
itd_state saved; /* Position d'analyse courante */
itanium_component *dim_expr; /* Dimension via expression */
/**
* La règle traitée ici est la suivante :
*
* ::= A _
* ::= A [] _
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'A'))
return NULL;
if (itd_number(context, &dim_number))
{
if (!check_input_buffer_char(ibuf, '_'))
return NULL;
type = itd_type(context);
if (type == NULL)
return NULL;
result = itd_make_array_with_dim_number(dim_number, type);
}
else
{
g_itanium_demangling_push_state(context, &saved);
dim_expr = itd_expression(context);
if (dim_expr == NULL)
g_itanium_demangling_pop_state(context, &saved);
if (!check_input_buffer_char(ibuf, '_'))
{
if (dim_expr != NULL)
itd_unref_comp(dim_expr);
return NULL;
}
type = itd_type(context);
if (type == NULL)
{
if (dim_expr != NULL)
itd_unref_comp(dim_expr);
return NULL;
}
result = itd_make_array_with_dim_expr(dim_expr, 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_pointer_to_member_type(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
itanium_component *class; /* Classe d'appatenance */
itanium_component *member; /* Membre représenté */
/**
* La règle traitée ici est la suivante :
*
* ::= M
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'M'))
return NULL;
class = itd_type(context);
if (class != NULL)
{
member = itd_type(context);
if (member != NULL)
result = itd_make_pointer_to_memeber_type(class, member);
else
{
itd_unref_comp(class);
result = NULL;
}
}
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_template_param(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char cur; /* Caractère analysé */
size_t id; /* Identifiant de substitution */
/**
* La règle traitée ici est la suivante :
*
* ::= T_ # first template parameter
* ::= T _
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'T'))
return NULL;
result = NULL;
if (get_input_buffer_next_char_carefully(ibuf, &cur))
{
if (cur == '_' || isdigit(cur) || isupper(cur))
{
if (!itd_seq_id(context, cur, &id))
return NULL;
result = g_itanium_demangling_get_template_arg(context, id);
if (result != NULL)
result = itd_make_unary(ICT_TEMPLATE_PARAM, 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_template_param(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère dispo. */
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'T')
result = itd_template_param(context);
else
result = itd_substitution(context);
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Détermine si le composant suivant correspond à un type donné.*
* *
* Retour : true si le décodage va à priori réussir, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool is_itd_template_args(GItaniumDemangling *context)
{
bool result; /* Bilan à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
/**
* La règle anticipée ici est la suivante :
*
* ::= I + E
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
result = (peek == 'I');
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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
itanium_component *arg; /* Nouvel argument extrait */
itd_state saved; /* Position d'analyse courante */
/**
* La règle traitée ici est la suivante :
*
* ::= I + E
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
if (!check_input_buffer_char(ibuf, 'I'))
return NULL;
arg = itd_template_arg(context);
if (arg == NULL) return NULL;
result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, NULL, arg);
while (1)
{
g_itanium_demangling_push_state(context, &saved);
arg = itd_template_arg(context);
if (arg == NULL)
{
g_itanium_demangling_pop_state(context, &saved);
break;
}
result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, result, arg);
}
if (!check_input_buffer_char(ibuf, 'E'))
{
itd_unref_comp(result);
return NULL;
}
result = itd_make_unary(ICT_TEMPLATE_ARGS, result);
g_itanium_demangling_add_template_args(context, 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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
itanium_component *packed; /* Argument compressé */
/**
* La règle traitée ici est la suivante :
*
* ::= # type or template
* ::= X E # expression
* ::= # simple expressions
* ::= J * E # argument pack
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'X')
{
advance_input_buffer(ibuf, 1);
result = itd_expression(context);
if (result != NULL && !check_input_buffer_char(ibuf, 'E'))
{
itd_unref_comp(result);
result = NULL;
}
}
else if (peek == 'L')
result = itd_expr_primary(context);
else if (peek == 'J')
{
advance_input_buffer(ibuf, 1);
result = NULL;
while (peek_input_buffer_char(ibuf) != 'E')
{
packed = itd_template_arg(context);
if (packed == NULL)
{
if (result != NULL)
{
itd_unref_comp(result);
result = NULL;
}
goto packed_failed;
}
result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, result, packed);
}
if (result == NULL)
result = itd_make_with_type(ICT_PACKED_EMPTY);
if (!check_input_buffer_char(ibuf, 'E'))
{
itd_unref_comp(result);
result = NULL;
}
}
else
result = itd_type(context);
packed_failed:
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_expression(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
char peek; /* Prochain caractère lu */
char next_peek; /* Caractère après le prochain */
itanium_component *targs; /* Composant 'template-args' */
ItaniumOperatorType otype; /* Type d'opérateur */
const void *odata; /* Données associées */
const itanium_operator_info *simple; /* Données d'opérateur simple */
int i; /* Boucle de parcours */
itanium_component *list; /* Liste de sous-expressions */
itanium_component *sub; /* Sous-expression chargée */
/**
* La règle traitée ici est la suivante :
*
* ::=
* ::=
* ::=
* ::= st
* ::=
* ::= sr # dependent name
* ::= sr # dependent template-id
* ::=
*
*/
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
peek = peek_input_buffer_char(ibuf);
if (peek == 'T')
result = itd_template_param(context);
else if (peek == 'L')
result = itd_expr_primary(context);
else if (islower(peek))
{
next_peek = peek_input_buffer_next_char(ibuf);
if (peek == 's' && next_peek == 't')
{
advance_input_buffer(ibuf, 2);
result = itd_type(context);
}
else if (peek == 's' && next_peek == 'r')
{
advance_input_buffer(ibuf, 2);
result = itd_type(context);
if (result != NULL)
{
itd_unref_comp(result);
result = itd_unqualified_name(context);
if (result)
{
peek = peek_input_buffer_char(ibuf);
if (peek == 'I')
{
targs = itd_template_args(context);
if (targs != NULL)
result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs);
else
{
itd_unref_comp(result);
result = NULL;
}
}
}
}
}
else
{
result = itd_operator_name(context);
if (result != NULL)
{
odata = itd_get_operator_info(result, &otype);
switch (otype)
{
case IOT_SIMPLE:
simple = (const itanium_operator_info *)odata;
list = NULL;
for (i = 0; i < simple->args; i++)
{
sub = itd_expression(context);
if (sub == NULL)
{
if (list != NULL)
{
itd_unref_comp(list);
list = NULL;
}
break;
}
list = itd_append_right_to_binary(ICT_EXPR_LIST, list, sub);
}
if (list == NULL)
{
itd_unref_comp(result);
result = NULL;
}
else
result = itd_make_binary(ICT_OPERATED_EXPRESSION, result, list);
break;
case IOT_CAST:
sub = itd_expression(context);
if (sub == NULL)
{
itd_unref_comp(result);
result = NULL;
}
else
{
list = itd_append_right_to_binary(ICT_EXPR_LIST, NULL, sub);
result = itd_make_binary(ICT_OPERATED_EXPRESSION, result, list);
}
break;
default:
assert(false);
itd_unref_comp(result);
result = NULL;
break;
}
}
}
}
else
result = NULL;
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(GItaniumDemangling *context, bool hex)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
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 :
*
* # integer literal
* # floating literal
*
*/
result = NULL;
ibuf = &G_DEMANGLING_CONTEXT(context)->buffer;
data = get_input_buffer_text_access(ibuf);
g_itanium_demangling_push_state(context, &saved);
while (1)
{
peek = peek_input_buffer_char(ibuf);
switch (peek)
{
case '0' ... '9':
advance_input_buffer(ibuf, 1);
break;
case 'a' ... 'f':
if (hex)
advance_input_buffer(ibuf, 1);
else
goto exit_iits;
break;
case 'E':
goto exit_loop;
break;
default:
goto exit_iits;
}
}
exit_loop:
g_itanium_demangling_push_state(context, &cur);
if ((cur.pos - saved.pos) > 0)
result = itd_make_name(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(GItaniumDemangling *context)
{
itanium_component *result; /* Construction à retourner */
input_buffer *ibuf; /* Tampon de texte manipulé */
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 :
*
* ::= L E # integer literal
* ::= L