| Index: gdb/c-exp.y
|
| diff --git a/gdb/c-exp.y b/gdb/c-exp.y
|
| index 0613799c27e27006c2751e5713024193a245b0a6..03af9e72d062bf86745f0e1127995fcd5b42c498 100644
|
| --- a/gdb/c-exp.y
|
| +++ b/gdb/c-exp.y
|
| @@ -1,6 +1,5 @@
|
| /* YACC parser for C expressions, for GDB.
|
| - Copyright (C) 1986, 1989-2000, 2003-2004, 2006-2012 Free Software
|
| - Foundation, Inc.
|
| + Copyright (C) 1986-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -37,7 +36,7 @@
|
| %{
|
|
|
| #include "defs.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include <ctype.h>
|
| #include "expression.h"
|
| #include "value.h"
|
| @@ -53,6 +52,9 @@
|
| #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)
|
|
|
| @@ -143,7 +145,6 @@ void yyerror (char *);
|
| gdb_byte val[16];
|
| struct type *type;
|
| } typed_val_decfloat;
|
| - struct symbol *sym;
|
| struct type *tval;
|
| struct stoken sval;
|
| struct typed_stoken tsval;
|
| @@ -152,20 +153,24 @@ void yyerror (char *);
|
| int voidval;
|
| struct block *bval;
|
| enum exp_opcode opcode;
|
| - struct internalvar *ivar;
|
|
|
| struct stoken_vector svec;
|
| 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 int parse_number (const char *, int, int, YYSTYPE *);
|
| static struct stoken operator_stoken (const char *);
|
| static void check_parameter_typelist (VEC (type_ptr) *);
|
| +static void write_destructor_name (struct stoken);
|
| +
|
| +static void c_print_token (FILE *file, int type, YYSTYPE value);
|
| +#define YYPRINT(FILE, TYPE, VALUE) c_print_token (FILE, TYPE, VALUE)
|
| %}
|
|
|
| %type <voidval> exp exp1 type_exp start variable qualified_name lcurly
|
| @@ -194,16 +199,24 @@ static void check_parameter_typelist (VEC (type_ptr) *);
|
| 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
|
| @@ -219,6 +232,9 @@ static void check_parameter_typelist (VEC (type_ptr) *);
|
| %type <sval> operator
|
| %token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
|
| %token ENTRY
|
| +%token TYPEOF
|
| +%token DECLTYPE
|
| +%token TYPEID
|
|
|
| /* Special type cases, put in to allow the parser to distinguish different
|
| legal basetypes. */
|
| @@ -249,7 +265,7 @@ static void check_parameter_typelist (VEC (type_ptr) *);
|
| %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
|
| @@ -268,6 +284,20 @@ type_exp: type
|
| { 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. */
|
| @@ -317,6 +347,14 @@ exp : exp DECREMENT %prec UNARY
|
| { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
|
| ;
|
|
|
| +exp : TYPEID '(' exp ')' %prec UNARY
|
| + { write_exp_elt_opcode (OP_TYPEID); }
|
| + ;
|
| +
|
| +exp : TYPEID '(' type_exp ')' %prec UNARY
|
| + { write_exp_elt_opcode (OP_TYPEID); }
|
| + ;
|
| +
|
| exp : SIZEOF exp %prec UNARY
|
| { write_exp_elt_opcode (UNOP_SIZEOF); }
|
| ;
|
| @@ -344,6 +382,19 @@ exp : exp ARROW COMPLETE
|
| write_exp_elt_opcode (STRUCTOP_PTR); }
|
| ;
|
|
|
| +exp : exp ARROW '~' name
|
| + { write_exp_elt_opcode (STRUCTOP_PTR);
|
| + write_destructor_name ($4);
|
| + write_exp_elt_opcode (STRUCTOP_PTR); }
|
| + ;
|
| +
|
| +exp : exp ARROW '~' name COMPLETE
|
| + { mark_struct_expression ();
|
| + write_exp_elt_opcode (STRUCTOP_PTR);
|
| + write_destructor_name ($4);
|
| + write_exp_elt_opcode (STRUCTOP_PTR); }
|
| + ;
|
| +
|
| exp : exp ARROW qualified_name
|
| { /* exp->type::name becomes exp->*(&type::name) */
|
| /* Note: this doesn't work if name is a
|
| @@ -379,6 +430,19 @@ exp : exp '.' COMPLETE
|
| write_exp_elt_opcode (STRUCTOP_STRUCT); }
|
| ;
|
|
|
| +exp : exp '.' '~' name
|
| + { write_exp_elt_opcode (STRUCTOP_STRUCT);
|
| + write_destructor_name ($4);
|
| + write_exp_elt_opcode (STRUCTOP_STRUCT); }
|
| + ;
|
| +
|
| +exp : exp '.' '~' name COMPLETE
|
| + { mark_struct_expression ();
|
| + write_exp_elt_opcode (STRUCTOP_STRUCT);
|
| + write_destructor_name ($4);
|
| + write_exp_elt_opcode (STRUCTOP_STRUCT); }
|
| + ;
|
| +
|
| exp : exp '.' qualified_name
|
| { /* exp.type::name becomes exp.*(&type::name) */
|
| /* Note: this doesn't work if name is a
|
| @@ -395,6 +459,78 @@ exp : exp '[' exp1 ']'
|
| { 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. */
|
| @@ -471,16 +607,12 @@ exp : lcurly arglist rcurly %prec ARROW
|
| 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 ')'
|
| @@ -629,6 +761,13 @@ exp : VARIABLE
|
| }
|
| ;
|
|
|
| +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 (lookup_signed_typename
|
| @@ -639,30 +778,22 @@ exp : SIZEOF '(' type ')' %prec UNARY
|
| 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:
|
| @@ -734,6 +865,14 @@ exp : string_exp
|
| }
|
| ;
|
|
|
| +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);
|
| @@ -768,7 +907,7 @@ block : BLOCKNAME
|
| 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."),
|
| copy_name ($3));
|
| @@ -793,7 +932,7 @@ variable: name_not_typename ENTRY
|
| 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."),
|
| copy_name ($3));
|
| @@ -820,7 +959,7 @@ qualified_name: TYPENAME COLONCOLON name
|
| && TYPE_CODE (type) != TYPE_CODE_UNION
|
| && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
|
| error (_("`%s' is not defined as an aggregate type."),
|
| - TYPE_NAME (type));
|
| + TYPE_SAFE_NAME (type));
|
|
|
| write_exp_elt_opcode (OP_SCOPE);
|
| write_exp_elt_type (type);
|
| @@ -831,18 +970,20 @@ qualified_name: TYPENAME COLONCOLON name
|
| {
|
| struct type *type = $1.type;
|
| struct stoken tmp_token;
|
| + char *buf;
|
| +
|
| CHECK_TYPEDEF (type);
|
| 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."),
|
| - TYPE_NAME (type));
|
| -
|
| - tmp_token.ptr = (char*) alloca ($4.length + 2);
|
| + TYPE_SAFE_NAME (type));
|
| + buf = alloca ($4.length + 2);
|
| + tmp_token.ptr = buf;
|
| tmp_token.length = $4.length + 1;
|
| - tmp_token.ptr[0] = '~';
|
| - memcpy (tmp_token.ptr+1, $4.ptr, $4.length);
|
| - tmp_token.ptr[tmp_token.length] = 0;
|
| + buf[0] = '~';
|
| + memcpy (buf+1, $4.ptr, $4.length);
|
| + buf[tmp_token.length] = 0;
|
|
|
| /* Check for valid destructor name. */
|
| destructor_name_p (tmp_token.ptr, $1.type);
|
| @@ -856,7 +997,7 @@ qualified_name: TYPENAME COLONCOLON name
|
| char *copy = copy_name ($3);
|
| error (_("No type \"%s\" within class "
|
| "or namespace \"%s\"."),
|
| - copy, TYPE_NAME ($1.type));
|
| + copy, TYPE_SAFE_NAME ($1.type));
|
| }
|
| ;
|
|
|
| @@ -865,11 +1006,11 @@ variable: qualified_name
|
| {
|
| char *name = copy_name ($2.stoken);
|
| struct symbol *sym;
|
| - struct minimal_symbol *msymbol;
|
| + struct bound_minimal_symbol msymbol;
|
|
|
| sym =
|
| lookup_symbol (name, (const struct block *) NULL,
|
| - VAR_DOMAIN, (int *) NULL);
|
| + VAR_DOMAIN, NULL);
|
| if (sym)
|
| {
|
| write_exp_elt_opcode (OP_VAR_VALUE);
|
| @@ -879,8 +1020,8 @@ variable: qualified_name
|
| break;
|
| }
|
|
|
| - msymbol = lookup_minimal_symbol (name, NULL, NULL);
|
| - if (msymbol != NULL)
|
| + msymbol = lookup_bound_minimal_symbol (name);
|
| + if (msymbol.minsym != NULL)
|
| write_exp_msymbol (msymbol);
|
| else if (!have_full_symbols () && !have_partial_symbols ())
|
| error (_("No symbol table is loaded. Use the \"file\" command."));
|
| @@ -927,12 +1068,12 @@ variable: name_not_typename
|
| }
|
| else
|
| {
|
| - struct minimal_symbol *msymbol;
|
| + struct bound_minimal_symbol msymbol;
|
| char *arg = copy_name ($1.stoken);
|
|
|
| msymbol =
|
| - lookup_minimal_symbol (arg, NULL, NULL);
|
| - if (msymbol != NULL)
|
| + lookup_bound_minimal_symbol (arg);
|
| + if (msymbol.minsym != NULL)
|
| write_exp_msymbol (msymbol);
|
| else if (!have_full_symbols () && !have_partial_symbols ())
|
| error (_("No symbol table is loaded. Use the \"file\" command."));
|
| @@ -1022,8 +1163,12 @@ direct_abs_decl: '(' abs_decl ')'
|
|
|
| array_mod: '[' ']'
|
| { $$ = -1; }
|
| + | OBJC_LBRAC ']'
|
| + { $$ = -1; }
|
| | '[' INT ']'
|
| { $$ = $2.val; }
|
| + | OBJC_LBRAC INT ']'
|
| + { $$ = $2.val; }
|
| ;
|
|
|
| func_mod: '(' ')'
|
| @@ -1161,15 +1306,59 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */
|
| | 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,
|
| @@ -1289,6 +1478,10 @@ 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 '-'
|
| @@ -1385,12 +1578,15 @@ operator: OPERATOR NEW
|
| { $$ = operator_stoken ("()"); }
|
| | OPERATOR '[' ']'
|
| { $$ = operator_stoken ("[]"); }
|
| + | 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);
|
| @@ -1419,17 +1615,37 @@ name_not_typename : NAME
|
| */
|
| | 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
|
| + = is_a_field_of_this.type != NULL;
|
| }
|
| | UNKNOWN_CPP_NAME
|
| ;
|
|
|
| %%
|
|
|
| +/* Like write_exp_string, but prepends a '~'. */
|
| +
|
| +static void
|
| +write_destructor_name (struct stoken token)
|
| +{
|
| + char *copy = alloca (token.length + 1);
|
| +
|
| + copy[0] = '~';
|
| + memcpy (©[1], token.ptr, token.length);
|
| +
|
| + token.ptr = copy;
|
| + ++token.length;
|
| +
|
| + write_exp_string (token);
|
| +}
|
| +
|
| /* Returns a stoken of the operator name given by OP (which does not
|
| include the string "operator"). */
|
| static struct stoken
|
| @@ -1437,13 +1653,16 @@ operator_stoken (const char *op)
|
| {
|
| static const char *operator_string = "operator";
|
| struct stoken st = { NULL, 0 };
|
| + char *buf;
|
| +
|
| st.length = strlen (operator_string) + strlen (op);
|
| - st.ptr = malloc (st.length + 1);
|
| - strcpy (st.ptr, operator_string);
|
| - strcat (st.ptr, op);
|
| + buf = malloc (st.length + 1);
|
| + strcpy (buf, operator_string);
|
| + strcat (buf, op);
|
| + st.ptr = buf;
|
|
|
| /* The toplevel (c_parse) will free the memory allocated here. */
|
| - make_cleanup (free, st.ptr);
|
| + make_cleanup (free, buf);
|
| return st;
|
| };
|
|
|
| @@ -1485,7 +1704,7 @@ check_parameter_typelist (VEC (type_ptr) *params)
|
| /*** Needs some error checking for the float case ***/
|
|
|
| static int
|
| -parse_number (char *p, int len, int parsed_float, YYSTYPE *putithere)
|
| +parse_number (const char *buf, int len, int parsed_float, YYSTYPE *putithere)
|
| {
|
| /* FIXME: Shouldn't these be unsigned? We don't deal with negative values
|
| here, and we do kind of silly things like cast to unsigned. */
|
| @@ -1507,6 +1726,10 @@ parse_number (char *p, int len, int parsed_float, YYSTYPE *putithere)
|
| ULONGEST high_bit;
|
| struct type *signed_type;
|
| struct type *unsigned_type;
|
| + char *p;
|
| +
|
| + p = alloca (len);
|
| + memcpy (p, buf, len);
|
|
|
| if (parsed_float)
|
| {
|
| @@ -1727,9 +1950,9 @@ static int tempbuf_init;
|
| character was emitted, 0 otherwise. */
|
|
|
| int
|
| -c_parse_escape (char **ptr, struct obstack *output)
|
| +c_parse_escape (const char **ptr, struct obstack *output)
|
| {
|
| - char *tokptr = *ptr;
|
| + const char *tokptr = *ptr;
|
| int result = 1;
|
|
|
| /* Some escape sequences undergo character set conversion. Those we
|
| @@ -1888,11 +2111,12 @@ c_parse_escape (char **ptr, struct obstack *output)
|
| CHAR, depending on what was parsed. *HOST_CHARS is set to the
|
| number of host characters in the literal. */
|
| static int
|
| -parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
|
| - int *host_chars)
|
| +parse_string_or_char (const char *tokptr, const char **outptr,
|
| + struct typed_stoken *value, int *host_chars)
|
| {
|
| 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
|
| @@ -1925,6 +2149,13 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
|
| type = C_STRING_32;
|
| ++tokptr;
|
| }
|
| + else if (*tokptr == '@')
|
| + {
|
| + /* An Objective C string. */
|
| + is_objc = 1;
|
| + type = C_STRING;
|
| + ++tokptr;
|
| + }
|
| else
|
| type = C_STRING;
|
|
|
| @@ -1972,22 +2203,37 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
|
|
|
| *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}
|
| };
|
|
|
| @@ -2015,48 +2261,56 @@ 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 },
|
| +
|
| + {"typeid", TYPEID, OP_TYPEID, FLAG_CXX}
|
| };
|
|
|
| /* When we find that lexptr (the global var defined in parse.c) is
|
| @@ -2076,7 +2330,7 @@ static const struct token ident_tokens[] =
|
| we evaluate ADDRESS in the scope of the current frame, but we
|
| evaluate CONDITION in the scope of the breakpoint's location. So
|
| it's simply wrong to try to macro-expand the whole thing at once. */
|
| -static char *macro_original_text;
|
| +static const char *macro_original_text;
|
|
|
| /* We save all intermediate macro expansions on this obstack for the
|
| duration of a single parse. The expansion text may sometimes have
|
| @@ -2161,16 +2415,17 @@ static int last_was_structop;
|
| /* Read one token, getting characters through lexptr. */
|
|
|
| static int
|
| -lex_one_token (void)
|
| +lex_one_token (int *is_quoted_name)
|
| {
|
| int c;
|
| int namelen;
|
| unsigned int i;
|
| - char *tokstart;
|
| + const char *tokstart;
|
| int saw_structop = last_was_structop;
|
| char *copy;
|
|
|
| last_was_structop = 0;
|
| + *is_quoted_name = 0;
|
|
|
| retry:
|
|
|
| @@ -2192,7 +2447,7 @@ lex_one_token (void)
|
| 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;
|
|
|
| @@ -2205,13 +2460,13 @@ lex_one_token (void)
|
| 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;
|
| }
|
| @@ -2250,6 +2505,8 @@ lex_one_token (void)
|
| case '(':
|
| paren_depth++;
|
| lexptr++;
|
| + if (parse_language->la_language == language_objc && c == '[')
|
| + return OBJC_LBRAC;
|
| return c;
|
|
|
| case ']':
|
| @@ -2272,7 +2529,7 @@ lex_one_token (void)
|
| /* 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. */
|
| }
|
| @@ -2291,7 +2548,7 @@ lex_one_token (void)
|
| {
|
| /* It's a number. */
|
| int got_dot = 0, got_e = 0, toktype;
|
| - char *p = tokstart;
|
| + const char *p = tokstart;
|
| int hex = input_radix > 10;
|
|
|
| if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
|
| @@ -2343,9 +2600,23 @@ lex_one_token (void)
|
|
|
| case '@':
|
| {
|
| - char *p = &tokstart[1];
|
| + const 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])
|
| @@ -2385,6 +2656,8 @@ lex_one_token (void)
|
| /* Fall through. */
|
| case '\'':
|
| case '"':
|
| +
|
| + parse_string:
|
| {
|
| int host_len;
|
| int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval,
|
| @@ -2397,6 +2670,8 @@ lex_one_token (void)
|
| {
|
| ++tokstart;
|
| namelen = lexptr - tokstart - 1;
|
| + *is_quoted_name = 1;
|
| +
|
| goto tryname;
|
| }
|
| else if (host_len > 1)
|
| @@ -2429,7 +2704,8 @@ lex_one_token (void)
|
| characters; for comparison expressions, e.g. "a < b > c",
|
| there must be spaces before the '<', etc. */
|
|
|
| - char * p = find_template_name_end (tokstart + namelen);
|
| + const char *p = find_template_name_end (tokstart + namelen);
|
| +
|
| if (p)
|
| namelen = p - tokstart;
|
| }
|
| @@ -2460,7 +2736,8 @@ lex_one_token (void)
|
| && (tokstart[namelen] == ' ' || tokstart[namelen] == '\t')
|
| && ! scanning_macro_expansion ())
|
| {
|
| - char *p = tokstart + namelen + 1;
|
| + const char *p = tokstart + namelen + 1;
|
| +
|
| while (*p == ' ' || *p == '\t')
|
| p++;
|
| if (*p >= '0' && *p <= '9')
|
| @@ -2479,10 +2756,26 @@ lex_one_token (void)
|
| 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;
|
| @@ -2492,8 +2785,12 @@ lex_one_token (void)
|
| if (*tokstart == '$')
|
| return VARIABLE;
|
|
|
| - if (in_parse_field && *lexptr == '\0')
|
| + if (parse_completion && *lexptr == '\0')
|
| saw_name_at_eof = 1;
|
| +
|
| + yylval.ssym.stoken = yylval.sval;
|
| + yylval.ssym.sym = NULL;
|
| + yylval.ssym.is_a_field_of_this = 0;
|
| return NAME;
|
| }
|
|
|
| @@ -2519,37 +2816,70 @@ static struct obstack name_obstack;
|
|
|
| /* Classify a NAME token. The contents of the token are in `yylval'.
|
| Updates yylval and returns the new token type. BLOCK is the block
|
| - in which lookups start; this can be NULL to mean the global
|
| - scope. */
|
| + in which lookups start; this can be NULL to mean the global scope.
|
| + IS_QUOTED_NAME is non-zero if the name token was originally quoted
|
| + in single quotes. */
|
| static int
|
| -classify_name (struct block *block)
|
| +classify_name (const struct block *block, int is_quoted_name)
|
| {
|
| 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)
|
| {
|
| - /* See if it's a file name. */
|
| - struct symtab *symtab;
|
| + /* 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;
|
| + }
|
| + }
|
|
|
| - symtab = lookup_symtab (copy);
|
| - if (symtab)
|
| + /* If we found a field, then we want to prefer it over a
|
| + filename. However, if the name was quoted, then it is better
|
| + to check for a filename or a block, since this is the only
|
| + way the user has of requiring the extension to be used. */
|
| + if (is_a_field_of_this.type == NULL || is_quoted_name)
|
| {
|
| - yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
|
| - return FILENAME;
|
| + /* See if it's a file name. */
|
| + struct symtab *symtab;
|
| +
|
| + symtab = lookup_symtab (copy);
|
| + if (symtab)
|
| + {
|
| + yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab),
|
| + STATIC_BLOCK);
|
| + return FILENAME;
|
| + }
|
| }
|
| }
|
|
|
| @@ -2565,6 +2895,20 @@ classify_name (struct block *block)
|
| 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. */
|
| @@ -2577,18 +2921,18 @@ classify_name (struct block *block)
|
| 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
|
| + && is_a_field_of_this.type == NULL
|
| && !lookup_minimal_symbol (copy, NULL, NULL))
|
| return UNKNOWN_CPP_NAME;
|
|
|
| @@ -2596,33 +2940,59 @@ classify_name (struct block *block)
|
| }
|
|
|
| /* 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. */
|
| + name might have already been seen. CONTEXT is the context type, or
|
| + NULL if this is the first component of a name. */
|
|
|
| static int
|
| -classify_inner_name (struct block *block, int first_name)
|
| +classify_inner_name (const struct block *block, struct type *context)
|
| {
|
| - struct type *type, *new_type;
|
| + struct type *type;
|
| char *copy;
|
|
|
| - if (first_name)
|
| - return classify_name (block);
|
| + if (context == NULL)
|
| + return classify_name (block, 0);
|
|
|
| - type = check_typedef (yylval.tsym.type);
|
| + type = check_typedef (context);
|
| if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|
| && TYPE_CODE (type) != TYPE_CODE_UNION
|
| && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
|
| return ERROR;
|
|
|
| - copy = copy_name (yylval.tsym.stoken);
|
| - yylval.ssym.sym = cp_lookup_nested_symbol (yylval.tsym.type, copy, block);
|
| + copy = copy_name (yylval.ssym.stoken);
|
| + yylval.ssym.sym = cp_lookup_nested_symbol (type, copy, block);
|
| +
|
| + /* If no symbol was found, search for a matching base class named
|
| + COPY. This will allow users to enter qualified names of class members
|
| + relative to the `this' pointer. */
|
| if (yylval.ssym.sym == NULL)
|
| - return ERROR;
|
| + {
|
| + struct type *base_type = find_type_baseclass_by_name (type, copy);
|
| +
|
| + if (base_type != NULL)
|
| + {
|
| + yylval.tsym.type = base_type;
|
| + return TYPENAME;
|
| + }
|
| +
|
| + return ERROR;
|
| + }
|
|
|
| switch (SYMBOL_CLASS (yylval.ssym.sym))
|
| {
|
| case LOC_BLOCK:
|
| case LOC_LABEL:
|
| + /* cp_lookup_nested_symbol might have accidentally found a constructor
|
| + named COPY when we really wanted a base class of the same name.
|
| + Double-check this case by looking for a base class. */
|
| + {
|
| + struct type *base_type = find_type_baseclass_by_name (type, copy);
|
| +
|
| + if (base_type != NULL)
|
| + {
|
| + yylval.tsym.type = base_type;
|
| + return TYPENAME;
|
| + }
|
| + }
|
| return ERROR;
|
|
|
| case LOC_TYPEDEF:
|
| @@ -2630,7 +3000,6 @@ classify_inner_name (struct block *block, int first_name)
|
| return TYPENAME;
|
|
|
| default:
|
| - yylval.ssym.is_a_field_of_this = 0;
|
| return NAME;
|
| }
|
| internal_error (__FILE__, __LINE__, _("not reached"));
|
| @@ -2651,63 +3020,105 @@ static int
|
| yylex (void)
|
| {
|
| token_and_value current;
|
| - int first_was_coloncolon, last_was_coloncolon, first_iter;
|
| + int first_was_coloncolon, last_was_coloncolon;
|
| + struct type *context_type = NULL;
|
| + int last_to_examine, next_to_examine, checkpoint;
|
| + const struct block *search_block;
|
| + int is_quoted_name;
|
|
|
| if (popping && !VEC_empty (token_and_value, token_fifo))
|
| - {
|
| - token_and_value tv = *VEC_index (token_and_value, token_fifo, 0);
|
| - VEC_ordered_remove (token_and_value, token_fifo, 0);
|
| - yylval = tv.value;
|
| - return tv.token;
|
| - }
|
| + goto do_pop;
|
| popping = 0;
|
|
|
| - current.token = lex_one_token ();
|
| + /* Read the first token and decide what to do. Most of the
|
| + subsequent code is C++-only; but also depends on seeing a "::" or
|
| + name-like token. */
|
| + current.token = lex_one_token (&is_quoted_name);
|
| if (current.token == NAME)
|
| - current.token = classify_name (expression_context_block);
|
| + current.token = classify_name (expression_context_block, is_quoted_name);
|
| if (parse_language->la_language != language_cplus
|
| - || (current.token != TYPENAME && current.token != COLONCOLON))
|
| + || (current.token != TYPENAME && current.token != COLONCOLON
|
| + && current.token != FILENAME))
|
| return current.token;
|
|
|
| - first_was_coloncolon = current.token == COLONCOLON;
|
| - last_was_coloncolon = first_was_coloncolon;
|
| - obstack_free (&name_obstack, obstack_base (&name_obstack));
|
| - if (!last_was_coloncolon)
|
| - obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length);
|
| + /* Read any sequence of alternating "::" and name-like tokens into
|
| + the token FIFO. */
|
| current.value = yylval;
|
| - first_iter = 1;
|
| + VEC_safe_push (token_and_value, token_fifo, ¤t);
|
| + last_was_coloncolon = current.token == COLONCOLON;
|
| while (1)
|
| {
|
| - token_and_value next;
|
| + int ignore;
|
| +
|
| + /* We ignore quoted names other than the very first one.
|
| + Subsequent ones do not have any special meaning. */
|
| + current.token = lex_one_token (&ignore);
|
| + current.value = yylval;
|
| + VEC_safe_push (token_and_value, token_fifo, ¤t);
|
| +
|
| + if ((last_was_coloncolon && current.token != NAME)
|
| + || (!last_was_coloncolon && current.token != COLONCOLON))
|
| + break;
|
| + last_was_coloncolon = !last_was_coloncolon;
|
| + }
|
| + popping = 1;
|
|
|
| - next.token = lex_one_token ();
|
| - next.value = yylval;
|
| + /* We always read one extra token, so compute the number of tokens
|
| + to examine accordingly. */
|
| + last_to_examine = VEC_length (token_and_value, token_fifo) - 2;
|
| + next_to_examine = 0;
|
|
|
| - if (next.token == NAME && last_was_coloncolon)
|
| + current = *VEC_index (token_and_value, token_fifo, next_to_examine);
|
| + ++next_to_examine;
|
| +
|
| + obstack_free (&name_obstack, obstack_base (&name_obstack));
|
| + checkpoint = 0;
|
| + if (current.token == FILENAME)
|
| + search_block = current.value.bval;
|
| + else if (current.token == COLONCOLON)
|
| + search_block = NULL;
|
| + else
|
| + {
|
| + gdb_assert (current.token == TYPENAME);
|
| + search_block = expression_context_block;
|
| + obstack_grow (&name_obstack, current.value.sval.ptr,
|
| + current.value.sval.length);
|
| + context_type = current.value.tsym.type;
|
| + checkpoint = 1;
|
| + }
|
| +
|
| + first_was_coloncolon = current.token == COLONCOLON;
|
| + last_was_coloncolon = first_was_coloncolon;
|
| +
|
| + while (next_to_examine <= last_to_examine)
|
| + {
|
| + token_and_value *next;
|
| +
|
| + next = VEC_index (token_and_value, token_fifo, next_to_examine);
|
| + ++next_to_examine;
|
| +
|
| + if (next->token == NAME && last_was_coloncolon)
|
| {
|
| int classification;
|
|
|
| - classification = classify_inner_name (first_was_coloncolon
|
| - ? NULL
|
| - : expression_context_block,
|
| - first_iter);
|
| + yylval = next->value;
|
| + classification = classify_inner_name (search_block, context_type);
|
| /* 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 && classification != NAME)
|
| - {
|
| - /* Push the final component and leave the loop. */
|
| - VEC_safe_push (token_and_value, token_fifo, &next);
|
| - break;
|
| - }
|
| + break;
|
| +
|
| + /* Accept up to this token. */
|
| + checkpoint = next_to_examine;
|
|
|
| /* Update the partial name we are constructing. */
|
| - if (!first_iter)
|
| + if (context_type != NULL)
|
| {
|
| /* We don't want to put a leading "::" into the name. */
|
| obstack_grow_str (&name_obstack, "::");
|
| }
|
| - obstack_grow (&name_obstack, next.value.sval.ptr,
|
| - next.value.sval.length);
|
| + obstack_grow (&name_obstack, next->value.sval.ptr,
|
| + next->value.sval.length);
|
|
|
| yylval.sval.ptr = obstack_base (&name_obstack);
|
| yylval.sval.length = obstack_object_size (&name_obstack);
|
| @@ -2715,39 +3126,38 @@ yylex (void)
|
| current.token = classification;
|
|
|
| last_was_coloncolon = 0;
|
| +
|
| + if (classification == NAME)
|
| + break;
|
| +
|
| + context_type = yylval.tsym.type;
|
| }
|
| - else if (next.token == COLONCOLON && !last_was_coloncolon)
|
| + else if (next->token == COLONCOLON && !last_was_coloncolon)
|
| last_was_coloncolon = 1;
|
| else
|
| {
|
| /* We've reached the end of the name. */
|
| - VEC_safe_push (token_and_value, token_fifo, &next);
|
| break;
|
| }
|
| -
|
| - first_iter = 0;
|
| }
|
|
|
| - popping = 1;
|
| -
|
| - /* If we ended with a "::", insert it too. */
|
| - if (last_was_coloncolon)
|
| + /* If we have a replacement token, install it as the first token in
|
| + the FIFO, and delete the other constituent tokens. */
|
| + if (checkpoint > 0)
|
| {
|
| - token_and_value cc;
|
| - memset (&cc, 0, sizeof (token_and_value));
|
| - if (first_was_coloncolon && first_iter)
|
| - {
|
| - yylval = cc.value;
|
| - return COLONCOLON;
|
| - }
|
| - cc.token = COLONCOLON;
|
| - VEC_safe_insert (token_and_value, token_fifo, 0, &cc);
|
| + current.value.sval.ptr = obstack_copy0 (&expansion_obstack,
|
| + current.value.sval.ptr,
|
| + current.value.sval.length);
|
| +
|
| + VEC_replace (token_and_value, token_fifo, 0, ¤t);
|
| + if (checkpoint > 1)
|
| + VEC_block_remove (token_and_value, token_fifo, 1, checkpoint - 1);
|
| }
|
|
|
| + do_pop:
|
| + current = *VEC_index (token_and_value, token_fifo, 0);
|
| + VEC_ordered_remove (token_and_value, token_fifo, 0);
|
| yylval = current.value;
|
| - yylval.sval.ptr = obstack_copy0 (&expansion_obstack,
|
| - yylval.sval.ptr,
|
| - yylval.sval.length);
|
| return current.token;
|
| }
|
|
|
| @@ -2791,6 +3201,59 @@ c_parse (void)
|
| return result;
|
| }
|
|
|
| +/* This is called via the YYPRINT macro when parser debugging is
|
| + enabled. It prints a token's value. */
|
| +
|
| +static void
|
| +c_print_token (FILE *file, int type, YYSTYPE value)
|
| +{
|
| + switch (type)
|
| + {
|
| + case INT:
|
| + fprintf (file, "typed_val_int<%s, %s>",
|
| + TYPE_SAFE_NAME (value.typed_val_int.type),
|
| + pulongest (value.typed_val_int.val));
|
| + break;
|
| +
|
| + case CHAR:
|
| + case STRING:
|
| + {
|
| + char *copy = alloca (value.tsval.length + 1);
|
| +
|
| + memcpy (copy, value.tsval.ptr, value.tsval.length);
|
| + copy[value.tsval.length] = '\0';
|
| +
|
| + fprintf (file, "tsval<type=%d, %s>", value.tsval.type, copy);
|
| + }
|
| + break;
|
| +
|
| + case NSSTRING:
|
| + case VARIABLE:
|
| + fprintf (file, "sval<%s>", copy_name (value.sval));
|
| + break;
|
| +
|
| + case TYPENAME:
|
| + fprintf (file, "tsym<type=%s, name=%s>",
|
| + TYPE_SAFE_NAME (value.tsym.type),
|
| + copy_name (value.tsym.stoken));
|
| + break;
|
| +
|
| + case NAME:
|
| + case UNKNOWN_CPP_NAME:
|
| + case NAME_OR_INT:
|
| + case BLOCKNAME:
|
| + fprintf (file, "ssym<name=%s, sym=%s, field_of_this=%d>",
|
| + copy_name (value.ssym.stoken),
|
| + (value.ssym.sym == NULL
|
| + ? "(null)" : SYMBOL_PRINT_NAME (value.ssym.sym)),
|
| + value.ssym.is_a_field_of_this);
|
| + break;
|
| +
|
| + case FILENAME:
|
| + fprintf (file, "bval<%s>", host_address_to_string (value.bval));
|
| + break;
|
| + }
|
| +}
|
|
|
| void
|
| yyerror (char *msg)
|
|
|