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