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) |