+ long param;
+
+ if (! d_check_char (di, 'T'))
+ return NULL;
+
+ param = d_compact_number (di);
+ if (param < 0)
+ return NULL;
+
+ ++di->did_subs;
+
+ return d_make_template_param (di, param);
+}
+
+/* <template-args> ::= I <template-arg>+ E */
+
+static struct demangle_component *
+d_template_args (struct d_info *di)
+{
+ struct demangle_component *hold_last_name;
+ struct demangle_component *al;
+ struct demangle_component **pal;
+
+ /* Preserve the last name we saw--don't let the template arguments
+ clobber it, as that would give us the wrong name for a subsequent
+ constructor or destructor. */
+ hold_last_name = di->last_name;
+
+ if (! d_check_char (di, 'I'))
+ return NULL;
+
+ if (d_peek_char (di) == 'E')
+ {
+ /* An argument pack can be empty. */
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
+ }
+
+ al = NULL;
+ pal = &al;
+ while (1)
+ {
+ struct demangle_component *a;
+
+ a = d_template_arg (di);
+ if (a == NULL)
+ return NULL;
+
+ *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
+ if (*pal == NULL)
+ return NULL;
+ pal = &d_right (*pal);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ di->last_name = hold_last_name;
+
+ return al;
+}
+
+/* <template-arg> ::= <type>
+ ::= X <expression> E
+ ::= <expr-primary>
+*/
+
+static struct demangle_component *
+d_template_arg (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ switch (d_peek_char (di))
+ {
+ case 'X':
+ d_advance (di, 1);
+ ret = d_expression (di);
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+
+ case 'L':
+ return d_expr_primary (di);
+
+ case 'I':
+ /* An argument pack. */
+ return d_template_args (di);
+
+ default:
+ return cplus_demangle_type (di);
+ }
+}
+
+/* Subroutine of <expression> ::= cl <expression>+ E */
+
+static struct demangle_component *
+d_exprlist (struct d_info *di)
+{
+ struct demangle_component *list = NULL;
+ struct demangle_component **p = &list;
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
+ }
+
+ while (1)
+ {
+ struct demangle_component *arg = d_expression (di);
+ if (arg == NULL)
+ return NULL;
+
+ *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
+ if (*p == NULL)
+ return NULL;
+ p = &d_right (*p);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ return list;
+}
+
+/* <expression> ::= <(unary) operator-name> <expression>
+ ::= <(binary) operator-name> <expression> <expression>
+ ::= <(trinary) operator-name> <expression> <expression> <expression>
+ ::= cl <expression>+ E
+ ::= st <type>
+ ::= <template-param>
+ ::= sr <type> <unqualified-name>
+ ::= sr <type> <unqualified-name> <template-args>
+ ::= <expr-primary>
+*/
+
+static struct demangle_component *
+d_expression (struct d_info *di)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'L')
+ return d_expr_primary (di);
+ else if (peek == 'T')
+ return d_template_param (di);
+ else if (peek == 's' && d_peek_next_char (di) == 'r')
+ {
+ struct demangle_component *type;
+ struct demangle_component *name;
+
+ d_advance (di, 2);
+ type = cplus_demangle_type (di);
+ name = d_unqualified_name (di);
+ if (d_peek_char (di) != 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
+ else
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
+ d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di)));
+ }
+ else if (peek == 's' && d_peek_next_char (di) == 'p')
+ {
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ d_expression (di), NULL);
+ }
+ else if (peek == 'f' && d_peek_next_char (di) == 'p')
+ {
+ /* Function parameter used in a late-specified return type. */
+ int index;
+ d_advance (di, 2);
+ index = d_compact_number (di);
+ if (index < 0)
+ return NULL;
+
+ return d_make_function_param (di, index);
+ }
+ else if (IS_DIGIT (peek))
+ {
+ /* We can get an unqualified name as an expression in the case of
+ a dependent member access, i.e. decltype(T().i). */
+ struct demangle_component *name = d_unqualified_name (di);
+ if (name == NULL)
+ return NULL;
+ if (d_peek_char (di) == 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di));
+ else
+ return name;
+ }
+ else
+ {
+ struct demangle_component *op;
+ int args;
+
+ op = d_operator_name (di);
+ if (op == NULL)
+ return NULL;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+ di->expansion += op->u.s_operator.op->len - 2;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR
+ && strcmp (op->u.s_operator.op->code, "st") == 0)
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ cplus_demangle_type (di));
+
+ switch (op->type)
+ {
+ default:
+ return NULL;
+ case DEMANGLE_COMPONENT_OPERATOR:
+ args = op->u.s_operator.op->args;
+ break;
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ args = op->u.s_extended_operator.args;
+ break;
+ case DEMANGLE_COMPONENT_CAST:
+ args = 1;
+ break;
+ }
+
+ switch (args)
+ {
+ case 1:
+ {
+ struct demangle_component *operand;
+ if (op->type == DEMANGLE_COMPONENT_CAST
+ && d_check_char (di, '_'))
+ operand = d_exprlist (di);
+ else
+ operand = d_expression (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ operand);
+ }
+ case 2:
+ {
+ struct demangle_component *left;
+ struct demangle_component *right;
+
+ left = d_expression (di);
+ if (!strcmp (op->u.s_operator.op->code, "cl"))
+ right = d_exprlist (di);
+ else
+ right = d_expression (di);
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ left, right));
+ }
+ case 3:
+ {
+ struct demangle_component *first;
+ struct demangle_component *second;
+
+ first = d_expression (di);
+ second = d_expression (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ first,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ second,
+ d_expression (di))));
+ }
+ default:
+ return NULL;
+ }
+ }
+}
+
+/* <expr-primary> ::= L <type> <(value) number> E
+ ::= L <type> <(value) float> E
+ ::= L <mangled-name> E
+*/
+
+static struct demangle_component *
+d_expr_primary (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'L'))
+ return NULL;
+ if (d_peek_char (di) == '_'
+ /* Workaround for G++ bug; see comment in write_template_arg. */
+ || d_peek_char (di) == 'Z')
+ ret = cplus_demangle_mangled_name (di, 0);
+ else
+ {
+ struct demangle_component *type;
+ enum demangle_component_type t;
+ const char *s;
+
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+
+ /* If we have a type we know how to print, we aren't going to
+ print the type name itself. */
+ if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
+ di->expansion -= type->u.s_builtin.type->len;
+
+ /* Rather than try to interpret the literal value, we just
+ collect it as a string. Note that it's possible to have a
+ floating point literal here. The ABI specifies that the
+ format of such literals is machine independent. That's fine,
+ but what's not fine is that versions of g++ up to 3.2 with
+ -fabi-version=1 used upper case letters in the hex constant,
+ and dumped out gcc's internal representation. That makes it
+ hard to tell where the constant ends, and hard to dump the
+ constant in any readable form anyhow. We don't attempt to
+ handle these cases. */
+
+ t = DEMANGLE_COMPONENT_LITERAL;
+ if (d_peek_char (di) == 'n')
+ {
+ t = DEMANGLE_COMPONENT_LITERAL_NEG;
+ d_advance (di, 1);
+ }
+ s = d_str (di);
+ while (d_peek_char (di) != 'E')
+ {
+ if (d_peek_char (di) == '\0')
+ return NULL;
+ d_advance (di, 1);
+ }
+ ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
+ }
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+ ::= Z <(function) encoding> E s [<discriminator>]
+*/
+
+static struct demangle_component *
+d_local_name (struct d_info *di)
+{
+ struct demangle_component *function;
+
+ if (! d_check_char (di, 'Z'))
+ return NULL;
+
+ function = d_encoding (di, 0);
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ if (d_peek_char (di) == 's')
+ {
+ d_advance (di, 1);
+ if (! d_discriminator (di))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
+ d_make_name (di, "string literal",
+ sizeof "string literal" - 1));
+ }
+ else
+ {
+ struct demangle_component *name;
+ int num = -1;
+
+ if (d_peek_char (di) == 'd')
+ {
+ /* Default argument scope: d <number> _. */
+ d_advance (di, 1);
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+ }
+
+ name = d_name (di);
+ if (name)
+ switch (name->type)
+ {
+ /* Lambdas and unnamed types have internal discriminators. */
+ case DEMANGLE_COMPONENT_LAMBDA:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ break;
+ default:
+ if (! d_discriminator (di))
+ return NULL;
+ }
+ if (num >= 0)
+ name = d_make_default_arg (di, num, name);
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
+ }
+}
+
+/* <discriminator> ::= _ <(non-negative) number>
+
+ We demangle the discriminator, but we don't print it out. FIXME:
+ We should print it out in verbose mode. */
+
+static int
+d_discriminator (struct d_info *di)
+{
+ long discrim;
+
+ if (d_peek_char (di) != '_')
+ return 1;
+ d_advance (di, 1);
+ discrim = d_number (di);
+ if (discrim < 0)
+ return 0;
+ return 1;
+}
+
+/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
+
+static struct demangle_component *
+d_lambda (struct d_info *di)
+{
+ struct demangle_component *tl;
+ struct demangle_component *ret;
+ int num;
+
+ if (! d_check_char (di, 'U'))
+ return NULL;
+ if (! d_check_char (di, 'l'))
+ return NULL;
+
+ tl = d_parmlist (di);
+ if (tl == NULL)
+ return NULL;
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+
+ ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_LAMBDA;
+ ret->u.s_unary_num.sub = tl;
+ ret->u.s_unary_num.num = num;
+ }
+
+ if (! d_add_substitution (di, ret))
+ return NULL;
+
+ return ret;
+}
+
+/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
+
+static struct demangle_component *
+d_unnamed_type (struct d_info *di)
+{
+ struct demangle_component *ret;
+ long num;
+
+ if (! d_check_char (di, 'U'))
+ return NULL;
+ if (! d_check_char (di, 't'))
+ return NULL;
+
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+
+ ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE;
+ ret->u.s_number.number = num;
+ }
+
+ if (! d_add_substitution (di, ret))
+ return NULL;
+
+ return ret;
+}
+
+/* Add a new substitution. */
+
+static int
+d_add_substitution (struct d_info *di, struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ if (di->next_sub >= di->num_subs)
+ return 0;
+ di->subs[di->next_sub] = dc;
+ ++di->next_sub;
+ return 1;
+}
+
+/* <substitution> ::= S <seq-id> _
+ ::= S_
+ ::= St
+ ::= Sa
+ ::= Sb
+ ::= Ss
+ ::= Si
+ ::= So
+ ::= Sd
+
+ If PREFIX is non-zero, then this type is being used as a prefix in
+ a qualified name. In this case, for the standard substitutions, we
+ need to check whether we are being used as a prefix for a
+ constructor or destructor, and return a full template name.
+ Otherwise we will get something like std::iostream::~iostream()
+ which does not correspond particularly well to any function which
+ actually appears in the source.
+*/
+
+static const struct d_standard_sub_info standard_subs[] =
+{
+ { 't', NL ("std"),
+ NL ("std"),
+ NULL, 0 },
+ { 'a', NL ("std::allocator"),
+ NL ("std::allocator"),
+ NL ("allocator") },
+ { 'b', NL ("std::basic_string"),
+ NL ("std::basic_string"),
+ NL ("basic_string") },
+ { 's', NL ("std::string"),
+ NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
+ NL ("basic_string") },
+ { 'i', NL ("std::istream"),
+ NL ("std::basic_istream<char, std::char_traits<char> >"),
+ NL ("basic_istream") },
+ { 'o', NL ("std::ostream"),
+ NL ("std::basic_ostream<char, std::char_traits<char> >"),
+ NL ("basic_ostream") },
+ { 'd', NL ("std::iostream"),
+ NL ("std::basic_iostream<char, std::char_traits<char> >"),
+ NL ("basic_iostream") }
+};
+
+static struct demangle_component *
+d_substitution (struct d_info *di, int prefix)
+{
+ char c;
+
+ if (! d_check_char (di, 'S'))
+ return NULL;
+
+ c = d_next_char (di);
+ if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
+ {
+ unsigned int id;
+
+ id = 0;
+ if (c != '_')
+ {
+ do
+ {
+ unsigned int new_id;
+
+ if (IS_DIGIT (c))
+ new_id = id * 36 + c - '0';
+ else if (IS_UPPER (c))
+ new_id = id * 36 + c - 'A' + 10;
+ else
+ return NULL;
+ if (new_id < id)
+ return NULL;
+ id = new_id;
+ c = d_next_char (di);
+ }
+ while (c != '_');
+
+ ++id;
+ }
+
+ if (id >= (unsigned int) di->next_sub)
+ return NULL;
+
+ ++di->did_subs;
+
+ return di->subs[id];
+ }
+ else
+ {
+ int verbose;
+ const struct d_standard_sub_info *p;
+ const struct d_standard_sub_info *pend;
+
+ verbose = (di->options & DMGL_VERBOSE) != 0;
+ if (! verbose && prefix)
+ {
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'C' || peek == 'D')
+ verbose = 1;
+ }
+
+ pend = (&standard_subs[0]
+ + sizeof standard_subs / sizeof standard_subs[0]);
+ for (p = &standard_subs[0]; p < pend; ++p)
+ {
+ if (c == p->code)
+ {
+ const char *s;
+ int len;
+
+ if (p->set_last_name != NULL)
+ di->last_name = d_make_sub (di, p->set_last_name,
+ p->set_last_name_len);
+ if (verbose)
+ {
+ s = p->full_expansion;
+ len = p->full_len;
+ }
+ else
+ {
+ s = p->simple_expansion;
+ len = p->simple_len;
+ }
+ di->expansion += len;
+ return d_make_sub (di, s, len);
+ }
+ }
+
+ return NULL;
+ }
+}
+
+/* Initialize a growable string. */
+
+static void
+d_growable_string_init (struct d_growable_string *dgs, size_t estimate)
+{
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 0;
+
+ if (estimate > 0)
+ d_growable_string_resize (dgs, estimate);
+}
+
+/* Grow a growable string to a given size. */
+
+static inline void
+d_growable_string_resize (struct d_growable_string *dgs, size_t need)
+{
+ size_t newalc;
+ char *newbuf;
+
+ if (dgs->allocation_failure)
+ return;
+
+ /* Start allocation at two bytes to avoid any possibility of confusion
+ with the special value of 1 used as a return in *palc to indicate
+ allocation failures. */
+ newalc = dgs->alc > 0 ? dgs->alc : 2;
+ while (newalc < need)
+ newalc <<= 1;
+
+ newbuf = (char *) realloc (dgs->buf, newalc);
+ if (newbuf == NULL)
+ {
+ free (dgs->buf);
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 1;
+ return;
+ }
+ dgs->buf = newbuf;
+ dgs->alc = newalc;
+}
+
+/* Append a buffer to a growable string. */
+
+static inline void
+d_growable_string_append_buffer (struct d_growable_string *dgs,
+ const char *s, size_t l)
+{
+ size_t need;
+
+ need = dgs->len + l + 1;
+ if (need > dgs->alc)
+ d_growable_string_resize (dgs, need);
+
+ if (dgs->allocation_failure)
+ return;
+
+ memcpy (dgs->buf + dgs->len, s, l);
+ dgs->buf[dgs->len + l] = '\0';
+ dgs->len += l;
+}
+
+/* Bridge growable strings to the callback mechanism. */
+
+static void
+d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
+{
+ struct d_growable_string *dgs = (struct d_growable_string*) opaque;
+
+ d_growable_string_append_buffer (dgs, s, l);
+}
+
+/* Initialize a print information structure. */
+
+static void
+d_print_init (struct d_print_info *dpi, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ dpi->options = options;
+ dpi->len = 0;
+ dpi->last_char = '\0';
+ dpi->templates = NULL;
+ dpi->modifiers = NULL;
+
+ dpi->callback = callback;
+ dpi->opaque = opaque;
+
+ dpi->demangle_failure = 0;
+}
+
+/* Indicate that an error occurred during printing, and test for error. */
+
+static inline void
+d_print_error (struct d_print_info *dpi)
+{
+ dpi->demangle_failure = 1;
+}
+
+static inline int
+d_print_saw_error (struct d_print_info *dpi)
+{
+ return dpi->demangle_failure != 0;
+}
+
+/* Flush buffered characters to the callback. */
+
+static inline void
+d_print_flush (struct d_print_info *dpi)
+{
+ dpi->buf[dpi->len] = '\0';
+ dpi->callback (dpi->buf, dpi->len, dpi->opaque);
+ dpi->len = 0;
+}
+
+/* Append characters and buffers for printing. */
+
+static inline void
+d_append_char (struct d_print_info *dpi, char c)
+{
+ if (dpi->len == sizeof (dpi->buf) - 1)
+ d_print_flush (dpi);
+
+ dpi->buf[dpi->len++] = c;
+ dpi->last_char = c;
+}
+
+static inline void
+d_append_buffer (struct d_print_info *dpi, const char *s, size_t l)
+{
+ size_t i;
+
+ for (i = 0; i < l; i++)
+ d_append_char (dpi, s[i]);
+}
+
+static inline void
+d_append_string (struct d_print_info *dpi, const char *s)
+{
+ d_append_buffer (dpi, s, strlen (s));
+}
+
+static inline void
+d_append_num (struct d_print_info *dpi, long l)
+{
+ char buf[25];
+ sprintf (buf,"%ld", l);
+ d_append_string (dpi, buf);
+}
+
+static inline char
+d_last_char (struct d_print_info *dpi)
+{
+ return dpi->last_char;
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ CALLBACK is a function to call to flush demangled string segments
+ as they fill the intermediate buffer, and OPAQUE is a generalized
+ callback argument. On success, this returns 1. On failure,
+ it returns 0, indicating a bad parse. It does not use heap
+ memory to build an output string, so cannot encounter memory
+ allocation failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_print_callback (int options,
+ const struct demangle_component *dc,
+ demangle_callbackref callback, void *opaque)
+{
+ struct d_print_info dpi;
+
+ d_print_init (&dpi, options, callback, opaque);
+
+ d_print_comp (&dpi, dc);
+
+ d_print_flush (&dpi);
+
+ return ! d_print_saw_error (&dpi);
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ ESTIMATE is a guess at the length of the result. This returns a
+ string allocated by malloc, or NULL on error. On success, this
+ sets *PALC to the size of the allocated buffer. On failure, this
+ sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
+ failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+char *
+cplus_demangle_print (int options, const struct demangle_component *dc,
+ int estimate, size_t *palc)
+{
+ struct d_growable_string dgs;
+
+ d_growable_string_init (&dgs, estimate);
+
+ if (! cplus_demangle_print_callback (options, dc,
+ d_growable_string_callback_adapter,
+ &dgs))
+ {
+ free (dgs.buf);
+ *palc = 0;
+ return NULL;
+ }