/* YACC parser for C++ names, for GDB.
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2017 Free Software Foundation, Inc.
Parts of the lexer are based on c-exp.y from GDB.
#include "defs.h"
-#include <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
-
#include "safe-ctype.h"
-#include "libiberty.h"
#include "demangle.h"
#include "cp-support.h"
struct demangle_info {
int used;
- struct demangle_info *prev, *next;
+ struct demangle_info *next;
struct demangle_component comps[ALLOC_CHUNK];
};
{
if (demangle_info->next == NULL)
{
- more = malloc (sizeof (struct demangle_info));
- more->prev = demangle_info;
+ more = XNEW (struct demangle_info);
more->next = NULL;
demangle_info->next = more;
}
#define yygindex cpname_yygindex
#define yytable cpname_yytable
#define yycheck cpname_yycheck
+#define yyss cpname_yyss
+#define yysslim cpname_yysslim
+#define yyssp cpname_yyssp
+#define yystacksize cpname_yystacksize
+#define yyvs cpname_yyvs
+#define yyvsp cpname_yyvsp
int yyparse (void);
static int yylex (void);
struct demangle_component *rhs)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_component (ret, d_type, lhs, rhs);
- return ret;
-}
+ int i;
+
+ i = cplus_demangle_fill_component (ret, d_type, lhs, rhs);
+ gdb_assert (i);
-static struct demangle_component *
-make_empty (enum demangle_component_type d_type)
-{
- struct demangle_component *ret = d_grab ();
- ret->type = d_type;
return ret;
}
make_operator (const char *name, int args)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_operator (ret, name, args);
+ int i;
+
+ i = cplus_demangle_fill_operator (ret, name, args);
+ gdb_assert (i);
+
return ret;
}
make_dtor (enum gnu_v3_dtor_kinds kind, struct demangle_component *name)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_dtor (ret, kind, name);
+ int i;
+
+ i = cplus_demangle_fill_dtor (ret, kind, name);
+ gdb_assert (i);
+
return ret;
}
make_builtin_type (const char *name)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_builtin_type (ret, name);
+ int i;
+
+ i = cplus_demangle_fill_builtin_type (ret, name);
+ gdb_assert (i);
+
return ret;
}
make_name (const char *name, int len)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_name (ret, name, len);
+ int i;
+
+ i = cplus_demangle_fill_name (ret, name, len);
+ gdb_assert (i);
+
return ret;
}
const char *opname;
}
-%type <comp> exp exp1 type start start_opt operator colon_name
+%type <comp> exp exp1 type start start_opt oper colon_name
%type <comp> unqualified_name colon_ext_name
-%type <comp> template template_arg
+%type <comp> templ template_arg
%type <comp> builtin_type
%type <comp> typespec_2 array_indicator
%type <comp> colon_ext_only ext_only_name
demangler_special
: DEMANGLER_SPECIAL start
- { $$ = make_empty ($1);
- d_left ($$) = $2;
- d_right ($$) = NULL; }
+ { $$ = fill_comp ((enum demangle_component_type) $1, $2, NULL); }
| CONSTRUCTION_VTABLE start CONSTRUCTION_IN start
{ $$ = fill_comp (DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, $2, $4); }
;
-operator : OPERATOR NEW
- { $$ = make_operator ("new", 1); }
+oper : OPERATOR NEW
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = make_operator ("new", 3);
+ }
| OPERATOR DELETE
- { $$ = make_operator ("delete", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = make_operator ("delete ", 1);
+ }
| OPERATOR NEW '[' ']'
- { $$ = make_operator ("new[]", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = make_operator ("new[]", 3);
+ }
| OPERATOR DELETE '[' ']'
- { $$ = make_operator ("delete[]", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = make_operator ("delete[] ", 1);
+ }
| OPERATOR '+'
{ $$ = make_operator ("+", 2); }
| OPERATOR '-'
since it's not clear that it's parseable. */
conversion_op
: OPERATOR typespec_2
- { $$ = fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL); }
+ { $$ = fill_comp (DEMANGLE_COMPONENT_CONVERSION, $2, NULL); }
;
conversion_op_name
/* DEMANGLE_COMPONENT_NAME */
/* This accepts certain invalid placements of '~'. */
-unqualified_name: operator
- | operator '<' template_params '>'
+unqualified_name: oper
+ | oper '<' template_params '>'
{ $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
| '~' NAME
{ $$ = make_dtor (gnu_v3_complete_object_dtor, $2); }
name : nested_name NAME %prec NAME
{ $$ = $1.comp; d_right ($1.last) = $2; }
| NAME %prec NAME
- | nested_name template %prec NAME
+ | nested_name templ %prec NAME
{ $$ = $1.comp; d_right ($1.last) = $2; }
- | template %prec NAME
+ | templ %prec NAME
;
colon_ext_name : colon_name
;
nested_name : NAME COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
| nested_name NAME COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
}
- | template COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
+ | templ COLONCOLON
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
- | nested_name template COLONCOLON
+ | nested_name templ COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
}
;
/* DEMANGLE_COMPONENT_TEMPLATE */
/* DEMANGLE_COMPONENT_TEMPLATE_ARGLIST */
-template : NAME '<' template_params '>'
+templ : NAME '<' template_params '>'
{ $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
;
;
ptr_operator : '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_POINTER);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_POINTER, NULL, NULL);
$$.last = &d_left ($$.comp);
$$.comp = d_qualify ($$.comp, $2, 0); }
/* g++ seems to allow qualifiers after the reference? */
| '&'
- { $$.comp = make_empty (DEMANGLE_COMPONENT_REFERENCE);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_REFERENCE, NULL, NULL);
+ $$.last = &d_left ($$.comp); }
+ | ANDAND
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_RVALUE_REFERENCE, NULL, NULL);
$$.last = &d_left ($$.comp); }
| nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $1.comp;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $1.comp, NULL);
/* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
*$1.last = *d_left ($1.last);
- $$.comp->u.s_binary.right = NULL;
$$.last = &d_right ($$.comp);
$$.comp = d_qualify ($$.comp, $3, 0); }
| COLONCOLON nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $2.comp;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $2.comp, NULL);
/* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
*$2.last = *d_left ($2.last);
- $$.comp->u.s_binary.right = NULL;
$$.last = &d_right ($$.comp);
$$.comp = d_qualify ($$.comp, $4, 0); }
;
array_indicator : '[' ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = NULL;
- }
+ { $$ = fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, NULL, NULL); }
| '[' INT ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = $2;
- }
+ { $$ = fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, $2, NULL); }
;
/* Details of this approach inspired by the G++ < 3.4 parser. */
$$.last = &d_right ($2);
}
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
;
$$.last = $1.last;
*$2.last = $1.comp; }
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
| direct_declarator_1
;
exp : SIZEOF '(' type ')' %prec UNARY
- { $$ = d_unary ("sizeof", $3); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = d_unary ("sizeof ", $3);
+ }
;
/* C++. */
generally allocate too many components, but the extra memory usage
doesn't hurt because the trees are temporary and the storage is
reused. More may be allocated later, by d_grab. */
-static void
+static struct demangle_info *
allocate_info (void)
{
- if (demangle_info == NULL)
- {
- demangle_info = malloc (sizeof (struct demangle_info));
- demangle_info->prev = NULL;
- demangle_info->next = NULL;
- }
- else
- while (demangle_info->prev)
- demangle_info = demangle_info->prev;
+ struct demangle_info *info = XNEW (struct demangle_info);
- demangle_info->used = 0;
+ info->next = NULL;
+ info->used = 0;
+ return info;
}
/* Convert RESULT to a string. The return value is allocated
&err);
}
+/* Constructor for demangle_parse_info. */
+
+demangle_parse_info::demangle_parse_info ()
+: info (NULL),
+ tree (NULL)
+{
+ obstack_init (&obstack);
+}
+
+/* Destructor for demangle_parse_info. */
+
+demangle_parse_info::~demangle_parse_info ()
+{
+ /* Free any allocated chunks of memory for the parse. */
+ while (info != NULL)
+ {
+ struct demangle_info *next = info->next;
+
+ free (info);
+ info = next;
+ }
+
+ /* Free any memory allocated during typedef replacement. */
+ obstack_free (&obstack, NULL);
+}
+
+/* Merge the two parse trees given by DEST and SRC. The parse tree
+ in SRC is attached to DEST at the node represented by TARGET.
+
+ NOTE 1: Since there is no API to merge obstacks, this function does
+ even attempt to try it. Fortunately, we do not (yet?) need this ability.
+ The code will assert if SRC->obstack is not empty.
+
+ NOTE 2: The string from which SRC was parsed must not be freed, since
+ this function will place pointers to that string into DEST. */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+ struct demangle_component *target,
+ struct demangle_parse_info *src)
+
+{
+ struct demangle_info *di;
+
+ /* Copy the SRC's parse data into DEST. */
+ *target = *src->tree;
+ di = dest->info;
+ while (di->next != NULL)
+ di = di->next;
+ di->next = src->info;
+
+ /* Clear the (pointer to) SRC's parse data so that it is not freed when
+ cp_demangled_parse_info_free is called. */
+ src->info = NULL;
+}
+
/* Convert a demangled name to a demangle_component tree. On success,
- the root of the new tree is returned; it is valid until the next
- call to this function and should not be freed. On error, NULL is
- returned, and an error message will be set in *ERRMSG (which does
- not need to be freed). */
+ a structure containing the root of the new tree is returned. On
+ error, NULL is returned, and an error message will be set in
+ *ERRMSG (which does not need to be freed). */
-struct demangle_component *
+struct std::unique_ptr<demangle_parse_info>
cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
{
static char errbuf[60];
- struct demangle_component *result;
prev_lexptr = lexptr = demangled_name;
error_lexptr = NULL;
global_errmsg = NULL;
- allocate_info ();
+ demangle_info = allocate_info ();
+
+ std::unique_ptr<demangle_parse_info> result (new demangle_parse_info);
+ result->info = demangle_info;
if (yyparse ())
{
return NULL;
}
- result = global_result;
+ result->tree = global_result;
global_result = NULL;
return result;
xfree (void *ptr)
{
if (ptr != NULL)
- free (ptr);
+ {
+ /* Literal `free' would get translated back to xfree again. */
+ CONCAT2 (fr,ee) (ptr);
+ }
+}
+
+/* GDB normally defines internal_error itself, but when this file is built
+ as a standalone program, we must also provide an implementation. */
+
+void
+internal_error (const char *file, int line, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (stderr, "%s:%d: internal error: ", file, line);
+ vfprintf (stderr, fmt, ap);
+ exit (1);
}
int
char buf[65536];
int arg;
const char *errmsg;
- struct demangle_component *result;
arg = 1;
if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
str2 = cplus_demangle (buf, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
if (str2 == NULL)
{
- /* printf ("Demangling error\n"); */
+ printf ("Demangling error\n");
if (c)
printf ("%s%c%s\n", buf, c, extra_chars);
else
printf ("%s\n", buf);
continue;
}
- result = cp_demangled_name_to_comp (str2, &errmsg);
+
+ std::unique_ptr<demangle_parse_info> result
+ = cp_demangled_name_to_comp (str2, &errmsg);
if (result == NULL)
{
fputs (errmsg, stderr);
continue;
}
- cp_print (result);
+ cp_print (result->tree);
free (str2);
if (c)
}
else
{
- result = cp_demangled_name_to_comp (argv[arg], &errmsg);
+ std::unique_ptr<demangle_parse_info> result
+ = cp_demangled_name_to_comp (argv[arg], &errmsg);
if (result == NULL)
{
fputs (errmsg, stderr);
fputc ('\n', stderr);
return 0;
}
- cp_print (result);
+ cp_print (result->tree);
putchar ('\n');
}
return 0;