/* 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 qualified_type
-%type <tvec> nonempty_typelist
+%type <tval> type typebase
+%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. */
%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD
-%token <voidval> VARIABLE
+%token <sval> VARIABLE
%token <opcode> ASSIGN_MODIFY
%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 : VARIABLE
- /* Already written by write_dollar_variable. */
+ {
+ write_dollar_variable ($1);
+ }
+ ;
+
+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. */
write_exp_elt_opcode (OP_VAR_VALUE); }
;
-qualified_name: typebase COLONCOLON name
+qualified_name: TYPENAME COLONCOLON name
{
- struct type *type = $1;
+ struct type *type = $1.type;
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.",
+ error (_("`%s' is not defined as an aggregate type."),
TYPE_NAME (type));
write_exp_elt_opcode (OP_SCOPE);
write_exp_string ($3);
write_exp_elt_opcode (OP_SCOPE);
}
- | typebase COLONCOLON '~' name
+ | TYPENAME COLONCOLON '~' name
{
- struct type *type = $1;
+ struct type *type = $1.type;
struct stoken tmp_token;
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.",
+ 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);
write_exp_elt_opcode (OP_SCOPE);
}
+ | TYPENAME COLONCOLON name COLONCOLON name
+ {
+ char *copy = copy_name ($3);
+ error (_("No type \"%s\" within class "
+ "or namespace \"%s\"."),
+ copy, TYPE_NAME ($1.type));
+ }
;
variable: qualified_name
- | COLONCOLON name
+ | COLONCOLON name_not_typename
{
- char *name = copy_name ($2);
+ char *name = copy_name ($2.stoken);
struct symbol *sym;
struct 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);
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. */
{ $$ = follow_types ($2); }
| typebase const_or_volatile_or_space_identifier_noopt
{ $$ = follow_types ($1); }
- | qualified_type
- ;
-
-/* FIXME: carlton/2003-09-25: This next bit leads to lots of
- reduce-reduce conflicts, because the parser doesn't know whether or
- not to use qualified_name or qualified_type: the rules are
- identical. If the parser is parsing 'A::B::x', then, when it sees
- the second '::', it knows that the expression to the left of it has
- to be a type, so it uses qualified_type. But if it is parsing just
- 'A::B', then it doesn't have any way of knowing which rule to use,
- so there's a reduce-reduce conflict; it picks qualified_name, since
- that occurs earlier in this file than qualified_type.
-
- There's no good way to fix this with the grammar as it stands; as
- far as I can tell, some of the problems arise from ambiguities that
- GDB introduces ('start' can be either an expression or a type), but
- some of it is inherent to the nature of C++ (you want to treat the
- input "(FOO)" fairly differently depending on whether FOO is an
- expression or a type, and if FOO is a complex expression, this can
- be hard to determine at the right time). Fortunately, it works
- pretty well in most cases. For example, if you do 'ptype A::B',
- where A::B is a nested type, then the parser will mistakenly
- misidentify it as an expression; but evaluate_subexp will get
- called with 'noside' set to EVAL_AVOID_SIDE_EFFECTS, and everything
- will work out anyways. But there are situations where the parser
- will get confused: the most common one that I've run into is when
- you want to do
-
- print *((A::B *) x)"
-
- where the parser doesn't realize that A::B has to be a type until
- it hits the first right paren, at which point it's too late. (The
- workaround is to type "print *(('A::B' *) x)" instead.) (And
- another solution is to fix our symbol-handling code so that the
- user never wants to type something like that in the first place,
- because we get all the types right without the user's help!)
-
- Perhaps we could fix this by making the lexer smarter. Some of
- this functionality used to be in the lexer, but in a way that
- worked even less well than the current solution: that attempt
- involved having the parser sometimes handle '::' and having the
- lexer sometimes handle it, and without a clear division of
- responsibility, it quickly degenerated into a big mess. Probably
- the eventual correct solution will give more of a role to the lexer
- (ideally via code that is shared between the lexer and
- decode_line_1), but I'm not holding my breath waiting for somebody
- to get around to cleaning this up... */
-
-qualified_type: typebase COLONCOLON name
- {
- struct type *type = $1;
- struct type *new_type;
- char *ncopy = alloca ($3.length + 1);
-
- memcpy (ncopy, $3.ptr, $3.length);
- ncopy[$3.length] = '\0';
-
- 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));
-
- new_type = cp_lookup_nested_type (type, ncopy,
- expression_context_block);
- if (new_type == NULL)
- error ("No type \"%s\" within class or namespace \"%s\".",
- ncopy, TYPE_NAME (type));
-
- $$ = new_type;
- }
;
typename: TYPENAME
{
$$.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
/* Read one token, getting characters through lexptr. */
static int
-yylex (void)
+lex_one_token (void)
{
int c;
int namelen;
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 (parse_completion && *lexptr == '\0')
+ saw_name_at_eof = 1;
+ return NAME;
+}
+
+/* An object of this type is pushed on a FIFO by the "outer" lexer. */
+typedef struct
+{
+ int token;
+ YYSTYPE value;
+} token_and_value;
+
+DEF_VEC_O (token_and_value);
+
+/* A FIFO of tokens that have been read but not yet returned to the
+ parser. */
+static VEC (token_and_value) *token_fifo;
+
+/* Non-zero if the lexer should return tokens from the FIFO. */
+static int popping;
+
+/* Temporary storage for c_lex; this holds symbol names as they are
+ built up. */
+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. */
+static int
+classify_name (const struct block *block)
+{
+ struct symbol *sym;
+ char *copy;
+ 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_name_of_this
+ ? &is_a_field_of_this : NULL);
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
- write_dollar_variable (yylval.sval);
- return VARIABLE;
+ yylval.ssym.sym = sym;
+ yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
+ return BLOCKNAME;
}
-
- /* Use token-type BLOCKNAME for symbols that happen to be defined as
- functions or symtabs. If this is not so, then ...
- Use token-type TYPENAME for symbols that happen to be defined
- currently as names of types; NAME for other symbols.
- The caller is not constrained to care about the distinction. */
- {
- struct symbol *sym;
- int is_a_field_of_this = 0;
- int hextype;
-
- sym = lookup_symbol (copy, expression_context_block,
- VAR_DOMAIN,
- parse_language->la_language == language_cplus
- ? &is_a_field_of_this : (int *) NULL);
- /* Call lookup_symtab, not lookup_partial_symtab, in case there are
- no psymtabs (coff, xcoff, or some future change to blow away the
- psymtabs once once symbols are read). */
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
- return BLOCKNAME;
- }
- else if (!sym)
- { /* See if it's a file name. */
- struct symtab *symtab;
+ else if (!sym)
+ {
+ /* See if it's a file name. */
+ struct symtab *symtab;
- symtab = lookup_symtab (copy);
+ symtab = lookup_symtab (copy);
+ if (symtab)
+ {
+ yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ return FILENAME;
+ }
- if (symtab)
- {
- 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;
- if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
- {
- /* NOTE: carlton/2003-09-25: There used to be code here to
- handle nested types. It didn't work very well. See the
- comment before qualified_type for more info. */
- yylval.tsym.type = SYMBOL_TYPE (sym);
- return TYPENAME;
- }
- yylval.tsym.type
- = language_lookup_primitive_type_by_name (parse_language,
- parse_gdbarch, copy);
- if (yylval.tsym.type != NULL)
+ 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)
+ {
+ yylval.tsym.type = SYMBOL_TYPE (sym);
return TYPENAME;
+ }
- /* 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 (!sym
- && ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10)
- || (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
- {
- YYSTYPE newlval; /* Its value is ignored. */
- hextype = parse_number (tokstart, namelen, 0, &newlval);
- if (hextype == INT)
- {
- yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
- return NAME_OR_INT;
- }
- }
+ yylval.tsym.type
+ = language_lookup_primitive_type_by_name (parse_language,
+ parse_gdbarch, copy);
+ if (yylval.tsym.type != NULL)
+ return TYPENAME;
- /* Any other kind of symbol */
- yylval.ssym.sym = sym;
- yylval.ssym.is_a_field_of_this = is_a_field_of_this;
- if (in_parse_field && *lexptr == '\0')
- saw_name_at_eof = 1;
- return NAME;
- }
+ /* 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 (!sym
+ && ((copy[0] >= 'a' && copy[0] < 'a' + input_radix - 10)
+ || (copy[0] >= 'A' && copy[0] < 'A' + input_radix - 10)))
+ {
+ YYSTYPE newlval; /* Its value is ignored. */
+ int hextype = parse_number (copy, yylval.sval.length, 0, &newlval);
+ if (hextype == INT)
+ {
+ yylval.ssym.sym = sym;
+ 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.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. */
+
+static int
+classify_inner_name (const struct block *block, int first_name)
+{
+ struct type *type, *new_type;
+ char *copy;
+
+ if (first_name)
+ return classify_name (block);
+
+ type = check_typedef (yylval.tsym.type);
+ 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);
+ if (yylval.ssym.sym == NULL)
+ return ERROR;
+
+ switch (SYMBOL_CLASS (yylval.ssym.sym))
+ {
+ case LOC_BLOCK:
+ case LOC_LABEL:
+ return ERROR;
+
+ case LOC_TYPEDEF:
+ yylval.tsym.type = SYMBOL_TYPE (yylval.ssym.sym);;
+ 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
+ to return tokens. It then either returns these tokens, or
+ aggregates them into a larger token. This lets us work around a
+ problem in our parsing approach, where the parser could not
+ distinguish between qualified names and qualified types at the
+ right point.
+
+ This approach is still not ideal, because it mishandles template
+ types. See the comment in lex_one_token for an example. However,
+ this is still an improvement over the earlier approach, and will
+ suffice until we move to better parsing technology. */
+static int
+yylex (void)
+{
+ token_and_value current;
+ int first_was_coloncolon, last_was_coloncolon, first_iter;
+
+ 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;
+ }
+ popping = 0;
+
+ current.token = lex_one_token ();
+ if (current.token == NAME)
+ current.token = classify_name (expression_context_block);
+ if (parse_language->la_language != language_cplus
+ || (current.token != TYPENAME && current.token != COLONCOLON))
+ 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);
+ current.value = yylval;
+ first_iter = 1;
+ while (1)
+ {
+ token_and_value next;
+
+ next.token = lex_one_token ();
+ next.value = yylval;
+
+ if (next.token == NAME && last_was_coloncolon)
+ {
+ int classification;
+
+ classification = classify_inner_name (first_was_coloncolon
+ ? NULL
+ : expression_context_block,
+ 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 && classification != NAME)
+ {
+ /* Push the final component and leave the loop. */
+ VEC_safe_push (token_and_value, token_fifo, &next);
+ break;
+ }
+
+ /* Update the partial name we are constructing. */
+ if (!first_iter)
+ {
+ /* 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);
+
+ yylval.sval.ptr = obstack_base (&name_obstack);
+ yylval.sval.length = obstack_object_size (&name_obstack);
+ current.value = yylval;
+ current.token = classification;
+
+ last_was_coloncolon = 0;
+ }
+ 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)
+ {
+ 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);
+ }
+
+ yylval = current.value;
+ yylval.sval.ptr = obstack_copy0 (&expansion_obstack,
+ yylval.sval.ptr,
+ yylval.sval.length);
+ return current.token;
}
int
last_was_structop = 0;
saw_name_at_eof = 0;
+ VEC_free (token_and_value, token_fifo);
+ popping = 0;
+ obstack_init (&name_obstack);
+ make_cleanup_obstack_free (&name_obstack);
+
result = yyparse ();
do_cleanups (back_to);
return result;
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);
}