/* YACC parser for C++ names, for GDB.
- Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2003-2019 Free Software Foundation, Inc.
Parts of the lexer are based on c-exp.y from GDB.
-This file is part of 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 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 3 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.
+ 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., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Note that malloc's and realloc's in this file are transformed to
xmalloc and xrealloc respectively by the same sed command in the
too messy, particularly when such includes can be inserted at random
times by the parser generator. */
+/* The Bison manual says that %pure-parser is deprecated, but we use
+ it anyway because it also works with Byacc. That is also why
+ this uses %lex-param and %parse-param rather than the simpler
+ %param -- Byacc does not support the latter. */
+%pure-parser
+%lex-param {struct cpname_state *state}
+%parse-param {struct cpname_state *state}
+
%{
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
+#include "defs.h"
+#include <unistd.h>
#include "safe-ctype.h"
-#include "libiberty.h"
#include "demangle.h"
+#include "cp-support.h"
+#include "c-support.h"
+#include "parser-defs.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;
+#define GDB_YY_REMAP_PREFIX cpname
+#include "yy-remap.h"
/* The components built by the parser are allocated ahead of time,
and cached in this structure. */
struct demangle_info {
int used;
- struct demangle_info *prev, *next;
+ struct demangle_info *next;
struct demangle_component comps[ALLOC_CHUNK];
};
-static struct demangle_info *demangle_info;
+%}
+
+%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;
+ const char *opname;
+ }
+
+%{
+
+struct cpname_state
+{
+ /* 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. */
+
+ const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
+
+ struct demangle_info *demangle_info;
+
+ /* The parse tree created by the parser is stored here after a
+ successful parse. */
+
+ struct demangle_component *global_result;
+
+ struct demangle_component *d_grab ();
+
+ /* Helper functions. These wrap the demangler tree interface,
+ handle allocation from our global store, and return the allocated
+ component. */
+
+ struct demangle_component *fill_comp (enum demangle_component_type d_type,
+ struct demangle_component *lhs,
+ struct demangle_component *rhs);
+
+ struct demangle_component *make_operator (const char *name, int args);
+
+ struct demangle_component *make_dtor (enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name);
+
+ struct demangle_component *make_builtin_type (const char *name);
-static struct demangle_component *
-d_grab (void)
+ struct demangle_component *make_name (const char *name, int len);
+
+ struct demangle_component *d_qualify (struct demangle_component *lhs,
+ int qualifiers, int is_method);
+
+ struct demangle_component *d_int_type (int flags);
+
+ struct demangle_component *d_unary (const char *name,
+ struct demangle_component *lhs);
+
+ struct demangle_component *d_binary (const char *name,
+ struct demangle_component *lhs,
+ struct demangle_component *rhs);
+
+ int parse_number (const char *p, int len, int parsed_float, YYSTYPE *lvalp);
+};
+
+struct demangle_component *
+cpname_state::d_grab ()
{
struct demangle_info *more;
{
if (demangle_info->next == NULL)
{
- more = malloc (sizeof (struct demangle_info));
- more->prev = demangle_info;
+ more = XNEW (struct demangle_info);
more->next = NULL;
demangle_info->next = more;
}
return &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 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
/* 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 *
+cpname_state::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;
-}
+ int i;
+
+ i = cplus_demangle_fill_component (ret, d_type, lhs, rhs);
+ gdb_assert (i);
-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 *
+cpname_state::make_operator (const char *name, int args)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_operator (ret, name, args);
+ int i;
+
+ i = cplus_demangle_fill_operator (ret, name, args);
+ gdb_assert (i);
+
return ret;
}
-static struct demangle_component *
-make_dtor (enum gnu_v3_dtor_kinds kind, struct demangle_component *name)
+struct demangle_component *
+cpname_state::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);
+ int i;
+
+ i = cplus_demangle_fill_dtor (ret, kind, name);
+ gdb_assert (i);
+
return ret;
}
-static struct demangle_component *
-make_builtin_type (const char *name)
+struct demangle_component *
+cpname_state::make_builtin_type (const char *name)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_builtin_type (ret, name);
+ int i;
+
+ i = cplus_demangle_fill_builtin_type (ret, name);
+ gdb_assert (i);
+
return ret;
}
-static struct demangle_component *
-make_name (const char *name, int len)
+struct demangle_component *
+cpname_state::make_name (const char *name, int len)
{
struct demangle_component *ret = d_grab ();
- cplus_demangle_fill_name (ret, name, len);
+ int i;
+
+ i = cplus_demangle_fill_name (ret, name, len);
+ gdb_assert (i);
+
return ret;
}
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
+static int yylex (YYSTYPE *, cpname_state *);
+static void yyerror (cpname_state *, const char *);
%}
-%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> exp exp1 type start start_opt oper colon_name
%type <comp> unqualified_name colon_ext_name
-%type <comp> template template_arg
+%type <comp> templ template_arg
%type <comp> builtin_type
%type <comp> typespec_2 array_indicator
%type <comp> colon_ext_only ext_only_name
/* 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. */
%%
result : start
- { global_result = $1; }
+ { state->global_result = $1; }
;
start : type
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); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME,
+ $1, $2.comp);
+ if ($3)
+ $$ = state->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); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ if ($3) $$ = state->fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); }
| conversion_op_name start_opt
{ $$ = $1.comp;
- if ($2) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2); }
+ if ($2) $$ = state->fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2); }
| conversion_op_name abstract_declarator_fn
{ if ($2.last)
{
}
/* If we have an arglist, build a function type. */
if ($2.fn.comp)
- $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1.comp, $2.fn.comp);
+ $$ = state->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);
+ if ($2.start) $$ = state->fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2.start);
}
;
demangler_special
: DEMANGLER_SPECIAL start
- { $$ = make_empty ($1);
- d_left ($$) = $2;
- d_right ($$) = NULL; }
+ { $$ = state->fill_comp ((enum demangle_component_type) $1, $2, 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; }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, $2, $4); }
;
-operator : OPERATOR NEW
- { $$ = make_operator ("new", 1); }
+oper : OPERATOR NEW
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = state->make_operator ("new", 3);
+ }
| OPERATOR DELETE
- { $$ = make_operator ("delete", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = state->make_operator ("delete ", 1);
+ }
| OPERATOR NEW '[' ']'
- { $$ = make_operator ("new[]", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = state->make_operator ("new[]", 3);
+ }
| OPERATOR DELETE '[' ']'
- { $$ = make_operator ("delete[]", 1); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = state->make_operator ("delete[] ", 1);
+ }
| OPERATOR '+'
- { $$ = make_operator ("+", 2); }
+ { $$ = state->make_operator ("+", 2); }
| OPERATOR '-'
- { $$ = make_operator ("-", 2); }
+ { $$ = state->make_operator ("-", 2); }
| OPERATOR '*'
- { $$ = make_operator ("*", 2); }
+ { $$ = state->make_operator ("*", 2); }
| OPERATOR '/'
- { $$ = make_operator ("/", 2); }
+ { $$ = state->make_operator ("/", 2); }
| OPERATOR '%'
- { $$ = make_operator ("%", 2); }
+ { $$ = state->make_operator ("%", 2); }
| OPERATOR '^'
- { $$ = make_operator ("^", 2); }
+ { $$ = state->make_operator ("^", 2); }
| OPERATOR '&'
- { $$ = make_operator ("&", 2); }
+ { $$ = state->make_operator ("&", 2); }
| OPERATOR '|'
- { $$ = make_operator ("|", 2); }
+ { $$ = state->make_operator ("|", 2); }
| OPERATOR '~'
- { $$ = make_operator ("~", 1); }
+ { $$ = state->make_operator ("~", 1); }
| OPERATOR '!'
- { $$ = make_operator ("!", 1); }
+ { $$ = state->make_operator ("!", 1); }
| OPERATOR '='
- { $$ = make_operator ("=", 2); }
+ { $$ = state->make_operator ("=", 2); }
| OPERATOR '<'
- { $$ = make_operator ("<", 2); }
+ { $$ = state->make_operator ("<", 2); }
| OPERATOR '>'
- { $$ = make_operator (">", 2); }
+ { $$ = state->make_operator (">", 2); }
| OPERATOR ASSIGN_MODIFY
- { $$ = make_operator ($2, 2); }
+ { $$ = state->make_operator ($2, 2); }
| OPERATOR LSH
- { $$ = make_operator ("<<", 2); }
+ { $$ = state->make_operator ("<<", 2); }
| OPERATOR RSH
- { $$ = make_operator (">>", 2); }
+ { $$ = state->make_operator (">>", 2); }
| OPERATOR EQUAL
- { $$ = make_operator ("==", 2); }
+ { $$ = state->make_operator ("==", 2); }
| OPERATOR NOTEQUAL
- { $$ = make_operator ("!=", 2); }
+ { $$ = state->make_operator ("!=", 2); }
| OPERATOR LEQ
- { $$ = make_operator ("<=", 2); }
+ { $$ = state->make_operator ("<=", 2); }
| OPERATOR GEQ
- { $$ = make_operator (">=", 2); }
+ { $$ = state->make_operator (">=", 2); }
| OPERATOR ANDAND
- { $$ = make_operator ("&&", 2); }
+ { $$ = state->make_operator ("&&", 2); }
| OPERATOR OROR
- { $$ = make_operator ("||", 2); }
+ { $$ = state->make_operator ("||", 2); }
| OPERATOR INCREMENT
- { $$ = make_operator ("++", 1); }
+ { $$ = state->make_operator ("++", 1); }
| OPERATOR DECREMENT
- { $$ = make_operator ("--", 1); }
+ { $$ = state->make_operator ("--", 1); }
| OPERATOR ','
- { $$ = make_operator (",", 2); }
+ { $$ = state->make_operator (",", 2); }
| OPERATOR ARROW '*'
- { $$ = make_operator ("->*", 2); }
+ { $$ = state->make_operator ("->*", 2); }
| OPERATOR ARROW
- { $$ = make_operator ("->", 2); }
+ { $$ = state->make_operator ("->", 2); }
| OPERATOR '(' ')'
- { $$ = make_operator ("()", 0); }
+ { $$ = state->make_operator ("()", 2); }
| OPERATOR '[' ']'
- { $$ = make_operator ("[]", 2); }
+ { $$ = state->make_operator ("[]", 2); }
;
/* Conversion operators. We don't try to handle some of
since it's not clear that it's parseable. */
conversion_op
: OPERATOR typespec_2
- { $$ = fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_CONVERSION, $2, NULL); }
;
conversion_op_name
/* DEMANGLE_COMPONENT_NAME */
/* This accepts certain invalid placements of '~'. */
-unqualified_name: operator
- | operator '<' template_params '>'
- { $$ = fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
+unqualified_name: oper
+ | oper '<' template_params '>'
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
| '~' NAME
- { $$ = make_dtor (gnu_v3_complete_object_dtor, $2); }
+ { $$ = state->make_dtor (gnu_v3_complete_object_dtor, $2); }
;
/* This rule is used in name and nested_name, and expanded inline there
name : nested_name NAME %prec NAME
{ $$ = $1.comp; d_right ($1.last) = $2; }
| NAME %prec NAME
- | nested_name template %prec NAME
+ | nested_name templ %prec NAME
{ $$ = $1.comp; d_right ($1.last) = $2; }
- | template %prec NAME
+ | templ %prec NAME
;
colon_ext_name : colon_name
;
nested_name : NAME COLONCOLON
- { $$.comp = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
- d_left ($$.comp) = $1;
- d_right ($$.comp) = NULL;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
| nested_name NAME COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = state->fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.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;
+ | templ COLONCOLON
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $1, NULL);
$$.last = $$.comp;
}
- | nested_name template COLONCOLON
+ | nested_name templ COLONCOLON
{ $$.comp = $1.comp;
- d_right ($1.last) = make_empty (DEMANGLE_COMPONENT_QUAL_NAME);
+ d_right ($1.last) = state->fill_comp (DEMANGLE_COMPONENT_QUAL_NAME, $2, NULL);
$$.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); }
+templ : NAME '<' template_params '>'
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); }
;
template_params : template_arg
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $1, NULL);
+ { $$.comp = state->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);
+ *$1.last = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, $3, NULL);
$$.last = &d_right (*$1.last);
}
;
*$2.last = $1;
}
| '&' start
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $2); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY, state->make_operator ("&", 1), $2); }
| '&' '(' start ')'
- { $$ = fill_comp (DEMANGLE_COMPONENT_UNARY, make_operator ("&", 1), $3); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY, state->make_operator ("&", 1), $3); }
| exp
;
function_args : typespec_2
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_ARGLIST, $1, NULL);
+ { $$.comp = state->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);
+ $$.comp = state->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);
+ { *$1.last = state->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);
+ *$1.last = state->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 ("..."),
+ = state->fill_comp (DEMANGLE_COMPONENT_ARGLIST,
+ state->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);
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, $2.comp);
$$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $4, 1); }
+ $$.comp = state->d_qualify ($$.comp, $4, 1); }
| '(' VOID ')' qualifiers_opt
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
$$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $4, 1); }
+ $$.comp = state->d_qualify ($$.comp, $4, 1); }
| '(' ')' qualifiers_opt
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, NULL, NULL);
$$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $3, 1); }
+ $$.comp = state->d_qualify ($$.comp, $3, 1); }
;
/* Should do something about DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL */
;
builtin_type : int_seq
- { $$ = d_int_type ($1); }
+ { $$ = state->d_int_type ($1); }
| FLOAT_KEYWORD
- { $$ = make_builtin_type ("float"); }
+ { $$ = state->make_builtin_type ("float"); }
| DOUBLE_KEYWORD
- { $$ = make_builtin_type ("double"); }
+ { $$ = state->make_builtin_type ("double"); }
| LONG DOUBLE_KEYWORD
- { $$ = make_builtin_type ("long double"); }
+ { $$ = state->make_builtin_type ("long double"); }
| BOOL
- { $$ = make_builtin_type ("bool"); }
+ { $$ = state->make_builtin_type ("bool"); }
| WCHAR_T
- { $$ = make_builtin_type ("wchar_t"); }
+ { $$ = state->make_builtin_type ("wchar_t"); }
| VOID
- { $$ = make_builtin_type ("void"); }
+ { $$ = state->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;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_POINTER, NULL, NULL);
$$.last = &d_left ($$.comp);
- $$.comp = d_qualify ($$.comp, $2, 0); }
+ $$.comp = state->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;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_REFERENCE, NULL, NULL);
+ $$.last = &d_left ($$.comp); }
+ | ANDAND
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_RVALUE_REFERENCE, NULL, NULL);
$$.last = &d_left ($$.comp); }
| nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $1.comp;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $1.comp, NULL);
/* 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); }
+ $$.comp = state->d_qualify ($$.comp, $3, 0); }
| COLONCOLON nested_name '*' qualifiers_opt
- { $$.comp = make_empty (DEMANGLE_COMPONENT_PTRMEM_TYPE);
- $$.comp->u.s_binary.left = $2.comp;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_PTRMEM_TYPE, $2.comp, NULL);
/* 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); }
+ $$.comp = state->d_qualify ($$.comp, $4, 0); }
;
array_indicator : '[' ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = NULL;
- }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, NULL, NULL); }
| '[' INT ']'
- { $$ = make_empty (DEMANGLE_COMPONENT_ARRAY_TYPE);
- d_left ($$) = $2;
- }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_ARRAY_TYPE, $2, NULL); }
;
/* Details of this approach inspired by the G++ < 3.4 parser. */
*/
typespec_2 : builtin_type qualifiers
- { $$ = d_qualify ($1, $2, 0); }
+ { $$ = state->d_qualify ($1, $2, 0); }
| builtin_type
| qualifiers builtin_type qualifiers
- { $$ = d_qualify ($2, $1 | $3, 0); }
+ { $$ = state->d_qualify ($2, $1 | $3, 0); }
| qualifiers builtin_type
- { $$ = d_qualify ($2, $1, 0); }
+ { $$ = state->d_qualify ($2, $1, 0); }
| name qualifiers
- { $$ = d_qualify ($1, $2, 0); }
+ { $$ = state->d_qualify ($1, $2, 0); }
| name
| qualifiers name qualifiers
- { $$ = d_qualify ($2, $1 | $3, 0); }
+ { $$ = state->d_qualify ($2, $1 | $3, 0); }
| qualifiers name
- { $$ = d_qualify ($2, $1, 0); }
+ { $$ = state->d_qualify ($2, $1, 0); }
| COLONCOLON name qualifiers
- { $$ = d_qualify ($2, $3, 0); }
+ { $$ = state->d_qualify ($2, $3, 0); }
| COLONCOLON name
{ $$ = $2; }
| qualifiers COLONCOLON name qualifiers
- { $$ = d_qualify ($3, $1 | $4, 0); }
+ { $$ = state->d_qualify ($3, $1 | $4, 0); }
| qualifiers COLONCOLON name
- { $$ = d_qualify ($3, $1, 0); }
+ { $$ = state->d_qualify ($3, $1, 0); }
;
abstract_declarator
$$.last = &d_right ($2);
}
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
;
$$.last = $1.last;
*$2.last = $1.comp; }
| colon_ext_name
- { $$.comp = make_empty (DEMANGLE_COMPONENT_TYPED_NAME);
- d_left ($$.comp) = $1;
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, NULL);
$$.last = &d_right ($$.comp);
}
| direct_declarator_1
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);
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
$$.last = $2.last;
- $$.comp = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
+ $$.comp = state->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);
+ $$.comp = state->fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$.comp, $4);
}
;
$$.last = &d_right ($2);
}
| colon_ext_name function_arglist
- { $$.comp = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp);
+ { $$.comp = state->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);
+ { $$.comp = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2);
$$.last = &d_right ($2);
}
;
;
exp1 : exp '>' exp
- { $$ = d_binary (">", $1, $3); }
+ { $$ = state->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); }
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY, state->make_operator ("&", 1), $2); }
+ | '&' '(' start ')'
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY, state->make_operator ("&", 1), $3); }
;
/* Expressions, not including the comma operator. */
exp : '-' exp %prec UNARY
- { $$ = d_unary ("-", $2); }
+ { $$ = state->d_unary ("-", $2); }
;
exp : '!' exp %prec UNARY
- { $$ = d_unary ("!", $2); }
+ { $$ = state->d_unary ("!", $2); }
;
exp : '~' exp %prec UNARY
- { $$ = d_unary ("~", $2); }
+ { $$ = state->d_unary ("~", $2); }
;
/* Casts. First your normal C-style cast. If exp is a LITERAL, just change
d_left ($4) = $2;
}
else
- $$ = fill_comp (DEMANGLE_COMPONENT_UNARY,
- fill_comp (DEMANGLE_COMPONENT_CAST, $2, NULL),
+ $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY,
+ state->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),
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY,
+ state->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),
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY,
+ state->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),
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_UNARY,
+ state->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);
- }
- ;
+/* Another form of C++-style cast is "type ( exp1 )". This creates too many
+ conflicts to support. For a while we supported the simpler
+ "typespec_2 ( exp1 )", but that conflicts with "& ( start )" as a
+ reference, deep within the wilderness of abstract declarators:
+ Qux<int(&(*))> vs Qux<int(&(var))>, a shift-reduce conflict at the
+ innermost left parenthesis. So we do not support function-like casts.
+ Fortunately they never appear in demangler output. */
/* TO INVESTIGATE: ._0 style anonymous names; anonymous namespaces */
/* Binary operators in order of decreasing precedence. */
exp : exp '*' exp
- { $$ = d_binary ("*", $1, $3); }
+ { $$ = state->d_binary ("*", $1, $3); }
;
exp : exp '/' exp
- { $$ = d_binary ("/", $1, $3); }
+ { $$ = state->d_binary ("/", $1, $3); }
;
exp : exp '%' exp
- { $$ = d_binary ("%", $1, $3); }
+ { $$ = state->d_binary ("%", $1, $3); }
;
exp : exp '+' exp
- { $$ = d_binary ("+", $1, $3); }
+ { $$ = state->d_binary ("+", $1, $3); }
;
exp : exp '-' exp
- { $$ = d_binary ("-", $1, $3); }
+ { $$ = state->d_binary ("-", $1, $3); }
;
exp : exp LSH exp
- { $$ = d_binary ("<<", $1, $3); }
+ { $$ = state->d_binary ("<<", $1, $3); }
;
exp : exp RSH exp
- { $$ = d_binary (">>", $1, $3); }
+ { $$ = state->d_binary (">>", $1, $3); }
;
exp : exp EQUAL exp
- { $$ = d_binary ("==", $1, $3); }
+ { $$ = state->d_binary ("==", $1, $3); }
;
exp : exp NOTEQUAL exp
- { $$ = d_binary ("!=", $1, $3); }
+ { $$ = state->d_binary ("!=", $1, $3); }
;
exp : exp LEQ exp
- { $$ = d_binary ("<=", $1, $3); }
+ { $$ = state->d_binary ("<=", $1, $3); }
;
exp : exp GEQ exp
- { $$ = d_binary (">=", $1, $3); }
+ { $$ = state->d_binary (">=", $1, $3); }
;
exp : exp '<' exp
- { $$ = d_binary ("<", $1, $3); }
+ { $$ = state->d_binary ("<", $1, $3); }
;
exp : exp '&' exp
- { $$ = d_binary ("&", $1, $3); }
+ { $$ = state->d_binary ("&", $1, $3); }
;
exp : exp '^' exp
- { $$ = d_binary ("^", $1, $3); }
+ { $$ = state->d_binary ("^", $1, $3); }
;
exp : exp '|' exp
- { $$ = d_binary ("|", $1, $3); }
+ { $$ = state->d_binary ("|", $1, $3); }
;
exp : exp ANDAND exp
- { $$ = d_binary ("&&", $1, $3); }
+ { $$ = state->d_binary ("&&", $1, $3); }
;
exp : exp OROR exp
- { $$ = d_binary ("||", $1, $3); }
+ { $$ = state->d_binary ("||", $1, $3); }
;
/* Not 100% sure these are necessary, but they're harmless. */
exp : exp ARROW NAME
- { $$ = d_binary ("->", $1, $3); }
+ { $$ = state->d_binary ("->", $1, $3); }
;
exp : exp '.' NAME
- { $$ = d_binary (".", $1, $3); }
+ { $$ = state->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)));
+ { $$ = state->fill_comp (DEMANGLE_COMPONENT_TRINARY, state->make_operator ("?", 3),
+ state->fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG1, $1,
+ state->fill_comp (DEMANGLE_COMPONENT_TRINARY_ARG2, $3, $5)));
}
;
;
exp : SIZEOF '(' type ')' %prec UNARY
- { $$ = d_unary ("sizeof", $3); }
+ {
+ /* Match the whitespacing of cplus_demangle_operators.
+ It would abort on unrecognized string otherwise. */
+ $$ = state->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 = state->make_name ("1", 1);
+ $$ = state->fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ state->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 = state->make_name ("0", 1);
+ $$ = state->fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ state->make_builtin_type ("bool"),
i);
}
;
may already be qualified; duplicate qualifiers are not created. */
struct demangle_component *
-d_qualify (struct demangle_component *lhs, int qualifiers, int is_method)
+cpname_state::d_qualify (struct demangle_component *lhs, int qualifiers,
+ int is_method)
{
struct demangle_component **inner_p;
enum demangle_component_type type;
#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 = fill_comp (is_method ? MTYPE : TYPE, \
+ *inner_p, NULL); \
inner_p = &d_left (*inner_p); \
type = (*inner_p)->type; \
} \
/* Return a builtin type corresponding to FLAGS. */
-static struct demangle_component *
-d_int_type (int flags)
+struct demangle_component *
+cpname_state::d_int_type (int flags)
{
const char *name;
/* Wrapper to create a unary operation. */
-static struct demangle_component *
-d_unary (const char *name, struct demangle_component *lhs)
+struct demangle_component *
+cpname_state::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)
+struct demangle_component *
+cpname_state::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));
+ fill_comp (DEMANGLE_COMPONENT_BINARY_ARGS, lhs, rhs));
}
/* Find the end of a symbol name starting at LEXPTR. */
{
const char *p = lexptr;
- while (*p && (ISALNUM (*p) || *p == '_' || *p == '$' || *p == '.'))
+ while (*p && (c_ident_is_alnum (*p) || *p == '_' || *p == '$' || *p == '.'))
p++;
return p;
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
+cpname_state::parse_number (const char *p, int len, int parsed_float,
+ YYSTYPE *lvalp)
{
int unsigned_p = 0;
return ERROR;
name = make_name (p, len);
- yylval.comp = fill_comp (literal_type, type, name);
+ lvalp->comp = fill_comp (literal_type, type, name);
return FLOAT;
}
type = signed_type;
name = make_name (p, len);
- yylval.comp = fill_comp (literal_type, type, name);
+ lvalp->comp = fill_comp (literal_type, type, name);
return INT;
}
-static char backslashable[] = "abefnrtv";
-static char represented[] = "\a\b\e\f\n\r\t\v";
+static const char backslashable[] = "abefnrtv";
+static const char represented[] = "\a\b\e\f\n\r\t\v";
/* Translate the backslash the way we would in the host character set. */
static int
after the zeros. A value of 0 does not mean end of string. */
static int
-parse_escape (const char **string_ptr)
+cp_parse_escape (const char **string_ptr)
{
int target_char;
int c = *(*string_ptr)++;
if (c == '?')
return 0177;
else if (c == '\\')
- target_char = parse_escape (string_ptr);
+ target_char = cp_parse_escape (string_ptr);
else
target_char = c;
#define HANDLE_SPECIAL(string, comp) \
if (strncmp (tokstart, string, sizeof (string) - 1) == 0) \
{ \
- lexptr = tokstart + sizeof (string) - 1; \
- yylval.lval = comp; \
+ state->lexptr = tokstart + sizeof (string) - 1; \
+ lvalp->lval = comp; \
return DEMANGLER_SPECIAL; \
}
#define HANDLE_TOKEN2(string, token) \
- if (lexptr[1] == string[1]) \
+ if (state->lexptr[1] == string[1]) \
{ \
- lexptr += 2; \
- yylval.opname = string; \
+ state->lexptr += 2; \
+ lvalp->opname = string; \
return token; \
}
#define HANDLE_TOKEN3(string, token) \
- if (lexptr[1] == string[1] && lexptr[2] == string[2]) \
+ if (state->lexptr[1] == string[1] && state->lexptr[2] == string[2]) \
{ \
- lexptr += 3; \
- yylval.opname = string; \
+ state->lexptr += 3; \
+ lvalp->opname = string; \
return token; \
}
/* Read one token, getting characters through LEXPTR. */
static int
-yylex (void)
+yylex (YYSTYPE *lvalp, cpname_state *state)
{
int c;
int namelen;
- const char *tokstart, *tokptr;
+ const char *tokstart;
retry:
- prev_lexptr = lexptr;
- tokstart = lexptr;
+ state->prev_lexptr = state->lexptr;
+ tokstart = state->lexptr;
switch (c = *tokstart)
{
case ' ':
case '\t':
case '\n':
- lexptr++;
+ state->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++;
+ state->lexptr++;
+ c = *state->lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = cp_parse_escape (&state->lexptr);
else if (c == '\'')
{
- yyerror ("empty character constant");
+ yyerror (state, _("empty character constant"));
return ERROR;
}
- c = *lexptr++;
+ c = *state->lexptr++;
if (c != '\'')
{
- yyerror ("invalid character constant");
+ yyerror (state, _("invalid character constant"));
return ERROR;
}
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));
+ lvalp->comp
+ = state->fill_comp (DEMANGLE_COMPONENT_LITERAL,
+ state->make_builtin_type ("char"),
+ state->make_name (tokstart,
+ state->lexptr - tokstart));
return INT;
case '(':
if (strncmp (tokstart, "(anonymous namespace)", 21) == 0)
{
- lexptr += 21;
- yylval.comp = make_name ("(anonymous namespace)",
- sizeof "(anonymous namespace)" - 1);
+ state->lexptr += 21;
+ lvalp->comp = state->make_name ("(anonymous namespace)",
+ sizeof "(anonymous namespace)" - 1);
return NAME;
}
/* FALL THROUGH */
case ')':
case ',':
- lexptr++;
+ state->lexptr++;
return c;
case '.':
- if (lexptr[1] == '.' && lexptr[2] == '.')
+ if (state->lexptr[1] == '.' && state->lexptr[2] == '.')
{
- lexptr += 3;
+ state->lexptr += 3;
return ELLIPSIS;
}
/* Might be a floating point number. */
- if (lexptr[1] < '0' || lexptr[1] > '9')
+ if (state->lexptr[1] < '0' || state->lexptr[1] > '9')
goto symbol; /* Nope, must be a symbol. */
goto try_number;
/* For construction vtables. This is kind of hokey. */
if (strncmp (tokstart, "-in-", 4) == 0)
{
- lexptr += 4;
+ state->lexptr += 4;
return CONSTRUCTION_IN;
}
- if (lexptr[1] < '0' || lexptr[1] > '9')
+ if (state->lexptr[1] < '0' || state->lexptr[1] > '9')
{
- lexptr++;
+ state->lexptr++;
return '-';
}
- /* FALL THRU into number case. */
+ /* FALL THRU. */
try_number:
case '0':
else if (! ISALNUM (*p))
break;
}
- toktype = parse_number (tokstart, p - tokstart, got_dot|got_e);
+ toktype = state->parse_number (tokstart, p - tokstart, got_dot|got_e,
+ lvalp);
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");
+ yyerror (state, _("invalid number"));
return ERROR;
}
- lexptr = p;
+ state->lexptr = p;
return toktype;
}
case '+':
HANDLE_TOKEN2 ("+=", ASSIGN_MODIFY);
HANDLE_TOKEN2 ("++", INCREMENT);
- lexptr++;
+ state->lexptr++;
return c;
case '*':
HANDLE_TOKEN2 ("*=", ASSIGN_MODIFY);
- lexptr++;
+ state->lexptr++;
return c;
case '/':
HANDLE_TOKEN2 ("/=", ASSIGN_MODIFY);
- lexptr++;
+ state->lexptr++;
return c;
case '%':
HANDLE_TOKEN2 ("%=", ASSIGN_MODIFY);
- lexptr++;
+ state->lexptr++;
return c;
case '|':
HANDLE_TOKEN2 ("|=", ASSIGN_MODIFY);
HANDLE_TOKEN2 ("||", OROR);
- lexptr++;
+ state->lexptr++;
return c;
case '&':
HANDLE_TOKEN2 ("&=", ASSIGN_MODIFY);
HANDLE_TOKEN2 ("&&", ANDAND);
- lexptr++;
+ state->lexptr++;
return c;
case '^':
HANDLE_TOKEN2 ("^=", ASSIGN_MODIFY);
- lexptr++;
+ state->lexptr++;
return c;
case '!':
HANDLE_TOKEN2 ("!=", NOTEQUAL);
- lexptr++;
+ state->lexptr++;
return c;
case '<':
HANDLE_TOKEN3 ("<<=", ASSIGN_MODIFY);
HANDLE_TOKEN2 ("<=", LEQ);
HANDLE_TOKEN2 ("<<", LSH);
- lexptr++;
+ state->lexptr++;
return c;
case '>':
HANDLE_TOKEN3 (">>=", ASSIGN_MODIFY);
HANDLE_TOKEN2 (">=", GEQ);
HANDLE_TOKEN2 (">>", RSH);
- lexptr++;
+ state->lexptr++;
return c;
case '=':
HANDLE_TOKEN2 ("==", EQUAL);
- lexptr++;
+ state->lexptr++;
return c;
case ':':
HANDLE_TOKEN2 ("::", COLONCOLON);
- lexptr++;
+ state->lexptr++;
return c;
case '[':
case '{':
case '}':
symbol:
- lexptr++;
+ state->lexptr++;
return c;
case '"':
/* These can't occur in C++ names. */
- yyerror ("unexpected string literal");
+ yyerror (state, _("unexpected string literal"));
return ERROR;
}
- if (!(c == '_' || c == '$' || ISALPHA (c)))
+ if (!(c == '_' || c == '$' || c_ident_is_alpha (c)))
{
/* We must have come across a bad character (e.g. ';'). */
- yyerror ("invalid character");
+ yyerror (state, _("invalid character"));
return ERROR;
}
namelen = 0;
do
c = tokstart[++namelen];
- while (ISALNUM (c) || c == '_' || c == '$');
+ while (c_ident_is_alnum (c) || c == '_' || c == '$');
- lexptr += namelen;
+ state->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
case 12:
if (strncmp (tokstart, "construction vtable for ", 24) == 0)
{
- lexptr = tokstart + 24;
+ state->lexptr = tokstart + 24;
return CONSTRUCTION_VTABLE;
}
if (strncmp (tokstart, "dynamic_cast", 12) == 0)
if (strncmp (tokstart, "global constructors keyed to ", 29) == 0)
{
const char *p;
- lexptr = tokstart + 29;
- yylval.typed_val_int.val = GLOBAL_CONSTRUCTORS;
+ state->lexptr = tokstart + 29;
+ lvalp->lval = DEMANGLE_COMPONENT_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;
+ p = symbol_end (state->lexptr);
+ lvalp->comp = state->make_name (state->lexptr, p - state->lexptr);
+ state->lexptr = p;
+ return DEMANGLER_SPECIAL;
}
if (strncmp (tokstart, "global destructors keyed to ", 28) == 0)
{
const char *p;
- lexptr = tokstart + 28;
- yylval.typed_val_int.val = GLOBAL_DESTRUCTORS;
+ state->lexptr = tokstart + 28;
+ lvalp->lval = DEMANGLE_COMPONENT_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;
+ p = symbol_end (state->lexptr);
+ lvalp->comp = state->make_name (state->lexptr, p - state->lexptr);
+ state->lexptr = p;
+ return DEMANGLER_SPECIAL;
}
HANDLE_SPECIAL ("vtable for ", DEMANGLE_COMPONENT_VTABLE);
break;
}
- yylval.comp = make_name (tokstart, namelen);
+ lvalp->comp = state->make_name (tokstart, namelen);
return NAME;
}
static void
-yyerror (char *msg)
+yyerror (cpname_state *state, const char *msg)
{
- if (global_errmsg)
+ if (state->global_errmsg)
return;
- error_lexptr = prev_lexptr;
- global_errmsg = msg ? msg : "parse error";
+ state->error_lexptr = state->prev_lexptr;
+ state->global_errmsg = msg ? msg : "parse error";
}
/* Allocate a chunk of 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 and the storage is
reused. More may be allocated later, by d_grab. */
-static void
+static struct demangle_info *
allocate_info (void)
{
- if (demangle_info == NULL)
- {
- demangle_info = malloc (sizeof (struct demangle_info));
- demangle_info->prev = NULL;
- demangle_info->next = NULL;
- }
- else
- while (demangle_info->prev)
- demangle_info = demangle_info->prev;
+ struct demangle_info *info = XNEW (struct demangle_info);
- demangle_info->used = 0;
+ info->next = NULL;
+ info->used = 0;
+ return info;
}
/* Convert RESULT to a string. The return value is allocated
cplus_demangle_print does not, specifically the global destructor
and constructor labels. */
-char *
+gdb::unique_xmalloc_ptr<char>
cp_comp_to_string (struct demangle_component *result, int estimated_len)
{
- char *str, *prefix = NULL, *buf;
- size_t err = 0;
+ size_t err;
- if (result->type == GLOBAL_DESTRUCTORS)
- {
- result = d_left (result);
- prefix = "global destructors keyed to ";
- }
- else if (result->type == GLOBAL_CONSTRUCTORS)
+ char *res = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI,
+ result, estimated_len, &err);
+ return gdb::unique_xmalloc_ptr<char> (res);
+}
+
+/* Constructor for demangle_parse_info. */
+
+demangle_parse_info::demangle_parse_info ()
+: info (NULL),
+ tree (NULL)
+{
+ obstack_init (&obstack);
+}
+
+/* Destructor for demangle_parse_info. */
+
+demangle_parse_info::~demangle_parse_info ()
+{
+ /* Free any allocated chunks of memory for the parse. */
+ while (info != NULL)
{
- result = d_left (result);
- prefix = "global constructors keyed to ";
+ struct demangle_info *next = info->next;
+
+ free (info);
+ info = next;
}
- str = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, result, estimated_len, &err);
- if (str == NULL)
- return NULL;
+ /* Free any memory allocated during typedef replacement. */
+ obstack_free (&obstack, NULL);
+}
- if (prefix == NULL)
- return str;
+/* Merge the two parse trees given by DEST and SRC. The parse tree
+ in SRC is attached to DEST at the node represented by TARGET.
- buf = malloc (strlen (str) + strlen (prefix) + 1);
- strcpy (buf, prefix);
- strcat (buf, str);
- free (str);
- return (buf);
+ NOTE 1: Since there is no API to merge obstacks, this function does
+ even attempt to try it. Fortunately, we do not (yet?) need this ability.
+ The code will assert if SRC->obstack is not empty.
+
+ NOTE 2: The string from which SRC was parsed must not be freed, since
+ this function will place pointers to that string into DEST. */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+ struct demangle_component *target,
+ struct demangle_parse_info *src)
+
+{
+ struct demangle_info *di;
+
+ /* Copy the SRC's parse data into DEST. */
+ *target = *src->tree;
+ di = dest->info;
+ while (di->next != NULL)
+ di = di->next;
+ di->next = src->info;
+
+ /* Clear the (pointer to) SRC's parse data so that it is not freed when
+ cp_demangled_parse_info_free is called. */
+ src->info = NULL;
}
/* Convert a demangled name to a demangle_component tree. On success,
- the root of the new tree is returned; it is valid until the next
- call to this function and should not be freed. On error, NULL is
- returned, and an error message will be set in *ERRMSG (which does
- not need to be freed). */
+ a structure containing the root of the new tree is returned. On
+ error, NULL is returned, and an error message will be set in
+ *ERRMSG. */
-struct demangle_component *
-cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
+struct std::unique_ptr<demangle_parse_info>
+cp_demangled_name_to_comp (const char *demangled_name,
+ std::string *errmsg)
{
- static char errbuf[60];
- struct demangle_component *result;
+ cpname_state state;
+
+ state.prev_lexptr = state.lexptr = demangled_name;
+ state.error_lexptr = NULL;
+ state.global_errmsg = NULL;
- prev_lexptr = lexptr = demangled_name;
- error_lexptr = NULL;
- global_errmsg = NULL;
+ state.demangle_info = allocate_info ();
- allocate_info ();
+ std::unique_ptr<demangle_parse_info> result (new demangle_parse_info);
+ result->info = state.demangle_info;
- if (yyparse ())
+ if (yyparse (&state))
{
- if (global_errmsg && errmsg)
- {
- snprintf (errbuf, sizeof (errbuf) - 2, "%s, near `%s",
- global_errmsg, error_lexptr);
- strcat (errbuf, "'");
- *errmsg = errbuf;
- }
+ if (state.global_errmsg && errmsg)
+ *errmsg = state.global_errmsg;
return NULL;
}
- result = global_result;
- global_result = NULL;
+ result->tree = state.global_result;
return 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;
return c;
}
+/* When this file is built as a standalone program, xmalloc comes from
+ libiberty --- in which case we have to provide xfree ourselves. */
+
+void
+xfree (void *ptr)
+{
+ if (ptr != NULL)
+ {
+ /* Literal `free' would get translated back to xfree again. */
+ CONCAT2 (fr,ee) (ptr);
+ }
+}
+
+/* GDB normally defines internal_error itself, but when this file is built
+ as a standalone program, we must also provide an implementation. */
+
+void
+internal_error (const char *file, int line, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (stderr, "%s:%d: internal error: ", file, line);
+ vfprintf (stderr, fmt, ap);
+ exit (1);
+}
+
int
main (int argc, char **argv)
{
- char *str2, *extra_chars = "", c;
+ char *str2, *extra_chars, c;
char buf[65536];
int arg;
- const char *errmsg;
- struct demangle_component *result;
arg = 1;
if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
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"); */
+ 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, &errmsg);
+
+ std::string errmsg;
+ std::unique_ptr<demangle_parse_info> result
+ = cp_demangled_name_to_comp (str2, &errmsg);
if (result == NULL)
{
- fputs (errmsg, stderr);
+ fputs (errmsg.c_str (), stderr);
fputc ('\n', stderr);
continue;
}
- cp_print (result);
+ cp_print (result->tree);
free (str2);
if (c)
}
else
{
- result = cp_demangled_name_to_comp (argv[arg], &errmsg);
+ std::string errmsg;
+ std::unique_ptr<demangle_parse_info> result
+ = cp_demangled_name_to_comp (argv[arg], &errmsg);
if (result == NULL)
{
- fputs (errmsg, stderr);
+ fputs (errmsg.c_str (), stderr);
fputc ('\n', stderr);
return 0;
}
- cp_print (result);
+ cp_print (result->tree);
putchar ('\n');
}
return 0;