]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/cp-demangle.c
Daily bump.
[thirdparty/gcc.git] / libiberty / cp-demangle.c
CommitLineData
69afa80d
AS
1/* Demangler for IA64 / g++ standard C++ ABI.
2 Copyright (C) 2000 CodeSourcery LLC.
3 Written by Alex Samuel <samuel@codesourcery.com>.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*/
19
20/* This file implements demangling of C++ names mangled according to
21 the IA64 / g++ standard C++ ABI. Use the cp_demangle function to
22 demangle a mangled name, or compile with the preprocessor macro
23 STANDALONE_DEMANGLER defined to create a demangling filter
24 executable. */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
69afa80d
AS
30#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
33
69afa80d 34#include <stdio.h>
69afa80d
AS
35
36#ifdef HAVE_STRING_H
37#include <string.h>
38#endif
39
40#include "ansidecl.h"
41#include "libiberty.h"
42#include "dyn-string.h"
7eb23b1f 43#include "demangle.h"
69afa80d
AS
44
45/* If CP_DEMANGLE_DEBUG is defined, a trace of the grammar evaluation,
46 and other debugging output, will be generated. */
47#ifdef CP_DEMANGLE_DEBUG
051664b0
AS
48#define DEMANGLE_TRACE(PRODUCTION, DM) \
49 fprintf (stderr, " -> %-24s at position %3d\n", \
69afa80d
AS
50 (PRODUCTION), current_position (DM));
51#else
52#define DEMANGLE_TRACE(PRODUCTION, DM)
53#endif
54
051664b0
AS
55/* Don't include <ctype.h>, to prevent additional unresolved symbols
56 from being dragged into the C++ runtime library. */
57#define IS_DIGIT(CHAR) ((CHAR) >= '0' && (CHAR) <= '9')
58#define IS_ALPHA(CHAR) \
59 (((CHAR) >= 'a' && (CHAR) <= 'z') \
60 || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
61
69afa80d
AS
62/* If flag_verbose is zero, some simplifications will be made to the
63 output to make it easier to read and supress details that are
64 generally not of interest to the average C++ programmer.
65 Otherwise, the demangled representation will attempt to convey as
66 much information as the mangled form. */
67static int flag_verbose;
68
69/* If flag_strict is non-zero, demangle strictly according to the
70 specification -- don't demangle special g++ manglings. */
71static int flag_strict;
72
73/* String_list_t is an extended form of dyn_string_t which provides a link
74 field. A string_list_t may safely be cast to and used as a
75 dyn_string_t. */
76
77struct string_list_def
78{
79 struct dyn_string string;
80 struct string_list_def *next;
81};
82
83typedef struct string_list_def *string_list_t;
84
85/* Data structure representing a potential substitution. */
86
87struct substitution_def
88{
89 /* The demangled text of the substitution. */
90 dyn_string_t text;
91
92 /* The template parameter that this represents, indexed from zero.
93 If this is not a template paramter number, the value is
94 NOT_TEMPLATE_PARM. */
95 int template_parm_number;
96
97 /* Whether this substitution represents a template item. */
98 int template_p : 1;
99};
100
101#define NOT_TEMPLATE_PARM (-1)
102
103/* Data structure representing a template argument list. */
104
105struct template_arg_list_def
106{
107 /* The next (lower) template argument list in the stack of currently
108 active template arguments. */
109 struct template_arg_list_def *next;
110
111 /* The first element in the list of template arguments in
112 left-to-right order. */
113 string_list_t first_argument;
114
115 /* The last element in the arguments lists. */
116 string_list_t last_argument;
117};
118
119typedef struct template_arg_list_def *template_arg_list_t;
120
121/* Data structure to maintain the state of the current demangling. */
122
123struct demangling_def
124{
125 /* The full mangled name being mangled. */
051664b0 126 const char *name;
69afa80d
AS
127
128 /* Pointer into name at the current position. */
051664b0 129 const char *next;
69afa80d
AS
130
131 /* Stack for strings containing demangled result generated so far.
132 Text is emitted to the topmost (first) string. */
133 string_list_t result;
134
135 /* The number of presently available substitutions. */
136 int num_substitutions;
137
138 /* The allocated size of the substitutions array. */
139 int substitutions_allocated;
140
141 /* An array of available substitutions. The number of elements in
142 the array is given by num_substitions, and the allocated array
143 size in substitutions_size.
144
145 The most recent substition is at the end, so
146
147 - `S_' corresponds to substititutions[num_substitutions - 1]
148 - `S0_' corresponds to substititutions[num_substitutions - 2]
149
150 etc. */
151 struct substitution_def *substitutions;
152
153 /* The stack of template argument lists. */
154 template_arg_list_t template_arg_lists;
155
156 /* The most recently demangled source-name. */
157 dyn_string_t last_source_name;
158};
159
160typedef struct demangling_def *demangling_t;
161
162/* This type is the standard return code from most functions. Values
163 other than STATUS_OK contain descriptive messages. */
164typedef const char *status_t;
165
166/* Special values that can be used as a status_t. */
051664b0
AS
167#define STATUS_OK NULL
168#define STATUS_ERROR "Error."
169#define STATUS_UNIMPLEMENTED "Unimplemented."
170#define STATUS_INTERNAL_ERROR "Internal error."
171
172/* This status code indicates a failure in malloc or realloc. */
173static const char* const status_allocation_failed = "Allocation failed.";
174#define STATUS_ALLOCATION_FAILED status_allocation_failed
175
176/* Non-zero if STATUS indicates that no error has occurred. */
177#define STATUS_NO_ERROR(STATUS) ((STATUS) == STATUS_OK)
178
179/* Evaluate EXPR, which must produce a status_t. If the status code
180 indicates an error, return from the current function with that
181 status code. */
182#define RETURN_IF_ERROR(EXPR) \
183 do \
184 { \
185 status_t s = EXPR; \
186 if (!STATUS_NO_ERROR (s)) \
187 return s; \
188 } \
189 while (0)
69afa80d 190
051664b0 191static status_t int_to_dyn_string
69afa80d
AS
192 PARAMS ((int, dyn_string_t));
193static string_list_t string_list_new
194 PARAMS ((int));
195static void string_list_delete
196 PARAMS ((string_list_t));
051664b0 197static status_t result_close_template_list
69afa80d 198 PARAMS ((demangling_t));
051664b0 199static status_t result_push
69afa80d
AS
200 PARAMS ((demangling_t));
201static string_list_t result_pop
202 PARAMS ((demangling_t));
203static int substitution_start
204 PARAMS ((demangling_t));
051664b0 205static status_t substitution_add
69afa80d
AS
206 PARAMS ((demangling_t, int, int, int));
207static dyn_string_t substitution_get
208 PARAMS ((demangling_t, int, int *));
209#ifdef CP_DEMANGLE_DEBUG
210static void substitutions_print
211 PARAMS ((demangling_t, FILE *));
212#endif
213static template_arg_list_t template_arg_list_new
214 PARAMS ((void));
215static void template_arg_list_delete
216 PARAMS ((template_arg_list_t));
217static void template_arg_list_add_arg
218 PARAMS ((template_arg_list_t, string_list_t));
219static string_list_t template_arg_list_get_arg
220 PARAMS ((template_arg_list_t, int));
221static void push_template_arg_list
222 PARAMS ((demangling_t, template_arg_list_t));
223static void pop_to_template_arg_list
224 PARAMS ((demangling_t, template_arg_list_t));
225#ifdef CP_DEMANGLE_DEBUG
226static void template_arg_list_print
227 PARAMS ((template_arg_list_t, FILE *));
228#endif
229static template_arg_list_t current_template_arg_list
230 PARAMS ((demangling_t));
231static demangling_t demangling_new
051664b0 232 PARAMS ((const char *));
69afa80d
AS
233static void demangling_delete
234 PARAMS ((demangling_t));
235
236/* The last character of DS. Warning: DS is evaluated twice. */
237#define dyn_string_last_char(DS) \
238 (dyn_string_buf (DS)[dyn_string_length (DS) - 1])
239
240/* Append a space character (` ') to DS if it does not already end
051664b0 241 with one. Evaluates to 1 on success, or 0 on allocation failure. */
69afa80d 242#define dyn_string_append_space(DS) \
051664b0
AS
243 ((dyn_string_length (DS) > 0 \
244 && dyn_string_last_char (DS) != ' ') \
245 ? dyn_string_append_char ((DS), ' ') \
246 : 1)
69afa80d
AS
247
248/* Returns the index of the current position in the mangled name. */
249#define current_position(DM) ((DM)->next - (DM)->name)
250
251/* Returns the character at the current position of the mangled name. */
252#define peek_char(DM) (*((DM)->next))
253
254/* Returns the character one past the current position of the mangled
255 name. */
256#define peek_char_next(DM) \
257 (peek_char (DM) == '\0' ? '\0' : (*((DM)->next + 1)))
258
259/* Returns the character at the current position, and advances the
260 current position to the next character. */
261#define next_char(DM) (*((DM)->next)++)
262
263/* Returns non-zero if the current position is the end of the mangled
264 name, i.e. one past the last character. */
265#define end_of_name_p(DM) (peek_char (DM) == '\0')
266
267/* Advances the current position by one character. */
268#define advance_char(DM) (++(DM)->next)
269
270/* Returns the string containing the current demangled result. */
271#define result_string(DM) (&(DM)->result->string)
272
273/* Appends a dyn_string_t to the demangled result. */
274#define result_append_string(DM, STRING) \
051664b0
AS
275 (dyn_string_append (&(DM)->result->string, (STRING)) \
276 ? STATUS_OK : STATUS_ALLOCATION_FAILED)
69afa80d
AS
277
278/* Appends NUL-terminated string CSTR to the demangled result. */
279#define result_append(DM, CSTR) \
051664b0
AS
280 (dyn_string_append_cstr (&(DM)->result->string, (CSTR)) \
281 ? STATUS_OK : STATUS_ALLOCATION_FAILED)
69afa80d
AS
282
283/* Appends character CHAR to the demangled result. */
284#define result_append_char(DM, CHAR) \
051664b0
AS
285 (dyn_string_append_char (&(DM)->result->string, (CHAR)) \
286 ? STATUS_OK : STATUS_ALLOCATION_FAILED)
69afa80d
AS
287
288/* The length of the current demangled result. */
289#define result_length(DM) \
290 dyn_string_length (&(DM)->result->string)
291
292/* Appends a space to the demangled result if the last character is
293 not a space. */
294#define result_append_space(DM) \
051664b0
AS
295 (dyn_string_append_space (&(DM)->result->string) \
296 ? STATUS_OK : STATUS_ALLOCATION_FAILED)
69afa80d 297
051664b0
AS
298/* Appends a base 10 representation of VALUE to DS. STATUS_OK on
299 success. On failure, deletes DS and returns an error code. */
69afa80d 300
051664b0 301static status_t
69afa80d
AS
302int_to_dyn_string (value, ds)
303 int value;
304 dyn_string_t ds;
305{
306 int i;
307 int mask = 1;
308
309 /* Handle zero up front. */
310 if (value == 0)
311 {
051664b0
AS
312 if (!dyn_string_append_char (ds, '0'))
313 return STATUS_ALLOCATION_FAILED;
314 return STATUS_OK;
69afa80d
AS
315 }
316
317 /* For negative numbers, emit a minus sign. */
318 if (value < 0)
319 {
051664b0
AS
320 if (!dyn_string_append_char (ds, '-'))
321 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
322 value = -value;
323 }
324
325 /* Find the power of 10 of the first digit. */
326 i = value;
327 while (i > 9)
328 {
329 mask *= 10;
330 i /= 10;
331 }
332
333 /* Write the digits. */
334 while (mask > 0)
335 {
336 int digit = value / mask;
051664b0
AS
337
338 if (!dyn_string_append_char (ds, '0' + digit))
339 return STATUS_ALLOCATION_FAILED;
340
69afa80d
AS
341 value -= digit * mask;
342 mask /= 10;
343 }
051664b0
AS
344
345 return STATUS_OK;
69afa80d
AS
346}
347
348/* Creates a new string list node. The contents of the string are
349 empty, but the initial buffer allocation is LENGTH. The string
051664b0
AS
350 list node should be deleted with string_list_delete. Returns NULL
351 if allocation fails. */
69afa80d
AS
352
353static string_list_t
354string_list_new (length)
355 int length;
356{
051664b0
AS
357 string_list_t s = (string_list_t) malloc (sizeof (struct string_list_def));
358 if (s == NULL)
359 return NULL;
360 if (!dyn_string_init ((dyn_string_t) s, length))
361 return NULL;
69afa80d
AS
362 return s;
363}
364
365/* Deletes the entire string list starting at NODE. */
366
367static void
368string_list_delete (node)
369 string_list_t node;
370{
371 while (node != NULL)
372 {
373 string_list_t next = node->next;
374 free (node);
375 node = next;
376 }
377}
378
379/* Appends a greater-than character to the demangled result. If the
380 last character is a greater-than character, a space is inserted
381 first, so that the two greater-than characters don't look like a
382 right shift token. */
383
051664b0 384static status_t
69afa80d
AS
385result_close_template_list (dm)
386 demangling_t dm;
387{
388 dyn_string_t s = &dm->result->string;
051664b0
AS
389
390 /* Add a space if the last character is already a closing angle
391 bracket, so that a nested template arg list doesn't look like
392 it's closed with a right-shift operator. */
69afa80d 393 if (dyn_string_last_char (s) == '>')
051664b0
AS
394 {
395 if (!dyn_string_append_char (s, ' '))
396 return STATUS_ALLOCATION_FAILED;
397 }
398
399 /* Add closing angle brackets. */
400 if (!dyn_string_append_char (s, '>'))
401 return STATUS_ALLOCATION_FAILED;
402
403 return STATUS_OK;
69afa80d
AS
404}
405
406/* Allocates and pushes a new string onto the demangled results stack
051664b0
AS
407 for DM. Subsequent demangling with DM will emit to the new string.
408 Returns STATUS_OK on success, STATUS_ALLOCATION_FAILED on
409 allocation failure. */
69afa80d 410
051664b0 411static status_t
69afa80d
AS
412result_push (dm)
413 demangling_t dm;
414{
415 string_list_t new_string = string_list_new (0);
051664b0
AS
416 if (new_string == NULL)
417 /* Allocation failed. */
418 return STATUS_ALLOCATION_FAILED;
419
420 /* Link the new string to the front of the list of result strings. */
69afa80d
AS
421 new_string->next = (string_list_t) dm->result;
422 dm->result = new_string;
051664b0 423 return STATUS_OK;
69afa80d
AS
424}
425
426/* Removes and returns the topmost element on the demangled results
427 stack for DM. The caller assumes ownership for the returned
428 string. */
429
430static string_list_t
431result_pop (dm)
432 demangling_t dm;
433{
434 string_list_t top = dm->result;
435 dm->result = top->next;
436 return top;
437}
438
439/* Returns the start position of a fragment of the demangled result
440 that will be a substitution candidate. Should be called at the
441 start of productions that can add substitutions. */
442
443static int
444substitution_start (dm)
445 demangling_t dm;
446{
447 return result_length (dm);
448}
449
450/* Adds the suffix of the current demangled result of DM starting at
451 START_POSITION as a potential substitution. If TEMPLATE_P is
452 non-zero, this potential substitution is a template-id.
453
454 If TEMPLATE_PARM_NUMBER is not NOT_TEMPLATE_PARM, the substitution
455 is for that particular <template-param>, and is distinct from other
456 otherwise-identical types and other <template-param>s with
457 different indices. */
458
051664b0 459static status_t
69afa80d
AS
460substitution_add (dm, start_position, template_p, template_parm_number)
461 demangling_t dm;
462 int start_position;
463 int template_p;
464 int template_parm_number;
465{
466 dyn_string_t result = result_string (dm);
467 dyn_string_t substitution = dyn_string_new (0);
468 int i;
469
051664b0
AS
470 if (substitution == NULL)
471 return STATUS_ALLOCATION_FAILED;
472
473 /* Extract the substring of the current demangling result that
474 represents the subsitution candidate. */
475 if (!dyn_string_substring (substitution,
476 result, start_position, result_length (dm)))
477 {
478 dyn_string_delete (substitution);
479 return STATUS_ALLOCATION_FAILED;
480 }
69afa80d
AS
481
482 /* Check whether SUBSTITUTION already occurs. */
483 for (i = 0; i < dm->num_substitutions; ++i)
484 if (dyn_string_eq (dm->substitutions[i].text, substitution)
485 && dm->substitutions[i].template_parm_number == template_parm_number)
486 /* Found SUBSTITUTION already present. */
487 {
488 /* Callers expect this function to take ownership of
489 SUBSTITUTION, so delete it. */
490 dyn_string_delete (substitution);
051664b0 491 return STATUS_OK;
69afa80d
AS
492 }
493
494 /* If there's no room for the new entry, grow the array. */
495 if (dm->substitutions_allocated == dm->num_substitutions)
496 {
051664b0 497 size_t new_array_size;
69afa80d 498 dm->substitutions_allocated *= 2;
051664b0
AS
499 new_array_size =
500 sizeof (struct substitution_def) * dm->substitutions_allocated;
501
502 dm->substitutions = (struct substitution_def *)
503 realloc (dm->substitutions, new_array_size);
504 if (dm->substitutions == NULL)
505 /* Realloc failed. */
506 {
507 dyn_string_delete (substitution);
508 return STATUS_ALLOCATION_FAILED;
509 }
69afa80d
AS
510 }
511
512 /* Add the substitution to the array. */
513 dm->substitutions[i].text = substitution;
514 dm->substitutions[i].template_p = template_p;
515 dm->substitutions[i].template_parm_number = template_parm_number;
516 ++dm->num_substitutions;
517
518#ifdef CP_DEMANGLE_DEBUG
519 substitutions_print (dm, stderr);
520#endif
051664b0
AS
521
522 return STATUS_OK;
69afa80d
AS
523}
524
525/* Returns the Nth-most-recent substitution. Sets *TEMPLATE_P to
526 non-zero if the substitution is a template-id, zero otherwise.
527 N is numbered from zero. DM retains ownership of the returned
528 string. If N is negative, or equal to or greater than the current
529 number of substitution candidates, returns NULL. */
530
531static dyn_string_t
532substitution_get (dm, n, template_p)
533 demangling_t dm;
534 int n;
535 int *template_p;
536{
537 struct substitution_def *sub;
538
539 /* Make sure N is in the valid range. */
540 if (n < 0 || n >= dm->num_substitutions)
541 return NULL;
542
543 sub = &(dm->substitutions[n]);
544 *template_p = sub->template_p;
545 return sub->text;
546}
547
548#ifdef CP_DEMANGLE_DEBUG
549/* Debugging routine to print the current substitutions to FP. */
550
551static void
552substitutions_print (dm, fp)
553 demangling_t dm;
554 FILE *fp;
555{
556 int seq_id;
557 int num = dm->num_substitutions;
558
559 fprintf (fp, "SUBSTITUTIONS:\n");
560 for (seq_id = -1; seq_id < num - 1; ++seq_id)
561 {
562 int template_p;
563 dyn_string_t text = substitution_get (dm, seq_id + 1, &template_p);
564
565 if (seq_id == -1)
566 fprintf (fp, " S_ ");
567 else
568 fprintf (fp, " S%d_", seq_id);
569 fprintf (fp, " %c: %s\n", template_p ? '*' : ' ', dyn_string_buf (text));
570 }
571}
572
573#endif /* CP_DEMANGLE_DEBUG */
574
051664b0
AS
575/* Creates a new template argument list. Returns NULL if allocation
576 fails. */
69afa80d
AS
577
578static template_arg_list_t
6223e158 579template_arg_list_new ()
69afa80d 580{
051664b0
AS
581 template_arg_list_t new_list =
582 (template_arg_list_t) malloc (sizeof (struct template_arg_list_def));
583 if (new_list == NULL)
584 return NULL;
69afa80d
AS
585 /* Initialize the new list to have no arguments. */
586 new_list->first_argument = NULL;
587 new_list->last_argument = NULL;
588 /* Return the new list. */
589 return new_list;
590}
591
592/* Deletes a template argument list and the template arguments it
593 contains. */
594
595static void
596template_arg_list_delete (list)
597 template_arg_list_t list;
598{
599 /* If there are any arguments on LIST, delete them. */
600 if (list->first_argument != NULL)
601 string_list_delete (list->first_argument);
602 /* Delete LIST. */
603 free (list);
604}
605
606/* Adds ARG to the template argument list ARG_LIST. */
607
608static void
609template_arg_list_add_arg (arg_list, arg)
610 template_arg_list_t arg_list;
611 string_list_t arg;
612{
613 if (arg_list->first_argument == NULL)
614 /* If there were no arguments before, ARG is the first one. */
615 arg_list->first_argument = arg;
616 else
617 /* Make ARG the last argument on the list. */
618 arg_list->last_argument->next = arg;
619 /* Make ARG the last on the list. */
620 arg_list->last_argument = arg;
621 arg->next = NULL;
622}
623
624/* Returns the template arugment at position INDEX in template
625 argument list ARG_LIST. */
626
627static string_list_t
628template_arg_list_get_arg (arg_list, index)
629 template_arg_list_t arg_list;
630 int index;
631{
632 string_list_t arg = arg_list->first_argument;
633 /* Scan down the list of arguments to find the one at position
634 INDEX. */
635 while (index--)
636 {
637 arg = arg->next;
638 if (arg == NULL)
639 /* Ran out of arguments before INDEX hit zero. That's an
640 error. */
641 return NULL;
642 }
643 /* Return the argument at position INDEX. */
644 return arg;
645}
646
647/* Pushes ARG_LIST onto the top of the template argument list stack. */
648
649static void
650push_template_arg_list (dm, arg_list)
651 demangling_t dm;
652 template_arg_list_t arg_list;
653{
654 arg_list->next = dm->template_arg_lists;
655 dm->template_arg_lists = arg_list;
656#ifdef CP_DEMANGLE_DEBUG
657 fprintf (stderr, " ** pushing template arg list\n");
658 template_arg_list_print (arg_list, stderr);
659#endif
660}
661
662/* Pops and deletes elements on the template argument list stack until
663 arg_list is the topmost element. If arg_list is NULL, all elements
664 are popped and deleted. */
665
666static void
667pop_to_template_arg_list (dm, arg_list)
668 demangling_t dm;
669 template_arg_list_t arg_list;
670{
671 while (dm->template_arg_lists != arg_list)
672 {
673 template_arg_list_t top = dm->template_arg_lists;
674 /* Disconnect the topmost element from the list. */
675 dm->template_arg_lists = top->next;
676 /* Delete the popped element. */
677 template_arg_list_delete (top);
678#ifdef CP_DEMANGLE_DEBUG
679 fprintf (stderr, " ** removing template arg list\n");
680#endif
681 }
682}
683
684#ifdef CP_DEMANGLE_DEBUG
685
686/* Prints the contents of ARG_LIST to FP. */
687
688static void
689template_arg_list_print (arg_list, fp)
690 template_arg_list_t arg_list;
691 FILE *fp;
692{
693 string_list_t arg;
694 int index = -1;
695
696 fprintf (fp, "TEMPLATE ARGUMENT LIST:\n");
697 for (arg = arg_list->first_argument; arg != NULL; arg = arg->next)
698 {
699 if (index == -1)
700 fprintf (fp, " T_ : ");
701 else
702 fprintf (fp, " T%d_ : ", index);
703 ++index;
704 fprintf (fp, "%s\n", dyn_string_buf ((dyn_string_t) arg));
705 }
706}
707
708#endif /* CP_DEMANGLE_DEBUG */
709
710/* Returns the topmost element on the stack of template argument
711 lists. If there is no list of template arguments, returns NULL. */
712
713static template_arg_list_t
714current_template_arg_list (dm)
715 demangling_t dm;
716{
717 return dm->template_arg_lists;
718}
719
720/* Allocates a demangling_t object for demangling mangled NAME. A new
051664b0
AS
721 result must be pushed before the returned object can be used.
722 Returns NULL if allocation fails. */
69afa80d
AS
723
724static demangling_t
725demangling_new (name)
051664b0 726 const char *name;
69afa80d 727{
051664b0
AS
728 demangling_t dm;
729 dm = (demangling_t) malloc (sizeof (struct demangling_def));
730 if (dm == NULL)
731 return NULL;
69afa80d
AS
732
733 dm->name = name;
734 dm->next = name;
735 dm->result = NULL;
69afa80d
AS
736 dm->num_substitutions = 0;
737 dm->substitutions_allocated = 10;
69afa80d 738 dm->template_arg_lists = NULL;
051664b0
AS
739 dm->last_source_name = dyn_string_new (0);
740 if (dm->last_source_name == NULL)
741 return NULL;
742 dm->substitutions = (struct substitution_def *)
743 malloc (dm->substitutions_allocated * sizeof (struct substitution_def));
744 if (dm->substitutions == NULL)
745 {
746 dyn_string_delete (dm->last_source_name);
747 return NULL;
748 }
69afa80d
AS
749
750 return dm;
751}
752
753/* Deallocates a demangling_t object and all memory associated with
754 it. */
755
756static void
757demangling_delete (dm)
758 demangling_t dm;
759{
760 int i;
761 template_arg_list_t arg_list = dm->template_arg_lists;
762
763 /* Delete the stack of template argument lists. */
764 while (arg_list != NULL)
765 {
766 template_arg_list_t next = arg_list->next;
767 template_arg_list_delete (arg_list);
768 arg_list = next;
769 }
770 /* Delete the list of substitutions. */
771 for (i = dm->num_substitutions; --i >= 0; )
772 dyn_string_delete (dm->substitutions[i].text);
773 free (dm->substitutions);
774 /* Delete the demangled result. */
775 string_list_delete (dm->result);
776 /* Delete the stored identifier name. */
777 dyn_string_delete (dm->last_source_name);
778 /* Delete the context object itself. */
779 free (dm);
780}
781
782/* These functions demangle an alternative of the corresponding
783 production in the mangling spec. The first argument of each is a
784 demangling context structure for the current demangling
785 operation. Most emit demangled text directly to the topmost result
786 string on the result string stack in the demangling context
787 structure. */
788
789static status_t demangle_char
69197e7e 790 PARAMS ((demangling_t, int));
69afa80d
AS
791static status_t demangle_mangled_name
792 PARAMS ((demangling_t));
793static status_t demangle_encoding
794 PARAMS ((demangling_t));
795static status_t demangle_name
796 PARAMS ((demangling_t, int *));
797static status_t demangle_nested_name
798 PARAMS ((demangling_t, int *));
799static status_t demangle_prefix
800 PARAMS ((demangling_t, int *));
801static status_t demangle_unqualified_name
802 PARAMS ((demangling_t));
803static status_t demangle_source_name
804 PARAMS ((demangling_t));
805static status_t demangle_number
806 PARAMS ((demangling_t, int *, int, int));
807static status_t demangle_number_literally
808 PARAMS ((demangling_t, dyn_string_t, int, int));
809static status_t demangle_identifier
810 PARAMS ((demangling_t, int, dyn_string_t));
811static status_t demangle_operator_name
812 PARAMS ((demangling_t, int, int *));
813static status_t demangle_special_name
814 PARAMS ((demangling_t));
815static status_t demangle_ctor_dtor_name
816 PARAMS ((demangling_t));
817static status_t demangle_type_ptr
818 PARAMS ((demangling_t));
819static status_t demangle_type
820 PARAMS ((demangling_t));
821static status_t demangle_CV_qualifiers
822 PARAMS ((demangling_t, dyn_string_t));
823static status_t demangle_builtin_type
824 PARAMS ((demangling_t));
825static status_t demangle_function_type
826 PARAMS ((demangling_t, int));
827static status_t demangle_bare_function_type
828 PARAMS ((demangling_t, int));
829static status_t demangle_class_enum_type
830 PARAMS ((demangling_t, int *));
831static status_t demangle_array_type
832 PARAMS ((demangling_t));
833static status_t demangle_template_param
834 PARAMS ((demangling_t, int *));
835static status_t demangle_template_args
836 PARAMS ((demangling_t));
837static status_t demangle_literal
838 PARAMS ((demangling_t));
839static status_t demangle_template_arg
840 PARAMS ((demangling_t));
841static status_t demangle_expression
69197e7e 842 PARAMS ((demangling_t));
69afa80d
AS
843static status_t demangle_scope_expression
844 PARAMS ((demangling_t));
845static status_t demangle_expr_primary
69197e7e 846 PARAMS ((demangling_t));
69afa80d
AS
847static status_t demangle_substitution
848 PARAMS ((demangling_t, int *, int *));
849static status_t demangle_local_name
850 PARAMS ((demangling_t));
851static status_t demangle_discriminator
852 PARAMS ((demangling_t, int));
7eb23b1f 853static status_t cp_demangle
051664b0 854 PARAMS ((const char *, dyn_string_t));
838f8562 855#ifdef IN_LIBGCC2
051664b0
AS
856static status_t cp_demangle_type
857 PARAMS ((const char*, dyn_string_t));
838f8562 858#endif
69afa80d
AS
859
860/* When passed to demangle_bare_function_type, indicates that the
861 function's return type is not encoded before its parameter types. */
862#define BFT_NO_RETURN_TYPE -1
863
864/* Check that the next character is C. If so, consume it. If not,
865 return an error. */
866
867static status_t
868demangle_char (dm, c)
869 demangling_t dm;
69197e7e 870 int c;
69afa80d
AS
871{
872 static char *error_message = NULL;
873
874 if (peek_char (dm) == c)
875 {
876 advance_char (dm);
877 return STATUS_OK;
878 }
879 else
880 {
881 if (error_message == NULL)
882 error_message = strdup ("Expected ?");
883 error_message[9] = c;
884 return error_message;
885 }
886}
887
888/* Demangles and emits a <mangled-name>.
889
890 <mangled-name> ::= _Z <encoding> */
891
892static status_t
893demangle_mangled_name (dm)
894 demangling_t dm;
895{
896 DEMANGLE_TRACE ("mangled-name", dm);
897 RETURN_IF_ERROR (demangle_char (dm, '_'));
898 RETURN_IF_ERROR (demangle_char (dm, 'Z'));
899 RETURN_IF_ERROR (demangle_encoding (dm));
900 return STATUS_OK;
901}
902
903/* Demangles and emits an <encoding>.
904
905 <encoding> ::= <function name> <bare-function-type>
906 ::= <data name>
bece74bd 907 ::= <special-name> */
69afa80d
AS
908
909static status_t
910demangle_encoding (dm)
911 demangling_t dm;
912{
913 int template_p;
69afa80d 914 int start_position;
69afa80d
AS
915 template_arg_list_t old_arg_list = current_template_arg_list (dm);
916 char peek = peek_char (dm);
917
918 DEMANGLE_TRACE ("encoding", dm);
919
920 /* Remember where the name starts. If it turns out to be a template
921 function, we'll have to insert the return type here. */
922 start_position = result_length (dm);
923
bece74bd 924 if (peek == 'G' || peek == 'T')
69afa80d
AS
925 RETURN_IF_ERROR (demangle_special_name (dm));
926 else
927 {
928 /* Now demangle the name. */
929 RETURN_IF_ERROR (demangle_name (dm, &template_p));
930
931 /* If there's anything left, the name was a function name, with
932 maybe its return type, and its parameters types, following. */
933 if (!end_of_name_p (dm)
934 && peek_char (dm) != 'E')
935 {
936 if (template_p)
937 /* Template functions have their return type encoded. The
938 return type should be inserted at start_position. */
939 RETURN_IF_ERROR
940 (demangle_bare_function_type (dm, start_position));
941 else
942 /* Non-template functions don't have their return type
943 encoded. */
944 RETURN_IF_ERROR
945 (demangle_bare_function_type (dm, BFT_NO_RETURN_TYPE));
946 }
69afa80d
AS
947 }
948
949 /* Pop off template argument lists that were built during the
950 mangling of this name, to restore the old template context. */
951 pop_to_template_arg_list (dm, old_arg_list);
952
953 return STATUS_OK;
954}
955
956/* Demangles and emits a <name>.
957
958 <name> ::= <unscoped-name>
959 ::= <unscoped-template-name> <template-args>
960 ::= <nested-name>
961 ::= <local-name>
962
963 <unscoped-name> ::= <unqualified-name>
964 ::= St <unqualified-name> # ::std::
965
966 <unscoped-template-name>
967 ::= <unscoped-name>
968 ::= <substitution> */
969
970static status_t
971demangle_name (dm, template_p)
972 demangling_t dm;
973 int *template_p;
974{
975 int special_std_substitution;
976 int start = substitution_start (dm);
977
978 DEMANGLE_TRACE ("name", dm);
979
980 switch (peek_char (dm))
981 {
982 case 'N':
983 /* This is a <nested-name>. */
984 RETURN_IF_ERROR (demangle_nested_name (dm, template_p));
985 break;
986
987 case 'Z':
988 RETURN_IF_ERROR (demangle_local_name (dm));
989 break;
990
991 case 'S':
992 /* The `St' substitution allows a name nested in std:: to appear
bece74bd 993 without being enclosed in a nested name. */
69afa80d
AS
994 if (peek_char_next (dm) == 't')
995 {
996 (void) next_char (dm);
997 (void) next_char (dm);
051664b0 998 RETURN_IF_ERROR (result_append (dm, "std::"));
69afa80d
AS
999 RETURN_IF_ERROR (demangle_unqualified_name (dm));
1000 }
1001 else
1002 {
1003 RETURN_IF_ERROR (demangle_substitution (dm, template_p,
1004 &special_std_substitution));
1005 if (special_std_substitution)
1006 {
1007 /* This was the magic `std::' substitution. We can have
1008 a <nested-name> or one of the unscoped names
1009 following. */
051664b0 1010 RETURN_IF_ERROR (result_append (dm, "::"));
69afa80d
AS
1011 RETURN_IF_ERROR (demangle_name (dm, template_p));
1012 }
1013 }
bece74bd
AS
1014 /* Check if a template argument list immediately follows.
1015 If so, then we just demangled an <unqualified-template-name>. */
1016 if (peek_char (dm) == 'I')
1017 {
1018 RETURN_IF_ERROR (substitution_add (dm, start, 0,
1019 NOT_TEMPLATE_PARM));
1020 RETURN_IF_ERROR (demangle_template_args (dm));
1021 }
69afa80d
AS
1022 break;
1023
1024 default:
1025 /* This is an <unscoped-name> or <unscoped-template-name>. */
1026 RETURN_IF_ERROR (demangle_unqualified_name (dm));
1027
1028 /* If the <unqualified-name> is followed by template args, this
1029 is an <unscoped-template-name>. */
1030 if (peek_char (dm) == 'I')
1031 {
1032 /* Add a substitution for the unqualified template name. */
051664b0
AS
1033 RETURN_IF_ERROR (substitution_add (dm, start, 0,
1034 NOT_TEMPLATE_PARM));
69afa80d
AS
1035
1036 RETURN_IF_ERROR (demangle_template_args (dm));
1037 *template_p = 1;
1038 }
1039 else
1040 *template_p = 0;
1041
1042 break;
1043 }
1044
1045 return STATUS_OK;
1046}
1047
1048/* Demangles and emits a <nested-name>.
1049
1050 <nested-name> ::= N [<CV-qualifiers>] <prefix> <component> E */
1051
1052static status_t
1053demangle_nested_name (dm, template_p)
1054 demangling_t dm;
1055 int *template_p;
1056{
1057 char peek;
1058
1059 DEMANGLE_TRACE ("nested-name", dm);
1060
1061 RETURN_IF_ERROR (demangle_char (dm, 'N'));
1062
1063 peek = peek_char (dm);
1064 if (peek == 'r' || peek == 'V' || peek == 'K')
1065 {
051664b0
AS
1066 status_t status;
1067
69afa80d
AS
1068 /* Snarf up and emit CV qualifiers. */
1069 dyn_string_t cv_qualifiers = dyn_string_new (24);
051664b0
AS
1070 if (cv_qualifiers == NULL)
1071 return STATUS_ALLOCATION_FAILED;
1072
69afa80d 1073 demangle_CV_qualifiers (dm, cv_qualifiers);
051664b0 1074 status = result_append_string (dm, cv_qualifiers);
69afa80d 1075 dyn_string_delete (cv_qualifiers);
051664b0
AS
1076 RETURN_IF_ERROR (status);
1077 RETURN_IF_ERROR (result_append_space (dm));
69afa80d
AS
1078 }
1079
1080 RETURN_IF_ERROR (demangle_prefix (dm, template_p));
1081 /* No need to demangle the final <component>; demangle_prefix will
1082 handle it. */
1083 RETURN_IF_ERROR (demangle_char (dm, 'E'));
1084
1085 return STATUS_OK;
1086}
1087
1088/* Demangles and emits a <prefix>.
1089
1090 <prefix> ::= <prefix> <component>
1091 ::= <template-prefix> <template-args>
1092 ::= # empty
1093 ::= <substitution>
1094
1095 <template-prefix> ::= <prefix>
1096 ::= <substitution>
1097
1098 <component> ::= <unqualified-name>
1099 ::= <local-name> */
1100
1101static status_t
1102demangle_prefix (dm, template_p)
1103 demangling_t dm;
1104 int *template_p;
1105{
1106 int start = substitution_start (dm);
1107 int nested = 0;
1108
1109 /* TEMPLATE_P is updated as we decend the nesting chain. After
1110 <template-args>, it is set to non-zero; after everything else it
1111 is set to zero. */
1112
1113 DEMANGLE_TRACE ("prefix", dm);
1114
1115 while (1)
1116 {
1117 char peek;
1118 int unused;
1119
1120 if (end_of_name_p (dm))
1121 return "Unexpected end of name in <compound-name>.";
1122
1123 peek = peek_char (dm);
1124
051664b0 1125 if (IS_DIGIT ((unsigned char) peek)
69afa80d
AS
1126 || (peek >= 'a' && peek <= 'z')
1127 || peek == 'C' || peek == 'D'
1128 || peek == 'S')
1129 {
1130 /* We have another level of scope qualification. */
1131 if (nested)
051664b0 1132 RETURN_IF_ERROR (result_append (dm, "::"));
69afa80d
AS
1133 else
1134 nested = 1;
1135
1136 if (peek == 'S')
1137 /* The substitution determines whether this is a
1138 template-id. */
1139 RETURN_IF_ERROR (demangle_substitution (dm, template_p,
1140 &unused));
1141 else
1142 {
1143 RETURN_IF_ERROR (demangle_unqualified_name (dm));
1144 *template_p = 0;
1145 }
1146 }
1147 else if (peek == 'Z')
1148 RETURN_IF_ERROR (demangle_local_name (dm));
1149 else if (peek == 'I')
1150 {
1151 if (*template_p)
1152 return STATUS_INTERNAL_ERROR;
1153 /* The template name is a substitution candidate. */
051664b0 1154 RETURN_IF_ERROR (substitution_add (dm, start, 0, NOT_TEMPLATE_PARM));
69afa80d
AS
1155 RETURN_IF_ERROR (demangle_template_args (dm));
1156 *template_p = 1;
1157 }
1158 else if (peek == 'E')
1159 /* All done. */
1160 return STATUS_OK;
1161 else
1162 return "Unexpected character in <compound-name>.";
1163
1164 /* Add a new substitution for the prefix thus far. */
051664b0
AS
1165 RETURN_IF_ERROR (substitution_add (dm, start, *template_p,
1166 NOT_TEMPLATE_PARM));
69afa80d
AS
1167 }
1168}
1169
1170/* Demangles and emits an <unqualified-name>. If the
1171 <unqualified-name> is a function and the first element in the
1172 argument list should be taken to be its return type,
1173 ENCODE_RETURN_TYPE is non-zero.
1174
1175 <unqualified-name> ::= <operator-name>
1176 ::= <special-name>
1177 ::= <source-name> */
1178
1179static status_t
1180demangle_unqualified_name (dm)
1181 demangling_t dm;
1182{
1183 char peek = peek_char (dm);
1184
1185 DEMANGLE_TRACE ("unqualified-name", dm);
1186
051664b0 1187 if (IS_DIGIT ((unsigned char) peek))
69afa80d
AS
1188 RETURN_IF_ERROR (demangle_source_name (dm));
1189 else if (peek >= 'a' && peek <= 'z')
1190 {
1191 int num_args;
1192 RETURN_IF_ERROR (demangle_operator_name (dm, 0, &num_args));
1193 }
1194 else if (peek == 'C' || peek == 'D')
1195 RETURN_IF_ERROR (demangle_ctor_dtor_name (dm));
1196 else
1197 return "Unexpected character in <unqualified-name>.";
1198
1199 return STATUS_OK;
1200}
1201
1202/* Demangles and emits <source-name>.
1203
1204 <source-name> ::= <length number> <identifier> */
1205
1206static status_t
1207demangle_source_name (dm)
1208 demangling_t dm;
1209{
1210 int length;
1211
1212 DEMANGLE_TRACE ("source-name", dm);
1213
1214 /* Decode the length of the identifier. */
1215 RETURN_IF_ERROR (demangle_number (dm, &length, 10, 0));
1216 if (length == 0)
1217 return "Zero length in <source-name>.";
1218
1219 /* Now the identifier itself. It's placed into last_source_name,
1220 where it can be used to build a constructor or destructor name. */
1221 RETURN_IF_ERROR (demangle_identifier (dm, length,
1222 dm->last_source_name));
1223
1224 /* Emit it. */
051664b0 1225 RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
69afa80d
AS
1226
1227 return STATUS_OK;
1228}
1229
1230/* Demangles a number, either a <number> or a <positive-number> at the
1231 current position, consuming all consecutive digit characters. Sets
1232 *VALUE to the resulting numberand returns STATUS_OK. The number is
1233 interpreted as BASE, which must be either 10 or 36. If IS_SIGNED
1234 is non-zero, negative numbers -- prefixed with `n' -- are accepted.
1235
1236 <number> ::= [n] <positive-number>
1237
1238 <positive-number> ::= <decimal integer> */
1239
1240static status_t
1241demangle_number (dm, value, base, is_signed)
1242 demangling_t dm;
1243 int *value;
1244 int base;
1245 int is_signed;
1246{
1247 dyn_string_t number = dyn_string_new (10);
1248
1249 DEMANGLE_TRACE ("number", dm);
1250
051664b0
AS
1251 if (number == NULL)
1252 return STATUS_ALLOCATION_FAILED;
1253
69afa80d
AS
1254 demangle_number_literally (dm, number, base, is_signed);
1255 *value = strtol (dyn_string_buf (number), NULL, base);
1256 dyn_string_delete (number);
1257
1258 return STATUS_OK;
1259}
1260
1261/* Demangles a number at the current position. The digits (and minus
1262 sign, if present) that make up the number are appended to STR.
1263 Only base-BASE digits are accepted; BASE must be either 10 or 36.
1264 If IS_SIGNED, negative numbers -- prefixed with `n' -- are
1265 accepted. Does not consume a trailing underscore or other
1266 terminating character. */
1267
1268static status_t
1269demangle_number_literally (dm, str, base, is_signed)
1270 demangling_t dm;
1271 dyn_string_t str;
1272 int base;
1273 int is_signed;
1274{
1275 DEMANGLE_TRACE ("number*", dm);
1276
1277 if (base != 10 && base != 36)
1278 return STATUS_INTERNAL_ERROR;
1279
1280 /* An `n' denotes a negative number. */
1281 if (is_signed && peek_char (dm) == 'n')
1282 {
1283 /* Skip past the n. */
1284 advance_char (dm);
1285 /* The normal way to write a negative number is with a minus
1286 sign. */
051664b0
AS
1287 if (!dyn_string_append_char (str, '-'))
1288 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1289 }
1290
1291 /* Loop until we hit a non-digit. */
1292 while (1)
1293 {
1294 char peek = peek_char (dm);
051664b0 1295 if (IS_DIGIT ((unsigned char) peek)
69afa80d 1296 || (base == 36 && peek >= 'A' && peek <= 'Z'))
051664b0
AS
1297 {
1298 /* Accumulate digits. */
1299 if (!dyn_string_append_char (str, next_char (dm)))
1300 return STATUS_ALLOCATION_FAILED;
1301 }
69afa80d
AS
1302 else
1303 /* Not a digit? All done. */
1304 break;
1305 }
1306
1307 return STATUS_OK;
1308}
1309
1310/* Demangles an identifier at the current position of LENGTH
1311 characters and places it in IDENTIFIER. */
1312
1313static status_t
1314demangle_identifier (dm, length, identifier)
1315 demangling_t dm;
1316 int length;
1317 dyn_string_t identifier;
1318{
1319 DEMANGLE_TRACE ("identifier", dm);
1320
1321 dyn_string_clear (identifier);
051664b0
AS
1322 if (!dyn_string_resize (identifier, length))
1323 return STATUS_ALLOCATION_FAILED;
1324
69afa80d
AS
1325 while (length-- > 0)
1326 {
1327 if (end_of_name_p (dm))
1328 return "Unexpected end of name in <identifier>.";
051664b0
AS
1329 if (!dyn_string_append_char (identifier, next_char (dm)))
1330 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1331 }
1332
1333 return STATUS_OK;
1334}
1335
1336/* Demangles and emits an <operator-name>. If SHORT_NAME is non-zero,
1337 the short form is emitted; otherwise the full source form
1338 (`operator +' etc.) is emitted. *NUM_ARGS is set to the number of
1339 operands that the operator takes.
1340
1341 <operator-name>
1342 ::= nw # new
1343 ::= na # new[]
1344 ::= dl # delete
1345 ::= da # delete[]
1346 ::= ps # + (unary)
1347 ::= ng # - (unary)
1348 ::= ad # & (unary)
1349 ::= de # * (unary)
1350 ::= co # ~
1351 ::= pl # +
1352 ::= mi # -
1353 ::= ml # *
1354 ::= dv # /
1355 ::= rm # %
1356 ::= an # &
1357 ::= or # |
1358 ::= eo # ^
1359 ::= aS # =
1360 ::= pL # +=
1361 ::= mI # -=
1362 ::= mL # *=
1363 ::= dV # /=
1364 ::= rM # %=
1365 ::= aN # &=
1366 ::= oR # |=
1367 ::= eO # ^=
1368 ::= ls # <<
1369 ::= rs # >>
1370 ::= lS # <<=
1371 ::= rS # >>=
1372 ::= eq # ==
1373 ::= ne # !=
1374 ::= lt # <
1375 ::= gt # >
1376 ::= le # <=
1377 ::= ge # >=
1378 ::= nt # !
1379 ::= aa # &&
1380 ::= oo # ||
1381 ::= pp # ++
1382 ::= mm # --
1383 ::= cm # ,
1384 ::= pm # ->*
1385 ::= pt # ->
1386 ::= cl # ()
1387 ::= ix # []
1388 ::= qu # ?
1389 ::= sz # sizeof
1390 ::= cv <type> # cast
1391 ::= vx <source-name> # vendor extended operator */
1392
1393static status_t
1394demangle_operator_name (dm, short_name, num_args)
1395 demangling_t dm;
1396 int short_name;
1397 int *num_args;
1398{
1399 struct operator_code
1400 {
1401 /* The mangled code for this operator. */
7eb23b1f 1402 const char *code;
69afa80d 1403 /* The source name of this operator. */
7eb23b1f 1404 const char *name;
69afa80d
AS
1405 /* The number of arguments this operator takes. */
1406 int num_args;
1407 };
1408
7eb23b1f 1409 static const struct operator_code operators[] =
69afa80d
AS
1410 {
1411 { "aN", "&=" , 2 },
1412 { "aS", "=" , 2 },
1413 { "aa", "&&" , 2 },
1414 { "ad", "&" , 1 },
1415 { "an", "&" , 2 },
1416 { "cl", "()" , 0 },
1417 { "cm", "," , 2 },
1418 { "co", "~" , 1 },
1419 { "dV", "/=" , 2 },
fe06b696 1420 { "da", " delete[]", 1 },
69afa80d 1421 { "de", "*" , 1 },
fe06b696 1422 { "dl", " delete" , 1 },
69afa80d
AS
1423 { "dv", "/" , 2 },
1424 { "eO", "^=" , 2 },
1425 { "eo", "^" , 2 },
1426 { "eq", "==" , 2 },
1427 { "ge", ">=" , 2 },
1428 { "gt", ">" , 2 },
1429 { "ix", "[]" , 2 },
1430 { "lS", "<<=" , 2 },
1431 { "le", "<=" , 2 },
1432 { "ls", "<<" , 2 },
1433 { "lt", "<" , 2 },
1434 { "mI", "-=" , 2 },
1435 { "mL", "*=" , 2 },
1436 { "mi", "-" , 2 },
1437 { "ml", "*" , 2 },
1438 { "mm", "--" , 1 },
fe06b696 1439 { "na", " new[]" , 1 },
69afa80d
AS
1440 { "ne", "!=" , 2 },
1441 { "ng", "-" , 1 },
1442 { "nt", "!" , 1 },
fe06b696 1443 { "nw", " new" , 1 },
69afa80d
AS
1444 { "oR", "|=" , 2 },
1445 { "oo", "||" , 2 },
1446 { "or", "|" , 2 },
1447 { "pL", "+=" , 2 },
1448 { "pl", "+" , 2 },
1449 { "pm", "->*" , 2 },
1450 { "pp", "++" , 1 },
1451 { "ps", "+" , 1 },
1452 { "qu", "?" , 3 },
1453 { "rM", "%=" , 2 },
1454 { "rS", ">>=" , 2 },
1455 { "rm", "%" , 2 },
1456 { "rs", ">>" , 2 },
fe06b696 1457 { "sz", " sizeof" , 1 }
69afa80d
AS
1458 };
1459
1460 const int num_operators =
1461 sizeof (operators) / sizeof (struct operator_code);
1462
1463 int c0 = next_char (dm);
1464 int c1 = next_char (dm);
7eb23b1f
KG
1465 const struct operator_code* p1 = operators;
1466 const struct operator_code* p2 = operators + num_operators;
69afa80d
AS
1467
1468 DEMANGLE_TRACE ("operator-name", dm);
1469
1470 /* Is this a vendor extended operator? */
1471 if (c0 == 'v' && c1 == 'x')
1472 {
051664b0 1473 RETURN_IF_ERROR (result_append (dm, "operator"));
69afa80d
AS
1474 RETURN_IF_ERROR (demangle_source_name (dm));
1475 *num_args = 0;
1476 return STATUS_OK;
1477 }
1478
1479 /* Is this a conversion operator? */
1480 if (c0 == 'c' && c1 == 'v')
1481 {
051664b0 1482 RETURN_IF_ERROR (result_append (dm, "operator "));
69afa80d
AS
1483 /* Demangle the converted-to type. */
1484 RETURN_IF_ERROR (demangle_type (dm));
1485 *num_args = 0;
1486 return STATUS_OK;
1487 }
1488
1489 /* Perform a binary search for the operator code. */
1490 while (1)
1491 {
7eb23b1f 1492 const struct operator_code* p = p1 + (p2 - p1) / 2;
69afa80d
AS
1493 char match0 = p->code[0];
1494 char match1 = p->code[1];
1495
1496 if (c0 == match0 && c1 == match1)
1497 /* Found it. */
1498 {
1499 if (!short_name)
051664b0
AS
1500 RETURN_IF_ERROR (result_append (dm, "operator"));
1501 RETURN_IF_ERROR (result_append (dm, p->name));
69afa80d
AS
1502 *num_args = p->num_args;
1503
1504 return STATUS_OK;
1505 }
1506
1507 if (p == p1)
1508 /* Couldn't find it. */
1509 return "Unknown code in <operator-name>.";
1510
1511 /* Try again. */
1512 if (c0 < match0 || (c0 == match0 && c1 < match1))
1513 p2 = p;
1514 else
1515 p1 = p;
1516 }
1517}
1518
1519/* Demangles and emits a <special-name>.
1520
1521 <special-name> ::= GV <object name> # Guard variable
1522 ::= Th[n] <offset number> _ <base name> <base encoding>
1523 # non-virtual base override thunk
1524 ::= Tv[n] <offset number> _ <vcall offset number>
1525 _ <base encoding>
1526 # virtual base override thunk
1527 ::= TV <type> # virtual table
1528 ::= TT <type> # VTT
1529 ::= TI <type> # typeinfo structure
1530 ::= TS <type> # typeinfo name
1531
fe06b696 1532 Also demangles the special g++ manglings,
69afa80d
AS
1533
1534 <special-name> ::= CT <type> <offset number> _ <base type>
fe06b696
ZW
1535 # construction vtable
1536 ::= TF <type> # typeinfo function (old ABI only)
1537 ::= TJ <type> # java Class structure */
69afa80d
AS
1538
1539static status_t
1540demangle_special_name (dm)
1541 demangling_t dm;
1542{
1543 dyn_string_t number;
1544 int unused;
1545 char peek = peek_char (dm);
1546
1547 DEMANGLE_TRACE ("special-name", dm);
1548
1549 if (peek == 'G')
1550 {
1551 /* A guard variable name. Consume the G. */
1552 advance_char (dm);
1553 RETURN_IF_ERROR (demangle_char (dm, 'V'));
051664b0 1554 RETURN_IF_ERROR (result_append (dm, "guard variable for "));
69afa80d
AS
1555 RETURN_IF_ERROR (demangle_name (dm, &unused));
1556 }
1557 else if (peek == 'T')
1558 {
051664b0
AS
1559 status_t status = STATUS_OK;
1560
69afa80d
AS
1561 /* Other C++ implementation miscellania. Consume the T. */
1562 advance_char (dm);
1563
1564 switch (peek_char (dm))
1565 {
1566 case 'V':
1567 /* Virtual table. */
1568 advance_char (dm);
051664b0 1569 RETURN_IF_ERROR (result_append (dm, "vtable for "));
69afa80d
AS
1570 RETURN_IF_ERROR (demangle_type (dm));
1571 break;
1572
1573 case 'T':
1574 /* VTT structure. */
1575 advance_char (dm);
051664b0 1576 RETURN_IF_ERROR (result_append (dm, "VTT for "));
69afa80d
AS
1577 RETURN_IF_ERROR (demangle_type (dm));
1578 break;
1579
1580 case 'I':
1581 /* Typeinfo structure. */
1582 advance_char (dm);
051664b0 1583 RETURN_IF_ERROR (result_append (dm, "typeinfo for "));
69afa80d
AS
1584 RETURN_IF_ERROR (demangle_type (dm));
1585 break;
1586
fe06b696
ZW
1587 case 'F':
1588 /* Typeinfo function. Used only in old ABI with new mangling. */
1589 advance_char (dm);
051664b0 1590 RETURN_IF_ERROR (result_append (dm, "typeinfo fn for "));
fe06b696
ZW
1591 RETURN_IF_ERROR (demangle_type (dm));
1592 break;
1593
69afa80d
AS
1594 case 'S':
1595 /* Character string containing type name, used in typeinfo. */
1596 advance_char (dm);
051664b0 1597 RETURN_IF_ERROR (result_append (dm, "typeinfo name for "));
69afa80d
AS
1598 RETURN_IF_ERROR (demangle_type (dm));
1599 break;
1600
fe06b696
ZW
1601 case 'J':
1602 /* The java Class variable corresponding to a C++ class. */
1603 advance_char (dm);
051664b0 1604 RETURN_IF_ERROR (result_append (dm, "java Class for "));
fe06b696
ZW
1605 RETURN_IF_ERROR (demangle_type (dm));
1606 break;
1607
69afa80d
AS
1608 case 'h':
1609 /* Non-virtual thunk. */
1610 advance_char (dm);
051664b0 1611 RETURN_IF_ERROR (result_append (dm, "non-virtual thunk"));
69afa80d
AS
1612 /* Demangle and emit the offset. */
1613 number = dyn_string_new (4);
051664b0
AS
1614 if (number == NULL)
1615 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1616 demangle_number_literally (dm, number, 10, 1);
1617 /* Don't display the offset unless in verbose mode. */
1618 if (flag_verbose)
1619 {
051664b0
AS
1620 status = result_append_char (dm, ' ');
1621 if (STATUS_NO_ERROR (status))
1622 status = result_append_string (dm, number);
69afa80d
AS
1623 }
1624 dyn_string_delete (number);
051664b0 1625 RETURN_IF_ERROR (status);
69afa80d
AS
1626 /* Demangle the separator. */
1627 RETURN_IF_ERROR (demangle_char (dm, '_'));
1628 /* Demangle and emit the target name and function type. */
051664b0 1629 RETURN_IF_ERROR (result_append (dm, " to "));
69afa80d
AS
1630 RETURN_IF_ERROR (demangle_encoding (dm));
1631 break;
1632
1633 case 'v':
1634 /* Virtual thunk. */
1635 advance_char (dm);
051664b0 1636 RETURN_IF_ERROR (result_append (dm, "virtual thunk "));
69afa80d
AS
1637 /* Demangle and emit the offset. */
1638 number = dyn_string_new (4);
051664b0
AS
1639 if (number == NULL)
1640 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1641 demangle_number_literally (dm, number, 10, 1);
1642 /* Don't display the offset unless in verbose mode. */
1643 if (flag_verbose)
1644 {
051664b0
AS
1645 status = result_append_string (dm, number);
1646 if (STATUS_NO_ERROR (status))
1647 result_append_char (dm, ' ');
69afa80d
AS
1648 }
1649 dyn_string_delete (number);
051664b0 1650 RETURN_IF_ERROR (status);
69afa80d
AS
1651 /* Demangle the separator. */
1652 RETURN_IF_ERROR (demangle_char (dm, '_'));
1653 /* Demangle and emit the vcall offset. */
1654 number = dyn_string_new (4);
051664b0
AS
1655 if (number == NULL)
1656 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1657 demangle_number_literally (dm, number, 10, 1);
1658 /* Don't display the vcall offset unless in verbose mode. */
1659 if (flag_verbose)
1660 {
051664b0
AS
1661 status = result_append_string (dm, number);
1662 if (STATUS_NO_ERROR (status))
1663 status = result_append_char (dm, ' ');
69afa80d
AS
1664 }
1665 dyn_string_delete (number);
051664b0 1666 RETURN_IF_ERROR (status);
69afa80d
AS
1667 /* Demangle the separator. */
1668 RETURN_IF_ERROR (demangle_char (dm, '_'));
1669 /* Demangle and emit the target function. */
051664b0 1670 RETURN_IF_ERROR (result_append (dm, "to "));
69afa80d
AS
1671 RETURN_IF_ERROR (demangle_encoding (dm));
1672 break;
1673
1674 case 'C':
1675 /* TC is a special g++ mangling for a construction vtable. */
1676 if (!flag_strict)
1677 {
229b8ec7
AS
1678 dyn_string_t derived_type;
1679
69afa80d 1680 advance_char (dm);
051664b0 1681 RETURN_IF_ERROR (result_append (dm, "construction vtable for "));
229b8ec7
AS
1682
1683 /* Demangle the derived type off to the side. */
1684 RETURN_IF_ERROR (result_push (dm));
69afa80d 1685 RETURN_IF_ERROR (demangle_type (dm));
229b8ec7
AS
1686 derived_type = (dyn_string_t) result_pop (dm);
1687
69afa80d
AS
1688 /* Demangle the offset. */
1689 number = dyn_string_new (4);
051664b0 1690 if (number == NULL)
229b8ec7
AS
1691 {
1692 dyn_string_delete (derived_type);
1693 return STATUS_ALLOCATION_FAILED;
1694 }
69afa80d
AS
1695 demangle_number_literally (dm, number, 10, 1);
1696 /* Demangle the underscore separator. */
229b8ec7
AS
1697 status = demangle_char (dm, '_');
1698
69afa80d 1699 /* Demangle the base type. */
229b8ec7
AS
1700 if (STATUS_NO_ERROR (status))
1701 status = demangle_type (dm);
1702
1703 /* Emit the derived type. */
1704 if (STATUS_NO_ERROR (status))
1705 status = result_append (dm, "-in-");
1706 if (STATUS_NO_ERROR (status))
1707 status = result_append_string (dm, derived_type);
1708 dyn_string_delete (derived_type);
1709
69afa80d
AS
1710 /* Don't display the offset unless in verbose mode. */
1711 if (flag_verbose)
1712 {
051664b0
AS
1713 status = result_append_char (dm, ' ');
1714 if (STATUS_NO_ERROR (status))
1715 result_append_string (dm, number);
69afa80d
AS
1716 }
1717 dyn_string_delete (number);
051664b0 1718 RETURN_IF_ERROR (status);
69afa80d
AS
1719 break;
1720 }
1721 /* If flag_strict, fall through. */
1722
1723 default:
1724 return "Unrecognized <special-name>.";
1725 }
1726 }
1727 else
1728 return STATUS_ERROR;
1729
1730 return STATUS_OK;
1731}
1732
1733/* Demangles and emits a <ctor-dtor-name>.
1734
1735 <ctor-dtor-name>
1736 ::= C1 # complete object (in-charge) ctor
1737 ::= C2 # base object (not-in-charge) ctor
1738 ::= C3 # complete object (in-charge) allocating ctor
1739 ::= C4 # base object (not-in-charge) allocating ctor
1740 ::= D0 # deleting (in-charge) dtor
1741 ::= D1 # complete object (in-charge) dtor
1742 ::= D2 # base object (not-in-charge) dtor */
1743
1744static status_t
1745demangle_ctor_dtor_name (dm)
1746 demangling_t dm;
1747{
1748 static const char *const ctor_flavors[] =
1749 {
1750 "in-charge",
1751 "not-in-charge",
1752 "in-charge allocating",
1753 "not-in-charge allocating"
1754 };
1755 static const char *const dtor_flavors[] =
1756 {
1757 "in-charge deleting",
1758 "in-charge",
1759 "not-in-charge"
1760 };
1761
1762 int flavor;
1763 char peek = peek_char (dm);
1764
1765 DEMANGLE_TRACE ("ctor-dtor-name", dm);
1766
1767 if (peek == 'C')
1768 {
1769 /* A constructor name. Consume the C. */
1770 advance_char (dm);
1771 if (peek_char (dm) < '1' || peek_char (dm) > '4')
1772 return "Unrecognized constructor.";
051664b0 1773 RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
69afa80d
AS
1774 /* Print the flavor of the constructor if in verbose mode. */
1775 flavor = next_char (dm) - '1';
1776 if (flag_verbose)
1777 {
051664b0
AS
1778 RETURN_IF_ERROR (result_append (dm, "["));
1779 RETURN_IF_ERROR (result_append (dm, ctor_flavors[flavor]));
1780 RETURN_IF_ERROR (result_append_char (dm, ']'));
69afa80d
AS
1781 }
1782 }
1783 else if (peek == 'D')
1784 {
1785 /* A destructor name. Consume the D. */
1786 advance_char (dm);
1787 if (peek_char (dm) < '0' || peek_char (dm) > '2')
1788 return "Unrecognized destructor.";
051664b0
AS
1789 RETURN_IF_ERROR (result_append_char (dm, '~'));
1790 RETURN_IF_ERROR (result_append_string (dm, dm->last_source_name));
69afa80d
AS
1791 /* Print the flavor of the destructor if in verbose mode. */
1792 flavor = next_char (dm) - '0';
1793 if (flag_verbose)
1794 {
051664b0
AS
1795 RETURN_IF_ERROR (result_append (dm, " ["));
1796 RETURN_IF_ERROR (result_append (dm, dtor_flavors[flavor]));
1797 RETURN_IF_ERROR (result_append_char (dm, ']'));
69afa80d
AS
1798 }
1799 }
1800 else
1801 return STATUS_ERROR;
1802
1803 return STATUS_OK;
1804}
1805
1806/* Handle pointer, reference, and pointer-to-member cases for
1807 demangle_type. All consecutive `P's, `R's, and 'M's are joined to
1808 build a pointer/reference type. We snarf all these, plus the
1809 following <type>, all at once since we need to know whether we have
1810 a pointer to data or pointer to function to construct the right
1811 output syntax. C++'s pointer syntax is hairy.
1812
1813 <type> ::= P <type>
1814 ::= R <type>
1815 ::= <pointer-to-member-type>
1816
1817 <pointer-to-member-type> ::= M </class/ type> </member/ type> */
1818
1819static status_t
1820demangle_type_ptr (dm)
1821 demangling_t dm;
1822{
1823 char next;
1824 status_t status;
1825
1826 /* Collect pointer symbols into this string. */
1827 dyn_string_t symbols = dyn_string_new (10);
1828
1829 DEMANGLE_TRACE ("type*", dm);
1830
051664b0
AS
1831 if (symbols == NULL)
1832 return STATUS_ALLOCATION_FAILED;
1833
69afa80d
AS
1834 /* Scan forward, collecting pointers and references into symbols,
1835 until we hit something else. Then emit the type. */
1836 while (1)
1837 {
1838 next = peek_char (dm);
1839 if (next == 'P')
1840 {
051664b0
AS
1841 if (!dyn_string_append_char (symbols, '*'))
1842 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1843 advance_char (dm);
1844 }
1845 else if (next == 'R')
1846 {
051664b0
AS
1847 if (!dyn_string_append_char (symbols, '&'))
1848 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1849 advance_char (dm);
1850 }
1851 else if (next == 'M')
1852 {
1853 /* Pointer-to-member. */
1854 dyn_string_t class_type;
1855
1856 /* Eat the 'M'. */
1857 advance_char (dm);
1858
1859 /* Capture the type of which this is a pointer-to-member. */
051664b0 1860 RETURN_IF_ERROR (result_push (dm));
69afa80d
AS
1861 RETURN_IF_ERROR (demangle_type (dm));
1862 class_type = (dyn_string_t) result_pop (dm);
1863
1864 /* Build the pointer-to-member notation. It comes before
1865 other pointer and reference qualifiers -- */
051664b0
AS
1866 if (!dyn_string_prepend_cstr (symbols, "::*"))
1867 return STATUS_ALLOCATION_FAILED;
1868 if (!dyn_string_prepend (symbols, class_type))
1869 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
1870 dyn_string_delete (class_type);
1871
1872 if (peek_char (dm) == 'F')
1873 continue;
1874
1875 /* Demangle the type of the pointed-to member. */
1876 status = demangle_type (dm);
1877 /* Make it pretty. */
051664b0
AS
1878 if (STATUS_NO_ERROR (status))
1879 status = result_append_space (dm);
69afa80d
AS
1880 /* Add the pointer-to-member syntax, and other pointer and
1881 reference symbols. */
051664b0
AS
1882 if (STATUS_NO_ERROR (status))
1883 status = result_append_string (dm, symbols);
69afa80d
AS
1884 /* Clean up. */
1885 dyn_string_delete (symbols);
1886
1887 RETURN_IF_ERROR (status);
1888 return STATUS_OK;
1889 }
1890 else if (next == 'F')
1891 {
1892 /* Ooh, tricky, a pointer-to-function. */
1893 int position = result_length (dm);
051664b0
AS
1894 status = result_append_char (dm, '(');
1895 if (STATUS_NO_ERROR (status))
1896 status = result_append_string (dm, symbols);
1897 if (STATUS_NO_ERROR (status))
1898 status = result_append_char (dm, ')');
69afa80d 1899 dyn_string_delete (symbols);
051664b0 1900 RETURN_IF_ERROR (status);
69afa80d
AS
1901
1902 RETURN_IF_ERROR (demangle_function_type (dm, position));
1903 return STATUS_OK;
1904 }
1905 else
1906 {
1907 /* No more pointe or reference tokens. Finish up. */
1908 status = demangle_type (dm);
1909
051664b0
AS
1910 if (STATUS_NO_ERROR (status))
1911 status = result_append_string (dm, symbols);
69afa80d 1912 dyn_string_delete (symbols);
051664b0 1913 RETURN_IF_ERROR (status);
69afa80d
AS
1914
1915 RETURN_IF_ERROR (status);
1916 return STATUS_OK;
1917 }
1918 }
1919}
1920
1921/* Demangles and emits a <type>.
1922
1923 <type> ::= <builtin-type>
1924 ::= <function-type>
1925 ::= <class-enum-type>
1926 ::= <array-type>
1927 ::= <pointer-to-member-type>
1928 ::= <template-param>
1929 ::= <CV-qualifiers> <type>
1930 ::= P <type> # pointer-to
1931 ::= R <type> # reference-to
1932 ::= C <type> # complex pair (C 2000)
1933 ::= G <type> # imaginary (C 2000)
1934 ::= U <source-name> <type> # vendor extended type qualifier
1935 ::= <substitution> */
1936
1937static status_t
1938demangle_type (dm)
1939 demangling_t dm;
1940{
1941 int start = substitution_start (dm);
1942 char peek = peek_char (dm);
bece74bd 1943 char peek_next;
69afa80d
AS
1944 int template_p = 0;
1945 int special_std_substitution;
1946 int is_builtin_type = 0;
1947 template_arg_list_t old_arg_list = current_template_arg_list (dm);
1948 int template_parm = NOT_TEMPLATE_PARM;
1949
1950 DEMANGLE_TRACE ("type", dm);
1951
1952 /* A <class-enum-type> can start with a digit (a <source-name>), an
1953 N (a <nested-name>), or a Z (a <local-name>). */
051664b0 1954 if (IS_DIGIT ((unsigned char) peek) || peek == 'N' || peek == 'Z')
69afa80d
AS
1955 RETURN_IF_ERROR (demangle_class_enum_type (dm, &template_p));
1956 else if (peek >= 'a' && peek <= 'z')
1957 {
1958 RETURN_IF_ERROR (demangle_builtin_type (dm));
1959 is_builtin_type = 1;
1960 }
1961 else
1962 switch (peek)
1963 {
1964 case 'r':
1965 case 'V':
1966 case 'K':
1967 {
1968 status_t status;
1969 dyn_string_t cv_qualifiers = dyn_string_new (24);
051664b0
AS
1970
1971 if (cv_qualifiers == NULL)
1972 return STATUS_ALLOCATION_FAILED;
1973
69afa80d
AS
1974 demangle_CV_qualifiers (dm, cv_qualifiers);
1975
1976 /* If the qualifiers apply to a pointer or reference, they
1977 need to come after the whole qualified type. */
1978 if (peek_char (dm) == 'P' || peek_char (dm) == 'R')
1979 {
1980 status = demangle_type (dm);
051664b0
AS
1981 if (STATUS_NO_ERROR (status))
1982 status = result_append_space (dm);
1983 if (STATUS_NO_ERROR (status))
1984 status = result_append_string (dm, cv_qualifiers);
69afa80d
AS
1985 }
1986 /* Otherwise, the qualifiers come first. */
1987 else
1988 {
051664b0
AS
1989 status = result_append_string (dm, cv_qualifiers);
1990 if (STATUS_NO_ERROR (status))
1991 status = result_append_space (dm);
1992 if (STATUS_NO_ERROR (status))
1993 status = demangle_type (dm);
69afa80d
AS
1994 }
1995
1996 dyn_string_delete (cv_qualifiers);
1997 RETURN_IF_ERROR (status);
1998 }
1999 break;
2000
2001 case 'F':
2002 return "Non-pointer or -reference function type.";
2003
2004 case 'A':
2005 RETURN_IF_ERROR (demangle_array_type (dm));
2006 break;
2007
2008 case 'T':
2009 RETURN_IF_ERROR (demangle_template_param (dm, &template_parm));
2010 break;
2011
2012 case 'S':
bece74bd
AS
2013 /* First check if this is a special substitution. If it is,
2014 this is a <class-enum-type>. Special substitutions have a
2015 letter following the `S'; other substitutions have a digit
2016 or underscore. */
2017 peek_next = peek_char_next (dm);
2018 if (IS_DIGIT (peek_next) || peek_next == '_')
2019 RETURN_IF_ERROR (demangle_substitution (dm, &template_p,
2020 &special_std_substitution));
2021 else
2022 demangle_class_enum_type (dm, &template_p);
69afa80d
AS
2023 break;
2024
2025 case 'P':
2026 case 'R':
2027 case 'M':
2028 RETURN_IF_ERROR (demangle_type_ptr (dm));
2029 break;
2030
2031 case 'C':
2032 /* A C99 complex type. */
051664b0 2033 RETURN_IF_ERROR (result_append (dm, "complex "));
69afa80d
AS
2034 advance_char (dm);
2035 RETURN_IF_ERROR (demangle_type (dm));
2036 break;
2037
2038 case 'G':
2039 /* A C99 imaginary type. */
051664b0 2040 RETURN_IF_ERROR (result_append (dm, "imaginary "));
69afa80d
AS
2041 advance_char (dm);
2042 RETURN_IF_ERROR (demangle_type (dm));
2043 break;
2044
2045 case 'U':
2046 /* Vendor extended type qualifier. */
2047 advance_char (dm);
2048 RETURN_IF_ERROR (demangle_source_name (dm));
051664b0 2049 RETURN_IF_ERROR (result_append_char (dm, ' '));
69afa80d
AS
2050 RETURN_IF_ERROR (demangle_type (dm));
2051 break;
2052
2053 default:
2054 return "Unexpected character in <type>.";
2055 }
2056
2057 /* Unqualified builin types are not substitution candidates. */
2058 if (!is_builtin_type)
2059 /* Add a new substitution for the type. If this type was a
2060 <template-param>, pass its index since from the point of
2061 substitutions, a <template-param> token is a substitution
2062 candidate distinct from the type that is substituted for it. */
051664b0 2063 RETURN_IF_ERROR (substitution_add (dm, start, template_p, template_parm));
69afa80d
AS
2064
2065 /* Pop off template argument lists added during mangling of this
2066 type. */
2067 pop_to_template_arg_list (dm, old_arg_list);
2068
2069 return STATUS_OK;
2070}
2071
2072/* C++ source names of builtin types, indexed by the mangled code
2073 letter's position in the alphabet ('a' -> 0, 'b' -> 1, etc). */
2074static const char *const builtin_type_names[26] =
2075{
2076 "signed char", /* a */
2077 "bool", /* b */
2078 "char", /* c */
2079 "double", /* d */
2080 "long double", /* e */
2081 "float", /* f */
2082 "__float128", /* g */
2083 "unsigned char", /* h */
2084 "int", /* i */
2085 "unsigned", /* j */
2086 NULL, /* k */
2087 "long", /* l */
2088 "unsigned long", /* m */
2089 "__int128", /* n */
2090 "unsigned __int128", /* o */
2091 NULL, /* p */
2092 NULL, /* q */
2093 NULL, /* r */
2094 "short", /* s */
2095 "unsigned short", /* t */
2096 NULL, /* u */
2097 "void", /* v */
2098 "wchar_t", /* w */
2099 "long long", /* x */
2100 "unsigned long long", /* y */
2101 "..." /* z */
2102};
2103
2104/* Demangles and emits a <builtin-type>.
2105
2106 <builtin-type> ::= v # void
2107 ::= w # wchar_t
2108 ::= b # bool
2109 ::= c # char
2110 ::= a # signed char
2111 ::= h # unsigned char
2112 ::= s # short
2113 ::= t # unsigned short
2114 ::= i # int
2115 ::= j # unsigned int
2116 ::= l # long
2117 ::= m # unsigned long
2118 ::= x # long long, __int64
2119 ::= y # unsigned long long, __int64
2120 ::= n # __int128
2121 ::= o # unsigned __int128
2122 ::= f # float
2123 ::= d # double
2124 ::= e # long double, __float80
2125 ::= g # __float128
2126 ::= z # ellipsis
2127 ::= u <source-name> # vendor extended type */
2128
2129static status_t
2130demangle_builtin_type (dm)
2131 demangling_t dm;
2132{
2133
2134 char code = peek_char (dm);
2135
2136 DEMANGLE_TRACE ("builtin-type", dm);
2137
2138 if (code == 'u')
2139 {
2140 advance_char (dm);
2141 RETURN_IF_ERROR (demangle_source_name (dm));
2142 return STATUS_OK;
2143 }
2144 else if (code >= 'a' && code <= 'z')
2145 {
2146 const char *type_name = builtin_type_names[code - 'a'];
2147 if (type_name == NULL)
2148 return "Unrecognized <builtin-type> code.";
2149
051664b0 2150 RETURN_IF_ERROR (result_append (dm, type_name));
69afa80d
AS
2151 advance_char (dm);
2152 return STATUS_OK;
2153 }
2154 else
2155 return "Non-alphabetic <builtin-type> code.";
2156}
2157
2158/* Demangles all consecutive CV-qualifiers (const, volatile, and
2159 restrict) at the current position. The qualifiers are appended to
2160 QUALIFIERS. Returns STATUS_OK. */
2161
2162static status_t
2163demangle_CV_qualifiers (dm, qualifiers)
2164 demangling_t dm;
2165 dyn_string_t qualifiers;
2166{
2167 DEMANGLE_TRACE ("CV-qualifiers", dm);
2168
2169 while (1)
2170 {
2171 switch (peek_char (dm))
2172 {
2173 case 'r':
051664b0
AS
2174 if (!dyn_string_append_space (qualifiers))
2175 return STATUS_ALLOCATION_FAILED;
2176 if (!dyn_string_append_cstr (qualifiers, "restrict"))
2177 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
2178 break;
2179
2180 case 'V':
051664b0
AS
2181 if (!dyn_string_append_space (qualifiers))
2182 return STATUS_ALLOCATION_FAILED;
2183 if (!dyn_string_append_cstr (qualifiers, "volatile"))
2184 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
2185 break;
2186
2187 case 'K':
051664b0
AS
2188 if (!dyn_string_append_space (qualifiers))
2189 return STATUS_ALLOCATION_FAILED;
2190 if (!dyn_string_append_cstr (qualifiers, "const"))
2191 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
2192 break;
2193
2194 default:
2195 return STATUS_OK;
2196 }
2197
2198 advance_char (dm);
2199 }
2200}
2201
2202/* Demangles and emits a <function-type> FUNCTION_NAME_POS is the
2203 position in the result string of the start of the function
2204 identifier, at which the function's return type will be inserted.
2205
2206 <function-type> ::= F [Y] <bare-function-type> E */
2207
2208static status_t
2209demangle_function_type (dm, function_name_pos)
2210 demangling_t dm;
2211 int function_name_pos;
2212{
2213 DEMANGLE_TRACE ("function-type", dm);
2214 RETURN_IF_ERROR (demangle_char (dm, 'F'));
2215 if (peek_char (dm) == 'Y')
2216 {
2217 /* Indicate this function has C linkage if in verbose mode. */
2218 if (flag_verbose)
051664b0 2219 RETURN_IF_ERROR (result_append (dm, " [extern \"C\"] "));
69afa80d
AS
2220 advance_char (dm);
2221 }
2222 RETURN_IF_ERROR (demangle_bare_function_type (dm, function_name_pos));
2223 RETURN_IF_ERROR (demangle_char (dm, 'E'));
2224 return STATUS_OK;
2225}
2226
2227/* Demangles and emits a <bare-function-type>. RETURN_TYPE_POS is the
2228 position in the result string at which the function return type
2229 should be inserted. If RETURN_TYPE_POS is BFT_NO_RETURN_TYPE, the
2230 function's return type is assumed not to be encoded.
2231
2232 <bare-function-type> ::= <signature type>+ */
2233
2234static status_t
2235demangle_bare_function_type (dm, return_type_pos)
2236 demangling_t dm;
2237 int return_type_pos;
2238{
2239 /* Sequence is the index of the current function parameter, counting
2240 from zero. The value -1 denotes the return type. */
2241 int sequence =
2242 (return_type_pos == BFT_NO_RETURN_TYPE ? 0 : -1);
2243
2244 DEMANGLE_TRACE ("bare-function-type", dm);
2245
051664b0 2246 RETURN_IF_ERROR (result_append_char (dm, '('));
69afa80d
AS
2247 while (!end_of_name_p (dm) && peek_char (dm) != 'E')
2248 {
2249 if (sequence == -1)
2250 /* We're decoding the function's return type. */
2251 {
2252 dyn_string_t return_type;
051664b0 2253 status_t status = STATUS_OK;
69afa80d
AS
2254
2255 /* Decode the return type off to the side. */
051664b0 2256 RETURN_IF_ERROR (result_push (dm));
69afa80d
AS
2257 RETURN_IF_ERROR (demangle_type (dm));
2258 return_type = (dyn_string_t) result_pop (dm);
2259
051664b0
AS
2260 /* Add a space to the end of the type. Insert the return
2261 type where we've been asked to. */
2262 if (!dyn_string_append_space (return_type)
2263 || !dyn_string_insert (result_string (dm), return_type_pos,
2264 return_type))
2265 status = STATUS_ALLOCATION_FAILED;
69afa80d 2266
69afa80d 2267 dyn_string_delete (return_type);
051664b0 2268 RETURN_IF_ERROR (status);
69afa80d
AS
2269 }
2270 else
2271 {
2272 /* Skip `void' parameter types. One should only occur as
2273 the only type in a parameter list; in that case, we want
2274 to print `foo ()' instead of `foo (void)'. */
2275 if (peek_char (dm) == 'v')
2276 {
2277 /* Consume the v. */
2278 advance_char (dm);
2279 continue;
2280 }
2281 /* Separate parameter types by commas. */
2282 if (sequence > 0)
051664b0 2283 RETURN_IF_ERROR (result_append (dm, ", "));
69afa80d
AS
2284 /* Demangle the type. */
2285 RETURN_IF_ERROR (demangle_type (dm));
2286 }
2287
2288 ++sequence;
2289 }
051664b0 2290 RETURN_IF_ERROR (result_append_char (dm, ')'));
69afa80d
AS
2291
2292 return STATUS_OK;
2293}
2294
2295/* Demangles and emits a <class-enum-type>. *TEMPLATE_P is set to
2296 non-zero if the type is a template-id, zero otherwise.
2297
2298 <class-enum-type> ::= <name> */
2299
2300static status_t
2301demangle_class_enum_type (dm, template_p)
2302 demangling_t dm;
2303 int *template_p;
2304{
2305 DEMANGLE_TRACE ("class-enum-type", dm);
2306
2307 RETURN_IF_ERROR (demangle_name (dm, template_p));
2308 return STATUS_OK;
2309}
2310
2311/* Demangles and emits an <array-type>.
2312
2313 <array-type> ::= A [<dimension number>] _ <element type> */
2314
2315static status_t
2316demangle_array_type (dm)
2317 demangling_t dm;
2318{
051664b0 2319 status_t status;
69afa80d
AS
2320 dyn_string_t array_size = dyn_string_new (10);
2321
051664b0
AS
2322 if (array_size == NULL)
2323 return STATUS_ALLOCATION_FAILED;
2324
2325 status = demangle_char (dm, 'A');
69afa80d
AS
2326
2327 /* Demangle the array size into array_size. */
051664b0
AS
2328 if (STATUS_NO_ERROR (status))
2329 status = demangle_number_literally (dm, array_size, 10, 0);
69afa80d
AS
2330
2331 /* Demangle the base type of the array. */
051664b0
AS
2332 if (STATUS_NO_ERROR (status))
2333 status = demangle_char (dm, '_');
2334 if (STATUS_NO_ERROR (status))
2335 status = demangle_type (dm);
69afa80d
AS
2336
2337 /* Emit the array dimension syntax. */
051664b0
AS
2338 if (STATUS_NO_ERROR (status))
2339 status = result_append_char (dm, '[');
2340 if (STATUS_NO_ERROR (status))
2341 status = result_append_string (dm, array_size);
2342 if (STATUS_NO_ERROR (status))
2343 status = result_append_char (dm, ']');
69afa80d
AS
2344 dyn_string_delete (array_size);
2345
051664b0
AS
2346 RETURN_IF_ERROR (status);
2347
69afa80d
AS
2348 return STATUS_OK;
2349}
2350
2351/* Demangles and emits a <template-param>. The zero-indexed position
2352 in the parameter list is placed in *TEMPLATE_PARM_NUMBER.
2353
2354 <template-param> ::= T_ # first template parameter
2355 ::= T <parameter-2 number> _ */
2356
2357static status_t
2358demangle_template_param (dm, template_parm_number)
2359 demangling_t dm;
2360 int *template_parm_number;
2361{
2362 int parm_number;
2363 template_arg_list_t current_arg_list = current_template_arg_list (dm);
2364 string_list_t arg;
2365
2366 DEMANGLE_TRACE ("template-param", dm);
2367
2368 /* Make sure there is a template argmust list in which to look up
2369 this parameter reference. */
2370 if (current_arg_list == NULL)
2371 return "Template parameter outside of template.";
2372
2373 RETURN_IF_ERROR (demangle_char (dm, 'T'));
2374 if (peek_char (dm) == '_')
2375 parm_number = 0;
2376 else
2377 {
2378 RETURN_IF_ERROR (demangle_number (dm, &parm_number, 10, 0));
2379 ++parm_number;
2380 }
2381 RETURN_IF_ERROR (demangle_char (dm, '_'));
2382
2383 arg = template_arg_list_get_arg (current_arg_list, parm_number);
2384 if (arg == NULL)
2385 /* parm_number exceeded the number of arguments in the current
2386 template argument list. */
2387 return "Template parameter number out of bounds.";
051664b0 2388 RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
69afa80d
AS
2389
2390 if (peek_char (dm) == 'I')
2391 RETURN_IF_ERROR (demangle_template_args (dm));
2392
2393 *template_parm_number = parm_number;
2394 return STATUS_OK;
2395}
2396
2397/* Demangles and emits a <template-args>.
2398
2399 <template-args> ::= I <template-arg>+ E */
2400
2401static status_t
2402demangle_template_args (dm)
2403 demangling_t dm;
2404{
2405 int first = 1;
051664b0 2406 dyn_string_t old_last_source_name;
69afa80d
AS
2407 template_arg_list_t arg_list = template_arg_list_new ();
2408
051664b0
AS
2409 if (arg_list == NULL)
2410 return STATUS_ALLOCATION_FAILED;
2411
69afa80d 2412 /* Preserve the most recently demangled source name. */
051664b0 2413 old_last_source_name = dm->last_source_name;
69afa80d
AS
2414 dm->last_source_name = dyn_string_new (0);
2415
2416 DEMANGLE_TRACE ("template-args", dm);
2417
051664b0
AS
2418 if (dm->last_source_name == NULL)
2419 return STATUS_ALLOCATION_FAILED;
2420
69afa80d 2421 RETURN_IF_ERROR (demangle_char (dm, 'I'));
051664b0 2422 RETURN_IF_ERROR (result_append_char (dm, '<'));
69afa80d
AS
2423 do
2424 {
2425 string_list_t arg;
2426
2427 if (first)
2428 first = 0;
2429 else
051664b0 2430 RETURN_IF_ERROR (result_append (dm, ", "));
69afa80d
AS
2431
2432 /* Capture the template arg. */
051664b0 2433 RETURN_IF_ERROR (result_push (dm));
69afa80d
AS
2434 RETURN_IF_ERROR (demangle_template_arg (dm));
2435 arg = result_pop (dm);
2436
2437 /* Emit it in the demangled name. */
051664b0 2438 RETURN_IF_ERROR (result_append_string (dm, (dyn_string_t) arg));
69afa80d
AS
2439
2440 /* Save it for use in expanding <template-param>s. */
2441 template_arg_list_add_arg (arg_list, arg);
2442 }
2443 while (peek_char (dm) != 'E');
2444 /* Append the '>'. */
051664b0 2445 RETURN_IF_ERROR (result_close_template_list (dm));
69afa80d
AS
2446
2447 /* Consume the 'E'. */
2448 advance_char (dm);
2449
2450 /* Restore the most recent demangled source name. */
2451 dyn_string_delete (dm->last_source_name);
2452 dm->last_source_name = old_last_source_name;
2453
2454 /* Push the list onto the top of the stack of template argument
2455 lists, so that arguments from it are used from now on when
2456 expanding <template-param>s. */
2457 push_template_arg_list (dm, arg_list);
2458
2459 return STATUS_OK;
2460}
2461
2462/* This function, which does not correspond to a production in the
2463 mangling spec, handles the `literal' production for both
2464 <template-arg> and <expr-primary>. It does not expect or consume
2465 the initial `L' or final `E'. The demangling is given by:
2466
2467 <literal> ::= <type> </value/ number>
2468
2469 and the emitted output is `(type)number'. */
2470
2471static status_t
2472demangle_literal (dm)
2473 demangling_t dm;
2474{
69afa80d 2475 char peek = peek_char (dm);
051664b0
AS
2476 dyn_string_t value_string;
2477 status_t status;
69afa80d
AS
2478
2479 DEMANGLE_TRACE ("literal", dm);
2480
2481 if (!flag_verbose && peek >= 'a' && peek <= 'z')
2482 {
2483 /* If not in verbose mode and this is a builtin type, see if we
2484 can produce simpler numerical output. In particular, for
2485 integer types shorter than `long', just write the number
2486 without type information; for bools, write `true' or `false'.
2487 Other refinements could be made here too. */
2488
2489 /* This constant string is used to map from <builtin-type> codes
2490 (26 letters of the alphabet) to codes that determine how the
2491 value will be displayed. The codes are:
2492 b: display as bool
2493 i: display as int
2494 l: display as long
2495 A space means the value will be represented using cast
2496 notation. */
2497 static const char *const code_map = "ibi iii ll ii i ";
2498
2499 char code = code_map[peek - 'a'];
2500 /* FIXME: Implement demangling of floats and doubles. */
2501 if (code == 'u')
2502 return STATUS_UNIMPLEMENTED;
2503 if (code == 'b')
2504 {
2505 /* It's a boolean. */
2506 char value;
2507
2508 /* Consume the b. */
2509 advance_char (dm);
2510 /* Look at the next character. It should be 0 or 1,
2511 corresponding to false or true, respectively. */
2512 value = peek_char (dm);
2513 if (value == '0')
051664b0 2514 RETURN_IF_ERROR (result_append (dm, "false"));
69afa80d 2515 else if (value == '1')
051664b0 2516 RETURN_IF_ERROR (result_append (dm, "true"));
69afa80d
AS
2517 else
2518 return "Unrecognized bool constant.";
2519 /* Consume the 0 or 1. */
2520 advance_char (dm);
2521 return STATUS_OK;
2522 }
2523 else if (code == 'i' || code == 'l')
2524 {
2525 /* It's an integer or long. */
2526
2527 /* Consume the type character. */
2528 advance_char (dm);
051664b0 2529
69afa80d 2530 /* Demangle the number and write it out. */
051664b0
AS
2531 value_string = dyn_string_new (0);
2532 status = demangle_number_literally (dm, value_string, 10, 1);
2533 if (STATUS_NO_ERROR (status))
2534 status = result_append_string (dm, value_string);
69afa80d 2535 /* For long integers, append an l. */
051664b0
AS
2536 if (code == 'l' && STATUS_NO_ERROR (status))
2537 status = result_append_char (dm, code);
2538 dyn_string_delete (value_string);
2539
2540 RETURN_IF_ERROR (status);
69afa80d
AS
2541 return STATUS_OK;
2542 }
2543 /* ...else code == ' ', so fall through to represent this
2544 literal's type explicitly using cast syntax. */
2545 }
2546
051664b0 2547 RETURN_IF_ERROR (result_append_char (dm, '('));
69afa80d 2548 RETURN_IF_ERROR (demangle_type (dm));
051664b0
AS
2549 RETURN_IF_ERROR (result_append_char (dm, ')'));
2550
2551 value_string = dyn_string_new (0);
2552 if (value_string == NULL)
2553 return STATUS_ALLOCATION_FAILED;
69afa80d 2554
051664b0
AS
2555 status = demangle_number_literally (dm, value_string, 10, 1);
2556 if (STATUS_NO_ERROR (status))
2557 status = result_append_string (dm, value_string);
2558 dyn_string_delete (value_string);
2559 RETURN_IF_ERROR (status);
69afa80d
AS
2560
2561 return STATUS_OK;
2562}
2563
2564/* Demangles and emits a <template-arg>.
2565
2566 <template-arg> ::= <type> # type
2567 ::= L <type> <value number> E # literal
2568 ::= LZ <encoding> E # external name
2569 ::= X <expression> E # expression */
2570
2571static status_t
2572demangle_template_arg (dm)
2573 demangling_t dm;
2574{
2575 DEMANGLE_TRACE ("template-arg", dm);
2576
2577 switch (peek_char (dm))
2578 {
2579 case 'L':
2580 advance_char (dm);
2581
2582 if (peek_char (dm) == 'Z')
2583 {
2584 /* External name. */
2585 advance_char (dm);
2586 /* FIXME: Standard is contradictory here. */
2587 RETURN_IF_ERROR (demangle_encoding (dm));
2588 }
2589 else
2590 RETURN_IF_ERROR (demangle_literal (dm));
2591 RETURN_IF_ERROR (demangle_char (dm, 'E'));
2592 break;
2593
2594 case 'X':
2595 /* Expression. */
2596 advance_char (dm);
2597 RETURN_IF_ERROR (demangle_expression (dm));
2598 break;
2599
2600 default:
2601 RETURN_IF_ERROR (demangle_type (dm));
2602 break;
2603 }
2604
2605 return STATUS_OK;
2606}
2607
2608/* Demangles and emits an <expression>.
2609
2610 <expression> ::= <unary operator-name> <expression>
2611 ::= <binary operator-name> <expression> <expression>
2612 ::= <expr-primary>
2613 ::= <scope-expression> */
2614
2615static status_t
2616demangle_expression (dm)
2617 demangling_t dm;
2618{
2619 char peek = peek_char (dm);
2620
2621 DEMANGLE_TRACE ("expression", dm);
2622
2623 if (peek == 'L' || peek == 'T')
2624 RETURN_IF_ERROR (demangle_expr_primary (dm));
2625 else if (peek == 's' && peek_char_next (dm) == 'r')
2626 RETURN_IF_ERROR (demangle_scope_expression (dm));
2627 else
2628 /* An operator expression. */
2629 {
2630 int num_args;
051664b0 2631 status_t status = STATUS_OK;
69afa80d
AS
2632 dyn_string_t operator_name;
2633
2634 /* We have an operator name. Since we want to output binary
2635 operations in infix notation, capture the operator name
2636 first. */
051664b0 2637 RETURN_IF_ERROR (result_push (dm));
69afa80d
AS
2638 RETURN_IF_ERROR (demangle_operator_name (dm, 1, &num_args));
2639 operator_name = (dyn_string_t) result_pop (dm);
2640
2641 /* If it's binary, do an operand first. */
2642 if (num_args > 1)
2643 {
051664b0
AS
2644 status = result_append_char (dm, '(');
2645 if (STATUS_NO_ERROR (status))
2646 status = demangle_expression (dm);
2647 if (STATUS_NO_ERROR (status))
2648 status = result_append_char (dm, ')');
69afa80d
AS
2649 }
2650
051664b0
AS
2651 /* Emit the operator. */
2652 if (STATUS_NO_ERROR (status))
2653 status = result_append_string (dm, operator_name);
69afa80d 2654 dyn_string_delete (operator_name);
051664b0
AS
2655 RETURN_IF_ERROR (status);
2656
2657 /* Emit its second (if binary) or only (if unary) operand. */
2658 RETURN_IF_ERROR (result_append_char (dm, '('));
69afa80d 2659 RETURN_IF_ERROR (demangle_expression (dm));
051664b0 2660 RETURN_IF_ERROR (result_append_char (dm, ')'));
69afa80d
AS
2661
2662 /* The ternary operator takes a third operand. */
2663 if (num_args == 3)
2664 {
051664b0 2665 RETURN_IF_ERROR (result_append (dm, ":("));
69afa80d 2666 RETURN_IF_ERROR (demangle_expression (dm));
051664b0 2667 RETURN_IF_ERROR (result_append_char (dm, ')'));
69afa80d
AS
2668 }
2669 }
2670
2671 return STATUS_OK;
2672}
2673
2674/* Demangles and emits a <scope-expression>.
2675
2676 <scope-expression> ::= sr <qualifying type> <source-name>
2677 ::= sr <qualifying type> <encoding> */
2678
2679static status_t
2680demangle_scope_expression (dm)
2681 demangling_t dm;
2682{
2683 RETURN_IF_ERROR (demangle_char (dm, 's'));
2684 RETURN_IF_ERROR (demangle_char (dm, 'r'));
2685 RETURN_IF_ERROR (demangle_type (dm));
051664b0 2686 RETURN_IF_ERROR (result_append (dm, "::"));
69afa80d
AS
2687 RETURN_IF_ERROR (demangle_encoding (dm));
2688 return STATUS_OK;
2689}
2690
2691/* Demangles and emits an <expr-primary>.
2692
2693 <expr-primary> ::= <template-param>
2694 ::= L <type> <value number> E # literal
2695 ::= L <mangled-name> E # external name */
2696
2697static status_t
2698demangle_expr_primary (dm)
2699 demangling_t dm;
2700{
2701 char peek = peek_char (dm);
2702 int unused;
2703
2704 DEMANGLE_TRACE ("expr-primary", dm);
2705
2706 if (peek == 'T')
2707 RETURN_IF_ERROR (demangle_template_param (dm, &unused));
2708 else if (peek == 'L')
2709 {
2710 /* Consume the `L'. */
2711 advance_char (dm);
2712 peek = peek_char (dm);
2713
2714 if (peek == '_')
2715 RETURN_IF_ERROR (demangle_mangled_name (dm));
2716 else
2717 RETURN_IF_ERROR (demangle_literal (dm));
2718
2719 RETURN_IF_ERROR (demangle_char (dm, 'E'));
2720 }
2721 else
2722 return STATUS_ERROR;
2723
2724 return STATUS_OK;
2725}
2726
2727/* Demangles and emits a <substitution>. Sets *TEMPLATE_P to non-zero
2728 if the substitution is the name of a template, zero otherwise. If
2729 the substitution token is St, which corresponds to the `::std::'
2730 namespace and can appear in a non-nested name, sets
2731 *SPECIAL_STD_SUBSTITUTION to non-zero; zero otherwise.
2732
2733 <substitution> ::= S <seq-id> _
2734 ::= S_
2735
2736 ::= St # ::std::
2737 ::= Sa # ::std::allocator
2738 ::= Sb # ::std::basic_string
2739 ::= Ss # ::std::basic_string<char,
2740 ::std::char_traits<char>,
2741 ::std::allocator<char> >
2742 ::= Si # ::std::basic_istream<char,
2743 std::char_traits<char> >
2744 ::= So # ::std::basic_ostream<char,
2745 std::char_traits<char> >
2746 ::= Sd # ::std::basic_iostream<char,
2747 std::char_traits<char> >
2748*/
2749
2750static status_t
2751demangle_substitution (dm, template_p, special_std_substitution)
2752 demangling_t dm;
2753 int *template_p;
2754 int *special_std_substitution;
2755{
2756 int seq_id;
2757 int peek;
2758 dyn_string_t text;
2759
2760 DEMANGLE_TRACE ("substitution", dm);
2761
2762 RETURN_IF_ERROR (demangle_char (dm, 'S'));
2763 *special_std_substitution = 0;
2764
2765 /* Scan the substitution sequence index. A missing number denotes
2766 the first index. */
2767 peek = peek_char (dm);
2768 if (peek == '_')
2769 seq_id = -1;
2770 /* If the following character is 0-9 or a capital letter, interpret
2771 the sequence up to the next underscore as a base-36 substitution
2772 index. */
051664b0 2773 else if (IS_DIGIT ((unsigned char) peek)
69afa80d
AS
2774 || (peek >= 'A' && peek <= 'Z'))
2775 RETURN_IF_ERROR (demangle_number (dm, &seq_id, 36, 0));
2776 else
2777 {
051664b0
AS
2778 const char *new_last_source_name = NULL;
2779
69afa80d
AS
2780 switch (peek)
2781 {
2782 case 't':
051664b0 2783 RETURN_IF_ERROR (result_append (dm, "std"));
69afa80d
AS
2784 *special_std_substitution = 1;
2785 break;
2786
2787 case 'a':
051664b0
AS
2788 RETURN_IF_ERROR (result_append (dm, "std::allocator"));
2789 new_last_source_name = "allocator";
bece74bd 2790 *template_p = 1;
69afa80d
AS
2791 break;
2792
2793 case 'b':
051664b0
AS
2794 RETURN_IF_ERROR (result_append (dm, "std::basic_string"));
2795 new_last_source_name = "basic_string";
bece74bd 2796 *template_p = 1;
69afa80d
AS
2797 break;
2798
2799 case 's':
2800 if (!flag_verbose)
2801 {
051664b0
AS
2802 RETURN_IF_ERROR (result_append (dm, "std::string"));
2803 new_last_source_name = "string";
69afa80d
AS
2804 }
2805 else
2806 {
051664b0
AS
2807 RETURN_IF_ERROR (result_append (dm, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"));
2808 new_last_source_name = "basic_string";
69afa80d 2809 }
bece74bd 2810 *template_p = 0;
69afa80d
AS
2811 break;
2812
2813 case 'i':
2814 if (!flag_verbose)
2815 {
051664b0
AS
2816 RETURN_IF_ERROR (result_append (dm, "std::istream"));
2817 new_last_source_name = "istream";
69afa80d
AS
2818 }
2819 else
2820 {
051664b0
AS
2821 RETURN_IF_ERROR (result_append (dm, "std::basic_istream<char, std::char_traints<char> >"));
2822 new_last_source_name = "basic_istream";
69afa80d 2823 }
bece74bd 2824 *template_p = 0;
69afa80d
AS
2825 break;
2826
2827 case 'o':
2828 if (!flag_verbose)
2829 {
051664b0
AS
2830 RETURN_IF_ERROR (result_append (dm, "std::ostream"));
2831 new_last_source_name = "ostream";
69afa80d
AS
2832 }
2833 else
2834 {
051664b0
AS
2835 RETURN_IF_ERROR (result_append (dm, "std::basic_ostream<char, std::char_traits<char> >"));
2836 new_last_source_name = "basic_ostream";
69afa80d 2837 }
bece74bd 2838 *template_p = 0;
69afa80d
AS
2839 break;
2840
2841 case 'd':
2842 if (!flag_verbose)
2843 {
051664b0
AS
2844 RETURN_IF_ERROR (result_append (dm, "std::iostream"));
2845 new_last_source_name = "iostream";
69afa80d
AS
2846 }
2847 else
2848 {
051664b0
AS
2849 RETURN_IF_ERROR (result_append (dm, "std::basic_iostream<char, std::char_traits<char> >"));
2850 new_last_source_name = "basic_iostream";
69afa80d 2851 }
bece74bd 2852 *template_p = 0;
69afa80d
AS
2853 break;
2854
2855 default:
2856 return "Unrecognized <substitution>.";
2857 }
2858
051664b0 2859 /* Consume the character we just processed. */
69afa80d 2860 advance_char (dm);
051664b0
AS
2861
2862 if (new_last_source_name != NULL)
2863 {
2864 if (!dyn_string_copy_cstr (dm->last_source_name,
2865 new_last_source_name))
2866 return STATUS_ALLOCATION_FAILED;
2867 }
2868
69afa80d
AS
2869 return STATUS_OK;
2870 }
2871
2872 /* Look up the substitution text. Since `S_' is the most recent
2873 substitution, `S0_' is the second-most-recent, etc., shift the
2874 numbering by one. */
2875 text = substitution_get (dm, seq_id + 1, template_p);
bece74bd 2876 if (text == NULL)
69afa80d
AS
2877 return "Substitution number out of range.";
2878
2879 /* Emit the substitution text. */
051664b0 2880 RETURN_IF_ERROR (result_append_string (dm, text));
69afa80d
AS
2881
2882 RETURN_IF_ERROR (demangle_char (dm, '_'));
2883 return STATUS_OK;
2884}
2885
2886/* Demangles and emits a <local-name>.
2887
2888 <local-name> := Z <function encoding> E <entity name> [<discriminator>]
2889 := Z <function encoding> E s [<discriminator>] */
2890
2891static status_t
2892demangle_local_name (dm)
2893 demangling_t dm;
2894{
2895 DEMANGLE_TRACE ("local-name", dm);
2896
2897 RETURN_IF_ERROR (demangle_char (dm, 'Z'));
2898 RETURN_IF_ERROR (demangle_encoding (dm));
2899 RETURN_IF_ERROR (demangle_char (dm, 'E'));
051664b0 2900 RETURN_IF_ERROR (result_append (dm, "'s "));
69afa80d
AS
2901
2902 if (peek_char (dm) == 's')
2903 {
2904 /* Local character string literal. */
051664b0 2905 RETURN_IF_ERROR (result_append (dm, "string literal"));
69afa80d
AS
2906 /* Consume the s. */
2907 advance_char (dm);
2908 RETURN_IF_ERROR (demangle_discriminator (dm, 0));
2909 }
2910 else
2911 {
2912 int unused;
051664b0 2913 RETURN_IF_ERROR (result_append (dm, "local "));
69afa80d
AS
2914 /* Local name for some other entity. Demangle its name. */
2915 RETURN_IF_ERROR (demangle_name (dm, &unused));
2916 RETURN_IF_ERROR (demangle_discriminator (dm, 1));
2917 }
2918
2919 return STATUS_OK;
2920 }
2921
2922 /* Optimonally demangles and emits a <discriminator>. If there is no
2923 <discriminator> at the current position in the mangled string, the
2924 descriminator is assumed to be zero. Emit the discriminator number
2925 in parentheses, unless SUPPRESS_FIRST is non-zero and the
2926 discriminator is zero.
2927
2928 <discriminator> ::= _ <number> */
2929
2930static status_t
2931demangle_discriminator (dm, suppress_first)
2932 demangling_t dm;
2933 int suppress_first;
2934{
2935 /* Output for <discriminator>s to the demangled name is completely
2936 supressed if not in verbose mode. */
2937
2938 if (peek_char (dm) == '_')
2939 {
2940 /* Consume the underscore. */
2941 advance_char (dm);
2942 if (flag_verbose)
051664b0 2943 RETURN_IF_ERROR (result_append (dm, " [#"));
69afa80d 2944 /* Check if there's a number following the underscore. */
051664b0 2945 if (IS_DIGIT ((unsigned char) peek_char (dm)))
69afa80d
AS
2946 {
2947 int discriminator;
2948 /* Demangle the number. */
2949 RETURN_IF_ERROR (demangle_number (dm, &discriminator, 10, 0));
2950 if (flag_verbose)
2951 /* Write the discriminator. The mangled number is two
2952 less than the discriminator ordinal, counting from
2953 zero. */
051664b0
AS
2954 RETURN_IF_ERROR (int_to_dyn_string (discriminator + 2,
2955 (dyn_string_t) dm->result));
69afa80d
AS
2956 }
2957 else
2958 {
2959 if (flag_verbose)
2960 /* A missing digit correspond to one. */
051664b0 2961 RETURN_IF_ERROR (result_append_char (dm, '1'));
69afa80d
AS
2962 }
2963 if (flag_verbose)
051664b0 2964 RETURN_IF_ERROR (result_append_char (dm, ']'));
69afa80d
AS
2965 }
2966 else if (!suppress_first)
2967 {
2968 if (flag_verbose)
051664b0 2969 RETURN_IF_ERROR (result_append (dm, " [#0]"));
69afa80d
AS
2970 }
2971
2972 return STATUS_OK;
2973}
2974
2975/* Demangle NAME into RESULT, which must be an initialized
2976 dyn_string_t. On success, returns STATUS_OK. On failure, returns
2977 an error message, and the contents of RESULT are unchanged. */
2978
7eb23b1f 2979static status_t
69afa80d 2980cp_demangle (name, result)
051664b0 2981 const char *name;
69afa80d
AS
2982 dyn_string_t result;
2983{
2984 status_t status;
2985 int length = strlen (name);
2986
2987 if (length > 2 && name[0] == '_' && name[1] == 'Z')
2988 {
2989 demangling_t dm = demangling_new (name);
051664b0
AS
2990 if (dm == NULL)
2991 return STATUS_ALLOCATION_FAILED;
69afa80d 2992
051664b0
AS
2993 status = result_push (dm);
2994 if (status != STATUS_OK)
2995 {
2996 demangling_delete (dm);
2997 return status;
2998 }
69afa80d 2999
051664b0
AS
3000 status = demangle_mangled_name (dm);
3001 if (STATUS_NO_ERROR (status))
69afa80d
AS
3002 {
3003 dyn_string_t demangled = (dyn_string_t) result_pop (dm);
051664b0
AS
3004 if (!dyn_string_copy (result, demangled))
3005 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
3006 dyn_string_delete (demangled);
3007 }
3008
3009 demangling_delete (dm);
3010 }
3011 else
3012 {
3013 /* It's evidently not a mangled C++ name. It could be the name
3014 of something with C linkage, though, so just copy NAME into
3015 RESULT. */
051664b0
AS
3016 if (!dyn_string_copy_cstr (result, name))
3017 return STATUS_ALLOCATION_FAILED;
69afa80d
AS
3018 status = STATUS_OK;
3019 }
3020
051664b0
AS
3021 return status;
3022}
3023
3024/* Demangle TYPE_NAME into RESULT, which must be an initialized
3025 dyn_string_t. On success, returns STATUS_OK. On failiure, returns
3026 an error message, and the contents of RESULT are unchanged. */
3027
838f8562 3028#ifdef IN_LIBGCC2
051664b0
AS
3029static status_t
3030cp_demangle_type (type_name, result)
3031 const char* type_name;
3032 dyn_string_t result;
3033{
3034 status_t status;
3035 demangling_t dm = demangling_new (type_name);
3036
3037 if (dm == NULL)
3038 return STATUS_ALLOCATION_FAILED;
3039
3040 /* Demangle the type name. The demangled name is stored in dm. */
3041 status = result_push (dm);
3042 if (status != STATUS_OK)
3043 {
3044 demangling_delete (dm);
3045 return status;
3046 }
3047
3048 status = demangle_type (dm);
3049
3050 if (STATUS_NO_ERROR (status))
3051 {
3052 /* The demangling succeeded. Pop the result out of dm and copy
3053 it into RESULT. */
3054 dyn_string_t demangled = (dyn_string_t) result_pop (dm);
3055 if (!dyn_string_copy (result, demangled))
3056 return STATUS_ALLOCATION_FAILED;
3057 dyn_string_delete (demangled);
3058 }
3059
3060 /* Clean up. */
3061 demangling_delete (dm);
3062
69afa80d
AS
3063 return status;
3064}
3065
051664b0
AS
3066extern char *__cxa_demangle PARAMS ((const char *, char *, size_t *, int *));
3067
3068/* ABI-mandated entry point in the C++ runtime library for performing
3069 demangling. MANGLED_NAME is a NUL-terminated character string
3070 containing the name to be demangled.
3071
3072 OUTPUT_BUFFER is a region of memory, allocated with malloc, of
3073 *LENGTH bytes, into which the demangled name is stored. If
3074 OUTPUT_BUFFER is not long enough, it is expanded using realloc.
3075 OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
3076 is placed in a region of memory allocated with malloc.
3077
3078 If LENGTH is non-NULL, the length of the buffer conaining the
3079 demangled name, is placed in *LENGTH.
3080
3081 The return value is a pointer to the start of the NUL-terminated
3082 demangled name, or NULL if the demangling fails. The caller is
3083 responsible for deallocating this memory using free.
3084
3085 *STATUS is set to one of the following values:
3086 0: The demangling operation succeeded.
3087 -1: A memory allocation failiure occurred.
3088 -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
3089 -3: One of the arguments is invalid.
3090
3091 The demagling is performed using the C++ ABI mangling rules, with
3092 GNU extensions. */
3093
3094char *
3095__cxa_demangle (mangled_name, output_buffer, length, status)
3096 const char *mangled_name;
3097 char *output_buffer;
3098 size_t *length;
3099 int *status;
3100{
3101 struct dyn_string demangled_name;
3102 status_t result;
3103
3104 if (status == NULL)
3105 return NULL;
3106
3107 if (mangled_name == NULL) {
3108 *status = -3;
3109 return NULL;
3110 }
3111
3112 /* Did the caller provide a buffer for the demangled name? */
3113 if (output_buffer == NULL) {
3114 /* No; dyn_string will malloc a buffer for us. */
3115 if (!dyn_string_init (&demangled_name, 0))
3116 {
3117 *status = -1;
3118 return NULL;
3119 }
3120 }
3121 else {
3122 /* Yes. Check that the length was provided. */
3123 if (length == NULL) {
3124 *status = -3;
3125 return NULL;
3126 }
3127 /* Install the buffer into a dyn_string. */
3128 demangled_name.allocated = *length;
3129 demangled_name.length = 0;
3130 demangled_name.s = output_buffer;
3131 }
3132
3133 if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
3134 /* MANGLED_NAME apprears to be a function or variable name.
3135 Demangle it accordingly. */
3136 result = cp_demangle (mangled_name, &demangled_name);
3137 else
3138 /* Try to demangled MANGLED_NAME as the name of a type. */
3139 result = cp_demangle_type (mangled_name, &demangled_name);
3140
3141 if (result == STATUS_OK)
3142 /* The demangling succeeded. */
3143 {
3144 /* If LENGTH isn't NULL, store the allocated buffer length
3145 there; the buffer may have been realloced by dyn_string
3146 functions. */
3147 if (length != NULL)
3148 *length = demangled_name.allocated;
3149 /* The operation was a success. */
3150 *status = 0;
3151 return dyn_string_buf (&demangled_name);
3152 }
3153 else if (result == STATUS_ALLOCATION_FAILED)
3154 /* A call to malloc or realloc failed during the demangling
3155 operation. */
3156 {
3157 *status = -1;
3158 return NULL;
3159 }
3160 else
3161 /* The demangling failed for another reason, most probably because
3162 MANGLED_NAME isn't a valid mangled name. */
3163 {
3164 /* If the buffer containing the demangled name wasn't provided
3165 by the caller, free it. */
3166 if (output_buffer == NULL)
3167 free (dyn_string_buf (&demangled_name));
3168 *status = -2;
3169 return NULL;
3170 }
3171}
3172
3173#else /* !IN_LIBGCC2 */
3174
69afa80d
AS
3175/* Variant entry point for integration with the existing cplus-dem
3176 demangler. Attempts to demangle MANGLED. If the demangling
3177 succeeds, returns a buffer, allocated with malloc, containing the
3178 demangled name. The caller must deallocate the buffer using free.
3179 If the demangling failes, returns NULL. */
3180
3181char *
3182cplus_demangle_new_abi (mangled)
3183 const char* mangled;
3184{
3185 /* Create a dyn_string to hold the demangled name. */
3186 dyn_string_t demangled = dyn_string_new (0);
3187 /* Attempt the demangling. */
3188 status_t status = cp_demangle ((char *) mangled, demangled);
051664b0 3189 if (STATUS_NO_ERROR (status))
69afa80d
AS
3190 /* Demangling succeeded. */
3191 {
3192 /* Grab the demangled result from the dyn_string. It was
3193 allocated with malloc, so we can return it directly. */
3194 char *return_value = dyn_string_release (demangled);
69afa80d
AS
3195 /* Hand back the demangled name. */
3196 return return_value;
3197 }
051664b0
AS
3198 else if (status == STATUS_ALLOCATION_FAILED)
3199 {
3200 fprintf (stderr, "Memory allocation failed.\n");
3201 abort ();
3202 }
69afa80d
AS
3203 else
3204 /* Demangling failed. */
3205 {
3206 dyn_string_delete (demangled);
3207 return NULL;
3208 }
3209}
3210
051664b0
AS
3211#endif /* IN_LIBGCC2 */
3212
69afa80d
AS
3213#ifdef STANDALONE_DEMANGLER
3214
3215#include "getopt.h"
3216
3217static void print_usage
3218 PARAMS ((FILE* fp, int exit_value));
3219
3220/* Non-zero if CHAR is a character than can occur in a mangled name. */
3faa108c 3221#define is_mangled_char(CHAR) \
051664b0 3222 (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) || (CHAR) == '_')
69afa80d
AS
3223
3224/* The name of this program, as invoked. */
3225const char* program_name;
3226
3227/* Prints usage summary to FP and then exits with EXIT_VALUE. */
3228
3229static void
3230print_usage (fp, exit_value)
3231 FILE* fp;
3232 int exit_value;
3233{
3234 fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
3235 fprintf (fp, "Options:\n", program_name);
3236 fprintf (fp, " -h,--help Display this message.\n");
3237 fprintf (fp, " -s,--strict Demangle standard names only.\n");
3238 fprintf (fp, " -v,--verbose Produce verbose demanglings.\n");
3239 fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n");
3240
3241 exit (exit_value);
3242}
3243
3244/* Option specification for getopt_long. */
3245static struct option long_options[] =
3246{
3247 { "help", no_argument, NULL, 'h' },
3248 { "strict", no_argument, NULL, 's' },
3249 { "verbose", no_argument, NULL, 'v' },
3250 { NULL, no_argument, NULL, 0 },
3251};
3252
3253/* Main entry for a demangling filter executable. It will demangle
3254 its command line arguments, if any. If none are provided, it will
3255 filter stdin to stdout, replacing any recognized mangled C++ names
3256 with their demangled equivalents. */
3257
3258int
3259main (argc, argv)
3260 int argc;
3261 char *argv[];
3262{
3263 status_t status;
3264 int i;
3265 int opt_char;
3266
3267 /* Use the program name of this program, as invoked. */
3268 program_name = argv[0];
3269
3270 /* Parse options. */
3271 do
3272 {
3273 opt_char = getopt_long (argc, argv, "hsv", long_options, NULL);
3274 switch (opt_char)
3275 {
3276 case '?': /* Unrecognized option. */
3277 print_usage (stderr, 1);
3278 break;
3279
3280 case 'h':
3281 print_usage (stdout, 0);
3282 break;
3283
3284 case 's':
3285 flag_strict = 1;
3286 break;
3287
3288 case 'v':
3289 flag_verbose = 1;
3290 break;
3291 }
3292 }
3293 while (opt_char != -1);
3294
3295 if (optind == argc)
3296 /* No command line arguments were provided. Filter stdin. */
3297 {
3298 dyn_string_t mangled = dyn_string_new (3);
3299 dyn_string_t demangled = dyn_string_new (0);
3300 status_t status;
3301
3302 /* Read all of input. */
3303 while (!feof (stdin))
3304 {
3305 char c = getchar ();
3306
3307 /* The first character of a mangled name is an underscore. */
3308 if (feof (stdin))
3309 break;
3310 if (c != '_')
3311 {
3312 /* It's not a mangled name. Print the character and go
3313 on. */
3314 putchar (c);
3315 continue;
3316 }
3317 c = getchar ();
3318
3319 /* The second character of a mangled name is a capital `Z'. */
3320 if (feof (stdin))
3321 break;
3322 if (c != 'Z')
3323 {
3324 /* It's not a mangled name. Print the previous
3325 underscore, the `Z', and go on. */
3326 putchar ('_');
3327 putchar (c);
3328 continue;
3329 }
3330
3331 /* Start keeping track of the candidate mangled name. */
3332 dyn_string_append_char (mangled, '_');
3333 dyn_string_append_char (mangled, 'Z');
3334
3335 /* Pile characters into mangled until we hit one that can't
3336 occur in a mangled name. */
3337 c = getchar ();
3338 while (!feof (stdin) && is_mangled_char (c))
3339 {
3340 dyn_string_append_char (mangled, c);
3341 if (feof (stdin))
3342 break;
3343 c = getchar ();
3344 }
3345
3346 /* Attempt to demangle the name. */
3347 status = cp_demangle (dyn_string_buf (mangled), demangled);
3348
3349 /* If the demangling succeeded, great! Print out the
3350 demangled version. */
051664b0 3351 if (STATUS_NO_ERROR (status))
69afa80d 3352 fputs (dyn_string_buf (demangled), stdout);
051664b0
AS
3353 /* Abort on allocation failures. */
3354 else if (status == STATUS_ALLOCATION_FAILED)
3355 {
3356 fprintf (stderr, "Memory allocation failed.\n");
3357 abort ();
3358 }
69afa80d
AS
3359 /* Otherwise, it might not have been a mangled name. Just
3360 print out the original text. */
3361 else
3362 fputs (dyn_string_buf (mangled), stdout);
3363
3364 /* If we haven't hit EOF yet, we've read one character that
3365 can't occur in a mangled name, so print it out. */
3366 if (!feof (stdin))
3367 putchar (c);
3368
3369 /* Clear the candidate mangled name, to start afresh next
3370 time we hit a `_Z'. */
3371 dyn_string_clear (mangled);
3372 }
3373
3374 dyn_string_delete (mangled);
3375 dyn_string_delete (demangled);
3376 }
3377 else
3378 /* Demangle command line arguments. */
3379 {
3380 dyn_string_t result = dyn_string_new (0);
3381
3382 /* Loop over command line arguments. */
3383 for (i = optind; i < argc; ++i)
3384 {
3385 /* Attempt to demangle. */
3386 status = cp_demangle (argv[i], result);
3387
3388 /* If it worked, print the demangled name. */
051664b0 3389 if (STATUS_NO_ERROR (status))
69afa80d 3390 printf ("%s\n", dyn_string_buf (result));
051664b0 3391 /* Abort on allocaiton failures. */
bece74bd 3392 else if (status == STATUS_ALLOCATION_FAILED)
051664b0
AS
3393 {
3394 fprintf (stderr, "Memory allocaiton failed.\n");
bece74bd 3395 abort ();
051664b0 3396 }
69afa80d
AS
3397 /* If not, print the error message to stderr instead. */
3398 else
3399 fprintf (stderr, "%s\n", status);
3400 }
3401 dyn_string_delete (result);
3402 }
3403
3404 return 0;
3405}
3406
3407#endif /* STANDALONE_DEMANGLER */