xref: /csrg-svn/usr.bin/ld/cplus-dem.c (revision 62051)
148862Sbostic /*-
248862Sbostic  * This code is derived from software copyrighted by the Free Software
348862Sbostic  * Foundation.
448862Sbostic  */
548862Sbostic 
648861Sbostic #ifndef lint
7*62051Sbostic static char sccsid[] = "@(#)cplus-dem.c	8.1 (Berkeley) 06/06/93";
848861Sbostic #endif /* not lint */
948861Sbostic 
1048853Sbostic /* Demangler for GNU C++
1148853Sbostic    Copyright (C) 1989 Free Software Foundation, Inc.
1248853Sbostic    written by James Clark (jjc@jclark.uucp)
1348853Sbostic 
1448853Sbostic    This program is free software; you can redistribute it and/or modify
1548853Sbostic    it under the terms of the GNU General Public License as published by
1648853Sbostic    the Free Software Foundation; either version 1, or (at your option)
1748853Sbostic    any later version.
1848853Sbostic 
1948853Sbostic    This program is distributed in the hope that it will be useful,
2048853Sbostic    but WITHOUT ANY WARRANTY; without even the implied warranty of
2148853Sbostic    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2248853Sbostic    GNU General Public License for more details.
2348853Sbostic 
2448853Sbostic    You should have received a copy of the GNU General Public License
2548853Sbostic    along with this program; if not, write to the Free Software
2648853Sbostic    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
2748853Sbostic 
2848853Sbostic /* This is for g++ 1.36.1 (November 6 version). It will probably
2948853Sbostic    require changes for any other version.
3048853Sbostic 
3148853Sbostic    Modified for g++ 1.36.2 (November 18 version).  */
3248853Sbostic 
3348853Sbostic /* This file exports one function
3448853Sbostic 
3548853Sbostic    char *cplus_demangle (const char *name)
3648853Sbostic 
3748853Sbostic    If `name' is a mangled function name produced by g++, then
3848853Sbostic    a pointer to a malloced string giving a C++ representation
3948853Sbostic    of the name will be returned; otherwise NULL will be returned.
4048853Sbostic    It is the caller's responsibility to free the string which
4148853Sbostic    is returned.
4248853Sbostic 
4348853Sbostic    For example,
4448853Sbostic 
4548853Sbostic    cplus_demangle ("_foo__1Ai")
4648853Sbostic 
4748853Sbostic    returns
4848853Sbostic 
4948853Sbostic    "A::foo(int)"
5048853Sbostic 
5148853Sbostic    This file imports xmalloc and xrealloc, which are like malloc and
5248853Sbostic    realloc except that they generate a fatal error if there is no
5348853Sbostic    available memory. */
5448853Sbostic 
5548853Sbostic /* #define nounderscore 1 /* define this is names don't start with _ */
5648853Sbostic 
5748853Sbostic #include <stdio.h>
5848853Sbostic #include <ctype.h>
5948853Sbostic 
6048853Sbostic #ifdef USG
6148853Sbostic #include <memory.h>
6248853Sbostic #include <string.h>
6348853Sbostic #else
6448853Sbostic #include <strings.h>
6548853Sbostic #define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
6648853Sbostic #define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
6748853Sbostic #define strchr index
6848853Sbostic #define strrchr rindex
6948853Sbostic #endif
7048853Sbostic 
7148853Sbostic #ifdef __STDC__
7248853Sbostic extern char *cplus_demangle (const char *type);
7348853Sbostic #else
7448853Sbostic extern char *cplus_demangle ();
7548853Sbostic #endif
7648853Sbostic 
7748853Sbostic #ifdef __STDC__
7848853Sbostic extern char *xmalloc (int);
7948853Sbostic extern char *xrealloc (char *, int);
8048853Sbostic #else
8148853Sbostic extern char *xmalloc ();
8248853Sbostic extern char *xrealloc ();
8348853Sbostic #endif
8448853Sbostic 
8548853Sbostic static char **typevec = 0;
8648853Sbostic static int ntypes = 0;
8748853Sbostic static int typevec_size = 0;
8848853Sbostic 
8948853Sbostic static struct {
9048853Sbostic   const char *in;
9148853Sbostic   const char *out;
9248853Sbostic } optable[] = {
9348853Sbostic   "new", " new",
9448853Sbostic   "delete", " delete",
9548853Sbostic   "ne", "!=",
9648853Sbostic   "eq", "==",
9748853Sbostic   "ge", ">=",
9848853Sbostic   "gt", ">",
9948853Sbostic   "le", "<=",
10048853Sbostic   "lt", "<",
10148853Sbostic   "plus", "+",
10248853Sbostic   "minus", "-",
10348853Sbostic   "mult", "*",
10448853Sbostic   "convert", "+",	/* unary + */
10548853Sbostic   "negate", "-",	/* unary - */
10648853Sbostic   "trunc_mod", "%",
10748853Sbostic   "trunc_div", "/",
10848853Sbostic   "truth_andif", "&&",
10948853Sbostic   "truth_orif", "||",
11048853Sbostic   "truth_not", "!",
11148853Sbostic   "postincrement", "++",
11248853Sbostic   "postdecrement", "--",
11348853Sbostic   "bit_ior", "|",
11448853Sbostic   "bit_xor", "^",
11548853Sbostic   "bit_and", "&",
11648853Sbostic   "bit_not", "~",
11748853Sbostic   "call", "()",
11848853Sbostic   "cond", "?:",
11948853Sbostic   "alshift", "<<",
12048853Sbostic   "arshift", ">>",
12148853Sbostic   "component", "->",
12248853Sbostic   "indirect", "*",
12348853Sbostic   "method_call", "->()",
12448853Sbostic   "addr", "&",		/* unary & */
12548853Sbostic   "array", "[]",
12648853Sbostic   "nop", "",			/* for operator= */
12748853Sbostic };
12848853Sbostic 
12948853Sbostic /* Beware: these aren't '\0' terminated. */
13048853Sbostic 
13148853Sbostic typedef struct {
13248853Sbostic   char *b;			/* pointer to start of string */
13348853Sbostic   char *p;			/* pointer after last character */
13448853Sbostic   char *e;			/* pointer after end of allocated space */
13548853Sbostic } string;
13648853Sbostic 
13748853Sbostic #ifdef __STDC__
13848853Sbostic static void string_need (string *s, int n);
13948853Sbostic static void string_delete (string *s);
14048853Sbostic static void string_init (string *s);
14148853Sbostic static void string_clear (string *s);
14248853Sbostic static int string_empty (string *s);
14348853Sbostic static void string_append (string *p, const char *s);
14448853Sbostic static void string_appends (string *p, string *s);
14548853Sbostic static void string_appendn (string *p, const char *s, int n);
14648853Sbostic static void string_prepend (string *p, const char *s);
14748853Sbostic #if 0
14848853Sbostic static void string_prepends (string *p, string *s);
14948853Sbostic #endif
15048853Sbostic static void string_prependn (string *p, const char *s, int n);
15148853Sbostic static int get_count (const char **type, int *count);
15248853Sbostic static int do_args (const char **type, string *decl);
15348853Sbostic static int do_type (const char **type, string *result);
15448853Sbostic static int do_arg (const char **type, string *result);
15548853Sbostic static int do_args (const char **type, string *decl);
15648853Sbostic static void munge_function_name (string *name);
15748853Sbostic static void remember_type (const char *type, int len);
15848853Sbostic #else
15948853Sbostic static void string_need ();
16048853Sbostic static void string_delete ();
16148853Sbostic static void string_init ();
16248853Sbostic static void string_clear ();
16348853Sbostic static int string_empty ();
16448853Sbostic static void string_append ();
16548853Sbostic static void string_appends ();
16648853Sbostic static void string_appendn ();
16748853Sbostic static void string_prepend ();
16848853Sbostic static void string_prepends ();
16948853Sbostic static void string_prependn ();
17048853Sbostic static int get_count ();
17148853Sbostic static int do_args ();
17248853Sbostic static int do_type ();
17348853Sbostic static int do_arg ();
17448853Sbostic static int do_args ();
17548853Sbostic static void munge_function_name ();
17648853Sbostic static void remember_type ();
17748853Sbostic #endif
17848853Sbostic 
17948853Sbostic char *
cplus_demangle(type)18048853Sbostic cplus_demangle (type)
18148853Sbostic      const char *type;
18248853Sbostic {
18348853Sbostic   string decl;
18448853Sbostic   int n;
18548853Sbostic   int success = 0;
18648853Sbostic   int constructor = 0;
18748853Sbostic   int const_flag = 0;
18848853Sbostic   int i;
18948853Sbostic   const char *p;
19048853Sbostic #ifndef LONGERNAMES
19148853Sbostic   const char *premangle;
19248853Sbostic #endif
19348853Sbostic 
19448853Sbostic   if (type == NULL || *type == '\0')
19548853Sbostic     return NULL;
19648853Sbostic #ifndef nounderscore
19748853Sbostic   if (*type++ != '_')
19848853Sbostic     return NULL;
19948853Sbostic #endif
20048853Sbostic   p = type;
20148853Sbostic   while (*p != '\0' && !(*p == '_' && p[1] == '_'))
20248853Sbostic     p++;
20348853Sbostic   if (*p == '\0')
20448853Sbostic     {
20548853Sbostic       /* destructor */
20648853Sbostic       if (type[0] == '_' && type[1] == '$' && type[2] == '_')
20748853Sbostic 	{
20848853Sbostic 	  int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
20948853Sbostic 	  char *tem = (char *) xmalloc (n);
21048853Sbostic 	  strcpy (tem, type + 3);
21148853Sbostic 	  strcat (tem, "::~");
21248853Sbostic 	  strcat (tem, type + 3);
21348853Sbostic 	  strcat (tem, "()");
21448853Sbostic 	  return tem;
21548853Sbostic 	}
21648853Sbostic       /* static data member */
21748853Sbostic       if (*type != '_' && (p = strchr (type, '$')) != NULL)
21848853Sbostic 	{
21948853Sbostic 	  int n = strlen (type) + 2;
22048853Sbostic 	  char *tem = (char *) xmalloc (n);
22148853Sbostic 	  memcpy (tem, type, p - type);
22248853Sbostic 	  strcpy (tem + (p - type), "::");
22348853Sbostic 	  strcpy (tem + (p - type) + 2, p + 1);
22448853Sbostic 	  return tem;
22548853Sbostic 	}
22648853Sbostic       /* virtual table */
22748853Sbostic       if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
22848853Sbostic 	{
22948853Sbostic 	  int n = strlen (type + 4) + 14 + 1;
23048853Sbostic 	  char *tem = (char *) xmalloc (n);
23148853Sbostic 	  strcpy (tem, type + 4);
23248853Sbostic 	  strcat (tem, " virtual table");
23348853Sbostic 	  return tem;
23448853Sbostic 	}
23548853Sbostic       return NULL;
23648853Sbostic     }
23748853Sbostic 
23848853Sbostic   string_init (&decl);
23948853Sbostic 
24048853Sbostic   if (p == type)
24148853Sbostic     {
24248853Sbostic       if (!isdigit (p[2]))
24348853Sbostic 	{
24448853Sbostic 	  string_delete (&decl);
24548853Sbostic 	  return NULL;
24648853Sbostic 	}
24748853Sbostic       constructor = 1;
24848853Sbostic     }
24948853Sbostic   else
25048853Sbostic     {
25148853Sbostic       string_appendn (&decl, type, p - type);
25248853Sbostic       munge_function_name (&decl);
25348853Sbostic     }
25448853Sbostic   p += 2;
25548853Sbostic 
25648853Sbostic #ifndef LONGERNAMES
25748853Sbostic   premangle = p;
25848853Sbostic #endif
25948853Sbostic   switch (*p)
26048853Sbostic     {
26148853Sbostic     case 'C':
26248853Sbostic       /* a const member function */
26348853Sbostic       if (!isdigit (p[1]))
26448853Sbostic 	{
26548853Sbostic 	  string_delete (&decl);
26648853Sbostic 	  return NULL;
26748853Sbostic 	}
26848853Sbostic       p += 1;
26948853Sbostic       const_flag = 1;
27048853Sbostic       /* fall through */
27148853Sbostic     case '0':
27248853Sbostic     case '1':
27348853Sbostic     case '2':
27448853Sbostic     case '3':
27548853Sbostic     case '4':
27648853Sbostic     case '5':
27748853Sbostic     case '6':
27848853Sbostic     case '7':
27948853Sbostic     case '8':
28048853Sbostic     case '9':
28148853Sbostic       n = 0;
28248853Sbostic       do
28348853Sbostic 	{
28448853Sbostic 	  n *= 10;
28548853Sbostic 	  n += *p - '0';
28648853Sbostic 	  p += 1;
28748853Sbostic 	}
28848853Sbostic       while (isdigit (*p));
28948853Sbostic       if (strlen (p) < n)
29048853Sbostic 	{
29148853Sbostic 	  string_delete (&decl);
29248853Sbostic 	  return NULL;
29348853Sbostic 	}
29448853Sbostic       if (constructor)
29548853Sbostic 	{
29648853Sbostic 	  string_appendn (&decl, p, n);
29748853Sbostic 	  string_append (&decl, "::");
29848853Sbostic 	  string_appendn (&decl, p, n);
29948853Sbostic 	}
30048853Sbostic       else
30148853Sbostic 	{
30248853Sbostic 	  string_prepend (&decl, "::");
30348853Sbostic 	  string_prependn (&decl, p, n);
30448853Sbostic 	}
30548853Sbostic       p += n;
30648853Sbostic #ifndef LONGERNAMES
30748853Sbostic       remember_type (premangle, p - premangle);
30848853Sbostic #endif
30948853Sbostic       success = do_args (&p, &decl);
31048853Sbostic       if (const_flag)
31148853Sbostic 	string_append (&decl, " const");
31248853Sbostic       break;
31348853Sbostic     case 'F':
31448853Sbostic       p += 1;
31548853Sbostic       success = do_args (&p, &decl);
31648853Sbostic       break;
31748853Sbostic     }
31848853Sbostic 
31948853Sbostic   for (i = 0; i < ntypes; i++)
32048853Sbostic     if (typevec[i] != NULL)
32148853Sbostic       free (typevec[i]);
32248853Sbostic   ntypes = 0;
32348853Sbostic   if (typevec != NULL)
32448853Sbostic     {
32548853Sbostic       free ((char *)typevec);
32648853Sbostic       typevec = NULL;
32748853Sbostic       typevec_size = 0;
32848853Sbostic     }
32948853Sbostic 
33048853Sbostic   if (success)
33148853Sbostic     {
33248853Sbostic       string_appendn (&decl, "", 1);
33348853Sbostic       return decl.b;
33448853Sbostic     }
33548853Sbostic   else
33648853Sbostic     {
33748853Sbostic       string_delete (&decl);
33848853Sbostic       return NULL;
33948853Sbostic     }
34048853Sbostic }
34148853Sbostic 
34248853Sbostic static int
get_count(type,count)34348853Sbostic get_count (type, count)
34448853Sbostic      const char **type;
34548853Sbostic      int *count;
34648853Sbostic {
34748853Sbostic   if (!isdigit (**type))
34848853Sbostic     return 0;
34948853Sbostic   *count = **type - '0';
35048853Sbostic   *type += 1;
35148853Sbostic   /* see flush_repeats in cplus-method.c */
35248853Sbostic   if (isdigit (**type))
35348853Sbostic     {
35448853Sbostic       const char *p = *type;
35548853Sbostic       int n = *count;
35648853Sbostic       do
35748853Sbostic 	{
35848853Sbostic 	  n *= 10;
35948853Sbostic 	  n += *p - '0';
36048853Sbostic 	  p += 1;
36148853Sbostic 	}
36248853Sbostic       while (isdigit (*p));
36348853Sbostic       if (*p == '_')
36448853Sbostic 	{
36548853Sbostic 	  *type = p + 1;
36648853Sbostic 	  *count = n;
36748853Sbostic 	}
36848853Sbostic     }
36948853Sbostic   return 1;
37048853Sbostic }
37148853Sbostic 
37248853Sbostic /* result will be initialised here; it will be freed on failure */
37348853Sbostic 
37448853Sbostic static int
do_type(type,result)37548853Sbostic do_type (type, result)
37648853Sbostic      const char **type;
37748853Sbostic      string *result;
37848853Sbostic {
37948853Sbostic   int n;
38048853Sbostic   int done;
38148853Sbostic   int non_empty = 0;
38248853Sbostic   int success;
38348853Sbostic   string decl;
38448853Sbostic   const char *remembered_type;
38548853Sbostic 
38648853Sbostic   string_init (&decl);
38748853Sbostic   string_init (result);
38848853Sbostic 
38948853Sbostic   done = 0;
39048853Sbostic   success = 1;
39148853Sbostic   while (success && !done)
39248853Sbostic     {
39348853Sbostic       int member;
39448853Sbostic       switch (**type)
39548853Sbostic 	{
39648853Sbostic 	case 'P':
39748853Sbostic 	  *type += 1;
39848853Sbostic 	  string_prepend (&decl, "*");
39948853Sbostic 	  break;
40048853Sbostic 
40148853Sbostic 	case 'R':
40248853Sbostic 	  *type += 1;
40348853Sbostic 	  string_prepend (&decl, "&");
40448853Sbostic 	  break;
40548853Sbostic 
40648853Sbostic 	case 'T':
40748853Sbostic 	  *type += 1;
40848853Sbostic 	  if (!get_count (type, &n) || n >= ntypes)
40948853Sbostic 	    success = 0;
41048853Sbostic 	  else
41148853Sbostic 	    {
41248853Sbostic 	      remembered_type = typevec[n];
41348853Sbostic 	      type = &remembered_type;
41448853Sbostic 	    }
41548853Sbostic 	  break;
41648853Sbostic 
41748853Sbostic 	case 'F':
41848853Sbostic 	  *type += 1;
41948853Sbostic 	  if (!string_empty (&decl) && decl.b[0] == '*')
42048853Sbostic 	    {
42148853Sbostic 	      string_prepend (&decl, "(");
42248853Sbostic 	      string_append (&decl, ")");
42348853Sbostic 	    }
42448853Sbostic 	  if (!do_args (type, &decl) || **type != '_')
42548853Sbostic 	    success = 0;
42648853Sbostic 	  else
42748853Sbostic 	    *type += 1;
42848853Sbostic 	  break;
42948853Sbostic 
43048853Sbostic 	case 'M':
43148853Sbostic 	case 'O':
43248853Sbostic 	  {
43348853Sbostic 	    int constp = 0;
43448853Sbostic 	    int volatilep = 0;
43548853Sbostic 
43648853Sbostic 	    member = **type == 'M';
43748853Sbostic 	    *type += 1;
43848853Sbostic 	    if (!isdigit (**type))
43948853Sbostic 	      {
44048853Sbostic 		success = 0;
44148853Sbostic 		break;
44248853Sbostic 	      }
44348853Sbostic 	    n = 0;
44448853Sbostic 	    do
44548853Sbostic 	      {
44648853Sbostic 		n *= 10;
44748853Sbostic 		n += **type - '0';
44848853Sbostic 		*type += 1;
44948853Sbostic 	      }
45048853Sbostic 	    while (isdigit (**type));
45148853Sbostic 	    if (strlen (*type) < n)
45248853Sbostic 	      {
45348853Sbostic 		success = 0;
45448853Sbostic 		break;
45548853Sbostic 	      }
45648853Sbostic 	    string_append (&decl, ")");
45748853Sbostic 	    string_prepend (&decl, "::");
45848853Sbostic 	    string_prependn (&decl, *type, n);
45948853Sbostic 	    string_prepend (&decl, "(");
46048853Sbostic 	    *type += n;
46148853Sbostic 	    if (member)
46248853Sbostic 	      {
46348853Sbostic 		if (**type == 'C')
46448853Sbostic 		  {
46548853Sbostic 		    *type += 1;
46648853Sbostic 		    constp = 1;
46748853Sbostic 		  }
46848853Sbostic 		if (**type == 'V')
46948853Sbostic 		  {
47048853Sbostic 		    *type += 1;
47148853Sbostic 		    volatilep = 1;
47248853Sbostic 		  }
47348853Sbostic 		if (*(*type)++ != 'F')
47448853Sbostic 		  {
47548853Sbostic 		    success = 0;
47648853Sbostic 		    break;
47748853Sbostic 		  }
47848853Sbostic 	      }
47948853Sbostic 	    if ((member && !do_args (type, &decl)) || **type != '_')
48048853Sbostic 	      {
48148853Sbostic 		success = 0;
48248853Sbostic 		break;
48348853Sbostic 	      }
48448853Sbostic 	    *type += 1;
48548853Sbostic 	    if (constp)
48648853Sbostic 	      {
48748853Sbostic 		if (non_empty)
48848853Sbostic 		  string_append (&decl, " ");
48948853Sbostic 		else
49048853Sbostic 		  non_empty = 1;
49148853Sbostic 		string_append (&decl, "const");
49248853Sbostic 	      }
49348853Sbostic 	    if (volatilep)
49448853Sbostic 	      {
49548853Sbostic 		if (non_empty)
49648853Sbostic 		  string_append (&decl, " ");
49748853Sbostic 		else
49848853Sbostic 		  non_empty = 1;
49948853Sbostic 		string_append (&decl, "volatilep");
50048853Sbostic 	      }
50148853Sbostic 	    break;
50248853Sbostic 	  }
50348853Sbostic 
50448853Sbostic 	case 'C':
50548853Sbostic 	  if ((*type)[1] == 'P')
50648853Sbostic 	    {
50748853Sbostic 	      *type += 1;
50848853Sbostic 	      if (!string_empty (&decl))
50948853Sbostic 		string_prepend (&decl, " ");
51048853Sbostic 	      string_prepend (&decl, "const");
51148853Sbostic 	      break;
51248853Sbostic 	    }
51348853Sbostic 
51448853Sbostic 	  /* fall through */
51548853Sbostic 	default:
51648853Sbostic 	  done = 1;
51748853Sbostic 	  break;
51848853Sbostic 	}
51948853Sbostic     }
52048853Sbostic 
52148853Sbostic   done = 0;
52248853Sbostic   non_empty = 0;
52348853Sbostic   while (success && !done)
52448853Sbostic     {
52548853Sbostic       switch (**type)
52648853Sbostic 	{
52748853Sbostic 	case 'C':
52848853Sbostic 	  *type += 1;
52948853Sbostic 	  if (non_empty)
53048853Sbostic 	    string_append (result, " ");
53148853Sbostic 	  else
53248853Sbostic 	    non_empty = 1;
53348853Sbostic 	  string_append (result, "const");
53448853Sbostic 	  break;
53548853Sbostic 	case 'U':
53648853Sbostic 	  *type += 1;
53748853Sbostic 	  if (non_empty)
53848853Sbostic 	    string_append (result, " ");
53948853Sbostic 	  else
54048853Sbostic 	    non_empty = 1;
54148853Sbostic 	  string_append (result, "unsigned");
54248853Sbostic 	  break;
54348853Sbostic 	case 'V':
54448853Sbostic 	  *type += 1;
54548853Sbostic 	  if (non_empty)
54648853Sbostic 	    string_append (result, " ");
54748853Sbostic 	  else
54848853Sbostic 	    non_empty = 1;
54948853Sbostic 	  string_append (result, "volatile");
55048853Sbostic 	  break;
55148853Sbostic 	default:
55248853Sbostic 	  done = 1;
55348853Sbostic 	  break;
55448853Sbostic 	}
55548853Sbostic     }
55648853Sbostic 
55748853Sbostic   if (success)
55848853Sbostic     switch (**type)
55948853Sbostic       {
56048853Sbostic       case '\0':
56148853Sbostic       case '_':
56248853Sbostic 	break;
56348853Sbostic       case 'v':
56448853Sbostic 	*type += 1;
56548853Sbostic 	if (non_empty)
56648853Sbostic 	  string_append (result, " ");
56748853Sbostic 	string_append (result, "void");
56848853Sbostic 	break;
56948853Sbostic       case 'x':
57048853Sbostic 	*type += 1;
57148853Sbostic 	if (non_empty)
57248853Sbostic 	  string_append (result, " ");
57348853Sbostic 	string_append (result, "long long");
57448853Sbostic 	break;
57548853Sbostic       case 'l':
57648853Sbostic 	*type += 1;
57748853Sbostic 	if (non_empty)
57848853Sbostic 	  string_append (result, " ");
57948853Sbostic 	string_append (result, "long");
58048853Sbostic 	break;
58148853Sbostic       case 'i':
58248853Sbostic 	*type += 1;
58348853Sbostic 	if (non_empty)
58448853Sbostic 	  string_append (result, " ");
58548853Sbostic 	string_append (result, "int");
58648853Sbostic 	break;
58748853Sbostic       case 's':
58848853Sbostic 	*type += 1;
58948853Sbostic 	if (non_empty)
59048853Sbostic 	  string_append (result, " ");
59148853Sbostic 	string_append (result, "short");
59248853Sbostic 	break;
59348853Sbostic       case 'c':
59448853Sbostic 	*type += 1;
59548853Sbostic 	if (non_empty)
59648853Sbostic 	  string_append (result, " ");
59748853Sbostic 	string_append (result, "char");
59848853Sbostic 	break;
59948853Sbostic       case 'r':
60048853Sbostic 	*type += 1;
60148853Sbostic 	if (non_empty)
60248853Sbostic 	  string_append (result, " ");
60348853Sbostic 	string_append (result, "long double");
60448853Sbostic 	break;
60548853Sbostic       case 'd':
60648853Sbostic 	*type += 1;
60748853Sbostic 	if (non_empty)
60848853Sbostic 	  string_append (result, " ");
60948853Sbostic 	string_append (result, "double");
61048853Sbostic 	break;
61148853Sbostic       case 'f':
61248853Sbostic 	*type += 1;
61348853Sbostic 	if (non_empty)
61448853Sbostic 	  string_append (result, " ");
61548853Sbostic 	string_append (result, "float");
61648853Sbostic 	break;
61748853Sbostic       case 'G':
61848853Sbostic 	*type += 1;
61948853Sbostic 	if (!isdigit (**type))
62048853Sbostic 	  {
62148853Sbostic 	    success = 0;
62248853Sbostic 	    break;
62348853Sbostic 	  }
62448853Sbostic 	/* fall through */
62548853Sbostic       case '0':
62648853Sbostic       case '1':
62748853Sbostic       case '2':
62848853Sbostic       case '3':
62948853Sbostic       case '4':
63048853Sbostic       case '5':
63148853Sbostic       case '6':
63248853Sbostic       case '7':
63348853Sbostic       case '8':
63448853Sbostic       case '9':
63548853Sbostic 	n = 0;
63648853Sbostic 	do
63748853Sbostic 	  {
63848853Sbostic 	    n *= 10;
63948853Sbostic 	    n += **type - '0';
64048853Sbostic 	    *type += 1;
64148853Sbostic 	  }
64248853Sbostic 	while (isdigit (**type));
64348853Sbostic 	if (strlen (*type) < n)
64448853Sbostic 	  {
64548853Sbostic 	    success = 0;
64648853Sbostic 	    break;
64748853Sbostic 	  }
64848853Sbostic 	if (non_empty)
64948853Sbostic 	  string_append (result, " ");
65048853Sbostic 	string_appendn (result, *type, n);
65148853Sbostic 	*type += n;
65248853Sbostic 	break;
65348853Sbostic       default:
65448853Sbostic 	success = 0;
65548853Sbostic 	break;
65648853Sbostic       }
65748853Sbostic 
65848853Sbostic   if (success)
65948853Sbostic     {
66048853Sbostic       if (!string_empty (&decl))
66148853Sbostic 	{
66248853Sbostic 	  string_append (result, " ");
66348853Sbostic 	  string_appends (result, &decl);
66448853Sbostic 	}
66548853Sbostic       string_delete (&decl);
66648853Sbostic       return 1;
66748853Sbostic     }
66848853Sbostic   else
66948853Sbostic     {
67048853Sbostic       string_delete (&decl);
67148853Sbostic       string_delete (result);
67248853Sbostic       return 0;
67348853Sbostic     }
67448853Sbostic }
67548853Sbostic 
67648853Sbostic /* `result' will be initialised in do_type; it will be freed on failure */
67748853Sbostic 
67848853Sbostic static int
do_arg(type,result)67948853Sbostic do_arg (type, result)
68048853Sbostic      const char **type;
68148853Sbostic      string *result;
68248853Sbostic {
68348853Sbostic   const char *start = *type;
68448853Sbostic 
68548853Sbostic   if (!do_type (type, result))
68648853Sbostic     return 0;
68748853Sbostic   remember_type (start, *type - start);
68848853Sbostic   return 1;
68948853Sbostic }
69048853Sbostic 
69148853Sbostic static void
remember_type(start,len)69248853Sbostic remember_type (start, len)
69348853Sbostic      const char *start;
69448853Sbostic      int len;
69548853Sbostic {
69648853Sbostic   char *tem;
69748853Sbostic 
69848853Sbostic   if (ntypes >= typevec_size)
69948853Sbostic     {
70048853Sbostic       if (typevec_size == 0)
70148853Sbostic 	{
70248853Sbostic 	  typevec_size = 3;
70348853Sbostic 	  typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
70448853Sbostic 	}
70548853Sbostic       else
70648853Sbostic 	{
70748853Sbostic 	  typevec_size *= 2;
70848853Sbostic 	  typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
70948853Sbostic 	}
71048853Sbostic     }
71148853Sbostic   tem = (char *) xmalloc (len + 1);
71248853Sbostic   memcpy (tem, start, len);
71348853Sbostic   tem[len] = '\0';
71448853Sbostic   typevec[ntypes++] = tem;
71548853Sbostic }
71648853Sbostic 
71748853Sbostic /* `decl' must be already initialised, usually non-empty;
71848853Sbostic    it won't be freed on failure */
71948853Sbostic 
72048853Sbostic static int
do_args(type,decl)72148853Sbostic do_args (type, decl)
72248853Sbostic      const char **type;
72348853Sbostic      string *decl;
72448853Sbostic {
72548853Sbostic   string arg;
72648853Sbostic   int need_comma = 0;
72748853Sbostic 
72848853Sbostic   string_append (decl, "(");
72948853Sbostic 
73048853Sbostic   while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
73148853Sbostic     {
73248853Sbostic       if (**type == 'N')
73348853Sbostic 	{
73448853Sbostic 	  int r;
73548853Sbostic 	  int t;
73648853Sbostic 	  *type += 1;
73748853Sbostic 	  if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
73848853Sbostic 	    return 0;
73948853Sbostic 	  while (--r >= 0)
74048853Sbostic 	    {
74148853Sbostic 	      const char *tem = typevec[t];
74248853Sbostic 	      if (need_comma)
74348853Sbostic 		string_append (decl, ", ");
74448853Sbostic 	      if (!do_arg (&tem, &arg))
74548853Sbostic 		return 0;
74648853Sbostic 	      string_appends (decl, &arg);
74748853Sbostic 	      string_delete (&arg);
74848853Sbostic 	      need_comma = 1;
74948853Sbostic 	    }
75048853Sbostic 	}
75148853Sbostic       else
75248853Sbostic 	{
75348853Sbostic 	  if (need_comma)
75448853Sbostic 	    string_append (decl, ", ");
75548853Sbostic 	  if (!do_arg (type, &arg))
75648853Sbostic 	    return 0;
75748853Sbostic 	  string_appends (decl, &arg);
75848853Sbostic 	  string_delete (&arg);
75948853Sbostic 	  need_comma = 1;
76048853Sbostic 	}
76148853Sbostic     }
76248853Sbostic 
76348853Sbostic   if (**type == 'v')
76448853Sbostic     *type += 1;
76548853Sbostic   else if (**type == 'e')
76648853Sbostic     {
76748853Sbostic       *type += 1;
76848853Sbostic       if (need_comma)
76948853Sbostic 	string_append (decl, ",");
77048853Sbostic       string_append (decl, "...");
77148853Sbostic     }
77248853Sbostic 
77348853Sbostic   string_append (decl, ")");
77448853Sbostic   return 1;
77548853Sbostic }
77648853Sbostic 
77748853Sbostic static void
munge_function_name(name)77848853Sbostic munge_function_name (name)
77948853Sbostic      string *name;
78048853Sbostic {
78148853Sbostic   if (!string_empty (name) && name->p - name->b >= 3
78248853Sbostic       && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
78348853Sbostic     {
78448853Sbostic       int i;
78548853Sbostic       /* see if it's an assignment expression */
78648853Sbostic       if (name->p - name->b >= 10 /* op$assign_ */
78748853Sbostic 	  && memcmp (name->b + 3, "assign_", 7) == 0)
78848853Sbostic 	{
78948853Sbostic 	  for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
79048853Sbostic 	    {
79148853Sbostic 	      int len = name->p - name->b - 10;
79248853Sbostic 	      if (strlen (optable[i].in) == len
79348853Sbostic 		  && memcmp (optable[i].in, name->b + 10, len) == 0)
79448853Sbostic 		{
79548853Sbostic 		  string_clear (name);
79648853Sbostic 		  string_append (name, "operator");
79748853Sbostic 		  string_append (name, optable[i].out);
79848853Sbostic 		  string_append (name, "=");
79948853Sbostic 		  return;
80048853Sbostic 		}
80148853Sbostic 	    }
80248853Sbostic 	}
80348853Sbostic       else
80448853Sbostic 	{
80548853Sbostic 	  for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
80648853Sbostic 	    {
80748853Sbostic 	      int len = name->p - name->b - 3;
80848853Sbostic 	      if (strlen (optable[i].in) == len
80948853Sbostic 		  && memcmp (optable[i].in, name->b + 3, len) == 0)
81048853Sbostic 		{
81148853Sbostic 		  string_clear (name);
81248853Sbostic 		  string_append (name, "operator");
81348853Sbostic 		  string_append (name, optable[i].out);
81448853Sbostic 		  return;
81548853Sbostic 		}
81648853Sbostic 	    }
81748853Sbostic 	}
81848853Sbostic       return;
81948853Sbostic     }
82048853Sbostic   else if (!string_empty (name) && name->p - name->b >= 5
82148853Sbostic 	   && memcmp (name->b, "type$", 5) == 0)
82248853Sbostic     {
82348853Sbostic       /* type conversion operator */
82448853Sbostic       string type;
82548853Sbostic       const char *tem = name->b + 5;
82648853Sbostic       if (do_type (&tem, &type))
82748853Sbostic 	{
82848853Sbostic 	  string_clear (name);
82948853Sbostic 	  string_append (name, "operator ");
83048853Sbostic 	  string_appends (name, &type);
83148853Sbostic 	  string_delete (&type);
83248853Sbostic 	  return;
83348853Sbostic 	}
83448853Sbostic     }
83548853Sbostic }
83648853Sbostic 
83748853Sbostic /* a mini string-handling package */
83848853Sbostic 
83948853Sbostic static void
string_need(s,n)84048853Sbostic string_need (s, n)
84148853Sbostic      string *s;
84248853Sbostic      int n;
84348853Sbostic {
84448853Sbostic   if (s->b == NULL)
84548853Sbostic     {
84648853Sbostic       if (n < 32)
84748853Sbostic 	n = 32;
84848853Sbostic       s->p = s->b = (char *) xmalloc (n);
84948853Sbostic       s->e = s->b + n;
85048853Sbostic     }
85148853Sbostic   else if (s->e - s->p < n)
85248853Sbostic     {
85348853Sbostic       int tem = s->p - s->b;
85448853Sbostic       n += tem;
85548853Sbostic       n *= 2;
85648853Sbostic       s->b = (char *) xrealloc (s->b, n);
85748853Sbostic       s->p = s->b + tem;
85848853Sbostic       s->e = s->b + n;
85948853Sbostic     }
86048853Sbostic }
86148853Sbostic 
86248853Sbostic static void
string_delete(s)86348853Sbostic string_delete (s)
86448853Sbostic      string *s;
86548853Sbostic {
86648853Sbostic   if (s->b != NULL)
86748853Sbostic     {
86848853Sbostic       free (s->b);
86948853Sbostic       s->b = s->e = s->p = NULL;
87048853Sbostic     }
87148853Sbostic }
87248853Sbostic 
87348853Sbostic static void
string_init(s)87448853Sbostic string_init (s)
87548853Sbostic      string *s;
87648853Sbostic {
87748853Sbostic   s->b = s->p = s->e = NULL;
87848853Sbostic }
87948853Sbostic 
88048853Sbostic static void
string_clear(s)88148853Sbostic string_clear (s)
88248853Sbostic      string *s;
88348853Sbostic {
88448853Sbostic   s->p = s->b;
88548853Sbostic }
88648853Sbostic 
88748853Sbostic static int
string_empty(s)88848853Sbostic string_empty (s)
88948853Sbostic      string *s;
89048853Sbostic {
89148853Sbostic   return s->b == s->p;
89248853Sbostic }
89348853Sbostic 
89448853Sbostic static void
string_append(p,s)89548853Sbostic string_append (p, s)
89648853Sbostic      string *p;
89748853Sbostic      const char *s;
89848853Sbostic {
89948853Sbostic   int n;
90048853Sbostic   if (s == NULL || *s == '\0')
90148853Sbostic     return;
90248853Sbostic   n = strlen (s);
90348853Sbostic   string_need (p, n);
90448853Sbostic   memcpy (p->p, s, n);
90548853Sbostic   p->p += n;
90648853Sbostic }
90748853Sbostic 
90848853Sbostic static void
string_appends(p,s)90948853Sbostic string_appends (p, s)
91048853Sbostic      string *p, *s;
91148853Sbostic {
91248853Sbostic   int n;
91348853Sbostic   if (s->b == s->p)
91448853Sbostic     return;
91548853Sbostic   n = s->p - s->b;
91648853Sbostic   string_need (p, n);
91748853Sbostic   memcpy (p->p, s->b, n);
91848853Sbostic   p->p += n;
91948853Sbostic }
92048853Sbostic 
92148853Sbostic static void
string_appendn(p,s,n)92248853Sbostic string_appendn (p, s, n)
92348853Sbostic      string *p;
92448853Sbostic      const char *s;
92548853Sbostic      int n;
92648853Sbostic {
92748853Sbostic   if (n == 0)
92848853Sbostic     return;
92948853Sbostic   string_need (p, n);
93048853Sbostic   memcpy (p->p, s, n);
93148853Sbostic   p->p += n;
93248853Sbostic }
93348853Sbostic 
93448853Sbostic static void
string_prepend(p,s)93548853Sbostic string_prepend (p, s)
93648853Sbostic      string *p;
93748853Sbostic      const char *s;
93848853Sbostic {
93948853Sbostic   if (s == NULL || *s == '\0')
94048853Sbostic     return;
94148853Sbostic   string_prependn (p, s, strlen (s));
94248853Sbostic }
94348853Sbostic 
94448853Sbostic #if 0
94548853Sbostic static void
94648853Sbostic string_prepends (p, s)
94748853Sbostic      string *p, *s;
94848853Sbostic {
94948853Sbostic   if (s->b == s->p)
95048853Sbostic     return;
95148853Sbostic   string_prependn (p, s->b, s->p - s->b);
95248853Sbostic }
95348853Sbostic #endif
95448853Sbostic 
95548853Sbostic static void
string_prependn(p,s,n)95648853Sbostic string_prependn (p, s, n)
95748853Sbostic      string *p;
95848853Sbostic      const char *s;
95948853Sbostic      int n;
96048853Sbostic {
96148853Sbostic   char *q;
96248853Sbostic 
96348853Sbostic   if (n == 0)
96448853Sbostic     return;
96548853Sbostic   string_need (p, n);
96648853Sbostic   for (q = p->p - 1; q >= p->b; q--)
96748853Sbostic     q[n] = q[0];
96848853Sbostic   memcpy (p->b, s, n);
96948853Sbostic   p->p += n;
97048853Sbostic }
971