* cp-name-parser.y: ... this.
* Makefile.in (SFILES, YYFILES, YYOBJ): Rename cp-names.y to
cp-name-parser.y.
(test-cp-names.o): Renamed to test-cp-name-parser.o.
(test-cp-names): Renamed to test-cp-name-parser.
(clean, local-maintainer-clean): Update.
(cp-names.o): Renamed to cp-name-parser.o.
+2005-05-12 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * cp-names.y: Renamed to ...
+ * cp-name-parser.y: ... this.
+ * Makefile.in (SFILES, YYFILES, YYOBJ): Rename cp-names.y to
+ cp-name-parser.y.
+ (test-cp-names.o): Renamed to test-cp-name-parser.o.
+ (test-cp-names): Renamed to test-cp-name-parser.
+ (clean, local-maintainer-clean): Update.
+ (cp-names.o): Renamed to cp-name-parser.o.
+
2005-05-12 Eli Zaretskii <eliz@gnu.org>
* observer.sh: Use observer.tmp instead of observer.inc-tmp which
charset.c cli-out.c coffread.c coff-pe-read.c \
complaints.c completer.c corefile.c \
cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
- cp-names.y \
+ cp-name-parser.y \
dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
dwarfread.c dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
# For now, shortcut the "configure GDB for fewer languages" stuff.
YYFILES = c-exp.c \
- cp-names.c \
+ cp-name-parser.c \
objc-exp.c \
ada-exp.c \
jv-exp.c \
f-exp.c m2-exp.c p-exp.c
YYOBJ = c-exp.o \
- cp-names.o \
+ cp-name-parser.o \
objc-exp.o \
ada-exp.o \
jv-exp.o \
$(DESTDIR)$(man1dir)/$$transformed_name.1
# The C++ name parser can be built standalone for testing.
-test-cp-names.o: cp-names.c $(safe_ctype_h) $(libiberty_h) $(demangle_h)
+test-cp-name-parser.o: cp-name-parser.c $(safe_ctype_h) $(libiberty_h) \
+ $(demangle_h)
$(CC) -c $(INTERNAL_CFLAGS) -DTEST_CPNAMES \
- -o test-cp-names.o cp-names.c
+ -o test-cp-name-parser.o cp-name-parser.c
-test-cp-names$(EXEEXT): test-cp-names.o $(LIBIBERTY)
- $(CC) -o test-cp-names$(EXEEXT) test-cp-names.o $(LIBIBERTY)
+test-cp-name-parser$(EXEEXT): test-cp-name-parser.o $(LIBIBERTY)
+ $(CC_LD) $(INTERNAL_LDFLAGS) -o test-cp-name-parser$(EXEEXT) \
+ test-cp-name-parser.o $(LIBIBERTY)
# We do this by grepping through sources. If that turns out to be too slow,
# maybe we could just require every .o file to have an initialization routine
rm -f init.c version.c
rm -f gdb$(EXEEXT) core make.log
rm -f gdb[0-9]$(EXEEXT)
- rm -f test-cp-names$(EXEEXT)
+ rm -f test-cp-name-parser$(EXEEXT)
.PHONY: clean-tui
clean-tui:
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f c-exp.c \
- cp-names.c \
+ cp-name-parser.c \
ada-lex.c ada-exp.c \
objc-exp.c \
jv-exp.tab \
$(inferior_h) $(target_h) $(gdb_string_h) $(gregset_h)
cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) $(gdbcmd_h) \
$(ui_out_h) $(gdb_string_h)
-cp-names.o: cp-names.c $(safe_ctype_h) $(libiberty_h) $(demangle_h)
+cp-name-parser.o: cp-name-parser.c $(safe_ctype_h) $(libiberty_h) $(demangle_h)
cp-namespace.o: cp-namespace.c $(defs_h) $(cp_support_h) $(gdb_obstack_h) \
$(symtab_h) $(symfile_h) $(gdb_assert_h) $(block_h) $(objfiles_h) \
$(gdbtypes_h) $(dictionary_h) $(command_h) $(frame_h)
--- /dev/null
+/* YACC parser for C++ names, for GDB.
+
+ Copyright 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+ Parts of the lexer are based on c-exp.y from GDB.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Note that malloc's and realloc's in this file are transformed to
+ xmalloc and xrealloc respectively by the same sed command in the
+ makefile that remaps any other malloc/realloc inserted by the parser
+ generator. Doing this with #defines and trying to control the interaction
+ with include files (<malloc.h> and <stdlib.h> for example) just became
+ too messy, particularly when such includes can be inserted at random
+ times by the parser generator. */
+
+%{
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "safe-ctype.h"
+#include "libiberty.h"
+#include "demangle.h"
+
+/* Bison does not make it easy to create a parser without global
+ state, unfortunately. Here are all the global variables used
+ in this parser. */
+
+/* LEXPTR is the current pointer into our lex buffer. PREV_LEXPTR
+ is the start of the last token lexed, only used for diagnostics.
+ ERROR_LEXPTR is the first place an error occurred. GLOBAL_ERRMSG
+ is the first error message encountered. */
+
+static const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
+
+/* The components built by the parser are allocated ahead of time,
+ and cached in this structure. */
+
+struct demangle_info {
+ int used;
+ struct demangle_component comps[1];
+};
+
+static struct demangle_info *demangle_info;
+#define d_grab() (&demangle_info->comps[demangle_info->used++])
+
+/* The parse tree created by the parser is stored here after a successful
+ parse. */
+
+static struct demangle_component *global_result;
+
+/* Prototypes for helper functions used when constructing the parse
+ tree. */
+
+static struct demangle_component *d_qualify (struct demangle_component *, int,
+ int);
+
+static struct demangle_component *d_int_type (int);
+
+static struct demangle_component *d_unary (const char *,
+ struct demangle_component *);
+static struct demangle_component *d_binary (const char *,
+ struct demangle_component *,
+ struct demangle_component *);
+
+/* Flags passed to d_qualify. */
+
+#define QUAL_CONST 1
+#define QUAL_RESTRICT 2
+#define QUAL_VOLATILE 4
+
+/* Flags passed to d_int_type. */
+
+#define INT_CHAR (1 << 0)
+#define INT_SHORT (1 << 1)
+#define INT_LONG (1 << 2)
+#define INT_LLONG (1 << 3)
+
+#define INT_SIGNED (1 << 4)
+#define INT_UNSIGNED (1 << 5)
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in gdb. Note that these are only the variables
+ produced by yacc. If other parser generators (bison, byacc, etc) produce
+ additional global names that conflict at link time, then those parser
+ generators need to be fixed instead of adding those names to this list. */
+
+#define yymaxdepth cpname_maxdepth
+#define yyparse cpname_parse
+#define yylex cpname_lex
+#define yyerror cpname_error
+#define yylval cpname_lval
+#define yychar cpname_char
+#define yydebug cpname_debug
+#define yypact cpname_pact
+#define yyr1 cpname_r1
+#define yyr2 cpname_r2
+#define yydef cpname_def
+#define yychk cpname_chk
+#define yypgo cpname_pgo
+#define yyact cpname_act
+#define yyexca cpname_exca
+#define yyerrflag cpname_errflag
+#define yynerrs cpname_nerrs
+#define yyps cpname_ps
+#define yypv cpname_pv
+#define yys cpname_s
+#define yy_yys cpname_yys
+#define yystate cpname_state
+#define yytmp cpname_tmp
+#define yyv cpname_v
+#define yy_yyv cpname_yyv
+#define yyval cpname_val
+#define yylloc cpname_lloc
+#define yyreds cpname_reds /* With YYDEBUG defined */
+#define yytoks cpname_toks /* With YYDEBUG defined */
+#define yyname cpname_name /* With YYDEBUG defined */
+#define yyrule cpname_rule /* With YYDEBUG defined */
+#define yylhs cpname_yylhs
+#define yylen cpname_yylen
+#define yydefred cpname_yydefred
+#define yydgoto cpname_yydgoto
+#define yysindex cpname_yysindex
+#define yyrindex cpname_yyrindex
+#define yygindex cpname_yygindex
+#define yytable cpname_yytable
+#define yycheck cpname_yycheck
+
+int yyparse (void);
+static int yylex (void);
+static void yyerror (char *);
+
+/* Enable yydebug for the stand-alone parser. */
+#ifdef TEST_CPNAMES
+# define YYDEBUG 1
+#endif
+
+/* Helper functions. These wrap the demangler tree interface, handle
+ allocation from our global store, and return the allocated component. */
+
+static struct demangle_component *
+fill_comp (enum demangle_component_type d_type, struct demangle_component *lhs,
+ struct demangle_component *rhs)
+{
+ struct demangle_component *ret = d_grab ();
+ cplus_demangle_fill_component (ret, d_type, lhs, rhs);
+ return ret;
+}
+
+static struct demangle_component *
+make_empty (enum demangle_component_type d_type)
+{
+ struct demangle_component *ret = d_grab ();
+ ret->type = d_type;
+ return ret;
+}
+
+static struct demangle_component *
+make_operator (const char *name, int args)
+{
+ struct demangle_component *ret = d_grab ();
+ cplus_demangle_fill_operator (ret, name, args);
+ return ret;
+}
+
+static struct demangle_component *
+make_dtor (enum gnu_v3_dtor_kinds kind, struct demangle_component *name)
+{
+ struct demangle_component *ret = d_grab ();
+ cplus_demangle_fill_dtor (ret, kind, name);
+ return ret;
+}
+
+static struct demangle_component *
+make_builtin_type (const char *name)
+{
+ struct demangle_component *ret = d_grab ();
+ cplus_demangle_fill_builtin_type (ret, name);
+ return ret;
+}
+
+static struct demangle_component *
+make_name (const char *name, int len)
+{
+ struct demangle_component *ret = d_grab ();
+ cplus_demangle_fill_name (ret, name, len);
+ return ret;
+}
+
+#define d_left(dc) (dc)->u.s_binary.left
+#define d_right(dc) (dc)->u.s_binary.right
+
+%}
+
+%union
+ {
+ struct demangle_component *comp;
+ struct nested {
+ struct demangle_component *comp;
+ struct demangle_component **last;
+ } nested;
+ struct {
+ struct demangle_component *comp, *last;
+ } nested1;
+ struct {
+ struct demangle_component *comp, **last;
+ struct nested fn;
+ struct demangle_component *start;
+ int fold_flag;
+ } abstract;
+ int lval;
+ struct {
+ int val;
+ struct demangle_component *type;
+ } typed_val_int;
+ const char *opname;
+ }
+
+%type <comp> exp exp1 type start start_opt operator colon_name
+%type <comp> unqualified_name colon_ext_name
+%type <comp> template template_arg
+%type <comp> builtin_type
+%type <comp> typespec_2 array_indicator
+%type <comp> colon_ext_only ext_only_name
+
+%type <comp> demangler_special function conversion_op
+%type <nested> conversion_op_name
+
+%type <abstract> abstract_declarator direct_abstract_declarator
+%type <abstract> abstract_declarator_fn
+%type <nested> declarator direct_declarator function_arglist
+
+%type <nested> declarator_1 direct_declarator_1
+
+%type <nested> template_params function_args
+%type <nested> ptr_operator
+
+%type <nested1> nested_name
+
+%type <lval> qualifier qualifiers qualifiers_opt
+
+%type <lval> int_part int_seq
+
+%token <comp> INT
+%token <comp> FLOAT
+
+%token <comp> NAME
+%type <comp> name
+
+%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON
+%token TEMPLATE
+%token ERROR
+%token NEW DELETE OPERATOR
+%token STATIC_CAST REINTERPRET_CAST DYNAMIC_CAST
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD BOOL
+%token ELLIPSIS RESTRICT VOID FLOAT_KEYWORD CHAR WCHAR_T
+
+%token <opname> ASSIGN_MODIFY
+
+/* C++ */
+%token TRUEKEYWORD
+%token FALSEKEYWORD
+
+/* Non-C++ things we get from the demangler. */
+%token <lval> DEMANGLER_SPECIAL
+%token CONSTRUCTION_VTABLE CONSTRUCTION_IN
+%token <typed_val_int> GLOBAL
+
+%{
+enum {
+ GLOBAL_CONSTRUCTORS = DEMANGLE_COMPONENT_LITERAL + 20,
+ GLOBAL_DESTRUCTORS = DEMANGLE_COMPONENT_LITERAL + 21
+};
+%}
+
+/* Precedence declarations. */
+
+/* Give NAME lower precedence than COLONCOLON, so that nested_name will
+ associate greedily. */
+%nonassoc NAME
+
+/* Give NEW and DELETE lower precedence than ']', because we can not
+ have an array of type operator new. This causes NEW '[' to be
+ parsed as operator new[]. */
+%nonassoc NEW DELETE
+
+/* Give VOID higher precedence than NAME. Then we can use %prec NAME
+ to prefer (VOID) to (function_args). */
+%nonassoc VOID
+
+/* Give VOID lower precedence than ')' for similar reasons. */
+%nonassoc ')'
+
+%left ','
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+
+/* We don't need a precedence for '(' in this reduced grammar, and it
+ can mask some unpleasant bugs, so disable it for now. */
+
+%right ARROW '.' '[' /* '(' */
+%left COLONCOLON
+
+\f
+%%
+
+result : start
+ { global_result = $1; }
+ ;
+
+start : type
+
+ | demangler_special
+
+ | function
+
+ ;
+
+start_opt : /* */
+ { $$ = NULL; }
+ | COLONCOLON start
+ { $$ = $2; }
+ ;
+
+function
+ /* Function with a return type. declarator_1 is used to prevent
+ ambiguity with the next rule. */
+ : typespec_2 declarator_1
+ { $$ = $2.comp;
+ *$2.last = $1;
+ }
+
+ /* Function without a return type. We need to use typespec_2
+ to prevent conflicts from qualifiers_opt - harmless. The
+ start_opt is used to handle "function-local" variables and
+ types. */
+ | typespec_2 function_arglist start_opt
+ { $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ if ($3) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); }
+ | colon_ext_only function_arglist start_opt
+ { $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ if ($3) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); }
+
+ | conversion_op_name start_opt
+ { $$ = $1.comp;
+ if ($2) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2); }
+ | conversion_op_name abstract_declarator_fn
+ { if ($2.last)
+ {
+ /* First complete the abstract_declarator's type using
+ the typespec from the conversion_op_name. */
+ *$2.last = *$1.last;
+ /* Then complete the conversion_op_name with the type. */
+ *$1.last = $2.comp;
+ }
+ /* If we have an arglist, build a function type. */
+ if ($2.fn.comp)
+ $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1.comp, $2.fn.comp);
+ else
+ $$ = $1.comp;
+ if ($2.start) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2.start);
+ }
+ ;
+
+demangler_special
+ : DEMANGLER_SPECIAL start
+ { $$ = make_empty ($1);
+ d_left ($$) = $2;
+ d_right ($$) = NULL; }
+ | CONSTRUCTION_VTABLE start CONSTRUCTION_IN start
+ { $$ = fill_comp (DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, $2, $4); }
+ | GLOBAL
+ { $$ = make_empty ($1.val);
+ d_left ($$) = $1.type;
+ d_right ($$) = NULL; }
+ ;
+
+operator : OPERATOR NEW
+ { $$ = make_operator ("new", 1); }
+ | OPERATOR DELETE
+ { $$ = make_operator ("delete", 1); }
+ | OPERATOR NEW '[' ']'
+ { $$ = make_operator ("new[]", 1); }
+ | OPERATOR DELETE '[' ']'
+ { $$ = make_operator ("delete[]", 1); }
+ | OPERATOR '+'
+ { $$ = make_operator ("+", 2); }
+ | OPERATOR '-'
+ { $$ = make_operator ("-", 2); }
+ | OPERATOR '*'
+ { $$ = make_operator ("*", 2); }
+ | OPERATOR '/'
+ { $$ = make_operator ("/", 2); }
+ | OPERATOR '%'
+ { $$ = make_operator ("%", 2); }
+ | OPERATOR '^'
+ { $$ = make_operator ("^", 2); }
+ | OPERATOR '&'
+ { $$ = make_operator ("&", 2); }
+ | OPERATOR '|'
+ { $$ = make_operator ("|", 2); }
+ | OPERATOR '~'
+ { $$ = make_operator ("~", 1); }
+ | OPERATOR '!'
+ { $$ = make_operator ("!", 1); }
+ | OPERATOR '='
+ { $$ = make_operator ("=", 2); }
+ | OPERATOR '<'
+ { $$ = make_operator ("<", 2); }
+ | OPERATOR '>'
+ { $$ = make_operator (">", 2); }
+ | OPERATOR ASSIGN_MODIFY
+ { $$ = make_operator ($2, 2); }
+ | OPERATOR LSH
+ { $$ = make_operator ("<<", 2); }
+ | OPERATOR RSH
+ { $$ = make_operator (">>", 2); }
+ | OPERATOR EQUAL
+ { $$ = make_operator ("==", 2); }
+ | OPERATOR NOTEQUAL
+ { $$ = make_operator ("!=", 2); }
+ | OPERATOR LEQ
+ { $$ = make_operator ("<=", 2); }
+ | OPERATOR GEQ
+ { $$ = make_operator (">=", 2); }
+ | OPERATOR ANDAND
+ { $$ = make_operator ("&&", 2); }
+ | OPERATOR OROR
+ { $$ = make_operator ("||", 2); }
+ | OPERATOR INCREMENT
+ { $$ = make_operator ("++", 1); }
+ | OPERATOR DECREMENT
+ { $$ = make_operator ("--", 1); }
+ | OPERATOR ','
+ { $$ = make_operator (",", 2); }
+ | OPERATOR ARROW '*'
+ { $$ = make_operator ("->*", 2); }
+ | OPERATOR ARROW
+ { $$ = make_operator ("->", 2); }
+ | OPERATOR '(' ')'
+ { $$ = make_operator ("()", 0); }
+ | OPERATOR '[' ']'
+ { $$ = make_operator ("[]", 2); }
+ ;
+
+ /* Conversion operators. We don't try to handle some of
+ the wackier demangler output for function pointers,
+ since it's not clear that it's parseable. */
+conversion_op
+ : OPERATOR typespec_2
+ { $$ = fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL); }
+ ;
+
+conversion_op_name
+ : nested_name conversion_op
+ { $$.comp = $1.comp;
+ d_right ($1.last) = $2;
+ $$.last = &d_left ($2);
+ }
+ | conversion_op
+ { $$.comp = $1;
+ $$.last = &d_left ($1);
+ }
+ | COLONCOLON nested_name conversion_op
+ { $$.comp = $2.comp;
+ d_right ($2.last) = $3;
+ $$.last = &d_left ($3);
+ }
+ | COLONCOLON conversion_op
+ { $$.comp = $2;
+ $$.last = &d_left ($2);
+ }
+ ;
+
+/* DEMANGLE_COMPONENT_NAME */
+/* This accepts certain invalid placements of '~'. */
+unqualified_name: operator
+ | operator '<' template_params '>'
+ { $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
+ | '~' NAME
+ { $$ = make_dtor (gnu_v3_complete_object_dtor, $2); }
+ ;
+
+/* This rule is used in name and nested_name, and expanded inline there
+ for efficiency. */
+/*
+scope_id : NAME
+ | template
+ ;
+*/
+
+colon_name : name
+ | COLONCOLON name
+ { $$ = $2; }
+ ;
+
+/* DEMANGLE_COMPONENT_QUAL_NAME */
+/* DEMANGLE_COMPONENT_CTOR / DEMANGLE_COMPONENT_DTOR ? */
+name : nested_name NAME %prec NAME
+ { $$ = $1.comp; d_right ($1.last) = $2; }
+ | NAME %prec NAME
+ | nested_name template %prec NAME
+ { $$ = $1.comp; d_right ($1.last) = $2; }
+ | template %prec NAME
+ ;
+
+colon_ext_name : colon_name
+ | colon_ext_only
+ ;
+
+colon_ext_only : ext_only_name
+ | COLONCOLON ext_only_name
+ { $$ = $2; }
+ ;
+
+ext_only_name : nested_name unqualified_name
+ { $$ = $1.comp; d_right ($1.last) = $2; }
+ | unqualified_name
+ ;
+
+nested_name : NAME COLONCOLON
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_left ($$.comp) = $1;
+ d_right ($$.comp) = NULL;
+ $$.last = $$.comp;
+ }
+ | nested_name NAME COLONCOLON
+ { $$.comp = $1.comp;
+ d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ $$.last = d_right ($1.last);
+ d_left ($$.last) = $2;
+ d_right ($$.last) = NULL;
+ }
+ | template COLONCOLON
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_left ($$.comp) = $1;
+ d_right ($$.comp) = NULL;
+ $$.last = $$.comp;
+ }
+ | nested_name template COLONCOLON
+ { $$.comp = $1.comp;
+ d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ $$.last = d_right ($1.last);
+ d_left ($$.last) = $2;
+ d_right ($$.last) = NULL;
+ }
+ ;
+
+/* DEMANGLE_COMPONENT_TEMPLATE */
+/* DEMANGLE_COMPONENT_TEMPLATE_ARGLIST */
+template : NAME '<' template_params '>'
+ { $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
+ ;
+
+template_params : template_arg
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $1, NULL);
+ $$.last = &d_right ($$.comp); }
+ | template_params ',' template_arg
+ { $$.comp = $1.comp;
+ *$1.last = fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $3, NULL);
+ $$.last = &d_right (*$1.last);
+ }
+ ;
+
+/* "type" is inlined into template_arg and function_args. */
+
+/* Also an integral constant-expression of integral type, and a
+ pointer to member (?) */
+template_arg : typespec_2
+ | typespec_2 abstract_declarator
+ { $$ = $2.comp;
+ *$2.last = $1;
+ }
+ | '&' start
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $2); }
+ | '&' '(' start ')'
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $3); }
+ | exp
+ ;
+
+function_args : typespec_2
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $1, NULL);
+ $$.last = &d_right ($$.comp);
+ }
+ | typespec_2 abstract_declarator
+ { *$2.last = $1;
+ $$.comp = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $2.comp, NULL);
+ $$.last = &d_right ($$.comp);
+ }
+ | function_args ',' typespec_2
+ { *$1.last = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $3, NULL);
+ $$.comp = $1.comp;
+ $$.last = &d_right (*$1.last);
+ }
+ | function_args ',' typespec_2 abstract_declarator
+ { *$4.last = $3;
+ *$1.last = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $4.comp, NULL);
+ $$.comp = $1.comp;
+ $$.last = &d_right (*$1.last);
+ }
+ | function_args ',' ELLIPSIS
+ { *$1.last
+ = fill_comp (DEMANGLE_COMPONENT_ARGLIST,
+ make_builtin_type ("..."),
+ NULL);
+ $$.comp = $1.comp;
+ $$.last = &d_right (*$1.last);
+ }
+ ;
+
+function_arglist: '(' function_args ')' qualifiers_opt %prec NAME
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, $2.comp);
+ $$.last = &d_left ($$.comp);
+ $$.comp = d_qualify ($$.comp, $4, 1); }
+ | '(' VOID ')' qualifiers_opt
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
+ $$.last = &d_left ($$.comp);
+ $$.comp = d_qualify ($$.comp, $4, 1); }
+ | '(' ')' qualifiers_opt
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
+ $$.last = &d_left ($$.comp);
+ $$.comp = d_qualify ($$.comp, $3, 1); }
+ ;
+
+/* Should do something about DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL */
+qualifiers_opt : /* epsilon */
+ { $$ = 0; }
+ | qualifiers
+ ;
+
+qualifier : RESTRICT
+ { $$ = QUAL_RESTRICT; }
+ | VOLATILE_KEYWORD
+ { $$ = QUAL_VOLATILE; }
+ | CONST_KEYWORD
+ { $$ = QUAL_CONST; }
+ ;
+
+qualifiers : qualifier
+ | qualifier qualifiers
+ { $$ = $1 | $2; }
+ ;
+
+/* This accepts all sorts of invalid constructions and produces
+ invalid output for them - an error would be better. */
+
+int_part : INT_KEYWORD
+ { $$ = 0; }
+ | SIGNED_KEYWORD
+ { $$ = INT_SIGNED; }
+ | UNSIGNED
+ { $$ = INT_UNSIGNED; }
+ | CHAR
+ { $$ = INT_CHAR; }
+ | LONG
+ { $$ = INT_LONG; }
+ | SHORT
+ { $$ = INT_SHORT; }
+ ;
+
+int_seq : int_part
+ | int_seq int_part
+ { $$ = $1 | $2; if ($1 & $2 & INT_LONG) $$ = $1 | INT_LLONG; }
+ ;
+
+builtin_type : int_seq
+ { $$ = d_int_type ($1); }
+ | FLOAT_KEYWORD
+ { $$ = make_builtin_type ("float"); }
+ | DOUBLE_KEYWORD
+ { $$ = make_builtin_type ("double"); }
+ | LONG DOUBLE_KEYWORD
+ { $$ = make_builtin_type ("long double"); }
+ | BOOL
+ { $$ = make_builtin_type ("bool"); }
+ | WCHAR_T
+ { $$ = make_builtin_type ("wchar_t"); }
+ | VOID
+ { $$ = make_builtin_type ("void"); }
+ ;
+
+ptr_operator : '*' qualifiers_opt
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_POINTER);
+ $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ $$.last = &d_left ($$.comp);
+ $$.comp = d_qualify ($$.comp, $2, 0); }
+ /* g++ seems to allow qualifiers after the reference? */
+ | '&'
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_REFERENCE);
+ $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
+ $$.last = &d_left ($$.comp); }
+ | nested_name '*' qualifiers_opt
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
+ $$.comp->u.s_binary.left = $1.comp;
+ /* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
+ *$1.last = *d_left ($1.last);
+ $$.comp->u.s_binary.right = NULL;
+ $$.last = &d_right ($$.comp);
+ $$.comp = d_qualify ($$.comp, $3, 0); }
+ | COLONCOLON nested_name '*' qualifiers_opt
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
+ $$.comp->u.s_binary.left = $2.comp;
+ /* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
+ *$2.last = *d_left ($2.last);
+ $$.comp->u.s_binary.right = NULL;
+ $$.last = &d_right ($$.comp);
+ $$.comp = d_qualify ($$.comp, $4, 0); }
+ ;
+
+array_indicator : '[' ']'
+ { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
+ d_left ($$) = NULL;
+ }
+ | '[' INT ']'
+ { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
+ d_left ($$) = $2;
+ }
+ ;
+
+/* Details of this approach inspired by the G++ < 3.4 parser. */
+
+/* This rule is only used in typespec_2, and expanded inline there for
+ efficiency. */
+/*
+typespec : builtin_type
+ | colon_name
+ ;
+*/
+
+typespec_2 : builtin_type qualifiers
+ { $$ = d_qualify ($1, $2, 0); }
+ | builtin_type
+ | qualifiers builtin_type qualifiers
+ { $$ = d_qualify ($2, $1 | $3, 0); }
+ | qualifiers builtin_type
+ { $$ = d_qualify ($2, $1, 0); }
+
+ | name qualifiers
+ { $$ = d_qualify ($1, $2, 0); }
+ | name
+ | qualifiers name qualifiers
+ { $$ = d_qualify ($2, $1 | $3, 0); }
+ | qualifiers name
+ { $$ = d_qualify ($2, $1, 0); }
+
+ | COLONCOLON name qualifiers
+ { $$ = d_qualify ($2, $3, 0); }
+ | COLONCOLON name
+ { $$ = $2; }
+ | qualifiers COLONCOLON name qualifiers
+ { $$ = d_qualify ($3, $1 | $4, 0); }
+ | qualifiers COLONCOLON name
+ { $$ = d_qualify ($3, $1, 0); }
+ ;
+
+abstract_declarator
+ : ptr_operator
+ { $$.comp = $1.comp; $$.last = $1.last;
+ $$.fn.comp = NULL; $$.fn.last = NULL; }
+ | ptr_operator abstract_declarator
+ { $$ = $2; $$.fn.comp = NULL; $$.fn.last = NULL;
+ if ($2.fn.comp) { $$.last = $2.fn.last; *$2.last = $2.fn.comp; }
+ *$$.last = $1.comp;
+ $$.last = $1.last; }
+ | direct_abstract_declarator
+ { $$.fn.comp = NULL; $$.fn.last = NULL;
+ if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
+ }
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ { $$ = $2; $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 1;
+ if ($2.fn.comp) { $$.last = $2.fn.last; *$2.last = $2.fn.comp; }
+ }
+ | direct_abstract_declarator function_arglist
+ { $$.fold_flag = 0;
+ if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
+ if ($1.fold_flag)
+ {
+ *$$.last = $2.comp;
+ $$.last = $2.last;
+ }
+ else
+ $$.fn = $2;
+ }
+ | direct_abstract_declarator array_indicator
+ { $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 0;
+ if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
+ *$1.last = $2;
+ $$.last = &d_right ($2);
+ }
+ | array_indicator
+ { $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 0;
+ $$.comp = $1;
+ $$.last = &d_right ($1);
+ }
+ /* G++ has the following except for () and (type). Then
+ (type) is handled in regcast_or_absdcl and () is handled
+ in fcast_or_absdcl.
+
+ However, this is only useful for function types, and
+ generates reduce/reduce conflicts with direct_declarator.
+ We're interested in pointer-to-function types, and in
+ functions, but not in function types - so leave this
+ out. */
+ /* | function_arglist */
+ ;
+
+abstract_declarator_fn
+ : ptr_operator
+ { $$.comp = $1.comp; $$.last = $1.last;
+ $$.fn.comp = NULL; $$.fn.last = NULL; $$.start = NULL; }
+ | ptr_operator abstract_declarator_fn
+ { $$ = $2;
+ if ($2.last)
+ *$$.last = $1.comp;
+ else
+ $$.comp = $1.comp;
+ $$.last = $1.last;
+ }
+ | direct_abstract_declarator
+ { $$.comp = $1.comp; $$.last = $1.last; $$.fn = $1.fn; $$.start = NULL; }
+ | direct_abstract_declarator function_arglist COLONCOLON start
+ { $$.start = $4;
+ if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
+ if ($1.fold_flag)
+ {
+ *$$.last = $2.comp;
+ $$.last = $2.last;
+ }
+ else
+ $$.fn = $2;
+ }
+ | function_arglist start_opt
+ { $$.fn = $1;
+ $$.start = $2;
+ $$.comp = NULL; $$.last = NULL;
+ }
+ ;
+
+type : typespec_2
+ | typespec_2 abstract_declarator
+ { $$ = $2.comp;
+ *$2.last = $1;
+ }
+ ;
+
+declarator : ptr_operator declarator
+ { $$.comp = $2.comp;
+ $$.last = $1.last;
+ *$2.last = $1.comp; }
+ | direct_declarator
+ ;
+
+direct_declarator
+ : '(' declarator ')'
+ { $$ = $2; }
+ | direct_declarator function_arglist
+ { $$.comp = $1.comp;
+ *$1.last = $2.comp;
+ $$.last = $2.last;
+ }
+ | direct_declarator array_indicator
+ { $$.comp = $1.comp;
+ *$1.last = $2;
+ $$.last = &d_right ($2);
+ }
+ | colon_ext_name
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
+ d_left ($$.comp) = $1;
+ $$.last = &d_right ($$.comp);
+ }
+ ;
+
+/* These are similar to declarator and direct_declarator except that they
+ do not permit ( colon_ext_name ), which is ambiguous with a function
+ argument list. They also don't permit a few other forms with redundant
+ parentheses around the colon_ext_name; any colon_ext_name in parentheses
+ must be followed by an argument list or an array indicator, or preceded
+ by a pointer. */
+declarator_1 : ptr_operator declarator_1
+ { $$.comp = $2.comp;
+ $$.last = $1.last;
+ *$2.last = $1.comp; }
+ | colon_ext_name
+ { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
+ d_left ($$.comp) = $1;
+ $$.last = &d_right ($$.comp);
+ }
+ | direct_declarator_1
+
+ /* Function local variable or type. The typespec to
+ our left is the type of the containing function.
+ This should be OK, because function local types
+ can not be templates, so the return types of their
+ members will not be mangled. If they are hopefully
+ they'll end up to the right of the ::. */
+ | colon_ext_name function_arglist COLONCOLON start
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ $$.last = $2.last;
+ $$.comp = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
+ }
+ | direct_declarator_1 function_arglist COLONCOLON start
+ { $$.comp = $1.comp;
+ *$1.last = $2.comp;
+ $$.last = $2.last;
+ $$.comp = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
+ }
+ ;
+
+direct_declarator_1
+ : '(' ptr_operator declarator ')'
+ { $$.comp = $3.comp;
+ $$.last = $2.last;
+ *$3.last = $2.comp; }
+ | direct_declarator_1 function_arglist
+ { $$.comp = $1.comp;
+ *$1.last = $2.comp;
+ $$.last = $2.last;
+ }
+ | direct_declarator_1 array_indicator
+ { $$.comp = $1.comp;
+ *$1.last = $2;
+ $$.last = &d_right ($2);
+ }
+ | colon_ext_name function_arglist
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ $$.last = $2.last;
+ }
+ | colon_ext_name array_indicator
+ { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2);
+ $$.last = &d_right ($2);
+ }
+ ;
+
+exp : '(' exp1 ')'
+ { $$ = $2; }
+ ;
+
+/* Silly trick. Only allow '>' when parenthesized, in order to
+ handle conflict with templates. */
+exp1 : exp
+ ;
+
+exp1 : exp '>' exp
+ { $$ = d_binary (">", $1, $3); }
+ ;
+
+/* References. Not allowed everywhere in template parameters, only
+ at the top level, but treat them as expressions in case they are wrapped
+ in parentheses. */
+exp1 : '&' start
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $2); }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '-' exp %prec UNARY
+ { $$ = d_unary ("-", $2); }
+ ;
+
+exp : '!' exp %prec UNARY
+ { $$ = d_unary ("!", $2); }
+ ;
+
+exp : '~' exp %prec UNARY
+ { $$ = d_unary ("~", $2); }
+ ;
+
+/* Casts. First your normal C-style cast. If exp is a LITERAL, just change
+ its type. */
+
+exp : '(' type ')' exp %prec UNARY
+ { if ($4->type == DEMANGLE_COMPONENT_LITERAL
+ || $4->type == DEMANGLE_COMPONENT_LITERAL_NEG)
+ {
+ $$ = $4;
+ d_left ($4) = $2;
+ }
+ else
+ $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
+ fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL),
+ $4);
+ }
+ ;
+
+/* Mangling does not differentiate between these, so we don't need to
+ either. */
+exp : STATIC_CAST '<' type '>' '(' exp1 ')' %prec UNARY
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
+ fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
+ $6);
+ }
+ ;
+
+exp : DYNAMIC_CAST '<' type '>' '(' exp1 ')' %prec UNARY
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
+ fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
+ $6);
+ }
+ ;
+
+exp : REINTERPRET_CAST '<' type '>' '(' exp1 ')' %prec UNARY
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
+ fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
+ $6);
+ }
+ ;
+
+/* Another form of C++-style cast. "type ( exp1 )" is not allowed (it's too
+ ambiguous), but "name ( exp1 )" is. Because we don't need to support
+ function types, we can handle this unambiguously (the use of typespec_2
+ prevents a silly, harmless conflict with qualifiers_opt). This does not
+ appear in demangler output so it's not a great loss if we need to
+ disable it. */
+exp : typespec_2 '(' exp1 ')' %prec UNARY
+ { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
+ fill_comp (DEMANGLE_COMPONENT_CAST, $1, NULL),
+ $3);
+ }
+ ;
+
+/* TO INVESTIGATE: ._0 style anonymous names; anonymous namespaces */
+
+/* Binary operators in order of decreasing precedence. */
+
+exp : exp '*' exp
+ { $$ = d_binary ("*", $1, $3); }
+ ;
+
+exp : exp '/' exp
+ { $$ = d_binary ("/", $1, $3); }
+ ;
+
+exp : exp '%' exp
+ { $$ = d_binary ("%", $1, $3); }
+ ;
+
+exp : exp '+' exp
+ { $$ = d_binary ("+", $1, $3); }
+ ;
+
+exp : exp '-' exp
+ { $$ = d_binary ("-", $1, $3); }
+ ;
+
+exp : exp LSH exp
+ { $$ = d_binary ("<<", $1, $3); }
+ ;
+
+exp : exp RSH exp
+ { $$ = d_binary (">>", $1, $3); }
+ ;
+
+exp : exp EQUAL exp
+ { $$ = d_binary ("==", $1, $3); }
+ ;
+
+exp : exp NOTEQUAL exp
+ { $$ = d_binary ("!=", $1, $3); }
+ ;
+
+exp : exp LEQ exp
+ { $$ = d_binary ("<=", $1, $3); }
+ ;
+
+exp : exp GEQ exp
+ { $$ = d_binary (">=", $1, $3); }
+ ;
+
+exp : exp '<' exp
+ { $$ = d_binary ("<", $1, $3); }
+ ;
+
+exp : exp '&' exp
+ { $$ = d_binary ("&", $1, $3); }
+ ;
+
+exp : exp '^' exp
+ { $$ = d_binary ("^", $1, $3); }
+ ;
+
+exp : exp '|' exp
+ { $$ = d_binary ("|", $1, $3); }
+ ;
+
+exp : exp ANDAND exp
+ { $$ = d_binary ("&&", $1, $3); }
+ ;
+
+exp : exp OROR exp
+ { $$ = d_binary ("||", $1, $3); }
+ ;
+
+/* Not 100% sure these are necessary, but they're harmless. */
+exp : exp ARROW NAME
+ { $$ = d_binary ("->", $1, $3); }
+ ;
+
+exp : exp '.' NAME
+ { $$ = d_binary (".", $1, $3); }
+ ;
+
+exp : exp '?' exp ':' exp %prec '?'
+ { $$ = fill_comp (DEMANGLE_COMPONENT_TRINARY, make_operator ("?", 3),
+ fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG1, $1,
+ fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG2, $3, $5)));
+ }
+ ;
+
+exp : INT
+ ;
+
+/* Not generally allowed. */
+exp : FLOAT
+ ;
+
+exp : SIZEOF '(' type ')' %prec UNARY
+ { $$ = d_unary ("sizeof", $3); }
+ ;
+
+/* C++. */
+exp : TRUEKEYWORD
+ { struct demangle_component *i;
+ i = make_name ("1", 1);
+ $$ = fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ make_builtin_type ("bool"),
+ i);
+ }
+ ;
+
+exp : FALSEKEYWORD
+ { struct demangle_component *i;
+ i = make_name ("0", 1);
+ $$ = fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ make_builtin_type ("bool"),
+ i);
+ }
+ ;
+
+/* end of C++. */
+
+%%
+
+/* Apply QUALIFIERS to LHS and return a qualified component. IS_METHOD
+ is set if LHS is a method, in which case the qualifiers are logically
+ applied to "this". We apply qualifiers in a consistent order; LHS
+ may already be qualified; duplicate qualifiers are not created. */
+
+struct demangle_component *
+d_qualify (struct demangle_component *lhs, int qualifiers, int is_method)
+{
+ struct demangle_component **inner_p;
+ enum demangle_component_type type;
+
+ /* For now the order is CONST (innermost), VOLATILE, RESTRICT. */
+
+#define HANDLE_QUAL(TYPE, MTYPE, QUAL) \
+ if ((qualifiers & QUAL) && (type != TYPE) && (type != MTYPE)) \
+ { \
+ *inner_p = fill_comp (is_method ? MTYPE : TYPE, \
+ *inner_p, NULL); \
+ inner_p = &d_left (*inner_p); \
+ type = (*inner_p)->type; \
+ } \
+ else if (type == TYPE || type == MTYPE) \
+ { \
+ inner_p = &d_left (*inner_p); \
+ type = (*inner_p)->type; \
+ }
+
+ inner_p = &lhs;
+
+ type = (*inner_p)->type;
+
+ HANDLE_QUAL (DEMANGLE_COMPONENT_RESTRICT, DEMANGLE_COMPONENT_RESTRICT_THIS, QUAL_RESTRICT);
+ HANDLE_QUAL (DEMANGLE_COMPONENT_VOLATILE, DEMANGLE_COMPONENT_VOLATILE_THIS, QUAL_VOLATILE);
+ HANDLE_QUAL (DEMANGLE_COMPONENT_CONST, DEMANGLE_COMPONENT_CONST_THIS, QUAL_CONST);
+
+ return lhs;
+}
+
+/* Return a builtin type corresponding to FLAGS. */
+
+static struct demangle_component *
+d_int_type (int flags)
+{
+ const char *name;
+
+ switch (flags)
+ {
+ case INT_SIGNED | INT_CHAR:
+ name = "signed char";
+ break;
+ case INT_CHAR:
+ name = "char";
+ break;
+ case INT_UNSIGNED | INT_CHAR:
+ name = "unsigned char";
+ break;
+ case 0:
+ case INT_SIGNED:
+ name = "int";
+ break;
+ case INT_UNSIGNED:
+ name = "unsigned int";
+ break;
+ case INT_LONG:
+ case INT_SIGNED | INT_LONG:
+ name = "long";
+ break;
+ case INT_UNSIGNED | INT_LONG:
+ name = "unsigned long";
+ break;
+ case INT_SHORT:
+ case INT_SIGNED | INT_SHORT:
+ name = "short";
+ break;
+ case INT_UNSIGNED | INT_SHORT:
+ name = "unsigned short";
+ break;
+ case INT_LLONG | INT_LONG:
+ case INT_SIGNED | INT_LLONG | INT_LONG:
+ name = "long long";
+ break;
+ case INT_UNSIGNED | INT_LLONG | INT_LONG:
+ name = "unsigned long long";
+ break;
+ default:
+ return NULL;
+ }
+
+ return make_builtin_type (name);
+}
+
+/* Wrapper to create a unary operation. */
+
+static struct demangle_component *
+d_unary (const char *name, struct demangle_component *lhs)
+{
+ return fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator (name, 1), lhs);
+}
+
+/* Wrapper to create a binary operation. */
+
+static struct demangle_component *
+d_binary (const char *name, struct demangle_component *lhs, struct demangle_component *rhs)
+{
+ return fill_comp (DEMANGLE_COMPONENT_BINARY, make_operator (name, 2),
+ fill_comp (DEMANGLE_COMPONENT_BINARY_ARGS, lhs, rhs));
+}
+
+/* Find the end of a symbol name starting at LEXPTR. */
+
+static const char *
+symbol_end (const char *lexptr)
+{
+ const char *p = lexptr;
+
+ while (*p && (ISALNUM (*p) || *p == '_' || *p == '$' || *p == '.'))
+ p++;
+
+ return p;
+}
+
+/* Take care of parsing a number (anything that starts with a digit).
+ The number starts at P and contains LEN characters. Store the result in
+ YYLVAL. */
+
+static int
+parse_number (const char *p, int len, int parsed_float)
+{
+ int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
+ int long_p = 0;
+
+ struct demangle_component *signed_type;
+ struct demangle_component *unsigned_type;
+ struct demangle_component *type, *name;
+ enum demangle_component_type literal_type;
+
+ if (p[0] == '-')
+ {
+ literal_type = DEMANGLE_COMPONENT_LITERAL_NEG;
+ p++;
+ len--;
+ }
+ else
+ literal_type = DEMANGLE_COMPONENT_LITERAL;
+
+ if (parsed_float)
+ {
+ /* It's a float since it contains a point or an exponent. */
+ char c;
+
+ /* The GDB lexer checks the result of scanf at this point. Not doing
+ this leaves our error checking slightly weaker but only for invalid
+ data. */
+
+ /* See if it has `f' or `l' suffix (float or long double). */
+
+ c = TOLOWER (p[len - 1]);
+
+ if (c == 'f')
+ {
+ len--;
+ type = make_builtin_type ("float");
+ }
+ else if (c == 'l')
+ {
+ len--;
+ type = make_builtin_type ("long double");
+ }
+ else if (ISDIGIT (c) || c == '.')
+ type = make_builtin_type ("double");
+ else
+ return ERROR;
+
+ name = make_name (p, len);
+ yylval.comp = fill_comp (literal_type, type, name);
+
+ return FLOAT;
+ }
+
+ /* This treats 0x1 and 1 as different literals. We also do not
+ automatically generate unsigned types. */
+
+ long_p = 0;
+ unsigned_p = 0;
+ while (len > 0)
+ {
+ if (p[len - 1] == 'l' || p[len - 1] == 'L')
+ {
+ len--;
+ long_p++;
+ continue;
+ }
+ if (p[len - 1] == 'u' || p[len - 1] == 'U')
+ {
+ len--;
+ unsigned_p++;
+ continue;
+ }
+ break;
+ }
+
+ if (long_p == 0)
+ {
+ unsigned_type = make_builtin_type ("unsigned int");
+ signed_type = make_builtin_type ("int");
+ }
+ else if (long_p == 1)
+ {
+ unsigned_type = make_builtin_type ("unsigned long");
+ signed_type = make_builtin_type ("long");
+ }
+ else
+ {
+ unsigned_type = make_builtin_type ("unsigned long long");
+ signed_type = make_builtin_type ("long long");
+ }
+
+ if (unsigned_p)
+ type = unsigned_type;
+ else
+ type = signed_type;
+
+ name = make_name (p, len);
+ yylval.comp = fill_comp (literal_type, type, name);
+
+ return INT;
+}
+
+static char backslashable[] = "abefnrtv";
+static char represented[] = "\a\b\e\f\n\r\t\v";
+
+/* Translate the backslash the way we would in the host character set. */
+static int
+c_parse_backslash (int host_char, int *target_char)
+{
+ const char *ix;
+ ix = strchr (backslashable, host_char);
+ if (! ix)
+ return 0;
+ else
+ *target_char = represented[ix - backslashable];
+ return 1;
+}
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ should point to the character after the \. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+static int
+parse_escape (const char **string_ptr)
+{
+ int target_char;
+ int c = *(*string_ptr)++;
+ if (c_parse_backslash (c, &target_char))
+ return target_char;
+ else
+ switch (c)
+ {
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ {
+ c = *(*string_ptr)++;
+
+ if (c == '?')
+ return 0177;
+ else if (c == '\\')
+ target_char = parse_escape (string_ptr);
+ else
+ target_char = c;
+
+ /* Now target_char is something like `c', and we want to find
+ its control-character equivalent. */
+ target_char = target_char & 037;
+
+ return target_char;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int i = c - '0';
+ int count = 0;
+ while (++count < 3)
+ {
+ c = (**string_ptr);
+ if (c >= '0' && c <= '7')
+ {
+ (*string_ptr)++;
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return target_char;
+ }
+}
+
+#define HANDLE_SPECIAL(string, comp) \
+ if (strncmp (tokstart, string, sizeof (string) - 1) == 0) \
+ { \
+ lexptr = tokstart + sizeof (string) - 1; \
+ yylval.lval = comp; \
+ return DEMANGLER_SPECIAL; \
+ }
+
+#define HANDLE_TOKEN2(string, token) \
+ if (lexptr[1] == string[1]) \
+ { \
+ lexptr += 2; \
+ yylval.opname = string; \
+ return token; \
+ }
+
+#define HANDLE_TOKEN3(string, token) \
+ if (lexptr[1] == string[1] && lexptr[2] == string[2]) \
+ { \
+ lexptr += 3; \
+ yylval.opname = string; \
+ return token; \
+ }
+
+/* Read one token, getting characters through LEXPTR. */
+
+static int
+yylex (void)
+{
+ int c;
+ int namelen;
+ const char *tokstart, *tokptr;
+
+ retry:
+ prev_lexptr = lexptr;
+ tokstart = lexptr;
+
+ switch (c = *tokstart)
+ {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case '\'':
+ /* We either have a character constant ('0' or '\177' for example)
+ or we have a quoted symbol reference ('foo(int,int)' in C++
+ for example). */
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+ else if (c == '\'')
+ {
+ yyerror ("empty character constant");
+ return ERROR;
+ }
+
+ c = *lexptr++;
+ if (c != '\'')
+ {
+ yyerror ("invalid character constant");
+ return ERROR;
+ }
+
+ /* FIXME: We should refer to a canonical form of the character,
+ presumably the same one that appears in manglings - the decimal
+ representation. But if that isn't in our input then we have to
+ allocate memory for it somewhere. */
+ yylval.comp = fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ make_builtin_type ("char"),
+ make_name (tokstart, lexptr - tokstart));
+
+ return INT;
+
+ case '(':
+ if (strncmp (tokstart, "(anonymous namespace)", 21) == 0)
+ {
+ lexptr += 21;
+ yylval.comp = make_name ("(anonymous namespace)",
+ sizeof "(anonymous namespace)" - 1);
+ return NAME;
+ }
+ /* FALL THROUGH */
+
+ case ')':
+ case ',':
+ lexptr++;
+ return c;
+
+ case '.':
+ if (lexptr[1] == '.' && lexptr[2] == '.')
+ {
+ lexptr += 3;
+ return ELLIPSIS;
+ }
+
+ /* Might be a floating point number. */
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ goto symbol; /* Nope, must be a symbol. */
+
+ goto try_number;
+
+ case '-':
+ HANDLE_TOKEN2 ("-=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 ("--", DECREMENT);
+ HANDLE_TOKEN2 ("->", ARROW);
+
+ /* For construction vtables. This is kind of hokey. */
+ if (strncmp (tokstart, "-in-", 4) == 0)
+ {
+ lexptr += 4;
+ return CONSTRUCTION_IN;
+ }
+
+ if (lexptr[1] < '0' || lexptr[1] > '9')
+ {
+ lexptr++;
+ return '-';
+ }
+ /* FALL THRU into number case. */
+
+ try_number:
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0, toktype;
+ const char *p = tokstart;
+ int hex = 0;
+
+ if (c == '-')
+ p++;
+
+ if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ hex = 1;
+ }
+ else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+ {
+ p += 2;
+ hex = 0;
+ }
+
+ for (;; ++p)
+ {
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
+ if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ /* This test does not include !hex, because a '.' always indicates
+ a decimal floating point number regardless of the radix.
+
+ NOTE drow/2005-03-09: This comment is not accurate in C99;
+ however, it's not clear that all the floating point support
+ in this file is doing any good here. */
+ else if (!got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ /* We will take any letters or digits. parse_number will
+ complain if past the radix, or if L or U are not final. */
+ else if (! ISALNUM (*p))
+ break;
+ }
+ toktype = parse_number (tokstart, p - tokstart, got_dot|got_e);
+ if (toktype == ERROR)
+ {
+ char *err_copy = (char *) alloca (p - tokstart + 1);
+
+ memcpy (err_copy, tokstart, p - tokstart);
+ err_copy[p - tokstart] = 0;
+ yyerror ("invalid number");
+ return ERROR;
+ }
+ lexptr = p;
+ return toktype;
+ }
+
+ case '+':
+ HANDLE_TOKEN2 ("+=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 ("++", INCREMENT);
+ lexptr++;
+ return c;
+ case '*':
+ HANDLE_TOKEN2 ("*=", ASSIGN_MODIFY);
+ lexptr++;
+ return c;
+ case '/':
+ HANDLE_TOKEN2 ("/=", ASSIGN_MODIFY);
+ lexptr++;
+ return c;
+ case '%':
+ HANDLE_TOKEN2 ("%=", ASSIGN_MODIFY);
+ lexptr++;
+ return c;
+ case '|':
+ HANDLE_TOKEN2 ("|=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 ("||", OROR);
+ lexptr++;
+ return c;
+ case '&':
+ HANDLE_TOKEN2 ("&=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 ("&&", ANDAND);
+ lexptr++;
+ return c;
+ case '^':
+ HANDLE_TOKEN2 ("^=", ASSIGN_MODIFY);
+ lexptr++;
+ return c;
+ case '!':
+ HANDLE_TOKEN2 ("!=", NOTEQUAL);
+ lexptr++;
+ return c;
+ case '<':
+ HANDLE_TOKEN3 ("<<=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 ("<=", LEQ);
+ HANDLE_TOKEN2 ("<<", LSH);
+ lexptr++;
+ return c;
+ case '>':
+ HANDLE_TOKEN3 (">>=", ASSIGN_MODIFY);
+ HANDLE_TOKEN2 (">=", GEQ);
+ HANDLE_TOKEN2 (">>", RSH);
+ lexptr++;
+ return c;
+ case '=':
+ HANDLE_TOKEN2 ("==", EQUAL);
+ lexptr++;
+ return c;
+ case ':':
+ HANDLE_TOKEN2 ("::", COLONCOLON);
+ lexptr++;
+ return c;
+
+ case '[':
+ case ']':
+ case '?':
+ case '@':
+ case '~':
+ case '{':
+ case '}':
+ symbol:
+ lexptr++;
+ return c;
+
+ case '"':
+ /* These can't occur in C++ names. */
+ yyerror ("unexpected string literal");
+ return ERROR;
+ }
+
+ if (!(c == '_' || c == '$' || ISALPHA (c)))
+ {
+ /* We must have come across a bad character (e.g. ';'). */
+ yyerror ("invalid character");
+ return ERROR;
+ }
+
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ do
+ c = tokstart[++namelen];
+ while (ISALNUM (c) || c == '_' || c == '$');
+
+ lexptr += namelen;
+
+ /* Catch specific keywords. Notice that some of the keywords contain
+ spaces, and are sorted by the length of the first word. They must
+ all include a trailing space in the string comparison. */
+ switch (namelen)
+ {
+ case 16:
+ if (strncmp (tokstart, "reinterpret_cast", 16) == 0)
+ return REINTERPRET_CAST;
+ break;
+ case 12:
+ if (strncmp (tokstart, "construction vtable for ", 24) == 0)
+ {
+ lexptr = tokstart + 24;
+ return CONSTRUCTION_VTABLE;
+ }
+ if (strncmp (tokstart, "dynamic_cast", 12) == 0)
+ return DYNAMIC_CAST;
+ break;
+ case 11:
+ if (strncmp (tokstart, "static_cast", 11) == 0)
+ return STATIC_CAST;
+ break;
+ case 9:
+ HANDLE_SPECIAL ("covariant return thunk to ", DEMANGLE_COMPONENT_COVARIANT_THUNK);
+ HANDLE_SPECIAL ("reference temporary for ", DEMANGLE_COMPONENT_REFTEMP);
+ break;
+ case 8:
+ HANDLE_SPECIAL ("typeinfo for ", DEMANGLE_COMPONENT_TYPEINFO);
+ HANDLE_SPECIAL ("typeinfo fn for ", DEMANGLE_COMPONENT_TYPEINFO_FN);
+ HANDLE_SPECIAL ("typeinfo name for ", DEMANGLE_COMPONENT_TYPEINFO_NAME);
+ if (strncmp (tokstart, "operator", 8) == 0)
+ return OPERATOR;
+ if (strncmp (tokstart, "restrict", 8) == 0)
+ return RESTRICT;
+ if (strncmp (tokstart, "unsigned", 8) == 0)
+ return UNSIGNED;
+ if (strncmp (tokstart, "template", 8) == 0)
+ return TEMPLATE;
+ if (strncmp (tokstart, "volatile", 8) == 0)
+ return VOLATILE_KEYWORD;
+ break;
+ case 7:
+ HANDLE_SPECIAL ("virtual thunk to ", DEMANGLE_COMPONENT_VIRTUAL_THUNK);
+ if (strncmp (tokstart, "wchar_t", 7) == 0)
+ return WCHAR_T;
+ break;
+ case 6:
+ if (strncmp (tokstart, "global constructors keyed to ", 29) == 0)
+ {
+ const char *p;
+ lexptr = tokstart + 29;
+ yylval.typed_val_int.val = GLOBAL_CONSTRUCTORS;
+ /* Find the end of the symbol. */
+ p = symbol_end (lexptr);
+ yylval.typed_val_int.type = make_name (lexptr, p - lexptr);
+ lexptr = p;
+ return GLOBAL;
+ }
+ if (strncmp (tokstart, "global destructors keyed to ", 28) == 0)
+ {
+ const char *p;
+ lexptr = tokstart + 28;
+ yylval.typed_val_int.val = GLOBAL_DESTRUCTORS;
+ /* Find the end of the symbol. */
+ p = symbol_end (lexptr);
+ yylval.typed_val_int.type = make_name (lexptr, p - lexptr);
+ lexptr = p;
+ return GLOBAL;
+ }
+
+ HANDLE_SPECIAL ("vtable for ", DEMANGLE_COMPONENT_VTABLE);
+ if (strncmp (tokstart, "delete", 6) == 0)
+ return DELETE;
+ if (strncmp (tokstart, "struct", 6) == 0)
+ return STRUCT;
+ if (strncmp (tokstart, "signed", 6) == 0)
+ return SIGNED_KEYWORD;
+ if (strncmp (tokstart, "sizeof", 6) == 0)
+ return SIZEOF;
+ if (strncmp (tokstart, "double", 6) == 0)
+ return DOUBLE_KEYWORD;
+ break;
+ case 5:
+ HANDLE_SPECIAL ("guard variable for ", DEMANGLE_COMPONENT_GUARD);
+ if (strncmp (tokstart, "false", 5) == 0)
+ return FALSEKEYWORD;
+ if (strncmp (tokstart, "class", 5) == 0)
+ return CLASS;
+ if (strncmp (tokstart, "union", 5) == 0)
+ return UNION;
+ if (strncmp (tokstart, "float", 5) == 0)
+ return FLOAT_KEYWORD;
+ if (strncmp (tokstart, "short", 5) == 0)
+ return SHORT;
+ if (strncmp (tokstart, "const", 5) == 0)
+ return CONST_KEYWORD;
+ break;
+ case 4:
+ if (strncmp (tokstart, "void", 4) == 0)
+ return VOID;
+ if (strncmp (tokstart, "bool", 4) == 0)
+ return BOOL;
+ if (strncmp (tokstart, "char", 4) == 0)
+ return CHAR;
+ if (strncmp (tokstart, "enum", 4) == 0)
+ return ENUM;
+ if (strncmp (tokstart, "long", 4) == 0)
+ return LONG;
+ if (strncmp (tokstart, "true", 4) == 0)
+ return TRUEKEYWORD;
+ break;
+ case 3:
+ HANDLE_SPECIAL ("VTT for ", DEMANGLE_COMPONENT_VTT);
+ HANDLE_SPECIAL ("non-virtual thunk to ", DEMANGLE_COMPONENT_THUNK);
+ if (strncmp (tokstart, "new", 3) == 0)
+ return NEW;
+ if (strncmp (tokstart, "int", 3) == 0)
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
+ }
+
+ yylval.comp = make_name (tokstart, namelen);
+ return NAME;
+}
+
+static void
+yyerror (char *msg)
+{
+ if (global_errmsg)
+ return;
+
+ error_lexptr = prev_lexptr;
+ global_errmsg = msg ? msg : "parse error";
+}
+
+/* Allocate all the components we'll need to build a tree. We generally
+ allocate too many components, but the extra memory usage doesn't hurt
+ because the trees are temporary. If we start keeping the trees for
+ a longer lifetime we'll need to be cleverer. */
+static struct demangle_info *
+allocate_info (int comps)
+{
+ struct demangle_info *ret;
+
+ ret = malloc (sizeof (struct demangle_info)
+ + sizeof (struct demangle_component) * (comps - 1));
+ ret->used = 0;
+ return ret;
+}
+
+/* Convert RESULT to a string. The return value is allocated
+ using xmalloc. ESTIMATED_LEN is used only as a guide to the
+ length of the result. This functions handles a few cases that
+ cplus_demangle_print does not, specifically the global destructor
+ and constructor labels. */
+
+char *
+cp_comp_to_string (struct demangle_component *result, int estimated_len)
+{
+ char *str, *prefix = NULL, *buf;
+ size_t err = 0;
+
+ if (result->type == GLOBAL_DESTRUCTORS)
+ {
+ result = d_left (result);
+ prefix = "global destructors keyed to ";
+ }
+ else if (result->type == GLOBAL_CONSTRUCTORS)
+ {
+ result = d_left (result);
+ prefix = "global constructors keyed to ";
+ }
+
+ str = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, result, estimated_len, &err);
+ if (str == NULL)
+ return NULL;
+
+ if (prefix == NULL)
+ return str;
+
+ buf = malloc (strlen (str) + strlen (prefix) + 1);
+ strcpy (buf, prefix);
+ strcat (buf, str);
+ free (str);
+ return (buf);
+}
+
+/* Convert a demangled name to a demangle_component tree. *MEMORY is set to the
+ block of used memory that should be freed when finished with the
+ tree. On error, NULL is returned, and an error message will be
+ set in *ERRMSG (which does not need to be freed). */
+
+struct demangle_component *
+cp_demangled_name_to_comp (const char *demangled_name, void **memory,
+ const char **errmsg)
+{
+ static char errbuf[60];
+ struct demangle_component *result;
+
+ int len = strlen (demangled_name);
+
+ len = len + len / 8;
+ prev_lexptr = lexptr = demangled_name;
+ error_lexptr = NULL;
+ global_errmsg = NULL;
+
+ demangle_info = allocate_info (len);
+
+ if (yyparse ())
+ {
+ if (global_errmsg && errmsg)
+ {
+ snprintf (errbuf, sizeof (errbuf) - 2, "%s, near `%s",
+ global_errmsg, error_lexptr);
+ strcat (errbuf, "'");
+ *errmsg = errbuf;
+ }
+ free (demangle_info);
+ return NULL;
+ }
+
+ *memory = demangle_info;
+ result = global_result;
+ global_result = NULL;
+
+ return result;
+}
+
+#ifdef TEST_CPNAMES
+
+static void
+cp_print (struct demangle_component *result)
+{
+ char *str;
+ size_t err = 0;
+
+ if (result->type == GLOBAL_DESTRUCTORS)
+ {
+ result = d_left (result);
+ fputs ("global destructors keyed to ", stdout);
+ }
+ else if (result->type == GLOBAL_CONSTRUCTORS)
+ {
+ result = d_left (result);
+ fputs ("global constructors keyed to ", stdout);
+ }
+
+ str = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, result, 64, &err);
+ if (str == NULL)
+ return;
+
+ fputs (str, stdout);
+
+ free (str);
+}
+
+static char
+trim_chars (char *lexptr, char **extra_chars)
+{
+ char *p = (char *) symbol_end (lexptr);
+ char c = 0;
+
+ if (*p)
+ {
+ c = *p;
+ *p = 0;
+ *extra_chars = p + 1;
+ }
+
+ return c;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *str2, *extra_chars, c;
+ char buf[65536];
+ int arg;
+ const char *errmsg;
+ void *memory;
+ struct demangle_component *result;
+
+ arg = 1;
+ if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
+ {
+ yydebug = 1;
+ arg++;
+ }
+
+ if (argv[arg] == NULL)
+ while (fgets (buf, 65536, stdin) != NULL)
+ {
+ int len;
+ buf[strlen (buf) - 1] = 0;
+ /* Use DMGL_VERBOSE to get expanded standard substitutions. */
+ c = trim_chars (buf, &extra_chars);
+ str2 = cplus_demangle (buf, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
+ if (str2 == NULL)
+ {
+ /* printf ("Demangling error\n"); */
+ if (c)
+ printf ("%s%c%s\n", buf, c, extra_chars);
+ else
+ printf ("%s\n", buf);
+ continue;
+ }
+ result = cp_demangled_name_to_comp (str2, &memory, &errmsg);
+ if (result == NULL)
+ {
+ fputs (errmsg, stderr);
+ fputc ('\n', stderr);
+ continue;
+ }
+
+ cp_print (result);
+ free (memory);
+
+ free (str2);
+ if (c)
+ {
+ putchar (c);
+ fputs (extra_chars, stdout);
+ }
+ putchar ('\n');
+ }
+ else
+ {
+ result = cp_demangled_name_to_comp (argv[arg], &memory, &errmsg);
+ if (result == NULL)
+ {
+ fputs (errmsg, stderr);
+ fputc ('\n', stderr);
+ return 0;
+ }
+ cp_print (result);
+ putchar ('\n');
+ free (memory);
+ }
+ return 0;
+}
+
+#endif
+++ /dev/null
-/* YACC parser for C++ names, for GDB.
-
- Copyright 2003, 2004, 2005
- Free Software Foundation, Inc.
-
- Parts of the lexer are based on c-exp.y from GDB.
-
-This file is part of GDB.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Note that malloc's and realloc's in this file are transformed to
- xmalloc and xrealloc respectively by the same sed command in the
- makefile that remaps any other malloc/realloc inserted by the parser
- generator. Doing this with #defines and trying to control the interaction
- with include files (<malloc.h> and <stdlib.h> for example) just became
- too messy, particularly when such includes can be inserted at random
- times by the parser generator. */
-
-%{
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "safe-ctype.h"
-#include "libiberty.h"
-#include "demangle.h"
-
-/* Bison does not make it easy to create a parser without global
- state, unfortunately. Here are all the global variables used
- in this parser. */
-
-/* LEXPTR is the current pointer into our lex buffer. PREV_LEXPTR
- is the start of the last token lexed, only used for diagnostics.
- ERROR_LEXPTR is the first place an error occurred. GLOBAL_ERRMSG
- is the first error message encountered. */
-
-static const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
-
-/* The components built by the parser are allocated ahead of time,
- and cached in this structure. */
-
-struct demangle_info {
- int used;
- struct demangle_component comps[1];
-};
-
-static struct demangle_info *demangle_info;
-#define d_grab() (&demangle_info->comps[demangle_info->used++])
-
-/* The parse tree created by the parser is stored here after a successful
- parse. */
-
-static struct demangle_component *global_result;
-
-/* Prototypes for helper functions used when constructing the parse
- tree. */
-
-static struct demangle_component *d_qualify (struct demangle_component *, int,
- int);
-
-static struct demangle_component *d_int_type (int);
-
-static struct demangle_component *d_unary (const char *,
- struct demangle_component *);
-static struct demangle_component *d_binary (const char *,
- struct demangle_component *,
- struct demangle_component *);
-
-/* Flags passed to d_qualify. */
-
-#define QUAL_CONST 1
-#define QUAL_RESTRICT 2
-#define QUAL_VOLATILE 4
-
-/* Flags passed to d_int_type. */
-
-#define INT_CHAR (1 << 0)
-#define INT_SHORT (1 << 1)
-#define INT_LONG (1 << 2)
-#define INT_LLONG (1 << 3)
-
-#define INT_SIGNED (1 << 4)
-#define INT_UNSIGNED (1 << 5)
-
-/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
- as well as gratuitiously global symbol names, so we can have multiple
- yacc generated parsers in gdb. Note that these are only the variables
- produced by yacc. If other parser generators (bison, byacc, etc) produce
- additional global names that conflict at link time, then those parser
- generators need to be fixed instead of adding those names to this list. */
-
-#define yymaxdepth cpname_maxdepth
-#define yyparse cpname_parse
-#define yylex cpname_lex
-#define yyerror cpname_error
-#define yylval cpname_lval
-#define yychar cpname_char
-#define yydebug cpname_debug
-#define yypact cpname_pact
-#define yyr1 cpname_r1
-#define yyr2 cpname_r2
-#define yydef cpname_def
-#define yychk cpname_chk
-#define yypgo cpname_pgo
-#define yyact cpname_act
-#define yyexca cpname_exca
-#define yyerrflag cpname_errflag
-#define yynerrs cpname_nerrs
-#define yyps cpname_ps
-#define yypv cpname_pv
-#define yys cpname_s
-#define yy_yys cpname_yys
-#define yystate cpname_state
-#define yytmp cpname_tmp
-#define yyv cpname_v
-#define yy_yyv cpname_yyv
-#define yyval cpname_val
-#define yylloc cpname_lloc
-#define yyreds cpname_reds /* With YYDEBUG defined */
-#define yytoks cpname_toks /* With YYDEBUG defined */
-#define yyname cpname_name /* With YYDEBUG defined */
-#define yyrule cpname_rule /* With YYDEBUG defined */
-#define yylhs cpname_yylhs
-#define yylen cpname_yylen
-#define yydefred cpname_yydefred
-#define yydgoto cpname_yydgoto
-#define yysindex cpname_yysindex
-#define yyrindex cpname_yyrindex
-#define yygindex cpname_yygindex
-#define yytable cpname_yytable
-#define yycheck cpname_yycheck
-
-int yyparse (void);
-static int yylex (void);
-static void yyerror (char *);
-
-/* Enable yydebug for the stand-alone parser. */
-#ifdef TEST_CPNAMES
-# define YYDEBUG 1
-#endif
-
-/* Helper functions. These wrap the demangler tree interface, handle
- allocation from our global store, and return the allocated component. */
-
-static struct demangle_component *
-fill_comp (enum demangle_component_type d_type, struct demangle_component *lhs,
- struct demangle_component *rhs)
-{
- struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_component (ret, d_type, lhs, rhs);
- return ret;
-}
-
-static struct demangle_component *
-make_empty (enum demangle_component_type d_type)
-{
- struct demangle_component *ret = d_grab ();
- ret->type = d_type;
- return ret;
-}
-
-static struct demangle_component *
-make_operator (const char *name, int args)
-{
- struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_operator (ret, name, args);
- return ret;
-}
-
-static struct demangle_component *
-make_dtor (enum gnu_v3_dtor_kinds kind, struct demangle_component *name)
-{
- struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_dtor (ret, kind, name);
- return ret;
-}
-
-static struct demangle_component *
-make_builtin_type (const char *name)
-{
- struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_builtin_type (ret, name);
- return ret;
-}
-
-static struct demangle_component *
-make_name (const char *name, int len)
-{
- struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_name (ret, name, len);
- return ret;
-}
-
-#define d_left(dc) (dc)->u.s_binary.left
-#define d_right(dc) (dc)->u.s_binary.right
-
-%}
-
-%union
- {
- struct demangle_component *comp;
- struct nested {
- struct demangle_component *comp;
- struct demangle_component **last;
- } nested;
- struct {
- struct demangle_component *comp, *last;
- } nested1;
- struct {
- struct demangle_component *comp, **last;
- struct nested fn;
- struct demangle_component *start;
- int fold_flag;
- } abstract;
- int lval;
- struct {
- int val;
- struct demangle_component *type;
- } typed_val_int;
- const char *opname;
- }
-
-%type <comp> exp exp1 type start start_opt operator colon_name
-%type <comp> unqualified_name colon_ext_name
-%type <comp> template template_arg
-%type <comp> builtin_type
-%type <comp> typespec_2 array_indicator
-%type <comp> colon_ext_only ext_only_name
-
-%type <comp> demangler_special function conversion_op
-%type <nested> conversion_op_name
-
-%type <abstract> abstract_declarator direct_abstract_declarator
-%type <abstract> abstract_declarator_fn
-%type <nested> declarator direct_declarator function_arglist
-
-%type <nested> declarator_1 direct_declarator_1
-
-%type <nested> template_params function_args
-%type <nested> ptr_operator
-
-%type <nested1> nested_name
-
-%type <lval> qualifier qualifiers qualifiers_opt
-
-%type <lval> int_part int_seq
-
-%token <comp> INT
-%token <comp> FLOAT
-
-%token <comp> NAME
-%type <comp> name
-
-%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON
-%token TEMPLATE
-%token ERROR
-%token NEW DELETE OPERATOR
-%token STATIC_CAST REINTERPRET_CAST DYNAMIC_CAST
-
-/* Special type cases, put in to allow the parser to distinguish different
- legal basetypes. */
-%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD BOOL
-%token ELLIPSIS RESTRICT VOID FLOAT_KEYWORD CHAR WCHAR_T
-
-%token <opname> ASSIGN_MODIFY
-
-/* C++ */
-%token TRUEKEYWORD
-%token FALSEKEYWORD
-
-/* Non-C++ things we get from the demangler. */
-%token <lval> DEMANGLER_SPECIAL
-%token CONSTRUCTION_VTABLE CONSTRUCTION_IN
-%token <typed_val_int> GLOBAL
-
-%{
-enum {
- GLOBAL_CONSTRUCTORS = DEMANGLE_COMPONENT_LITERAL + 20,
- GLOBAL_DESTRUCTORS = DEMANGLE_COMPONENT_LITERAL + 21
-};
-%}
-
-/* Precedence declarations. */
-
-/* Give NAME lower precedence than COLONCOLON, so that nested_name will
- associate greedily. */
-%nonassoc NAME
-
-/* Give NEW and DELETE lower precedence than ']', because we can not
- have an array of type operator new. This causes NEW '[' to be
- parsed as operator new[]. */
-%nonassoc NEW DELETE
-
-/* Give VOID higher precedence than NAME. Then we can use %prec NAME
- to prefer (VOID) to (function_args). */
-%nonassoc VOID
-
-/* Give VOID lower precedence than ')' for similar reasons. */
-%nonassoc ')'
-
-%left ','
-%right '=' ASSIGN_MODIFY
-%right '?'
-%left OROR
-%left ANDAND
-%left '|'
-%left '^'
-%left '&'
-%left EQUAL NOTEQUAL
-%left '<' '>' LEQ GEQ
-%left LSH RSH
-%left '@'
-%left '+' '-'
-%left '*' '/' '%'
-%right UNARY INCREMENT DECREMENT
-
-/* We don't need a precedence for '(' in this reduced grammar, and it
- can mask some unpleasant bugs, so disable it for now. */
-
-%right ARROW '.' '[' /* '(' */
-%left COLONCOLON
-
-\f
-%%
-
-result : start
- { global_result = $1; }
- ;
-
-start : type
-
- | demangler_special
-
- | function
-
- ;
-
-start_opt : /* */
- { $$ = NULL; }
- | COLONCOLON start
- { $$ = $2; }
- ;
-
-function
- /* Function with a return type. declarator_1 is used to prevent
- ambiguity with the next rule. */
- : typespec_2 declarator_1
- { $$ = $2.comp;
- *$2.last = $1;
- }
-
- /* Function without a return type. We need to use typespec_2
- to prevent conflicts from qualifiers_opt - harmless. The
- start_opt is used to handle "function-local" variables and
- types. */
- | typespec_2 function_arglist start_opt
- { $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
- if ($3) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); }
- | colon_ext_only function_arglist start_opt
- { $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
- if ($3) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); }
-
- | conversion_op_name start_opt
- { $$ = $1.comp;
- if ($2) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2); }
- | conversion_op_name abstract_declarator_fn
- { if ($2.last)
- {
- /* First complete the abstract_declarator's type using
- the typespec from the conversion_op_name. */
- *$2.last = *$1.last;
- /* Then complete the conversion_op_name with the type. */
- *$1.last = $2.comp;
- }
- /* If we have an arglist, build a function type. */
- if ($2.fn.comp)
- $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1.comp, $2.fn.comp);
- else
- $$ = $1.comp;
- if ($2.start) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2.start);
- }
- ;
-
-demangler_special
- : DEMANGLER_SPECIAL start
- { $$ = make_empty ($1);
- d_left ($$) = $2;
- d_right ($$) = NULL; }
- | CONSTRUCTION_VTABLE start CONSTRUCTION_IN start
- { $$ = fill_comp (DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, $2, $4); }
- | GLOBAL
- { $$ = make_empty ($1.val);
- d_left ($$) = $1.type;
- d_right ($$) = NULL; }
- ;
-
-operator : OPERATOR NEW
- { $$ = make_operator ("new", 1); }
- | OPERATOR DELETE
- { $$ = make_operator ("delete", 1); }
- | OPERATOR NEW '[' ']'
- { $$ = make_operator ("new[]", 1); }
- | OPERATOR DELETE '[' ']'
- { $$ = make_operator ("delete[]", 1); }
- | OPERATOR '+'
- { $$ = make_operator ("+", 2); }
- | OPERATOR '-'
- { $$ = make_operator ("-", 2); }
- | OPERATOR '*'
- { $$ = make_operator ("*", 2); }
- | OPERATOR '/'
- { $$ = make_operator ("/", 2); }
- | OPERATOR '%'
- { $$ = make_operator ("%", 2); }
- | OPERATOR '^'
- { $$ = make_operator ("^", 2); }
- | OPERATOR '&'
- { $$ = make_operator ("&", 2); }
- | OPERATOR '|'
- { $$ = make_operator ("|", 2); }
- | OPERATOR '~'
- { $$ = make_operator ("~", 1); }
- | OPERATOR '!'
- { $$ = make_operator ("!", 1); }
- | OPERATOR '='
- { $$ = make_operator ("=", 2); }
- | OPERATOR '<'
- { $$ = make_operator ("<", 2); }
- | OPERATOR '>'
- { $$ = make_operator (">", 2); }
- | OPERATOR ASSIGN_MODIFY
- { $$ = make_operator ($2, 2); }
- | OPERATOR LSH
- { $$ = make_operator ("<<", 2); }
- | OPERATOR RSH
- { $$ = make_operator (">>", 2); }
- | OPERATOR EQUAL
- { $$ = make_operator ("==", 2); }
- | OPERATOR NOTEQUAL
- { $$ = make_operator ("!=", 2); }
- | OPERATOR LEQ
- { $$ = make_operator ("<=", 2); }
- | OPERATOR GEQ
- { $$ = make_operator (">=", 2); }
- | OPERATOR ANDAND
- { $$ = make_operator ("&&", 2); }
- | OPERATOR OROR
- { $$ = make_operator ("||", 2); }
- | OPERATOR INCREMENT
- { $$ = make_operator ("++", 1); }
- | OPERATOR DECREMENT
- { $$ = make_operator ("--", 1); }
- | OPERATOR ','
- { $$ = make_operator (",", 2); }
- | OPERATOR ARROW '*'
- { $$ = make_operator ("->*", 2); }
- | OPERATOR ARROW
- { $$ = make_operator ("->", 2); }
- | OPERATOR '(' ')'
- { $$ = make_operator ("()", 0); }
- | OPERATOR '[' ']'
- { $$ = make_operator ("[]", 2); }
- ;
-
- /* Conversion operators. We don't try to handle some of
- the wackier demangler output for function pointers,
- since it's not clear that it's parseable. */
-conversion_op
- : OPERATOR typespec_2
- { $$ = fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL); }
- ;
-
-conversion_op_name
- : nested_name conversion_op
- { $$.comp = $1.comp;
- d_right ($1.last) = $2;
- $$.last = &d_left ($2);
- }
- | conversion_op
- { $$.comp = $1;
- $$.last = &d_left ($1);
- }
- | COLONCOLON nested_name conversion_op
- { $$.comp = $2.comp;
- d_right ($2.last) = $3;
- $$.last = &d_left ($3);
- }
- | COLONCOLON conversion_op
- { $$.comp = $2;
- $$.last = &d_left ($2);
- }
- ;
-
-/* DEMANGLE_COMPONENT_NAME */
-/* This accepts certain invalid placements of '~'. */
-unqualified_name: operator
- | operator '<' template_params '>'
- { $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
- | '~' NAME
- { $$ = make_dtor (gnu_v3_complete_object_dtor, $2); }
- ;
-
-/* This rule is used in name and nested_name, and expanded inline there
- for efficiency. */
-/*
-scope_id : NAME
- | template
- ;
-*/
-
-colon_name : name
- | COLONCOLON name
- { $$ = $2; }
- ;
-
-/* DEMANGLE_COMPONENT_QUAL_NAME */
-/* DEMANGLE_COMPONENT_CTOR / DEMANGLE_COMPONENT_DTOR ? */
-name : nested_name NAME %prec NAME
- { $$ = $1.comp; d_right ($1.last) = $2; }
- | NAME %prec NAME
- | nested_name template %prec NAME
- { $$ = $1.comp; d_right ($1.last) = $2; }
- | template %prec NAME
- ;
-
-colon_ext_name : colon_name
- | colon_ext_only
- ;
-
-colon_ext_only : ext_only_name
- | COLONCOLON ext_only_name
- { $$ = $2; }
- ;
-
-ext_only_name : nested_name unqualified_name
- { $$ = $1.comp; d_right ($1.last) = $2; }
- | unqualified_name
- ;
-
-nested_name : NAME COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
- $$.last = $$.comp;
- }
- | nested_name NAME COLONCOLON
- { $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- $$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
- }
- | template COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
- $$.last = $$.comp;
- }
- | nested_name template COLONCOLON
- { $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- $$.last = d_right ($1.last);
- d_left ($$.last) = $2;
- d_right ($$.last) = NULL;
- }
- ;
-
-/* DEMANGLE_COMPONENT_TEMPLATE */
-/* DEMANGLE_COMPONENT_TEMPLATE_ARGLIST */
-template : NAME '<' template_params '>'
- { $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
- ;
-
-template_params : template_arg
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $1, NULL);
- $$.last = &d_right ($$.comp); }
- | template_params ',' template_arg
- { $$.comp = $1.comp;
- *$1.last = fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $3, NULL);
- $$.last = &d_right (*$1.last);
- }
- ;
-
-/* "type" is inlined into template_arg and function_args. */
-
-/* Also an integral constant-expression of integral type, and a
- pointer to member (?) */
-template_arg : typespec_2
- | typespec_2 abstract_declarator
- { $$ = $2.comp;
- *$2.last = $1;
- }
- | '&' start
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $2); }
- | '&' '(' start ')'
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $3); }
- | exp
- ;
-
-function_args : typespec_2
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $1, NULL);
- $$.last = &d_right ($$.comp);
- }
- | typespec_2 abstract_declarator
- { *$2.last = $1;
- $$.comp = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $2.comp, NULL);
- $$.last = &d_right ($$.comp);
- }
- | function_args ',' typespec_2
- { *$1.last = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $3, NULL);
- $$.comp = $1.comp;
- $$.last = &d_right (*$1.last);
- }
- | function_args ',' typespec_2 abstract_declarator
- { *$4.last = $3;
- *$1.last = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $4.comp, NULL);
- $$.comp = $1.comp;
- $$.last = &d_right (*$1.last);
- }
- | function_args ',' ELLIPSIS
- { *$1.last
- = fill_comp (DEMANGLE_COMPONENT_ARGLIST,
- make_builtin_type ("..."),
- NULL);
- $$.comp = $1.comp;
- $$.last = &d_right (*$1.last);
- }
- ;
-
-function_arglist: '(' function_args ')' qualifiers_opt %prec NAME
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, $2.comp);
- $$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $4, 1); }
- | '(' VOID ')' qualifiers_opt
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
- $$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $4, 1); }
- | '(' ')' qualifiers_opt
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
- $$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $3, 1); }
- ;
-
-/* Should do something about DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL */
-qualifiers_opt : /* epsilon */
- { $$ = 0; }
- | qualifiers
- ;
-
-qualifier : RESTRICT
- { $$ = QUAL_RESTRICT; }
- | VOLATILE_KEYWORD
- { $$ = QUAL_VOLATILE; }
- | CONST_KEYWORD
- { $$ = QUAL_CONST; }
- ;
-
-qualifiers : qualifier
- | qualifier qualifiers
- { $$ = $1 | $2; }
- ;
-
-/* This accepts all sorts of invalid constructions and produces
- invalid output for them - an error would be better. */
-
-int_part : INT_KEYWORD
- { $$ = 0; }
- | SIGNED_KEYWORD
- { $$ = INT_SIGNED; }
- | UNSIGNED
- { $$ = INT_UNSIGNED; }
- | CHAR
- { $$ = INT_CHAR; }
- | LONG
- { $$ = INT_LONG; }
- | SHORT
- { $$ = INT_SHORT; }
- ;
-
-int_seq : int_part
- | int_seq int_part
- { $$ = $1 | $2; if ($1 & $2 & INT_LONG) $$ = $1 | INT_LLONG; }
- ;
-
-builtin_type : int_seq
- { $$ = d_int_type ($1); }
- | FLOAT_KEYWORD
- { $$ = make_builtin_type ("float"); }
- | DOUBLE_KEYWORD
- { $$ = make_builtin_type ("double"); }
- | LONG DOUBLE_KEYWORD
- { $$ = make_builtin_type ("long double"); }
- | BOOL
- { $$ = make_builtin_type ("bool"); }
- | WCHAR_T
- { $$ = make_builtin_type ("wchar_t"); }
- | VOID
- { $$ = make_builtin_type ("void"); }
- ;
-
-ptr_operator : '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_POINTER);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
- $$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $2, 0); }
- /* g++ seems to allow qualifiers after the reference? */
- | '&'
- { $$.comp = make_empty (DEMANGLE_COMPONENT_REFERENCE);
- $$.comp->u.s_binary.left = $$.comp->u.s_binary.right = NULL;
- $$.last = &d_left ($$.comp); }
- | nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $1.comp;
- /* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
- *$1.last = *d_left ($1.last);
- $$.comp->u.s_binary.right = NULL;
- $$.last = &d_right ($$.comp);
- $$.comp = d_qualify ($$.comp, $3, 0); }
- | COLONCOLON nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $2.comp;
- /* Convert the innermost DEMANGLE_COMPONENT_QUAL_NAME to a DEMANGLE_COMPONENT_NAME. */
- *$2.last = *d_left ($2.last);
- $$.comp->u.s_binary.right = NULL;
- $$.last = &d_right ($$.comp);
- $$.comp = d_qualify ($$.comp, $4, 0); }
- ;
-
-array_indicator : '[' ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = NULL;
- }
- | '[' INT ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = $2;
- }
- ;
-
-/* Details of this approach inspired by the G++ < 3.4 parser. */
-
-/* This rule is only used in typespec_2, and expanded inline there for
- efficiency. */
-/*
-typespec : builtin_type
- | colon_name
- ;
-*/
-
-typespec_2 : builtin_type qualifiers
- { $$ = d_qualify ($1, $2, 0); }
- | builtin_type
- | qualifiers builtin_type qualifiers
- { $$ = d_qualify ($2, $1 | $3, 0); }
- | qualifiers builtin_type
- { $$ = d_qualify ($2, $1, 0); }
-
- | name qualifiers
- { $$ = d_qualify ($1, $2, 0); }
- | name
- | qualifiers name qualifiers
- { $$ = d_qualify ($2, $1 | $3, 0); }
- | qualifiers name
- { $$ = d_qualify ($2, $1, 0); }
-
- | COLONCOLON name qualifiers
- { $$ = d_qualify ($2, $3, 0); }
- | COLONCOLON name
- { $$ = $2; }
- | qualifiers COLONCOLON name qualifiers
- { $$ = d_qualify ($3, $1 | $4, 0); }
- | qualifiers COLONCOLON name
- { $$ = d_qualify ($3, $1, 0); }
- ;
-
-abstract_declarator
- : ptr_operator
- { $$.comp = $1.comp; $$.last = $1.last;
- $$.fn.comp = NULL; $$.fn.last = NULL; }
- | ptr_operator abstract_declarator
- { $$ = $2; $$.fn.comp = NULL; $$.fn.last = NULL;
- if ($2.fn.comp) { $$.last = $2.fn.last; *$2.last = $2.fn.comp; }
- *$$.last = $1.comp;
- $$.last = $1.last; }
- | direct_abstract_declarator
- { $$.fn.comp = NULL; $$.fn.last = NULL;
- if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
- }
- ;
-
-direct_abstract_declarator
- : '(' abstract_declarator ')'
- { $$ = $2; $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 1;
- if ($2.fn.comp) { $$.last = $2.fn.last; *$2.last = $2.fn.comp; }
- }
- | direct_abstract_declarator function_arglist
- { $$.fold_flag = 0;
- if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
- if ($1.fold_flag)
- {
- *$$.last = $2.comp;
- $$.last = $2.last;
- }
- else
- $$.fn = $2;
- }
- | direct_abstract_declarator array_indicator
- { $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 0;
- if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
- *$1.last = $2;
- $$.last = &d_right ($2);
- }
- | array_indicator
- { $$.fn.comp = NULL; $$.fn.last = NULL; $$.fold_flag = 0;
- $$.comp = $1;
- $$.last = &d_right ($1);
- }
- /* G++ has the following except for () and (type). Then
- (type) is handled in regcast_or_absdcl and () is handled
- in fcast_or_absdcl.
-
- However, this is only useful for function types, and
- generates reduce/reduce conflicts with direct_declarator.
- We're interested in pointer-to-function types, and in
- functions, but not in function types - so leave this
- out. */
- /* | function_arglist */
- ;
-
-abstract_declarator_fn
- : ptr_operator
- { $$.comp = $1.comp; $$.last = $1.last;
- $$.fn.comp = NULL; $$.fn.last = NULL; $$.start = NULL; }
- | ptr_operator abstract_declarator_fn
- { $$ = $2;
- if ($2.last)
- *$$.last = $1.comp;
- else
- $$.comp = $1.comp;
- $$.last = $1.last;
- }
- | direct_abstract_declarator
- { $$.comp = $1.comp; $$.last = $1.last; $$.fn = $1.fn; $$.start = NULL; }
- | direct_abstract_declarator function_arglist COLONCOLON start
- { $$.start = $4;
- if ($1.fn.comp) { $$.last = $1.fn.last; *$1.last = $1.fn.comp; }
- if ($1.fold_flag)
- {
- *$$.last = $2.comp;
- $$.last = $2.last;
- }
- else
- $$.fn = $2;
- }
- | function_arglist start_opt
- { $$.fn = $1;
- $$.start = $2;
- $$.comp = NULL; $$.last = NULL;
- }
- ;
-
-type : typespec_2
- | typespec_2 abstract_declarator
- { $$ = $2.comp;
- *$2.last = $1;
- }
- ;
-
-declarator : ptr_operator declarator
- { $$.comp = $2.comp;
- $$.last = $1.last;
- *$2.last = $1.comp; }
- | direct_declarator
- ;
-
-direct_declarator
- : '(' declarator ')'
- { $$ = $2; }
- | direct_declarator function_arglist
- { $$.comp = $1.comp;
- *$1.last = $2.comp;
- $$.last = $2.last;
- }
- | direct_declarator array_indicator
- { $$.comp = $1.comp;
- *$1.last = $2;
- $$.last = &d_right ($2);
- }
- | colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
- $$.last = &d_right ($$.comp);
- }
- ;
-
-/* These are similar to declarator and direct_declarator except that they
- do not permit ( colon_ext_name ), which is ambiguous with a function
- argument list. They also don't permit a few other forms with redundant
- parentheses around the colon_ext_name; any colon_ext_name in parentheses
- must be followed by an argument list or an array indicator, or preceded
- by a pointer. */
-declarator_1 : ptr_operator declarator_1
- { $$.comp = $2.comp;
- $$.last = $1.last;
- *$2.last = $1.comp; }
- | colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
- $$.last = &d_right ($$.comp);
- }
- | direct_declarator_1
-
- /* Function local variable or type. The typespec to
- our left is the type of the containing function.
- This should be OK, because function local types
- can not be templates, so the return types of their
- members will not be mangled. If they are hopefully
- they'll end up to the right of the ::. */
- | colon_ext_name function_arglist COLONCOLON start
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
- $$.last = $2.last;
- $$.comp = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
- }
- | direct_declarator_1 function_arglist COLONCOLON start
- { $$.comp = $1.comp;
- *$1.last = $2.comp;
- $$.last = $2.last;
- $$.comp = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
- }
- ;
-
-direct_declarator_1
- : '(' ptr_operator declarator ')'
- { $$.comp = $3.comp;
- $$.last = $2.last;
- *$3.last = $2.comp; }
- | direct_declarator_1 function_arglist
- { $$.comp = $1.comp;
- *$1.last = $2.comp;
- $$.last = $2.last;
- }
- | direct_declarator_1 array_indicator
- { $$.comp = $1.comp;
- *$1.last = $2;
- $$.last = &d_right ($2);
- }
- | colon_ext_name function_arglist
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
- $$.last = $2.last;
- }
- | colon_ext_name array_indicator
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2);
- $$.last = &d_right ($2);
- }
- ;
-
-exp : '(' exp1 ')'
- { $$ = $2; }
- ;
-
-/* Silly trick. Only allow '>' when parenthesized, in order to
- handle conflict with templates. */
-exp1 : exp
- ;
-
-exp1 : exp '>' exp
- { $$ = d_binary (">", $1, $3); }
- ;
-
-/* References. Not allowed everywhere in template parameters, only
- at the top level, but treat them as expressions in case they are wrapped
- in parentheses. */
-exp1 : '&' start
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $2); }
- ;
-
-/* Expressions, not including the comma operator. */
-exp : '-' exp %prec UNARY
- { $$ = d_unary ("-", $2); }
- ;
-
-exp : '!' exp %prec UNARY
- { $$ = d_unary ("!", $2); }
- ;
-
-exp : '~' exp %prec UNARY
- { $$ = d_unary ("~", $2); }
- ;
-
-/* Casts. First your normal C-style cast. If exp is a LITERAL, just change
- its type. */
-
-exp : '(' type ')' exp %prec UNARY
- { if ($4->type == DEMANGLE_COMPONENT_LITERAL
- || $4->type == DEMANGLE_COMPONENT_LITERAL_NEG)
- {
- $$ = $4;
- d_left ($4) = $2;
- }
- else
- $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL),
- $4);
- }
- ;
-
-/* Mangling does not differentiate between these, so we don't need to
- either. */
-exp : STATIC_CAST '<' type '>' '(' exp1 ')' %prec UNARY
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
- $6);
- }
- ;
-
-exp : DYNAMIC_CAST '<' type '>' '(' exp1 ')' %prec UNARY
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
- $6);
- }
- ;
-
-exp : REINTERPRET_CAST '<' type '>' '(' exp1 ')' %prec UNARY
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $3, NULL),
- $6);
- }
- ;
-
-/* Another form of C++-style cast. "type ( exp1 )" is not allowed (it's too
- ambiguous), but "name ( exp1 )" is. Because we don't need to support
- function types, we can handle this unambiguously (the use of typespec_2
- prevents a silly, harmless conflict with qualifiers_opt). This does not
- appear in demangler output so it's not a great loss if we need to
- disable it. */
-exp : typespec_2 '(' exp1 ')' %prec UNARY
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $1, NULL),
- $3);
- }
- ;
-
-/* TO INVESTIGATE: ._0 style anonymous names; anonymous namespaces */
-
-/* Binary operators in order of decreasing precedence. */
-
-exp : exp '*' exp
- { $$ = d_binary ("*", $1, $3); }
- ;
-
-exp : exp '/' exp
- { $$ = d_binary ("/", $1, $3); }
- ;
-
-exp : exp '%' exp
- { $$ = d_binary ("%", $1, $3); }
- ;
-
-exp : exp '+' exp
- { $$ = d_binary ("+", $1, $3); }
- ;
-
-exp : exp '-' exp
- { $$ = d_binary ("-", $1, $3); }
- ;
-
-exp : exp LSH exp
- { $$ = d_binary ("<<", $1, $3); }
- ;
-
-exp : exp RSH exp
- { $$ = d_binary (">>", $1, $3); }
- ;
-
-exp : exp EQUAL exp
- { $$ = d_binary ("==", $1, $3); }
- ;
-
-exp : exp NOTEQUAL exp
- { $$ = d_binary ("!=", $1, $3); }
- ;
-
-exp : exp LEQ exp
- { $$ = d_binary ("<=", $1, $3); }
- ;
-
-exp : exp GEQ exp
- { $$ = d_binary (">=", $1, $3); }
- ;
-
-exp : exp '<' exp
- { $$ = d_binary ("<", $1, $3); }
- ;
-
-exp : exp '&' exp
- { $$ = d_binary ("&", $1, $3); }
- ;
-
-exp : exp '^' exp
- { $$ = d_binary ("^", $1, $3); }
- ;
-
-exp : exp '|' exp
- { $$ = d_binary ("|", $1, $3); }
- ;
-
-exp : exp ANDAND exp
- { $$ = d_binary ("&&", $1, $3); }
- ;
-
-exp : exp OROR exp
- { $$ = d_binary ("||", $1, $3); }
- ;
-
-/* Not 100% sure these are necessary, but they're harmless. */
-exp : exp ARROW NAME
- { $$ = d_binary ("->", $1, $3); }
- ;
-
-exp : exp '.' NAME
- { $$ = d_binary (".", $1, $3); }
- ;
-
-exp : exp '?' exp ':' exp %prec '?'
- { $$ = fill_comp (DEMANGLE_COMPONENT_TRINARY, make_operator ("?", 3),
- fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG1, $1,
- fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG2, $3, $5)));
- }
- ;
-
-exp : INT
- ;
-
-/* Not generally allowed. */
-exp : FLOAT
- ;
-
-exp : SIZEOF '(' type ')' %prec UNARY
- { $$ = d_unary ("sizeof", $3); }
- ;
-
-/* C++. */
-exp : TRUEKEYWORD
- { struct demangle_component *i;
- i = make_name ("1", 1);
- $$ = fill_comp (DEMANGLE_COMPONENT_LITERAL,
- make_builtin_type ("bool"),
- i);
- }
- ;
-
-exp : FALSEKEYWORD
- { struct demangle_component *i;
- i = make_name ("0", 1);
- $$ = fill_comp (DEMANGLE_COMPONENT_LITERAL,
- make_builtin_type ("bool"),
- i);
- }
- ;
-
-/* end of C++. */
-
-%%
-
-/* Apply QUALIFIERS to LHS and return a qualified component. IS_METHOD
- is set if LHS is a method, in which case the qualifiers are logically
- applied to "this". We apply qualifiers in a consistent order; LHS
- may already be qualified; duplicate qualifiers are not created. */
-
-struct demangle_component *
-d_qualify (struct demangle_component *lhs, int qualifiers, int is_method)
-{
- struct demangle_component **inner_p;
- enum demangle_component_type type;
-
- /* For now the order is CONST (innermost), VOLATILE, RESTRICT. */
-
-#define HANDLE_QUAL(TYPE, MTYPE, QUAL) \
- if ((qualifiers & QUAL) && (type != TYPE) && (type != MTYPE)) \
- { \
- *inner_p = fill_comp (is_method ? MTYPE : TYPE, \
- *inner_p, NULL); \
- inner_p = &d_left (*inner_p); \
- type = (*inner_p)->type; \
- } \
- else if (type == TYPE || type == MTYPE) \
- { \
- inner_p = &d_left (*inner_p); \
- type = (*inner_p)->type; \
- }
-
- inner_p = &lhs;
-
- type = (*inner_p)->type;
-
- HANDLE_QUAL (DEMANGLE_COMPONENT_RESTRICT, DEMANGLE_COMPONENT_RESTRICT_THIS, QUAL_RESTRICT);
- HANDLE_QUAL (DEMANGLE_COMPONENT_VOLATILE, DEMANGLE_COMPONENT_VOLATILE_THIS, QUAL_VOLATILE);
- HANDLE_QUAL (DEMANGLE_COMPONENT_CONST, DEMANGLE_COMPONENT_CONST_THIS, QUAL_CONST);
-
- return lhs;
-}
-
-/* Return a builtin type corresponding to FLAGS. */
-
-static struct demangle_component *
-d_int_type (int flags)
-{
- const char *name;
-
- switch (flags)
- {
- case INT_SIGNED | INT_CHAR:
- name = "signed char";
- break;
- case INT_CHAR:
- name = "char";
- break;
- case INT_UNSIGNED | INT_CHAR:
- name = "unsigned char";
- break;
- case 0:
- case INT_SIGNED:
- name = "int";
- break;
- case INT_UNSIGNED:
- name = "unsigned int";
- break;
- case INT_LONG:
- case INT_SIGNED | INT_LONG:
- name = "long";
- break;
- case INT_UNSIGNED | INT_LONG:
- name = "unsigned long";
- break;
- case INT_SHORT:
- case INT_SIGNED | INT_SHORT:
- name = "short";
- break;
- case INT_UNSIGNED | INT_SHORT:
- name = "unsigned short";
- break;
- case INT_LLONG | INT_LONG:
- case INT_SIGNED | INT_LLONG | INT_LONG:
- name = "long long";
- break;
- case INT_UNSIGNED | INT_LLONG | INT_LONG:
- name = "unsigned long long";
- break;
- default:
- return NULL;
- }
-
- return make_builtin_type (name);
-}
-
-/* Wrapper to create a unary operation. */
-
-static struct demangle_component *
-d_unary (const char *name, struct demangle_component *lhs)
-{
- return fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator (name, 1), lhs);
-}
-
-/* Wrapper to create a binary operation. */
-
-static struct demangle_component *
-d_binary (const char *name, struct demangle_component *lhs, struct demangle_component *rhs)
-{
- return fill_comp (DEMANGLE_COMPONENT_BINARY, make_operator (name, 2),
- fill_comp (DEMANGLE_COMPONENT_BINARY_ARGS, lhs, rhs));
-}
-
-/* Find the end of a symbol name starting at LEXPTR. */
-
-static const char *
-symbol_end (const char *lexptr)
-{
- const char *p = lexptr;
-
- while (*p && (ISALNUM (*p) || *p == '_' || *p == '$' || *p == '.'))
- p++;
-
- return p;
-}
-
-/* Take care of parsing a number (anything that starts with a digit).
- The number starts at P and contains LEN characters. Store the result in
- YYLVAL. */
-
-static int
-parse_number (const char *p, int len, int parsed_float)
-{
- int unsigned_p = 0;
-
- /* Number of "L" suffixes encountered. */
- int long_p = 0;
-
- struct demangle_component *signed_type;
- struct demangle_component *unsigned_type;
- struct demangle_component *type, *name;
- enum demangle_component_type literal_type;
-
- if (p[0] == '-')
- {
- literal_type = DEMANGLE_COMPONENT_LITERAL_NEG;
- p++;
- len--;
- }
- else
- literal_type = DEMANGLE_COMPONENT_LITERAL;
-
- if (parsed_float)
- {
- /* It's a float since it contains a point or an exponent. */
- char c;
-
- /* The GDB lexer checks the result of scanf at this point. Not doing
- this leaves our error checking slightly weaker but only for invalid
- data. */
-
- /* See if it has `f' or `l' suffix (float or long double). */
-
- c = TOLOWER (p[len - 1]);
-
- if (c == 'f')
- {
- len--;
- type = make_builtin_type ("float");
- }
- else if (c == 'l')
- {
- len--;
- type = make_builtin_type ("long double");
- }
- else if (ISDIGIT (c) || c == '.')
- type = make_builtin_type ("double");
- else
- return ERROR;
-
- name = make_name (p, len);
- yylval.comp = fill_comp (literal_type, type, name);
-
- return FLOAT;
- }
-
- /* This treats 0x1 and 1 as different literals. We also do not
- automatically generate unsigned types. */
-
- long_p = 0;
- unsigned_p = 0;
- while (len > 0)
- {
- if (p[len - 1] == 'l' || p[len - 1] == 'L')
- {
- len--;
- long_p++;
- continue;
- }
- if (p[len - 1] == 'u' || p[len - 1] == 'U')
- {
- len--;
- unsigned_p++;
- continue;
- }
- break;
- }
-
- if (long_p == 0)
- {
- unsigned_type = make_builtin_type ("unsigned int");
- signed_type = make_builtin_type ("int");
- }
- else if (long_p == 1)
- {
- unsigned_type = make_builtin_type ("unsigned long");
- signed_type = make_builtin_type ("long");
- }
- else
- {
- unsigned_type = make_builtin_type ("unsigned long long");
- signed_type = make_builtin_type ("long long");
- }
-
- if (unsigned_p)
- type = unsigned_type;
- else
- type = signed_type;
-
- name = make_name (p, len);
- yylval.comp = fill_comp (literal_type, type, name);
-
- return INT;
-}
-
-static char backslashable[] = "abefnrtv";
-static char represented[] = "\a\b\e\f\n\r\t\v";
-
-/* Translate the backslash the way we would in the host character set. */
-static int
-c_parse_backslash (int host_char, int *target_char)
-{
- const char *ix;
- ix = strchr (backslashable, host_char);
- if (! ix)
- return 0;
- else
- *target_char = represented[ix - backslashable];
- return 1;
-}
-
-/* Parse a C escape sequence. STRING_PTR points to a variable
- containing a pointer to the string to parse. That pointer
- should point to the character after the \. That pointer
- is updated past the characters we use. The value of the
- escape sequence is returned.
-
- A negative value means the sequence \ newline was seen,
- which is supposed to be equivalent to nothing at all.
-
- If \ is followed by a null character, we return a negative
- value and leave the string pointer pointing at the null character.
-
- If \ is followed by 000, we return 0 and leave the string pointer
- after the zeros. A value of 0 does not mean end of string. */
-
-static int
-parse_escape (const char **string_ptr)
-{
- int target_char;
- int c = *(*string_ptr)++;
- if (c_parse_backslash (c, &target_char))
- return target_char;
- else
- switch (c)
- {
- case '\n':
- return -2;
- case 0:
- (*string_ptr)--;
- return 0;
- case '^':
- {
- c = *(*string_ptr)++;
-
- if (c == '?')
- return 0177;
- else if (c == '\\')
- target_char = parse_escape (string_ptr);
- else
- target_char = c;
-
- /* Now target_char is something like `c', and we want to find
- its control-character equivalent. */
- target_char = target_char & 037;
-
- return target_char;
- }
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- int i = c - '0';
- int count = 0;
- while (++count < 3)
- {
- c = (**string_ptr);
- if (c >= '0' && c <= '7')
- {
- (*string_ptr)++;
- i *= 8;
- i += c - '0';
- }
- else
- {
- break;
- }
- }
- return i;
- }
- default:
- return target_char;
- }
-}
-
-#define HANDLE_SPECIAL(string, comp) \
- if (strncmp (tokstart, string, sizeof (string) - 1) == 0) \
- { \
- lexptr = tokstart + sizeof (string) - 1; \
- yylval.lval = comp; \
- return DEMANGLER_SPECIAL; \
- }
-
-#define HANDLE_TOKEN2(string, token) \
- if (lexptr[1] == string[1]) \
- { \
- lexptr += 2; \
- yylval.opname = string; \
- return token; \
- }
-
-#define HANDLE_TOKEN3(string, token) \
- if (lexptr[1] == string[1] && lexptr[2] == string[2]) \
- { \
- lexptr += 3; \
- yylval.opname = string; \
- return token; \
- }
-
-/* Read one token, getting characters through LEXPTR. */
-
-static int
-yylex (void)
-{
- int c;
- int namelen;
- const char *tokstart, *tokptr;
-
- retry:
- prev_lexptr = lexptr;
- tokstart = lexptr;
-
- switch (c = *tokstart)
- {
- case 0:
- return 0;
-
- case ' ':
- case '\t':
- case '\n':
- lexptr++;
- goto retry;
-
- case '\'':
- /* We either have a character constant ('0' or '\177' for example)
- or we have a quoted symbol reference ('foo(int,int)' in C++
- for example). */
- lexptr++;
- c = *lexptr++;
- if (c == '\\')
- c = parse_escape (&lexptr);
- else if (c == '\'')
- {
- yyerror ("empty character constant");
- return ERROR;
- }
-
- c = *lexptr++;
- if (c != '\'')
- {
- yyerror ("invalid character constant");
- return ERROR;
- }
-
- /* FIXME: We should refer to a canonical form of the character,
- presumably the same one that appears in manglings - the decimal
- representation. But if that isn't in our input then we have to
- allocate memory for it somewhere. */
- yylval.comp = fill_comp (DEMANGLE_COMPONENT_LITERAL,
- make_builtin_type ("char"),
- make_name (tokstart, lexptr - tokstart));
-
- return INT;
-
- case '(':
- if (strncmp (tokstart, "(anonymous namespace)", 21) == 0)
- {
- lexptr += 21;
- yylval.comp = make_name ("(anonymous namespace)",
- sizeof "(anonymous namespace)" - 1);
- return NAME;
- }
- /* FALL THROUGH */
-
- case ')':
- case ',':
- lexptr++;
- return c;
-
- case '.':
- if (lexptr[1] == '.' && lexptr[2] == '.')
- {
- lexptr += 3;
- return ELLIPSIS;
- }
-
- /* Might be a floating point number. */
- if (lexptr[1] < '0' || lexptr[1] > '9')
- goto symbol; /* Nope, must be a symbol. */
-
- goto try_number;
-
- case '-':
- HANDLE_TOKEN2 ("-=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 ("--", DECREMENT);
- HANDLE_TOKEN2 ("->", ARROW);
-
- /* For construction vtables. This is kind of hokey. */
- if (strncmp (tokstart, "-in-", 4) == 0)
- {
- lexptr += 4;
- return CONSTRUCTION_IN;
- }
-
- if (lexptr[1] < '0' || lexptr[1] > '9')
- {
- lexptr++;
- return '-';
- }
- /* FALL THRU into number case. */
-
- try_number:
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- /* It's a number. */
- int got_dot = 0, got_e = 0, toktype;
- const char *p = tokstart;
- int hex = 0;
-
- if (c == '-')
- p++;
-
- if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
- {
- p += 2;
- hex = 1;
- }
- else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
- {
- p += 2;
- hex = 0;
- }
-
- for (;; ++p)
- {
- /* This test includes !hex because 'e' is a valid hex digit
- and thus does not indicate a floating point number when
- the radix is hex. */
- if (!hex && !got_e && (*p == 'e' || *p == 'E'))
- got_dot = got_e = 1;
- /* This test does not include !hex, because a '.' always indicates
- a decimal floating point number regardless of the radix.
-
- NOTE drow/2005-03-09: This comment is not accurate in C99;
- however, it's not clear that all the floating point support
- in this file is doing any good here. */
- else if (!got_dot && *p == '.')
- got_dot = 1;
- else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
- && (*p == '-' || *p == '+'))
- /* This is the sign of the exponent, not the end of the
- number. */
- continue;
- /* We will take any letters or digits. parse_number will
- complain if past the radix, or if L or U are not final. */
- else if (! ISALNUM (*p))
- break;
- }
- toktype = parse_number (tokstart, p - tokstart, got_dot|got_e);
- if (toktype == ERROR)
- {
- char *err_copy = (char *) alloca (p - tokstart + 1);
-
- memcpy (err_copy, tokstart, p - tokstart);
- err_copy[p - tokstart] = 0;
- yyerror ("invalid number");
- return ERROR;
- }
- lexptr = p;
- return toktype;
- }
-
- case '+':
- HANDLE_TOKEN2 ("+=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 ("++", INCREMENT);
- lexptr++;
- return c;
- case '*':
- HANDLE_TOKEN2 ("*=", ASSIGN_MODIFY);
- lexptr++;
- return c;
- case '/':
- HANDLE_TOKEN2 ("/=", ASSIGN_MODIFY);
- lexptr++;
- return c;
- case '%':
- HANDLE_TOKEN2 ("%=", ASSIGN_MODIFY);
- lexptr++;
- return c;
- case '|':
- HANDLE_TOKEN2 ("|=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 ("||", OROR);
- lexptr++;
- return c;
- case '&':
- HANDLE_TOKEN2 ("&=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 ("&&", ANDAND);
- lexptr++;
- return c;
- case '^':
- HANDLE_TOKEN2 ("^=", ASSIGN_MODIFY);
- lexptr++;
- return c;
- case '!':
- HANDLE_TOKEN2 ("!=", NOTEQUAL);
- lexptr++;
- return c;
- case '<':
- HANDLE_TOKEN3 ("<<=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 ("<=", LEQ);
- HANDLE_TOKEN2 ("<<", LSH);
- lexptr++;
- return c;
- case '>':
- HANDLE_TOKEN3 (">>=", ASSIGN_MODIFY);
- HANDLE_TOKEN2 (">=", GEQ);
- HANDLE_TOKEN2 (">>", RSH);
- lexptr++;
- return c;
- case '=':
- HANDLE_TOKEN2 ("==", EQUAL);
- lexptr++;
- return c;
- case ':':
- HANDLE_TOKEN2 ("::", COLONCOLON);
- lexptr++;
- return c;
-
- case '[':
- case ']':
- case '?':
- case '@':
- case '~':
- case '{':
- case '}':
- symbol:
- lexptr++;
- return c;
-
- case '"':
- /* These can't occur in C++ names. */
- yyerror ("unexpected string literal");
- return ERROR;
- }
-
- if (!(c == '_' || c == '$' || ISALPHA (c)))
- {
- /* We must have come across a bad character (e.g. ';'). */
- yyerror ("invalid character");
- return ERROR;
- }
-
- /* It's a name. See how long it is. */
- namelen = 0;
- do
- c = tokstart[++namelen];
- while (ISALNUM (c) || c == '_' || c == '$');
-
- lexptr += namelen;
-
- /* Catch specific keywords. Notice that some of the keywords contain
- spaces, and are sorted by the length of the first word. They must
- all include a trailing space in the string comparison. */
- switch (namelen)
- {
- case 16:
- if (strncmp (tokstart, "reinterpret_cast", 16) == 0)
- return REINTERPRET_CAST;
- break;
- case 12:
- if (strncmp (tokstart, "construction vtable for ", 24) == 0)
- {
- lexptr = tokstart + 24;
- return CONSTRUCTION_VTABLE;
- }
- if (strncmp (tokstart, "dynamic_cast", 12) == 0)
- return DYNAMIC_CAST;
- break;
- case 11:
- if (strncmp (tokstart, "static_cast", 11) == 0)
- return STATIC_CAST;
- break;
- case 9:
- HANDLE_SPECIAL ("covariant return thunk to ", DEMANGLE_COMPONENT_COVARIANT_THUNK);
- HANDLE_SPECIAL ("reference temporary for ", DEMANGLE_COMPONENT_REFTEMP);
- break;
- case 8:
- HANDLE_SPECIAL ("typeinfo for ", DEMANGLE_COMPONENT_TYPEINFO);
- HANDLE_SPECIAL ("typeinfo fn for ", DEMANGLE_COMPONENT_TYPEINFO_FN);
- HANDLE_SPECIAL ("typeinfo name for ", DEMANGLE_COMPONENT_TYPEINFO_NAME);
- if (strncmp (tokstart, "operator", 8) == 0)
- return OPERATOR;
- if (strncmp (tokstart, "restrict", 8) == 0)
- return RESTRICT;
- if (strncmp (tokstart, "unsigned", 8) == 0)
- return UNSIGNED;
- if (strncmp (tokstart, "template", 8) == 0)
- return TEMPLATE;
- if (strncmp (tokstart, "volatile", 8) == 0)
- return VOLATILE_KEYWORD;
- break;
- case 7:
- HANDLE_SPECIAL ("virtual thunk to ", DEMANGLE_COMPONENT_VIRTUAL_THUNK);
- if (strncmp (tokstart, "wchar_t", 7) == 0)
- return WCHAR_T;
- break;
- case 6:
- if (strncmp (tokstart, "global constructors keyed to ", 29) == 0)
- {
- const char *p;
- lexptr = tokstart + 29;
- yylval.typed_val_int.val = GLOBAL_CONSTRUCTORS;
- /* Find the end of the symbol. */
- p = symbol_end (lexptr);
- yylval.typed_val_int.type = make_name (lexptr, p - lexptr);
- lexptr = p;
- return GLOBAL;
- }
- if (strncmp (tokstart, "global destructors keyed to ", 28) == 0)
- {
- const char *p;
- lexptr = tokstart + 28;
- yylval.typed_val_int.val = GLOBAL_DESTRUCTORS;
- /* Find the end of the symbol. */
- p = symbol_end (lexptr);
- yylval.typed_val_int.type = make_name (lexptr, p - lexptr);
- lexptr = p;
- return GLOBAL;
- }
-
- HANDLE_SPECIAL ("vtable for ", DEMANGLE_COMPONENT_VTABLE);
- if (strncmp (tokstart, "delete", 6) == 0)
- return DELETE;
- if (strncmp (tokstart, "struct", 6) == 0)
- return STRUCT;
- if (strncmp (tokstart, "signed", 6) == 0)
- return SIGNED_KEYWORD;
- if (strncmp (tokstart, "sizeof", 6) == 0)
- return SIZEOF;
- if (strncmp (tokstart, "double", 6) == 0)
- return DOUBLE_KEYWORD;
- break;
- case 5:
- HANDLE_SPECIAL ("guard variable for ", DEMANGLE_COMPONENT_GUARD);
- if (strncmp (tokstart, "false", 5) == 0)
- return FALSEKEYWORD;
- if (strncmp (tokstart, "class", 5) == 0)
- return CLASS;
- if (strncmp (tokstart, "union", 5) == 0)
- return UNION;
- if (strncmp (tokstart, "float", 5) == 0)
- return FLOAT_KEYWORD;
- if (strncmp (tokstart, "short", 5) == 0)
- return SHORT;
- if (strncmp (tokstart, "const", 5) == 0)
- return CONST_KEYWORD;
- break;
- case 4:
- if (strncmp (tokstart, "void", 4) == 0)
- return VOID;
- if (strncmp (tokstart, "bool", 4) == 0)
- return BOOL;
- if (strncmp (tokstart, "char", 4) == 0)
- return CHAR;
- if (strncmp (tokstart, "enum", 4) == 0)
- return ENUM;
- if (strncmp (tokstart, "long", 4) == 0)
- return LONG;
- if (strncmp (tokstart, "true", 4) == 0)
- return TRUEKEYWORD;
- break;
- case 3:
- HANDLE_SPECIAL ("VTT for ", DEMANGLE_COMPONENT_VTT);
- HANDLE_SPECIAL ("non-virtual thunk to ", DEMANGLE_COMPONENT_THUNK);
- if (strncmp (tokstart, "new", 3) == 0)
- return NEW;
- if (strncmp (tokstart, "int", 3) == 0)
- return INT_KEYWORD;
- break;
- default:
- break;
- }
-
- yylval.comp = make_name (tokstart, namelen);
- return NAME;
-}
-
-static void
-yyerror (char *msg)
-{
- if (global_errmsg)
- return;
-
- error_lexptr = prev_lexptr;
- global_errmsg = msg ? msg : "parse error";
-}
-
-/* Allocate all the components we'll need to build a tree. We generally
- allocate too many components, but the extra memory usage doesn't hurt
- because the trees are temporary. If we start keeping the trees for
- a longer lifetime we'll need to be cleverer. */
-static struct demangle_info *
-allocate_info (int comps)
-{
- struct demangle_info *ret;
-
- ret = malloc (sizeof (struct demangle_info)
- + sizeof (struct demangle_component) * (comps - 1));
- ret->used = 0;
- return ret;
-}
-
-/* Convert RESULT to a string. The return value is allocated
- using xmalloc. ESTIMATED_LEN is used only as a guide to the
- length of the result. This functions handles a few cases that
- cplus_demangle_print does not, specifically the global destructor
- and constructor labels. */
-
-char *
-cp_comp_to_string (struct demangle_component *result, int estimated_len)
-{
- char *str, *prefix = NULL, *buf;
- size_t err = 0;
-
- if (result->type == GLOBAL_DESTRUCTORS)
- {
- result = d_left (result);
- prefix = "global destructors keyed to ";
- }
- else if (result->type == GLOBAL_CONSTRUCTORS)
- {
- result = d_left (result);
- prefix = "global constructors keyed to ";
- }
-
- str = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, result, estimated_len, &err);
- if (str == NULL)
- return NULL;
-
- if (prefix == NULL)
- return str;
-
- buf = malloc (strlen (str) + strlen (prefix) + 1);
- strcpy (buf, prefix);
- strcat (buf, str);
- free (str);
- return (buf);
-}
-
-/* Convert a demangled name to a demangle_component tree. *MEMORY is set to the
- block of used memory that should be freed when finished with the
- tree. On error, NULL is returned, and an error message will be
- set in *ERRMSG (which does not need to be freed). */
-
-struct demangle_component *
-cp_demangled_name_to_comp (const char *demangled_name, void **memory,
- const char **errmsg)
-{
- static char errbuf[60];
- struct demangle_component *result;
-
- int len = strlen (demangled_name);
-
- len = len + len / 8;
- prev_lexptr = lexptr = demangled_name;
- error_lexptr = NULL;
- global_errmsg = NULL;
-
- demangle_info = allocate_info (len);
-
- if (yyparse ())
- {
- if (global_errmsg && errmsg)
- {
- snprintf (errbuf, sizeof (errbuf) - 2, "%s, near `%s",
- global_errmsg, error_lexptr);
- strcat (errbuf, "'");
- *errmsg = errbuf;
- }
- free (demangle_info);
- return NULL;
- }
-
- *memory = demangle_info;
- result = global_result;
- global_result = NULL;
-
- return result;
-}
-
-#ifdef TEST_CPNAMES
-
-static void
-cp_print (struct demangle_component *result)
-{
- char *str;
- size_t err = 0;
-
- if (result->type == GLOBAL_DESTRUCTORS)
- {
- result = d_left (result);
- fputs ("global destructors keyed to ", stdout);
- }
- else if (result->type == GLOBAL_CONSTRUCTORS)
- {
- result = d_left (result);
- fputs ("global constructors keyed to ", stdout);
- }
-
- str = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, result, 64, &err);
- if (str == NULL)
- return;
-
- fputs (str, stdout);
-
- free (str);
-}
-
-static char
-trim_chars (char *lexptr, char **extra_chars)
-{
- char *p = (char *) symbol_end (lexptr);
- char c = 0;
-
- if (*p)
- {
- c = *p;
- *p = 0;
- *extra_chars = p + 1;
- }
-
- return c;
-}
-
-int
-main (int argc, char **argv)
-{
- char *str2, *extra_chars, c;
- char buf[65536];
- int arg;
- const char *errmsg;
- void *memory;
- struct demangle_component *result;
-
- arg = 1;
- if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
- {
- yydebug = 1;
- arg++;
- }
-
- if (argv[arg] == NULL)
- while (fgets (buf, 65536, stdin) != NULL)
- {
- int len;
- buf[strlen (buf) - 1] = 0;
- /* Use DMGL_VERBOSE to get expanded standard substitutions. */
- c = trim_chars (buf, &extra_chars);
- str2 = cplus_demangle (buf, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
- if (str2 == NULL)
- {
- /* printf ("Demangling error\n"); */
- if (c)
- printf ("%s%c%s\n", buf, c, extra_chars);
- else
- printf ("%s\n", buf);
- continue;
- }
- result = cp_demangled_name_to_comp (str2, &memory, &errmsg);
- if (result == NULL)
- {
- fputs (errmsg, stderr);
- fputc ('\n', stderr);
- continue;
- }
-
- cp_print (result);
- free (memory);
-
- free (str2);
- if (c)
- {
- putchar (c);
- fputs (extra_chars, stdout);
- }
- putchar ('\n');
- }
- else
- {
- result = cp_demangled_name_to_comp (argv[arg], &memory, &errmsg);
- if (result == NULL)
- {
- fputs (errmsg, stderr);
- fputc ('\n', stderr);
- return 0;
- }
- cp_print (result);
- putchar ('\n');
- free (memory);
- }
- return 0;
-}
-
-#endif