diff mbox

Improve ada demangler

Message ID 20100907091214.GA27991@ulanbator.act-europe.fr
State New
Headers show

Commit Message

Tristan Gingold Sept. 7, 2010, 9:12 a.m. UTC
Hi,

this patch adds demangling of Ada stream operations and controlled type
operations.  It also fixes a few corner cases that can occur within
instantiated generics.

Ok for mainline ?

Tristan.


libiberty:
2010-09-07  Tristan Gingold  <gingold@adacore.com>

	* cplus-dem.c (ada_demangle): Add comments.
	Handle stream and controlled type operations.
	Decoding of some uppercase letters moved before separators.
	* testsuite/demangle-expected: Add tests.

Comments

Tristan Gingold Sept. 21, 2010, 12:56 p.m. UTC | #1
Ping for this libiberty patch.

Thanks,
Tristan.

On Sep 7, 2010, at 11:12 AM, Tristan Gingold wrote:

> Hi,
> 
> this patch adds demangling of Ada stream operations and controlled type
> operations.  It also fixes a few corner cases that can occur within
> instantiated generics.
> 
> Ok for mainline ?
> 
> Tristan.
> 
> 
> libiberty:
> 2010-09-07  Tristan Gingold  <gingold@adacore.com>
> 
> 	* cplus-dem.c (ada_demangle): Add comments.
> 	Handle stream and controlled type operations.
> 	Decoding of some uppercase letters moved before separators.
> 	* testsuite/demangle-expected: Add tests.
> 
> diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
> index f20a5ef..396e617 100644
> --- a/libiberty/cplus-dem.c
> +++ b/libiberty/cplus-dem.c
> @@ -895,18 +895,20 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
> 
>   /* Most of the demangling will trivially remove chars.  Operator names
>      may add one char but because they are always preceeded by '__' which is
> -     replaced by '.', they eventually never expand the size.  '___elabs' and
> -     '___elabb' add only 2 chars, but they occur only once.  */
> -  len0 = strlen (mangled) + 2 + 1;
> +     replaced by '.', they eventually never expand the size.
> +     A few special names such as '___elabs' add a few chars (at most 7), but
> +     they occur only once.  */
> +  len0 = strlen (mangled) + 7 + 1;
>   demangled = XNEWVEC (char, len0);
> 
>   d = demangled;
>   p = mangled;
>   while (1)
>     {
> -      /* Convert name, which is always lower-case.  */
> +      /* An entity names is expected.  */
>       if (ISLOWER (*p))
>         {
> +          /* An identifier, which is always lower case.  */
>           do
>             *d++ = *p++;
>           while (ISLOWER(*p) || ISDIGIT (*p)
> @@ -914,6 +916,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
>         }
>       else if (p[0] == 'O')
>         {
> +          /* An operator name.  */
>           static const char * const operators[][2] =
>             {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"},
>              {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"},
> @@ -948,6 +951,92 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
>           goto unknown;
>         }
> 
> +      /* The name can be directly followed by some uppercase letters.  */
> +      if (p[0] == 'T' && p[1] == 'K')
> +        {
> +          /* Task stuff.  */
> +          if (p[2] == 'B' && p[3] == 0)
> +            {
> +              /* Subprogram for task body.  */
> +              break;
> +            }
> +          else if (p[2] == '_' && p[3] == '_')
> +            {
> +              /* Inner declarations in a task.  */
> +              p += 4;
> +              *d++ = '.';
> +              continue;
> +            }
> +          else
> +            goto unknown;
> +        }
> +      if (p[0] == 'E' && p[1] == 0)
> +        {
> +          /* Exception name.  */
> +          goto unknown;
> +        }
> +      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
> +        {
> +          /* Protected type subprogram.  */
> +          break;
> +        }
> +      if ((*p == 'N' || *p == 'S') && p[1] == 0)
> +        {
> +          /* Enumerated type name table.  */
> +          goto unknown;
> +        }
> +      if (p[0] == 'X')
> +        {
> +          /* Body nested.  */
> +          p++;
> +          while (p[0] == 'n' || p[0] == 'b')
> +            p++;
> +        }
> +      if (p[0] == 'S' && p[1] && (p[2] == '_' || p[2] == 0))
> +        {
> +          /* Stream operations.  */
> +          const char *name;
> +          switch (p[1])
> +            {
> +            case 'R':
> +              name = "'Read";
> +              break;
> +            case 'W':
> +              name = "'Write";
> +              break;
> +            case 'I':
> +              name = "'Input";
> +              break;
> +            case 'O':
> +              name = "'Output";
> +              break;
> +            default:
> +              goto unknown;
> +            }
> +          p += 2;
> +          strcpy (d, name);
> +          d += strlen (name);
> +        }
> +      else if (p[0] == 'D')
> +        {
> +          /* Controlled type operation.  */
> +          const char *name;
> +          switch (p[1])
> +            {
> +            case 'F':
> +              name = ".Finalize";
> +              break;
> +            case 'A':
> +              name = ".Adjust";
> +              break;
> +            default:
> +              goto unknown;
> +            }
> +          strcpy (d, name);
> +          d += strlen (name);
> +          break;
> +        }
> +
>       if (p[0] == '_')
>         {
>           /* Separator.  */
> @@ -955,24 +1044,49 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
>             {
>               /* Standard separator.  Handled first.  */
>               p += 2;
> +
>               if (ISDIGIT (*p))
>                 {
> -                  /* Overloading.  */
> +                  /* Overloading number.  */
>                   do
>                     p++;
>                   while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
> +                  if (*p == 'X')
> +                    {
> +                      p++;
> +                      while (p[0] == 'n' || p[0] == 'b')
> +                        p++;
> +                    }
>                 }
> -              else if (*p == '_' && !strcmp (p + 1, "elabb"))
> -                {
> -                  memcpy (d, "'Elab_Body", 10);
> -                  d += 10;
> -                  break;
> -                }
> -              else if (*p == '_' && !strcmp (p + 1, "elabs"))
> +              else if (p[0] == '_' && p[1] != '_')
>                 {
> -                  memcpy (d, "'Elab_Spec", 10);
> -                  d += 10;
> -                  break;
> +                  /* Special names.  */
> +                  static const char * const special[][2] = {
> +                    { "_elabb", "'Elab_Body" },
> +                    { "_elabs", "'Elab_Spec" },
> +                    { "_size", "'Size" },
> +                    { "_alignment", "'Alignment" },
> +                    { "_assign", ".\":=\"" },
> +                    { NULL, NULL }
> +                  };
> +                  int k;
> +
> +                  for (k = 0; special[k][0]; k++)
> +                    {
> +                      int l = strlen (special[k][0]);
> +                      if (!strncmp (p, special[k][0], l))
> +                        {
> +                          p += l;
> +                          l = strlen (special[k][1]);
> +                          memcpy (d, special[k][1], l);
> +                          d += l;
> +                          break;
> +                        }
> +                    }
> +                  if (special[k][0])
> +                    break;
> +                  else
> +                    goto unknown;
>                 }
>               else
>                 {
> @@ -995,46 +1109,6 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
>             goto unknown;
>         }
> 
> -      if (p[0] == 'T' && p[1] == 'K')
> -        {
> -          if (p[2] == 'B' && p[3] == 0)
> -            {
> -              /* Subprogram for task body.  */
> -              break;
> -            }
> -          else if (p[2] == '_' && p[3] == '_')
> -            {
> -              /* Inner declarations in a task.  */
> -              p += 4;
> -              *d++ = '.';
> -              continue;
> -            }
> -          else
> -            goto unknown;
> -        }
> -      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
> -        {
> -          /* Protected type subprogram.  */
> -          break;
> -        }
> -      if (p[0] == 'E' && p[1] == 0)
> -        {
> -          /* Exception name.  */
> -          goto unknown;
> -        }
> -      if (*p == 'N' || *p == 'S')
> -        {
> -          /* Enumerated type name table.  */
> -          goto unknown;
> -        }
> -      if (p[0] == 'X')
> -        {
> -          /* Body nested.  */
> -          if (p[1] == 'n' || p[1] == 'b')
> -            p += 2;
> -          else if (p[1] == 0)
> -            p++;
> -        }
>       if (p[0] == '.' && ISDIGIT (p[1]))
>         {
>           /* Nested subprogram.  */
> diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
> index 15a0fe7..2cd5251 100644
> --- a/libiberty/testsuite/demangle-expected
> +++ b/libiberty/testsuite/demangle-expected
> @@ -4047,6 +4047,36 @@ prot.lock.update
> --format=gnat
> prot__lock__update_E6s
> prot.lock.update
> +# Controlled types
> +--format=gnat
> +gnat__sockets__sockets_library_controllerDF__2
> +gnat.sockets.sockets_library_controller.Finalize
> +--format=gnat
> +system__partition_interface__racw_stub_typeDA
> +system.partition_interface.racw_stub_type.Adjust
> +# Stream operations
> +--format=gnat
> +gnat__wide_wide_string_split__slice_setSR__2
> +gnat.wide_wide_string_split.slice_set'Read
> +--format=gnat
> +ada__real_time__timing_events__events__listSW__2Xnn
> +ada.real_time.timing_events.events.list'Write
> +--format=gnat
> +system__finalization_root__root_controlledSI
> +system.finalization_root.root_controlled'Input
> +--format=gnat
> +ada__finalization__limited_controlledSO__2
> +ada.finalization.limited_controlled'Output
> +# Tagged types
> +--format=gnat
> +ada__synchronous_task_control___size__2
> +ada.synchronous_task_control'Size
> +--format=gnat
> +ada__real_time__timing_events__events___alignment__2Xnn
> +ada.real_time.timing_events.events'Alignment
> +--format=gnat
> +system__finalization_root___assign__2
> +system.finalization_root.":="
> #
> # Used to crash the demangler.
> --format=gnu-v3
Ian Lance Taylor Sept. 21, 2010, 2:30 p.m. UTC | #2
Tristan Gingold <gingold@adacore.com> writes:

>> libiberty:
>> 2010-09-07  Tristan Gingold  <gingold@adacore.com>
>> 
>> 	* cplus-dem.c (ada_demangle): Add comments.
>> 	Handle stream and controlled type operations.
>> 	Decoding of some uppercase letters moved before separators.
>> 	* testsuite/demangle-expected: Add tests.

>> +      if (p[0] == 'S' && p[1] && (p[2] == '_' || p[2] == 0))

Write p[1] != 0 or p[1] != '\0'.

>> +                      int l = strlen (special[k][0]);

l is kind of a poor choice of variable name in this code which is
littered with 1's.  Consider len.  Also consider changing the type to
size_t.

>> +                      if (!strncmp (p, special[k][0], l))

Write strncmp (p, special[k][0], l) != 0 rather than using ! (I know the
existing code used !).

>> +                  if (special[k][0])

Write special[k][0] != 0 or special[k][0] != '\0'.


This is OK with those changes.

Thanks.

Ian
diff mbox

Patch

diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
index f20a5ef..396e617 100644
--- a/libiberty/cplus-dem.c
+++ b/libiberty/cplus-dem.c
@@ -895,18 +895,20 @@  ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
 
   /* Most of the demangling will trivially remove chars.  Operator names
      may add one char but because they are always preceeded by '__' which is
-     replaced by '.', they eventually never expand the size.  '___elabs' and
-     '___elabb' add only 2 chars, but they occur only once.  */
-  len0 = strlen (mangled) + 2 + 1;
+     replaced by '.', they eventually never expand the size.
+     A few special names such as '___elabs' add a few chars (at most 7), but
+     they occur only once.  */
+  len0 = strlen (mangled) + 7 + 1;
   demangled = XNEWVEC (char, len0);
   
   d = demangled;
   p = mangled;
   while (1)
     {
-      /* Convert name, which is always lower-case.  */
+      /* An entity names is expected.  */
       if (ISLOWER (*p))
         {
+          /* An identifier, which is always lower case.  */
           do
             *d++ = *p++;
           while (ISLOWER(*p) || ISDIGIT (*p)
@@ -914,6 +916,7 @@  ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
         }
       else if (p[0] == 'O')
         {
+          /* An operator name.  */
           static const char * const operators[][2] =
             {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"},
              {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"},
@@ -948,6 +951,92 @@  ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
           goto unknown;
         }
 
+      /* The name can be directly followed by some uppercase letters.  */
+      if (p[0] == 'T' && p[1] == 'K')
+        {
+          /* Task stuff.  */
+          if (p[2] == 'B' && p[3] == 0)
+            {
+              /* Subprogram for task body.  */
+              break;
+            }
+          else if (p[2] == '_' && p[3] == '_')
+            {
+              /* Inner declarations in a task.  */
+              p += 4;
+              *d++ = '.';
+              continue;
+            }
+          else
+            goto unknown;
+        }
+      if (p[0] == 'E' && p[1] == 0)
+        {
+          /* Exception name.  */
+          goto unknown;
+        }
+      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
+        {
+          /* Protected type subprogram.  */
+          break;
+        }
+      if ((*p == 'N' || *p == 'S') && p[1] == 0)
+        {
+          /* Enumerated type name table.  */
+          goto unknown;
+        }
+      if (p[0] == 'X')
+        {
+          /* Body nested.  */
+          p++;
+          while (p[0] == 'n' || p[0] == 'b')
+            p++;
+        }
+      if (p[0] == 'S' && p[1] && (p[2] == '_' || p[2] == 0))
+        {
+          /* Stream operations.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'R':
+              name = "'Read";
+              break;
+            case 'W':
+              name = "'Write";
+              break;
+            case 'I':
+              name = "'Input";
+              break;
+            case 'O':
+              name = "'Output";
+              break;
+            default:
+              goto unknown;
+            }
+          p += 2;
+          strcpy (d, name);
+          d += strlen (name);
+        }
+      else if (p[0] == 'D')
+        {
+          /* Controlled type operation.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'F':
+              name = ".Finalize";
+              break;
+            case 'A':
+              name = ".Adjust";
+              break;
+            default:
+              goto unknown;
+            }
+          strcpy (d, name);
+          d += strlen (name);
+          break;
+        }
+
       if (p[0] == '_')
         {
           /* Separator.  */
@@ -955,24 +1044,49 @@  ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
             {
               /* Standard separator.  Handled first.  */
               p += 2;
+
               if (ISDIGIT (*p))
                 {
-                  /* Overloading.  */
+                  /* Overloading number.  */
                   do
                     p++;
                   while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
+                  if (*p == 'X')
+                    {
+                      p++;
+                      while (p[0] == 'n' || p[0] == 'b')
+                        p++;
+                    }
                 }
-              else if (*p == '_' && !strcmp (p + 1, "elabb"))
-                {
-                  memcpy (d, "'Elab_Body", 10);
-                  d += 10;
-                  break;
-                }
-              else if (*p == '_' && !strcmp (p + 1, "elabs"))
+              else if (p[0] == '_' && p[1] != '_')
                 {
-                  memcpy (d, "'Elab_Spec", 10);
-                  d += 10;
-                  break;
+                  /* Special names.  */
+                  static const char * const special[][2] = {
+                    { "_elabb", "'Elab_Body" },
+                    { "_elabs", "'Elab_Spec" },
+                    { "_size", "'Size" },
+                    { "_alignment", "'Alignment" },
+                    { "_assign", ".\":=\"" },
+                    { NULL, NULL }
+                  };
+                  int k;
+
+                  for (k = 0; special[k][0]; k++)
+                    {
+                      int l = strlen (special[k][0]);
+                      if (!strncmp (p, special[k][0], l))
+                        {
+                          p += l;
+                          l = strlen (special[k][1]);
+                          memcpy (d, special[k][1], l);
+                          d += l;
+                          break;
+                        }
+                    }
+                  if (special[k][0])
+                    break;
+                  else
+                    goto unknown;
                 }
               else
                 {
@@ -995,46 +1109,6 @@  ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
             goto unknown;
         }
 
-      if (p[0] == 'T' && p[1] == 'K')
-        {
-          if (p[2] == 'B' && p[3] == 0)
-            {
-              /* Subprogram for task body.  */
-              break;
-            }
-          else if (p[2] == '_' && p[3] == '_')
-            {
-              /* Inner declarations in a task.  */
-              p += 4;
-              *d++ = '.';
-              continue;
-            }
-          else
-            goto unknown;
-        }
-      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
-        {
-          /* Protected type subprogram.  */
-          break;
-        }
-      if (p[0] == 'E' && p[1] == 0)
-        {
-          /* Exception name.  */
-          goto unknown;
-        }
-      if (*p == 'N' || *p == 'S')
-        {
-          /* Enumerated type name table.  */
-          goto unknown;
-        }
-      if (p[0] == 'X')
-        {
-          /* Body nested.  */
-          if (p[1] == 'n' || p[1] == 'b')
-            p += 2;
-          else if (p[1] == 0)
-            p++;
-        }
       if (p[0] == '.' && ISDIGIT (p[1]))
         {
           /* Nested subprogram.  */
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 15a0fe7..2cd5251 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4047,6 +4047,36 @@  prot.lock.update
 --format=gnat
 prot__lock__update_E6s
 prot.lock.update
+# Controlled types
+--format=gnat
+gnat__sockets__sockets_library_controllerDF__2
+gnat.sockets.sockets_library_controller.Finalize
+--format=gnat
+system__partition_interface__racw_stub_typeDA
+system.partition_interface.racw_stub_type.Adjust
+# Stream operations
+--format=gnat
+gnat__wide_wide_string_split__slice_setSR__2
+gnat.wide_wide_string_split.slice_set'Read
+--format=gnat
+ada__real_time__timing_events__events__listSW__2Xnn
+ada.real_time.timing_events.events.list'Write
+--format=gnat
+system__finalization_root__root_controlledSI
+system.finalization_root.root_controlled'Input
+--format=gnat
+ada__finalization__limited_controlledSO__2
+ada.finalization.limited_controlled'Output
+# Tagged types
+--format=gnat
+ada__synchronous_task_control___size__2
+ada.synchronous_task_control'Size
+--format=gnat
+ada__real_time__timing_events__events___alignment__2Xnn
+ada.real_time.timing_events.events'Alignment
+--format=gnat
+system__finalization_root___assign__2
+system.finalization_root.":="
 #
 # Used to crash the demangler.
 --format=gnu-v3