aboutsummaryrefslogtreecommitdiff
path: root/gdb/cp-name-parser.y
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/cp-name-parser.y')
-rw-r--r--gdb/cp-name-parser.y134
1 files changed, 112 insertions, 22 deletions
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 286bbb4..f257370 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -41,6 +41,7 @@
#include "libiberty.h"
#include "demangle.h"
#include "cp-support.h"
+#include "gdb_assert.h"
/* Bison does not make it easy to create a parser without global
state, unfortunately. Here are all the global variables used
@@ -60,7 +61,7 @@ static const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
struct demangle_info {
int used;
- struct demangle_info *prev, *next;
+ struct demangle_info *next;
struct demangle_component comps[ALLOC_CHUNK];
};
@@ -76,7 +77,6 @@ d_grab (void)
if (demangle_info->next == NULL)
{
more = malloc (sizeof (struct demangle_info));
- more->prev = demangle_info;
more->next = NULL;
demangle_info->next = more;
}
@@ -1935,20 +1935,14 @@ yyerror (char *msg)
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 = malloc (sizeof (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
@@ -1966,23 +1960,102 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len)
&err);
}
+/* A convenience function to allocate and initialize a new struct
+ demangled_parse_info. */
+
+struct demangle_parse_info *
+cp_new_demangle_parse_info (void)
+{
+ struct demangle_parse_info *info;
+
+ info = malloc (sizeof (struct demangle_parse_info));
+ info->info = NULL;
+ info->tree = NULL;
+ obstack_init (&info->obstack);
+
+ return info;
+}
+
+/* Free any memory associated with the given PARSE_INFO. */
+
+void
+cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
+{
+ struct demangle_info *info = parse_info->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 (&parse_info->obstack, NULL);
+
+ /* Free the parser info. */
+ free (parse_info);
+}
+
+/* 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.
+ SRC is then freed.
+
+ 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;
+
+ /* Assert if the SRC obstack is not empty. */
+ gdb_assert (obstack_empty_p (&src->obstack));
+
+ /* Free SRC. */
+ cp_demangled_name_parse_free (src);
+}
+
/* 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
+ a structure containing the root of the new tree is returned; it must
+ be freed by calling cp_demangled_name_parse_free. 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 demangle_parse_info *
cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
{
static char errbuf[60];
- struct demangle_component *result;
+ struct demangle_parse_info *result;
prev_lexptr = lexptr = demangled_name;
error_lexptr = NULL;
global_errmsg = NULL;
- allocate_info ();
+ demangle_info = allocate_info ();
+
+ result = cp_new_demangle_parse_info ();
+ result->info = demangle_info;
if (yyparse ())
{
@@ -1993,10 +2066,11 @@ cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
strcat (errbuf, "'");
*errmsg = errbuf;
}
+ cp_demangled_name_parse_free (result);
return NULL;
}
- result = global_result;
+ result->tree = global_result;
global_result = NULL;
return result;
@@ -2048,6 +2122,20 @@ xfree (void *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
main (int argc, char **argv)
{
@@ -2055,7 +2143,7 @@ main (int argc, char **argv)
char buf[65536];
int arg;
const char *errmsg;
- struct demangle_component *result;
+ struct demangle_parse_info *result;
arg = 1;
if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
@@ -2089,7 +2177,8 @@ main (int argc, char **argv)
continue;
}
- cp_print (result);
+ cp_print (result->tree);
+ cp_demangled_name_parse_free (result);
free (str2);
if (c)
@@ -2108,7 +2197,8 @@ main (int argc, char **argv)
fputc ('\n', stderr);
return 0;
}
- cp_print (result);
+ cp_print (result->tree);
+ cp_demangled_name_parse_free (result);
putchar ('\n');
}
return 0;