/* YACC parser for C expressions, for GDB.
- Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2003, 2004, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "dfp.h"
#include "gdb_assert.h"
#include "macroscope.h"
+#include "objc-lang.h"
+#include "typeprint.h"
+#include "cp-abi.h"
#define parse_type builtin_type (parse_gdbarch)
#define yygindex c_yygindex
#define yytable c_yytable
#define yycheck c_yycheck
+#define yyss c_yyss
+#define yysslim c_yysslim
+#define yyssp c_yyssp
+#define yystacksize c_yystacksize
+#define yyvs c_yyvs
+#define yyvsp c_yyvsp
#ifndef YYDEBUG
#define YYDEBUG 1 /* Default to yydebug support */
struct internalvar *ivar;
struct stoken_vector svec;
- struct type **tvec;
+ VEC (type_ptr) *tvec;
int *ivec;
+
+ struct type_stack *type_stack;
+
+ struct objc_class_str class;
}
%{
/* YYSTYPE gets defined by %union */
static int parse_number (char *, int, int, YYSTYPE *);
static struct stoken operator_stoken (const char *);
+static void check_parameter_typelist (VEC (type_ptr) *);
%}
%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
%type <lval> rcurly
%type <tval> type typebase
-%type <tvec> nonempty_typelist
+%type <tvec> nonempty_typelist func_mod parameter_typelist
/* %type <bval> block */
/* Fancy type parsing. */
-%type <voidval> func_mod direct_abs_decl abs_decl
%type <tval> ptype
%type <lval> array_mod
+%type <tval> conversion_type_id
+
+%type <type_stack> ptr_operator_ts abs_decl direct_abs_decl
%token <typed_val_int> INT
%token <typed_val_float> FLOAT
nonterminal "name", which matches either NAME or TYPENAME. */
%token <tsval> STRING
+%token <sval> NSSTRING /* ObjC Foundation "NSString" literal */
+%token SELECTOR /* ObjC "@selector" pseudo-operator */
%token <tsval> CHAR
%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <ssym> UNKNOWN_CPP_NAME
%token <voidval> COMPLETE
%token <tsym> TYPENAME
+%token <class> CLASSNAME /* ObjC Class name */
%type <sval> name
%type <svec> string_exp
%type <ssym> name_not_typename
%type <tsym> typename
+ /* This is like a '[' token, but is only generated when parsing
+ Objective C. This lets us reuse the same parser without
+ erroneously parsing ObjC-specific expressions in C. */
+%token OBJC_LBRAC
+
/* A NAME_OR_INT is a symbol which is not known in the symbol table,
but which would parse as a valid number in the current input radix.
E.g. "c" when input_radix==16. Depending on the parse, it will be
%token NEW DELETE
%type <sval> operator
%token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
+%token ENTRY
+%token TYPEOF
+%token DECLTYPE
/* Special type cases, put in to allow the parser to distinguish different
legal basetypes. */
%left '+' '-'
%left '*' '/' '%'
%right UNARY INCREMENT DECREMENT
-%right ARROW ARROW_STAR '.' DOT_STAR '[' '('
+%right ARROW ARROW_STAR '.' DOT_STAR '[' OBJC_LBRAC '('
%token <ssym> BLOCKNAME
%token <bval> FILENAME
%type <bval> block
%left COLONCOLON
+%token DOTDOTDOT
+
\f
%%
{ write_exp_elt_opcode(OP_TYPE);
write_exp_elt_type($1);
write_exp_elt_opcode(OP_TYPE);}
+ | TYPEOF '(' exp ')'
+ {
+ write_exp_elt_opcode (OP_TYPEOF);
+ }
+ | TYPEOF '(' type ')'
+ {
+ write_exp_elt_opcode (OP_TYPE);
+ write_exp_elt_type ($3);
+ write_exp_elt_opcode (OP_TYPE);
+ }
+ | DECLTYPE '(' exp ')'
+ {
+ write_exp_elt_opcode (OP_DECLTYPE);
+ }
;
/* Expressions, including the comma operator. */
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
;
+exp : exp OBJC_LBRAC exp1 ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+ ;
+
+/*
+ * The rules below parse ObjC message calls of the form:
+ * '[' target selector {':' argument}* ']'
+ */
+
+exp : OBJC_LBRAC TYPENAME
+ {
+ CORE_ADDR class;
+
+ class = lookup_objc_class (parse_gdbarch,
+ copy_name ($2.stoken));
+ if (class == 0)
+ error (_("%s is not an ObjC Class"),
+ copy_name ($2.stoken));
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (parse_type->builtin_int);
+ write_exp_elt_longcst ((LONGEST) class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+exp : OBJC_LBRAC CLASSNAME
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (parse_type->builtin_int);
+ write_exp_elt_longcst ((LONGEST) $2.class);
+ write_exp_elt_opcode (OP_LONG);
+ start_msglist();
+ }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+exp : OBJC_LBRAC exp
+ { start_msglist(); }
+ msglist ']'
+ { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ end_msglist();
+ write_exp_elt_opcode (OP_OBJC_MSGCALL);
+ }
+ ;
+
+msglist : name
+ { add_msglist(&$1, 0); }
+ | msgarglist
+ ;
+
+msgarglist : msgarg
+ | msgarglist msgarg
+ ;
+
+msgarg : name ':' exp
+ { add_msglist(&$1, 1); }
+ | ':' exp /* Unnamed arg. */
+ { add_msglist(0, 1); }
+ | ',' exp /* Variable number of args. */
+ { add_msglist(0, 0); }
+ ;
+
exp : exp '('
/* This is to save the value of arglist_len
being accumulated by an outer function call. */
write_exp_elt_opcode (OP_FUNCALL); }
;
+exp : UNKNOWN_CPP_NAME '('
+ {
+ /* This could potentially be a an argument defined
+ lookup function (Koenig). */
+ write_exp_elt_opcode (OP_ADL_FUNC);
+ write_exp_elt_block (expression_context_block);
+ write_exp_elt_sym (NULL); /* Placeholder. */
+ write_exp_string ($1.stoken);
+ write_exp_elt_opcode (OP_ADL_FUNC);
+
+ /* This is to save the value of arglist_len
+ being accumulated by an outer function call. */
+
+ start_arglist ();
+ }
+ arglist ')' %prec ARROW
+ {
+ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL);
+ }
+ ;
+
lcurly : '{'
{ start_arglist (); }
;
{ arglist_len++; }
;
-exp : exp '(' nonempty_typelist ')' const_or_volatile
+exp : exp '(' parameter_typelist ')' const_or_volatile
{ int i;
+ VEC (type_ptr) *type_list = $3;
+ struct type *type_elt;
+ LONGEST len = VEC_length (type_ptr, type_list);
+
write_exp_elt_opcode (TYPE_INSTANCE);
- write_exp_elt_longcst ((LONGEST) $<ivec>3[0]);
- for (i = 0; i < $<ivec>3[0]; ++i)
- write_exp_elt_type ($<tvec>3[i + 1]);
- write_exp_elt_longcst((LONGEST) $<ivec>3[0]);
+ write_exp_elt_longcst (len);
+ for (i = 0;
+ VEC_iterate (type_ptr, type_list, i, type_elt);
+ ++i)
+ write_exp_elt_type (type_elt);
+ write_exp_elt_longcst(len);
write_exp_elt_opcode (TYPE_INSTANCE);
- free ($3);
+ VEC_free (type_ptr, type_list);
}
;
write_exp_elt_opcode (OP_ARRAY); }
;
-exp : lcurly type rcurly exp %prec UNARY
- { write_exp_elt_opcode (UNOP_MEMVAL);
- write_exp_elt_type ($2);
- write_exp_elt_opcode (UNOP_MEMVAL); }
+exp : lcurly type_exp rcurly exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_MEMVAL_TYPE); }
;
-exp : '(' type ')' exp %prec UNARY
- { write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type ($2);
- write_exp_elt_opcode (UNOP_CAST); }
+exp : '(' type_exp ')' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST_TYPE); }
;
exp : '(' exp1 ')'
}
;
+exp : SELECTOR '(' name ')'
+ {
+ write_exp_elt_opcode (OP_OBJC_SELECTOR);
+ write_exp_string ($3);
+ write_exp_elt_opcode (OP_OBJC_SELECTOR); }
+ ;
+
exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (parse_type->builtin_int);
+ write_exp_elt_type (lookup_signed_typename
+ (parse_language, parse_gdbarch,
+ "int"));
CHECK_TYPEDEF ($3);
write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
;
-exp : REINTERPRET_CAST '<' type '>' '(' exp ')' %prec UNARY
- { write_exp_elt_opcode (UNOP_REINTERPRET_CAST);
- write_exp_elt_type ($3);
- write_exp_elt_opcode (UNOP_REINTERPRET_CAST); }
+exp : REINTERPRET_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_REINTERPRET_CAST); }
;
-exp : STATIC_CAST '<' type '>' '(' exp ')' %prec UNARY
- { write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type ($3);
- write_exp_elt_opcode (UNOP_CAST); }
+exp : STATIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_CAST_TYPE); }
;
-exp : DYNAMIC_CAST '<' type '>' '(' exp ')' %prec UNARY
- { write_exp_elt_opcode (UNOP_DYNAMIC_CAST);
- write_exp_elt_type ($3);
- write_exp_elt_opcode (UNOP_DYNAMIC_CAST); }
+exp : DYNAMIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+ { write_exp_elt_opcode (UNOP_DYNAMIC_CAST); }
;
-exp : CONST_CAST '<' type '>' '(' exp ')' %prec UNARY
+exp : CONST_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
{ /* We could do more error checking here, but
it doesn't seem worthwhile. */
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type ($3);
- write_exp_elt_opcode (UNOP_CAST); }
+ write_exp_elt_opcode (UNOP_CAST_TYPE); }
;
string_exp:
case C_STRING_32:
if (type != C_STRING
&& type != $1.tokens[i].type)
- error ("Undefined string concatenation.");
+ error (_("Undefined string concatenation."));
type = $1.tokens[i].type;
break;
default:
}
;
+exp : NSSTRING /* ObjC NextStep NSString constant
+ * of the form '@' '"' string '"'.
+ */
+ { write_exp_elt_opcode (OP_OBJC_NSSTRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_OBJC_NSSTRING); }
+ ;
+
/* C++. */
exp : TRUEKEYWORD
{ write_exp_elt_opcode (OP_LONG);
if ($1.sym)
$$ = SYMBOL_BLOCK_VALUE ($1.sym);
else
- error ("No file or function \"%s\".",
+ error (_("No file or function \"%s\"."),
copy_name ($1.stoken));
}
| FILENAME
block : block COLONCOLON name
{ struct symbol *tem
= lookup_symbol (copy_name ($3), $1,
- VAR_DOMAIN, (int *) NULL);
+ VAR_DOMAIN, NULL);
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
- error ("No function \"%s\" in specified context.",
+ error (_("No function \"%s\" in specified context."),
copy_name ($3));
$$ = SYMBOL_BLOCK_VALUE (tem); }
;
+variable: name_not_typename ENTRY
+ { struct symbol *sym = $1.sym;
+
+ if (sym == NULL || !SYMBOL_IS_ARGUMENT (sym)
+ || !symbol_read_needs_frame (sym))
+ error (_("@entry can be used only for function "
+ "parameters, not for \"%s\""),
+ copy_name ($1.stoken));
+
+ write_exp_elt_opcode (OP_VAR_ENTRY_VALUE);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_ENTRY_VALUE);
+ }
+ ;
+
variable: block COLONCOLON name
{ struct symbol *sym;
sym = lookup_symbol (copy_name ($3), $1,
- VAR_DOMAIN, (int *) NULL);
+ VAR_DOMAIN, NULL);
if (sym == 0)
- error ("No symbol \"%s\" in specified context.",
+ error (_("No symbol \"%s\" in specified context."),
copy_name ($3));
+ if (symbol_read_needs_frame (sym))
+ {
+ if (innermost_block == 0
+ || contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
write_exp_elt_opcode (OP_VAR_VALUE);
/* block_found is set by lookup_symbol. */
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
- error ("`%s' is not defined as an aggregate type.",
+ error (_("`%s' is not defined as an aggregate type."),
TYPE_NAME (type));
write_exp_elt_opcode (OP_SCOPE);
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
- error ("`%s' is not defined as an aggregate type.",
+ error (_("`%s' is not defined as an aggregate type."),
TYPE_NAME (type));
tmp_token.ptr = (char*) alloca ($4.length + 2);
tmp_token.ptr[tmp_token.length] = 0;
/* Check for valid destructor name. */
- destructor_name_p (tmp_token.ptr, type);
+ destructor_name_p (tmp_token.ptr, $1.type);
write_exp_elt_opcode (OP_SCOPE);
write_exp_elt_type (type);
write_exp_string (tmp_token);
sym =
lookup_symbol (name, (const struct block *) NULL,
- VAR_DOMAIN, (int *) NULL);
+ VAR_DOMAIN, NULL);
if (sym)
{
write_exp_elt_opcode (OP_VAR_VALUE);
if (msymbol != NULL)
write_exp_msymbol (msymbol);
else if (!have_full_symbols () && !have_partial_symbols ())
- error ("No symbol table is loaded. Use the \"file\" command.");
+ error (_("No symbol table is loaded. Use the \"file\" command."));
else
- error ("No symbol \"%s\" in current context.", name);
+ error (_("No symbol \"%s\" in current context."), name);
}
;
if (msymbol != NULL)
write_exp_msymbol (msymbol);
else if (!have_full_symbols () && !have_partial_symbols ())
- error ("No symbol table is loaded. Use the \"file\" command.");
+ error (_("No symbol table is loaded. Use the \"file\" command."));
else
- error ("No symbol \"%s\" in current context.",
+ error (_("No symbol \"%s\" in current context."),
copy_name ($1.stoken));
}
}
;
space_identifier : '@' NAME
- { push_type_address_space (copy_name ($2.stoken));
- push_type (tp_space_identifier);
- }
+ { insert_type_address_space (copy_name ($2.stoken)); }
;
const_or_volatile: const_or_volatile_noopt
|
;
-abs_decl: '*'
- { push_type (tp_pointer); $$ = 0; }
- | '*' abs_decl
- { push_type (tp_pointer); $$ = $2; }
+ptr_operator:
+ ptr_operator '*'
+ { insert_type (tp_pointer); }
+ const_or_volatile_or_space_identifier
+ | '*'
+ { insert_type (tp_pointer); }
+ const_or_volatile_or_space_identifier
| '&'
- { push_type (tp_reference); $$ = 0; }
- | '&' abs_decl
- { push_type (tp_reference); $$ = $2; }
+ { insert_type (tp_reference); }
+ | '&' ptr_operator
+ { insert_type (tp_reference); }
+ ;
+
+ptr_operator_ts: ptr_operator
+ {
+ $$ = get_type_stack ();
+ /* This cleanup is eventually run by
+ c_parse. */
+ make_cleanup (type_stack_cleanup, $$);
+ }
+ ;
+
+abs_decl: ptr_operator_ts direct_abs_decl
+ { $$ = append_type_stack ($2, $1); }
+ | ptr_operator_ts
| direct_abs_decl
;
{ $$ = $2; }
| direct_abs_decl array_mod
{
+ push_type_stack ($1);
push_type_int ($2);
push_type (tp_array);
+ $$ = get_type_stack ();
}
| array_mod
{
push_type_int ($1);
push_type (tp_array);
- $$ = 0;
+ $$ = get_type_stack ();
}
| direct_abs_decl func_mod
- { push_type (tp_function); }
+ {
+ push_type_stack ($1);
+ push_typelist ($2);
+ $$ = get_type_stack ();
+ }
| func_mod
- { push_type (tp_function); }
+ {
+ push_typelist ($1);
+ $$ = get_type_stack ();
+ }
;
array_mod: '[' ']'
{ $$ = -1; }
+ | OBJC_LBRAC ']'
+ { $$ = -1; }
| '[' INT ']'
{ $$ = $2.val; }
+ | OBJC_LBRAC INT ']'
+ { $$ = $2.val; }
;
func_mod: '(' ')'
- { $$ = 0; }
- | '(' nonempty_typelist ')'
- { free ($2); $$ = 0; }
+ { $$ = NULL; }
+ | '(' parameter_typelist ')'
+ { $$ = $2; }
;
/* We used to try to recognize pointer to member types here, but
: TYPENAME
{ $$ = $1.type; }
| INT_KEYWORD
- { $$ = parse_type->builtin_int; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "int"); }
| LONG
- { $$ = parse_type->builtin_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| SHORT
- { $$ = parse_type->builtin_short; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| LONG INT_KEYWORD
- { $$ = parse_type->builtin_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = parse_type->builtin_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| LONG SIGNED_KEYWORD
- { $$ = parse_type->builtin_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| SIGNED_KEYWORD LONG INT_KEYWORD
- { $$ = parse_type->builtin_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| UNSIGNED LONG INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| LONG UNSIGNED INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| LONG UNSIGNED
- { $$ = parse_type->builtin_unsigned_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long"); }
| LONG LONG
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| LONG LONG INT_KEYWORD
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| LONG LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| LONG LONG SIGNED_KEYWORD
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| SIGNED_KEYWORD LONG LONG
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| SIGNED_KEYWORD LONG LONG INT_KEYWORD
- { $$ = parse_type->builtin_long_long; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| UNSIGNED LONG LONG
- { $$ = parse_type->builtin_unsigned_long_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| UNSIGNED LONG LONG INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_long_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| LONG LONG UNSIGNED
- { $$ = parse_type->builtin_unsigned_long_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| LONG LONG UNSIGNED INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_long_long; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "long long"); }
| SHORT INT_KEYWORD
- { $$ = parse_type->builtin_short; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| SHORT SIGNED_KEYWORD INT_KEYWORD
- { $$ = parse_type->builtin_short; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| SHORT SIGNED_KEYWORD
- { $$ = parse_type->builtin_short; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| UNSIGNED SHORT INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_short; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| SHORT UNSIGNED
- { $$ = parse_type->builtin_unsigned_short; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| SHORT UNSIGNED INT_KEYWORD
- { $$ = parse_type->builtin_unsigned_short; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "short"); }
| DOUBLE_KEYWORD
- { $$ = parse_type->builtin_double; }
+ { $$ = lookup_typename (parse_language, parse_gdbarch,
+ "double", (struct block *) NULL,
+ 0); }
| LONG DOUBLE_KEYWORD
- { $$ = parse_type->builtin_long_double; }
+ { $$ = lookup_typename (parse_language, parse_gdbarch,
+ "long double",
+ (struct block *) NULL, 0); }
| STRUCT name
{ $$ = lookup_struct (copy_name ($2),
expression_context_block); }
+ | STRUCT COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_STRUCT, "", 0);
+ $$ = NULL;
+ }
+ | STRUCT name COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_STRUCT, $2.ptr,
+ $2.length);
+ $$ = NULL;
+ }
| CLASS name
{ $$ = lookup_struct (copy_name ($2),
expression_context_block); }
+ | CLASS COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_CLASS, "", 0);
+ $$ = NULL;
+ }
+ | CLASS name COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_CLASS, $2.ptr,
+ $2.length);
+ $$ = NULL;
+ }
| UNION name
{ $$ = lookup_union (copy_name ($2),
expression_context_block); }
+ | UNION COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_UNION, "", 0);
+ $$ = NULL;
+ }
+ | UNION name COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_UNION, $2.ptr,
+ $2.length);
+ $$ = NULL;
+ }
| ENUM name
{ $$ = lookup_enum (copy_name ($2),
expression_context_block); }
+ | ENUM COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_ENUM, "", 0);
+ $$ = NULL;
+ }
+ | ENUM name COMPLETE
+ {
+ mark_completion_tag (TYPE_CODE_ENUM, $2.ptr,
+ $2.length);
+ $$ = NULL;
+ }
| UNSIGNED typename
{ $$ = lookup_unsigned_typename (parse_language,
parse_gdbarch,
TYPE_NAME($2.type)); }
| UNSIGNED
- { $$ = parse_type->builtin_unsigned_int; }
+ { $$ = lookup_unsigned_typename (parse_language,
+ parse_gdbarch,
+ "int"); }
| SIGNED_KEYWORD typename
{ $$ = lookup_signed_typename (parse_language,
parse_gdbarch,
TYPE_NAME($2.type)); }
| SIGNED_KEYWORD
- { $$ = parse_type->builtin_int; }
+ { $$ = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "int"); }
/* It appears that this rule for templates is never
reduced; template recognition happens by lookahead
in the token processing code in yylex. */
{
$$.stoken.ptr = "int";
$$.stoken.length = 3;
- $$.type = parse_type->builtin_int;
+ $$.type = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "int");
}
| LONG
{
$$.stoken.ptr = "long";
$$.stoken.length = 4;
- $$.type = parse_type->builtin_long;
+ $$.type = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "long");
}
| SHORT
{
$$.stoken.ptr = "short";
$$.stoken.length = 5;
- $$.type = parse_type->builtin_short;
+ $$.type = lookup_signed_typename (parse_language,
+ parse_gdbarch,
+ "short");
}
;
+parameter_typelist:
+ nonempty_typelist
+ { check_parameter_typelist ($1); }
+ | nonempty_typelist ',' DOTDOTDOT
+ {
+ VEC_safe_push (type_ptr, $1, NULL);
+ check_parameter_typelist ($1);
+ $$ = $1;
+ }
+ ;
+
nonempty_typelist
: type
- { $$ = (struct type **) malloc (sizeof (struct type *) * 2);
- $<ivec>$[0] = 1; /* Number of types in vector */
- $$[1] = $1;
+ {
+ VEC (type_ptr) *typelist = NULL;
+ VEC_safe_push (type_ptr, typelist, $1);
+ $$ = typelist;
}
| nonempty_typelist ',' type
- { int len = sizeof (struct type *) * (++($<ivec>1[0]) + 1);
- $$ = (struct type **) realloc ((char *) $1, len);
- $$[$<ivec>$[0]] = $3;
+ {
+ VEC_safe_push (type_ptr, $1, $3);
+ $$ = $1;
}
;
ptype : typebase
- | ptype const_or_volatile_or_space_identifier abs_decl const_or_volatile_or_space_identifier
+ | ptype abs_decl
+ {
+ push_type_stack ($2);
+ $$ = follow_types ($1);
+ }
+ ;
+
+conversion_type_id: typebase conversion_declarator
{ $$ = follow_types ($1); }
;
+conversion_declarator: /* Nothing. */
+ | ptr_operator conversion_declarator
+ ;
+
const_and_volatile: CONST_KEYWORD VOLATILE_KEYWORD
| VOLATILE_KEYWORD CONST_KEYWORD
;
const_or_volatile_noopt: const_and_volatile
- { push_type (tp_const);
- push_type (tp_volatile);
+ { insert_type (tp_const);
+ insert_type (tp_volatile);
}
| CONST_KEYWORD
- { push_type (tp_const); }
+ { insert_type (tp_const); }
| VOLATILE_KEYWORD
- { push_type (tp_volatile); }
+ { insert_type (tp_volatile); }
;
operator: OPERATOR NEW
{ $$ = operator_stoken (" new[]"); }
| OPERATOR DELETE '[' ']'
{ $$ = operator_stoken (" delete[]"); }
+ | OPERATOR NEW OBJC_LBRAC ']'
+ { $$ = operator_stoken (" new[]"); }
+ | OPERATOR DELETE OBJC_LBRAC ']'
+ { $$ = operator_stoken (" delete[]"); }
| OPERATOR '+'
{ $$ = operator_stoken ("+"); }
| OPERATOR '-'
{ $$ = operator_stoken ("()"); }
| OPERATOR '[' ']'
{ $$ = operator_stoken ("[]"); }
- | OPERATOR ptype
+ | OPERATOR OBJC_LBRAC ']'
+ { $$ = operator_stoken ("[]"); }
+ | OPERATOR conversion_type_id
{ char *name;
long length;
struct ui_file *buf = mem_fileopen ();
- c_print_type ($2, NULL, buf, -1, 0);
+ c_print_type ($2, NULL, buf, -1, 0,
+ &type_print_raw_options);
name = ui_file_xstrdup (buf, &length);
ui_file_delete (buf);
$$ = operator_stoken (name);
| BLOCKNAME { $$ = $1.stoken; }
| TYPENAME { $$ = $1.stoken; }
| NAME_OR_INT { $$ = $1.stoken; }
+ | UNKNOWN_CPP_NAME { $$ = $1.stoken; }
| operator { $$ = $1; }
;
context where only a name could occur, this might be useful.
| NAME_OR_INT
*/
+ | operator
+ {
+ struct field_of_this_result is_a_field_of_this;
+
+ $$.stoken = $1;
+ $$.sym = lookup_symbol ($1.ptr,
+ expression_context_block,
+ VAR_DOMAIN,
+ &is_a_field_of_this);
+ $$.is_a_field_of_this
+ = is_a_field_of_this.type != NULL;
+ }
+ | UNKNOWN_CPP_NAME
;
%%
return st;
};
+/* Validate a parameter typelist. */
+
+static void
+check_parameter_typelist (VEC (type_ptr) *params)
+{
+ struct type *type;
+ int ix;
+
+ for (ix = 0; VEC_iterate (type_ptr, params, ix, type); ++ix)
+ {
+ if (type != NULL && TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID)
+ {
+ if (ix == 0)
+ {
+ if (VEC_length (type_ptr, params) == 1)
+ {
+ /* Ok. */
+ break;
+ }
+ VEC_free (type_ptr, params);
+ error (_("parameter types following 'void'"));
+ }
+ else
+ {
+ VEC_free (type_ptr, params);
+ error (_("'void' invalid as parameter type"));
+ }
+ }
+ }
+}
+
/* Take care of parsing a number (anything that starts with a digit).
Set yylval and return the token type; update lexptr.
LEN is the number of characters in it. */
if (parsed_float)
{
- /* It's a float since it contains a point or an exponent. */
- char *s;
- int num; /* number of tokens scanned by scanf */
- char saved_char;
-
/* If it ends at "df", "dd" or "dl", take it as type of decimal floating
point. Return DECFLOAT. */
return DECFLOAT;
}
- s = malloc (len);
- saved_char = p[len];
- p[len] = 0; /* null-terminate the token */
- num = sscanf (p, "%" DOUBLEST_SCAN_FORMAT "%s",
- &putithere->typed_val_float.dval, s);
- p[len] = saved_char; /* restore the input stream */
-
- if (num == 1)
- putithere->typed_val_float.type =
- parse_type->builtin_double;
-
- if (num == 2 )
- {
- /* See if it has any float suffix: 'f' for float, 'l' for long
- double. */
- if (!strcasecmp (s, "f"))
- putithere->typed_val_float.type =
- parse_type->builtin_float;
- else if (!strcasecmp (s, "l"))
- putithere->typed_val_float.type =
- parse_type->builtin_long_double;
- else
- {
- free (s);
- return ERROR;
- }
- }
-
- free (s);
+ if (! parse_c_float (parse_gdbarch, p, len,
+ &putithere->typed_val_float.dval,
+ &putithere->typed_val_float.type))
+ return ERROR;
return FLOAT;
}
if (c != 'l' && c != 'u' && n != 0)
{
if ((unsigned_p && (ULONGEST) prevn >= (ULONGEST) n))
- error ("Numeric constant too large.");
+ error (_("Numeric constant too large."));
}
prevn = n;
}
parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
int *host_chars)
{
- int quote, i;
+ int quote;
enum c_string_type type;
+ int is_objc = 0;
/* Build the gdb internal form of the input string in tempbuf. Note
that the buffer is null byte terminated *only* for the
type = C_STRING_32;
++tokptr;
}
+ else if (*tokptr == '@')
+ {
+ /* An Objective C string. */
+ is_objc = 1;
+ type = C_STRING;
+ ++tokptr;
+ }
else
type = C_STRING;
if (*tokptr != quote)
{
if (quote == '"')
- error ("Unterminated string in expression.");
+ error (_("Unterminated string in expression."));
else
- error ("Unmatched single quote.");
+ error (_("Unmatched single quote."));
}
++tokptr;
*outptr = tokptr;
- return quote == '"' ? STRING : CHAR;
+ return quote == '"' ? (is_objc ? NSSTRING : STRING) : CHAR;
}
+/* This is used to associate some attributes with a token. */
+
+enum token_flags
+{
+ /* If this bit is set, the token is C++-only. */
+
+ FLAG_CXX = 1,
+
+ /* If this bit is set, the token is conditional: if there is a
+ symbol of the same name, then the token is a symbol; otherwise,
+ the token is a keyword. */
+
+ FLAG_SHADOW = 2
+};
+
struct token
{
char *operator;
int token;
enum exp_opcode opcode;
- int cxx_only;
+ enum token_flags flags;
};
static const struct token tokentab3[] =
{
{">>=", ASSIGN_MODIFY, BINOP_RSH, 0},
{"<<=", ASSIGN_MODIFY, BINOP_LSH, 0},
- {"->*", ARROW_STAR, BINOP_END, 1}
+ {"->*", ARROW_STAR, BINOP_END, FLAG_CXX},
+ {"...", DOTDOTDOT, BINOP_END, 0}
};
static const struct token tokentab2[] =
{"!=", NOTEQUAL, BINOP_END, 0},
{"<=", LEQ, BINOP_END, 0},
{">=", GEQ, BINOP_END, 0},
- {".*", DOT_STAR, BINOP_END, 1}
+ {".*", DOT_STAR, BINOP_END, FLAG_CXX}
};
/* Identifier-like tokens. */
static const struct token ident_tokens[] =
{
{"unsigned", UNSIGNED, OP_NULL, 0},
- {"template", TEMPLATE, OP_NULL, 1},
+ {"template", TEMPLATE, OP_NULL, FLAG_CXX},
{"volatile", VOLATILE_KEYWORD, OP_NULL, 0},
{"struct", STRUCT, OP_NULL, 0},
{"signed", SIGNED_KEYWORD, OP_NULL, 0},
{"sizeof", SIZEOF, OP_NULL, 0},
{"double", DOUBLE_KEYWORD, OP_NULL, 0},
- {"false", FALSEKEYWORD, OP_NULL, 1},
- {"class", CLASS, OP_NULL, 1},
+ {"false", FALSEKEYWORD, OP_NULL, FLAG_CXX},
+ {"class", CLASS, OP_NULL, FLAG_CXX},
{"union", UNION, OP_NULL, 0},
{"short", SHORT, OP_NULL, 0},
{"const", CONST_KEYWORD, OP_NULL, 0},
{"enum", ENUM, OP_NULL, 0},
{"long", LONG, OP_NULL, 0},
- {"true", TRUEKEYWORD, OP_NULL, 1},
+ {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
{"int", INT_KEYWORD, OP_NULL, 0},
- {"new", NEW, OP_NULL, 1},
- {"delete", DELETE, OP_NULL, 1},
- {"operator", OPERATOR, OP_NULL, 1},
-
- {"and", ANDAND, BINOP_END, 1},
- {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, 1},
- {"bitand", '&', OP_NULL, 1},
- {"bitor", '|', OP_NULL, 1},
- {"compl", '~', OP_NULL, 1},
- {"not", '!', OP_NULL, 1},
- {"not_eq", NOTEQUAL, BINOP_END, 1},
- {"or", OROR, BINOP_END, 1},
- {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 1},
- {"xor", '^', OP_NULL, 1},
- {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 1},
-
- {"const_cast", CONST_CAST, OP_NULL, 1 },
- {"dynamic_cast", DYNAMIC_CAST, OP_NULL, 1 },
- {"static_cast", STATIC_CAST, OP_NULL, 1 },
- {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 }
+ {"new", NEW, OP_NULL, FLAG_CXX},
+ {"delete", DELETE, OP_NULL, FLAG_CXX},
+ {"operator", OPERATOR, OP_NULL, FLAG_CXX},
+
+ {"and", ANDAND, BINOP_END, FLAG_CXX},
+ {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, FLAG_CXX},
+ {"bitand", '&', OP_NULL, FLAG_CXX},
+ {"bitor", '|', OP_NULL, FLAG_CXX},
+ {"compl", '~', OP_NULL, FLAG_CXX},
+ {"not", '!', OP_NULL, FLAG_CXX},
+ {"not_eq", NOTEQUAL, BINOP_END, FLAG_CXX},
+ {"or", OROR, BINOP_END, FLAG_CXX},
+ {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, FLAG_CXX},
+ {"xor", '^', OP_NULL, FLAG_CXX},
+ {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, FLAG_CXX},
+
+ {"const_cast", CONST_CAST, OP_NULL, FLAG_CXX },
+ {"dynamic_cast", DYNAMIC_CAST, OP_NULL, FLAG_CXX },
+ {"static_cast", STATIC_CAST, OP_NULL, FLAG_CXX },
+ {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX },
+
+ {"__typeof__", TYPEOF, OP_TYPEOF, 0 },
+ {"__typeof", TYPEOF, OP_TYPEOF, 0 },
+ {"typeof", TYPEOF, OP_TYPEOF, FLAG_SHADOW },
+ {"__decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX },
+ {"decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX | FLAG_SHADOW }
};
/* When we find that lexptr (the global var defined in parse.c) is
for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
{
- if (tokentab3[i].cxx_only
+ if ((tokentab3[i].flags & FLAG_CXX) != 0
&& parse_language->la_language != language_cplus)
break;
for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
{
- if (tokentab2[i].cxx_only
+ if ((tokentab2[i].flags & FLAG_CXX) != 0
&& parse_language->la_language != language_cplus)
break;
lexptr += 2;
yylval.opcode = tokentab2[i].opcode;
- if (in_parse_field && tokentab2[i].token == ARROW)
+ if (parse_completion && tokentab2[i].token == ARROW)
last_was_structop = 1;
return tokentab2[i].token;
}
case '(':
paren_depth++;
lexptr++;
+ if (parse_language->la_language == language_objc && c == '[')
+ return OBJC_LBRAC;
return c;
case ']':
/* Might be a floating point number. */
if (lexptr[1] < '0' || lexptr[1] > '9')
{
- if (in_parse_field)
+ if (parse_completion)
last_was_structop = 1;
goto symbol; /* Nope, must be a symbol. */
}
memcpy (err_copy, tokstart, p - tokstart);
err_copy[p - tokstart] = 0;
- error ("Invalid number \"%s\".", err_copy);
+ error (_("Invalid number \"%s\"."), err_copy);
}
lexptr = p;
return toktype;
}
+ case '@':
+ {
+ char *p = &tokstart[1];
+ size_t len = strlen ("entry");
+
+ if (parse_language->la_language == language_objc)
+ {
+ size_t len = strlen ("selector");
+
+ if (strncmp (p, "selector", len) == 0
+ && (p[len] == '\0' || isspace (p[len])))
+ {
+ lexptr = p + len;
+ return SELECTOR;
+ }
+ else if (*p == '"')
+ goto parse_string;
+ }
+
+ while (isspace (*p))
+ p++;
+ if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
+ && p[len] != '_')
+ {
+ lexptr = &p[len];
+ return ENTRY;
+ }
+ }
+ /* FALLTHRU */
case '+':
case '-':
case '*':
case '^':
case '~':
case '!':
- case '@':
case '<':
case '>':
case '?':
/* Fall through. */
case '\'':
case '"':
+
+ parse_string:
{
int host_len;
int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval,
if (result == CHAR)
{
if (host_len == 0)
- error ("Empty character constant.");
+ error (_("Empty character constant."));
else if (host_len > 2 && c == '\'')
{
++tokstart;
goto tryname;
}
else if (host_len > 1)
- error ("Invalid character constant.");
+ error (_("Invalid character constant."));
}
return result;
}
if (!(c == '_' || c == '$'
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
/* We must have come across a bad character (e.g. ';'). */
- error ("Invalid character '%c' in expression.", c);
+ error (_("Invalid character '%c' in expression."), c);
/* It's a name. See how long it is. */
namelen = 0;
for (i = 0; i < sizeof ident_tokens / sizeof ident_tokens[0]; i++)
if (strcmp (copy, ident_tokens[i].operator) == 0)
{
- if (ident_tokens[i].cxx_only
+ if ((ident_tokens[i].flags & FLAG_CXX) != 0
&& parse_language->la_language != language_cplus)
break;
+ if ((ident_tokens[i].flags & FLAG_SHADOW) != 0)
+ {
+ struct field_of_this_result is_a_field_of_this;
+
+ if (lookup_symbol (copy, expression_context_block,
+ VAR_DOMAIN,
+ (parse_language->la_language == language_cplus
+ ? &is_a_field_of_this
+ : NULL))
+ != NULL)
+ {
+ /* The keyword is shadowed. */
+ break;
+ }
+ }
+
/* It is ok to always set this, even though we don't always
strictly need to. */
yylval.opcode = ident_tokens[i].opcode;
if (*tokstart == '$')
return VARIABLE;
- if (in_parse_field && *lexptr == '\0')
+ if (parse_completion && *lexptr == '\0')
saw_name_at_eof = 1;
return NAME;
}
typedef struct
{
int token;
- union YYSTYPE value;
+ YYSTYPE value;
} token_and_value;
DEF_VEC_O (token_and_value);
in which lookups start; this can be NULL to mean the global
scope. */
static int
-classify_name (struct block *block)
+classify_name (const struct block *block)
{
struct symbol *sym;
char *copy;
- int is_a_field_of_this = 0;
+ struct field_of_this_result is_a_field_of_this;
copy = copy_name (yylval.sval);
+ /* Initialize this in case we *don't* use it in this call; that way
+ we can refer to it unconditionally below. */
+ memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this));
+
sym = lookup_symbol (copy, block, VAR_DOMAIN,
- parse_language->la_language == language_cplus
- ? &is_a_field_of_this : (int *) NULL);
+ parse_language->la_name_of_this
+ ? &is_a_field_of_this : NULL);
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
return BLOCKNAME;
}
else if (!sym)
yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
return FILENAME;
}
+
+ /* If we found a field of 'this', we might have erroneously
+ found a constructor where we wanted a type name. Handle this
+ case by noticing that we found a constructor and then look up
+ the type tag instead. */
+ if (is_a_field_of_this.type != NULL
+ && is_a_field_of_this.fn_field != NULL
+ && TYPE_FN_FIELD_CONSTRUCTOR (is_a_field_of_this.fn_field->fn_fields,
+ 0))
+ {
+ struct field_of_this_result inner_is_a_field_of_this;
+
+ sym = lookup_symbol (copy, block, STRUCT_DOMAIN,
+ &inner_is_a_field_of_this);
+ if (sym != NULL)
+ {
+ yylval.tsym.type = SYMBOL_TYPE (sym);
+ return TYPENAME;
+ }
+ }
}
if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
if (yylval.tsym.type != NULL)
return TYPENAME;
+ /* See if it's an ObjC classname. */
+ if (parse_language->la_language == language_objc && !sym)
+ {
+ CORE_ADDR Class = lookup_objc_class (parse_gdbarch, copy);
+ if (Class)
+ {
+ yylval.class.class = Class;
+ sym = lookup_struct_typedef (copy, expression_context_block, 1);
+ if (sym)
+ yylval.class.type = SYMBOL_TYPE (sym);
+ return CLASSNAME;
+ }
+ }
+
/* Input names that aren't symbols but ARE valid hex numbers, when
the input radix permits them, can be names or numbers depending
on the parse. Note we support radixes > 16 here. */
if (hextype == INT)
{
yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
return NAME_OR_INT;
}
}
/* Any other kind of symbol */
yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
+
+ if (sym == NULL
+ && parse_language->la_language == language_cplus
+ && is_a_field_of_this.type == NULL
+ && !lookup_minimal_symbol (copy, NULL, NULL))
+ return UNKNOWN_CPP_NAME;
+
return NAME;
}
/* Like classify_name, but used by the inner loop of the lexer, when a
name might have already been seen. FIRST_NAME is true if the token
- in `yylval' is the first component of a name, false otherwise. If
- this function returns NAME, it might not have updated `yylval'.
- This is ok because the caller only cares about TYPENAME. */
+ in `yylval' is the first component of a name, false otherwise. */
+
static int
-classify_inner_name (struct block *block, int first_name)
+classify_inner_name (const struct block *block, int first_name)
{
struct type *type, *new_type;
char *copy;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
- /* We know the caller won't expect us to update yylval. */
- return NAME;
+ return ERROR;
copy = copy_name (yylval.tsym.stoken);
- new_type = cp_lookup_nested_type (type, copy, block);
+ yylval.ssym.sym = cp_lookup_nested_symbol (yylval.tsym.type, copy, block);
+ if (yylval.ssym.sym == NULL)
+ return ERROR;
+
+ switch (SYMBOL_CLASS (yylval.ssym.sym))
+ {
+ case LOC_BLOCK:
+ case LOC_LABEL:
+ return ERROR;
- if (new_type == NULL)
- /* We know the caller won't expect us to update yylval. */
- return NAME;
+ case LOC_TYPEDEF:
+ yylval.tsym.type = SYMBOL_TYPE (yylval.ssym.sym);;
+ return TYPENAME;
- yylval.tsym.type = new_type;
- return TYPENAME;
+ default:
+ yylval.ssym.is_a_field_of_this = 0;
+ return NAME;
+ }
+ internal_error (__FILE__, __LINE__, _("not reached"));
}
/* The outer level of a two-level lexer. This calls the inner lexer
yylex (void)
{
token_and_value current;
- char *name;
int first_was_coloncolon, last_was_coloncolon, first_iter;
if (popping && !VEC_empty (token_and_value, token_fifo))
first_iter);
/* We keep going until we either run out of names, or until
we have a qualified name which is not a type. */
- if (classification != TYPENAME)
+ if (classification != TYPENAME && classification != NAME)
{
/* Push the final component and leave the loop. */
VEC_safe_push (token_and_value, token_fifo, &next);
{
token_and_value cc;
memset (&cc, 0, sizeof (token_and_value));
- if (first_was_coloncolon)
+ if (first_was_coloncolon && first_iter)
{
yylval = cc.value;
return COLONCOLON;
if (prev_lexptr)
lexptr = prev_lexptr;
- error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+ error (_("A %s in expression, near `%s'."), (msg ? msg : "error"), lexptr);
}