OSDN Git Service

merge from glibc
[pf3gnuchains/gcc-fork.git] / libiberty / cp-demangle.c
index a5e5ded..a6a2c1e 100644 (file)
@@ -1,5 +1,5 @@
-/* Demangler for IA64 / g++ standard C++ ABI.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+/* Demangler for IA64 / g++ V3 ABI.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>. 
 
    This file is part of GNU CC.
@@ -20,7 +20,7 @@
 */
 
 /* This file implements demangling of C++ names mangled according to
-   the IA64 / g++ standard C++ ABI.  Use the cp_demangle function to
+   the IA64 / g++ V3 ABI.  Use the cp_demangle function to
    demangle a mangled name, or compile with the preprocessor macro
    STANDALONE_DEMANGLER defined to create a demangling filter
    executable (functionally similar to c++filt, but includes this
@@ -68,6 +68,9 @@
    anonymous namespace.  */
 #define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
 
+/* Character(s) to use for namespace separation in demangled output */
+#define NAMESPACE_SEPARATOR (dm->style == DMGL_JAVA ? "." : "::")
+
 /* If flag_verbose is zero, some simplifications will be made to the
    output to make it easier to read and supress details that are
    generally not of interest to the average C++ programmer.
@@ -166,6 +169,18 @@ struct demangling_def
 
   /* The most recently demangled source-name.  */
   dyn_string_t last_source_name;
+  
+  /* Language style to use for demangled output. */
+  int style;
+
+  /* Set to non-zero iff this name is a constructor.  The actual value
+     indicates what sort of constructor this is; see demangle.h.  */
+  enum gnu_v3_ctor_kinds is_constructor;
+
+  /* Set to non-zero iff this name is a destructor.  The actual value
+     indicates what sort of destructor this is; see demangle.h.  */
+  enum gnu_v3_dtor_kinds is_destructor;
+
 };
 
 typedef struct demangling_def *demangling_t;
@@ -240,7 +255,7 @@ static void template_arg_list_print
 static template_arg_list_t current_template_arg_list
   PARAMS ((demangling_t));
 static demangling_t demangling_new
-  PARAMS ((const char *));
+  PARAMS ((const char *, int));
 static void demangling_delete 
   PARAMS ((demangling_t));
 
@@ -409,7 +424,7 @@ string_list_delete (node)
   while (node != NULL)
     {
       string_list_t next = node->next;
-      free (node);
+      dyn_string_delete ((dyn_string_t) node);
       node = next;
     }
 }
@@ -783,8 +798,9 @@ current_template_arg_list (dm)
    Returns NULL if allocation fails.  */
 
 static demangling_t
-demangling_new (name)
+demangling_new (name, style)
      const char *name;
+     int style;
 {
   demangling_t dm;
   dm = (demangling_t) malloc (sizeof (struct demangling_def));
@@ -807,6 +823,9 @@ demangling_new (name)
       dyn_string_delete (dm->last_source_name);
       return NULL;
     }
+  dm->style = style;
+  dm->is_constructor = 0;
+  dm->is_destructor = 0;
 
   return dm;
 }
@@ -918,7 +937,7 @@ static status_t demangle_local_name
 static status_t demangle_discriminator 
   PARAMS ((demangling_t, int));
 static status_t cp_demangle
-  PARAMS ((const char *, dyn_string_t));
+  PARAMS ((const char *, dyn_string_t, int));
 #ifdef IN_LIBGCC2
 static status_t cp_demangle_type
   PARAMS ((const char*, dyn_string_t));
@@ -1222,7 +1241,7 @@ demangle_prefix (dm, encode_return_type)
        {
          /* We have another level of scope qualification.  */
          if (nested)
-           RETURN_IF_ERROR (result_add (dm, "::"));
+           RETURN_IF_ERROR (result_add (dm, NAMESPACE_SEPARATOR));
          else
            nested = 1;
 
@@ -2010,15 +2029,24 @@ demangle_ctor_dtor_name (dm)
     {
       /* A constructor name.  Consume the C.  */
       advance_char (dm);
-      if (peek_char (dm) < '1' || peek_char (dm) > '3')
+      flavor = next_char (dm);
+      if (flavor < '1' || flavor > '3')
        return "Unrecognized constructor.";
       RETURN_IF_ERROR (result_add_string (dm, dm->last_source_name));
+      switch (flavor)
+       {
+       case '1': dm->is_constructor = gnu_v3_complete_object_ctor;
+         break;
+       case '2': dm->is_constructor = gnu_v3_base_object_ctor;
+         break;
+       case '3': dm->is_constructor = gnu_v3_complete_object_allocating_ctor;
+         break;
+       }
       /* Print the flavor of the constructor if in verbose mode.  */
-      flavor = next_char (dm) - '1';
       if (flag_verbose)
        {
          RETURN_IF_ERROR (result_add (dm, "["));
-         RETURN_IF_ERROR (result_add (dm, ctor_flavors[flavor]));
+         RETURN_IF_ERROR (result_add (dm, ctor_flavors[flavor - '1']));
          RETURN_IF_ERROR (result_add_char (dm, ']'));
        }
     }
@@ -2026,16 +2054,25 @@ demangle_ctor_dtor_name (dm)
     {
       /* A destructor name.  Consume the D.  */
       advance_char (dm);
-      if (peek_char (dm) < '0' || peek_char (dm) > '2')
+      flavor = next_char (dm);
+      if (flavor < '0' || flavor > '2')
        return "Unrecognized destructor.";
       RETURN_IF_ERROR (result_add_char (dm, '~'));
       RETURN_IF_ERROR (result_add_string (dm, dm->last_source_name));
+      switch (flavor)
+       {
+       case '0': dm->is_destructor = gnu_v3_deleting_dtor;
+         break;
+       case '1': dm->is_destructor = gnu_v3_complete_object_dtor;
+         break;
+       case '2': dm->is_destructor = gnu_v3_base_object_dtor;
+         break;
+       }
       /* Print the flavor of the destructor if in verbose mode.  */
-      flavor = next_char (dm) - '0';
       if (flag_verbose)
        {
          RETURN_IF_ERROR (result_add (dm, " ["));
-         RETURN_IF_ERROR (result_add (dm, dtor_flavors[flavor]));
+         RETURN_IF_ERROR (result_add (dm, dtor_flavors[flavor - '0']));
          RETURN_IF_ERROR (result_add_char (dm, ']'));
        }
     }
@@ -2093,8 +2130,10 @@ demangle_type_ptr (dm, insert_pos, substitution_start)
       RETURN_IF_ERROR (demangle_type_ptr (dm, insert_pos, 
                                          substitution_start));
       /* Insert an asterisk where we're told to; it doesn't
-        necessarily go at the end.  */
-      RETURN_IF_ERROR (result_insert_char (dm, *insert_pos, '*'));
+        necessarily go at the end.  If we're doing Java style output, 
+        there is no pointer symbol.  */
+      if (dm->style != DMGL_JAVA)
+       RETURN_IF_ERROR (result_insert_char (dm, *insert_pos, '*'));
       /* The next (outermost) pointer or reference character should go
         after this one.  */
       ++(*insert_pos);
@@ -2469,6 +2508,39 @@ static const char *const builtin_type_names[26] =
   "..."                       /* z */
 };
 
+/* Java source names of builtin types.  Types that arn't valid in Java
+   are also included here - we don't fail if someone attempts to demangle a 
+   C++ symbol in Java style. */
+static const char *const java_builtin_type_names[26] = 
+{
+  "signed char",                /* a */
+  "boolean", /* C++ "bool" */   /* b */
+  "byte", /* C++ "char" */      /* c */
+  "double",                     /* d */
+  "long double",                /* e */
+  "float",                      /* f */
+  "__float128",                 /* g */
+  "unsigned char",              /* h */
+  "int",                        /* i */
+  "unsigned",                   /* j */
+  NULL,                         /* k */
+  "long",                       /* l */
+  "unsigned long",              /* m */
+  "__int128",                   /* n */
+  "unsigned __int128",          /* o */
+  NULL,                         /* p */
+  NULL,                         /* q */
+  NULL,                         /* r */
+  "short",                      /* s */
+  "unsigned short",             /* t */
+  NULL,                         /* u */
+  "void",                       /* v */
+  "char", /* C++ "wchar_t" */   /* w */
+  "long", /* C++ "long long" */ /* x */
+  "unsigned long long",         /* y */
+  "..."                         /* z */
+};
+
 /* Demangles and emits a <builtin-type>.  
 
     <builtin-type> ::= v  # void
@@ -2511,7 +2583,12 @@ demangle_builtin_type (dm)
     }
   else if (code >= 'a' && code <= 'z')
     {
-      const char *type_name = builtin_type_names[code - 'a'];
+      const char *type_name;
+      /* Java uses different names for some built-in types. */
+      if (dm->style == DMGL_JAVA)
+        type_name = java_builtin_type_names[code - 'a'];
+      else
+        type_name = builtin_type_names[code - 'a'];
       if (type_name == NULL)
        return "Unrecognized <builtin-type> code.";
 
@@ -3369,15 +3446,11 @@ demangle_discriminator (dm, suppress_first)
            /* Write the discriminator.  The mangled number is two
               less than the discriminator ordinal, counting from
               zero.  */
-           RETURN_IF_ERROR (int_to_dyn_string (discriminator + 2, 
+           RETURN_IF_ERROR (int_to_dyn_string (discriminator + 1,
                                                (dyn_string_t) dm->result));
        }
       else
-       {
-         if (flag_verbose)
-           /* A missing digit correspond to one.  */
-           RETURN_IF_ERROR (result_add_char (dm, '1'));
-       }
+       return STATUS_ERROR;
       if (flag_verbose)
        RETURN_IF_ERROR (result_add_char (dm, ']'));
     }
@@ -3395,16 +3468,17 @@ demangle_discriminator (dm, suppress_first)
    an error message, and the contents of RESULT are unchanged.  */
 
 static status_t
-cp_demangle (name, result)
+cp_demangle (name, result, style)
      const char *name;
      dyn_string_t result;
+     int style;
 {
   status_t status;
   int length = strlen (name);
 
   if (length > 2 && name[0] == '_' && name[1] == 'Z')
     {
-      demangling_t dm = demangling_new (name);
+      demangling_t dm = demangling_new (name, style);
       if (dm == NULL)
        return STATUS_ALLOCATION_FAILED;
 
@@ -3483,7 +3557,7 @@ cp_demangle_type (type_name, result)
 
 extern char *__cxa_demangle PARAMS ((const char *, char *, size_t *, int *));
 
-/* ABI-mandated entry point in the C++ runtime library for performing
+/* ia64 ABI-mandated entry point in the C++ runtime library for performing
    demangling.  MANGLED_NAME is a NUL-terminated character string
    containing the name to be demangled.  
 
@@ -3551,7 +3625,7 @@ __cxa_demangle (mangled_name, output_buffer, length, status)
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     /* MANGLED_NAME apprears to be a function or variable name.
        Demangle it accordingly.  */
-    result = cp_demangle (mangled_name, &demangled_name);
+    result = cp_demangle (mangled_name, &demangled_name, 0);
   else
     /* Try to demangled MANGLED_NAME as the name of a type.  */
     result = cp_demangle_type (mangled_name, &demangled_name);
@@ -3597,13 +3671,21 @@ __cxa_demangle (mangled_name, output_buffer, length, status)
    If the demangling failes, returns NULL.  */
 
 char *
-cplus_demangle_new_abi (mangled)
+cplus_demangle_v3 (mangled)
      const char* mangled;
 {
+  dyn_string_t demangled;
+  status_t status;
+
+  /* If this isn't a mangled name, don't pretend to demangle it.  */
+  if (strncmp (mangled, "_Z", 2) != 0)
+    return NULL;
+
   /* Create a dyn_string to hold the demangled name.  */
-  dyn_string_t demangled = dyn_string_new (0);
+  demangled = dyn_string_new (0);
   /* Attempt the demangling.  */
-  status_t status = cp_demangle ((char *) mangled, demangled);
+  status = cp_demangle ((char *) mangled, demangled, 0);
+
   if (STATUS_NO_ERROR (status))
     /* Demangling succeeded.  */
     {
@@ -3626,8 +3708,194 @@ cplus_demangle_new_abi (mangled)
     }
 }
 
+/* Demangle a Java symbol.  Java uses a subset of the V3 ABI C++ mangling 
+   conventions, but the output formatting is a little different.
+   This instructs the C++ demangler not to emit pointer characters ("*"), and 
+   to use Java's namespace separator symbol ("." instead of "::").  It then 
+   does an additional pass over the demangled output to replace instances 
+   of JArray<TYPE> with TYPE[].  */
+
+char *
+java_demangle_v3 (mangled)
+     const char* mangled;
+{
+  dyn_string_t demangled;
+  char *next;
+  char *end;
+  int len;
+  status_t status;
+  int nesting = 0;
+  char *cplus_demangled;
+  char *return_value;
+    
+  /* Create a dyn_string to hold the demangled name.  */
+  demangled = dyn_string_new (0);
+
+  /* Attempt the demangling.  */
+  status = cp_demangle ((char *) mangled, demangled, DMGL_JAVA);
+
+  if (STATUS_NO_ERROR (status))
+    /* Demangling succeeded.  */
+    {
+      /* Grab the demangled result from the dyn_string. */
+      cplus_demangled = dyn_string_release (demangled);
+    }
+  else if (status == STATUS_ALLOCATION_FAILED)
+    {
+      fprintf (stderr, "Memory allocation failed.\n");
+      abort ();
+    }
+  else
+    /* Demangling failed.  */
+    {
+      dyn_string_delete (demangled);
+      return NULL;
+    }
+  
+  len = strlen (cplus_demangled);
+  next = cplus_demangled;
+  end = next + len;
+  demangled = NULL;
+
+  /* Replace occurances of JArray<TYPE> with TYPE[]. */
+  while (next < end)
+    {
+      char *open_str = strstr (next, "JArray<");
+      char *close_str = NULL;
+      if (nesting > 0)
+       close_str = strchr (next, '>');
+    
+      if (open_str != NULL && (close_str == NULL || close_str > open_str))
+        {
+         ++nesting;
+         
+         if (!demangled)
+           demangled = dyn_string_new(len);
+
+          /* Copy prepending symbols, if any. */
+         if (open_str > next)
+           {
+             open_str[0] = 0;
+             dyn_string_append_cstr (demangled, next);
+           }     
+         next = open_str + 7;
+       }
+      else if (close_str != NULL)
+        {
+         --nesting;
+         
+          /* Copy prepending type symbol, if any. Squash any spurious 
+            whitespace. */
+         if (close_str > next && next[0] != ' ')
+           {
+             close_str[0] = 0;
+             dyn_string_append_cstr (demangled, next);
+           }
+         dyn_string_append_cstr (demangled, "[]");       
+         next = close_str + 1;
+       }
+      else
+        {
+         /* There are no more arrays. Copy the rest of the symbol, or
+            simply return the original symbol if no changes were made. */
+         if (next == cplus_demangled)
+           return cplus_demangled;
+
+          dyn_string_append_cstr (demangled, next);
+         next = end;
+       }
+    }
+
+  free (cplus_demangled);
+  
+  return_value = dyn_string_release (demangled);
+  return return_value;
+}
+
 #endif /* IN_LIBGCC2 */
 
+
+/* Demangle NAME in the G++ V3 ABI demangling style, and return either
+   zero, indicating that some error occurred, or a demangling_t
+   holding the results.  */
+static demangling_t
+demangle_v3_with_details (name)
+     const char *name;
+{
+  demangling_t dm;
+  status_t status;
+
+  if (strncmp (name, "_Z", 2))
+    return 0;
+
+  dm = demangling_new (name, DMGL_GNU_V3);
+  if (dm == NULL)
+    {
+      fprintf (stderr, "Memory allocation failed.\n");
+      abort ();
+    }
+
+  status = result_push (dm);
+  if (! STATUS_NO_ERROR (status))
+    {
+      demangling_delete (dm);
+      fprintf (stderr, "%s\n", status);
+      abort ();
+    }
+
+  status = demangle_mangled_name (dm);
+  if (STATUS_NO_ERROR (status))
+    return dm;
+
+  demangling_delete (dm);
+  return 0;
+}
+
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+   in the G++ V3 ABI demangling style.  Specifically, return:
+   - '1' if NAME is a complete object constructor,
+   - '2' if NAME is a base object constructor, or
+   - '3' if NAME is a complete object allocating constructor.  */
+enum gnu_v3_ctor_kinds
+is_gnu_v3_mangled_ctor (name)
+     const char *name;
+{
+  demangling_t dm = demangle_v3_with_details (name);
+
+  if (dm)
+    {
+      enum gnu_v3_ctor_kinds result = dm->is_constructor;
+      demangling_delete (dm);
+      return result;
+    }
+  else
+    return 0;
+}
+
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+   in the G++ V3 ABI demangling style.  Specifically, return:
+   - '0' if NAME is a deleting destructor,
+   - '1' if NAME is a complete object destructor, or
+   - '2' if NAME is a base object destructor.  */
+enum gnu_v3_dtor_kinds
+is_gnu_v3_mangled_dtor (name)
+     const char *name;
+{
+  demangling_t dm = demangle_v3_with_details (name);
+
+  if (dm)
+    {
+      enum gnu_v3_dtor_kinds result = dm->is_destructor;
+      demangling_delete (dm);
+      return result;
+    }
+  else
+    return 0;
+}
+
+
 #ifdef STANDALONE_DEMANGLER
 
 #include "getopt.h"
@@ -3763,7 +4031,7 @@ main (argc, argv)
            }
 
          /* Attempt to demangle the name.  */
-         status = cp_demangle (dyn_string_buf (mangled), demangled);
+         status = cp_demangle (dyn_string_buf (mangled), demangled, 0);
 
          /* If the demangling succeeded, great!  Print out the
             demangled version.  */
@@ -3802,7 +4070,7 @@ main (argc, argv)
       for (i = optind; i < argc; ++i)
        {
          /* Attempt to demangle.  */
-         status = cp_demangle (argv[i], result);
+         status = cp_demangle (argv[i], result, 0);
 
          /* If it worked, print the demangled name.  */
          if (STATUS_NO_ERROR (status))
@@ -3810,7 +4078,7 @@ main (argc, argv)
          /* Abort on allocaiton failures.  */
          else if (status == STATUS_ALLOCATION_FAILED)
            {
-             fprintf (stderr, "Memory allocaiton failed.\n");
+             fprintf (stderr, "Memory allocation failed.\n");
              abort ();
            }
          /* If not, print the error message to stderr instead.  */