/* YACC parser for C expressions, for GDB.
- Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000
+ Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2003, 2004, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Parse a C expression from text in a string,
and return the result as a struct expression pointer.
#include "bfd.h" /* Required by objfiles.h. */
#include "symfile.h" /* Required by objfiles.h. */
#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
-#include "completer.h" /* For skip_quoted(). */
+#include "charset.h"
+#include "block.h"
+#include "cp-support.h"
+#include "dfp.h"
-/* Flag indicating we're dealing with HP-compiled objects */
-extern int hp_som_som_object_present;
+#define parse_type builtin_type (parse_gdbarch)
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
as well as gratuitiously global symbol names, so we can have multiple
generators need to be fixed instead of adding those names to this list. */
#define yymaxdepth c_maxdepth
-#define yyparse c_parse
+#define yyparse c_parse_internal
#define yylex c_lex
#define yyerror c_error
#define yylval c_lval
DOUBLEST dval;
struct type *type;
} typed_val_float;
+ struct {
+ gdb_byte val[16];
+ struct type *type;
+ } typed_val_decfloat;
struct symbol *sym;
struct type *tval;
struct stoken sval;
%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
%type <lval> rcurly
-%type <tval> type typebase
+%type <tval> type typebase qualified_type
%type <tvec> nonempty_typelist
/* %type <bval> block */
%token <typed_val_int> INT
%token <typed_val_float> FLOAT
+%token <typed_val_decfloat> DECFLOAT
/* Both NAME and TYPENAME tokens represent symbols in the input,
and both convey their data as strings.
%token <sval> STRING
%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
+%token <voidval> COMPLETE
%token <tsym> TYPENAME
-%type <sval> name
+%type <sval> name string_exp
%type <ssym> name_not_typename
%type <tsym> typename
%token <opcode> ASSIGN_MODIFY
/* C++ */
-%token THIS
%token TRUEKEYWORD
%token FALSEKEYWORD
/* Expressions, not including the comma operator. */
exp : '*' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_IND); }
+ ;
exp : '&' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_ADDR); }
+ ;
exp : '-' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_NEG); }
;
+exp : '+' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_PLUS); }
+ ;
+
exp : '!' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
;
write_exp_elt_opcode (STRUCTOP_PTR); }
;
+exp : exp ARROW name COMPLETE
+ { mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+ ;
+
+exp : exp ARROW COMPLETE
+ { struct stoken s;
+ mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ s.ptr = "";
+ s.length = 0;
+ write_exp_string (s);
+ 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
write_exp_elt_opcode (STRUCTOP_STRUCT); }
;
+exp : exp '.' name COMPLETE
+ { mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($3);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
+exp : exp '.' COMPLETE
+ { struct stoken s;
+ mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ s.ptr = "";
+ s.length = 0;
+ write_exp_string (s);
+ 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
write_exp_elt_opcode (OP_DOUBLE); }
;
+exp : DECFLOAT
+ { write_exp_elt_opcode (OP_DECFLOAT);
+ write_exp_elt_type ($1.type);
+ write_exp_elt_decfloatcst ($1.val);
+ write_exp_elt_opcode (OP_DECFLOAT); }
+ ;
+
exp : variable
;
exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_int);
+ write_exp_elt_type (parse_type->builtin_int);
CHECK_TYPEDEF ($3);
write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
;
-exp : STRING
+string_exp:
+ STRING
+ {
+ /* We copy the string here, and not in the
+ lexer, to guarantee that we do not leak a
+ string. Note that we follow the
+ NUL-termination convention of the
+ lexer. */
+ $$.length = $1.length;
+ $$.ptr = malloc ($1.length + 1);
+ memcpy ($$.ptr, $1.ptr, $1.length + 1);
+ }
+
+ | string_exp STRING
+ {
+ /* Note that we NUL-terminate here, but just
+ for convenience. */
+ struct stoken t;
+ t.length = $1.length + $2.length;
+ t.ptr = malloc (t.length + 1);
+ memcpy (t.ptr, $1.ptr, $1.length);
+ memcpy (t.ptr + $1.length, $2.ptr, $2.length + 1);
+ free ($1.ptr);
+ $$ = t;
+ }
+ ;
+
+exp : string_exp
{ /* C strings are converted into array constants with
an explicit null byte added at the end. Thus
the array upper bound is the string length.
while (count-- > 0)
{
write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_char);
+ write_exp_elt_type (parse_type->builtin_char);
write_exp_elt_longcst ((LONGEST)(*sp++));
write_exp_elt_opcode (OP_LONG);
}
write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_char);
+ write_exp_elt_type (parse_type->builtin_char);
write_exp_elt_longcst ((LONGEST)'\0');
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (OP_ARRAY);
write_exp_elt_longcst ((LONGEST) 0);
write_exp_elt_longcst ((LONGEST) ($1.length));
- write_exp_elt_opcode (OP_ARRAY); }
+ write_exp_elt_opcode (OP_ARRAY);
+ free ($1.ptr);
+ }
;
/* C++. */
-exp : THIS
- { write_exp_elt_opcode (OP_THIS);
- write_exp_elt_opcode (OP_THIS); }
- ;
-
exp : TRUEKEYWORD
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_type (parse_type->builtin_bool);
write_exp_elt_longcst ((LONGEST) 1);
write_exp_elt_opcode (OP_LONG); }
;
exp : FALSEKEYWORD
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_bool);
+ write_exp_elt_type (parse_type->builtin_bool);
write_exp_elt_longcst ((LONGEST) 0);
write_exp_elt_opcode (OP_LONG); }
;
block : block COLONCOLON name
{ struct symbol *tem
= lookup_symbol (copy_name ($3), $1,
- VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL);
+ VAR_DOMAIN, (int *) NULL);
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
error ("No function \"%s\" in specified context.",
copy_name ($3));
variable: block COLONCOLON name
{ struct symbol *sym;
sym = lookup_symbol (copy_name ($3), $1,
- VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL);
+ VAR_DOMAIN, (int *) NULL);
if (sym == 0)
error ("No symbol \"%s\" in specified context.",
copy_name ($3));
{
struct type *type = $1;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
- && TYPE_CODE (type) != TYPE_CODE_UNION)
+ && TYPE_CODE (type) != TYPE_CODE_UNION
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
error ("`%s' is not defined as an aggregate type.",
TYPE_NAME (type));
struct type *type = $1;
struct stoken tmp_token;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
- && TYPE_CODE (type) != TYPE_CODE_UNION)
+ && TYPE_CODE (type) != TYPE_CODE_UNION
+ && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
error ("`%s' is not defined as an aggregate type.",
TYPE_NAME (type));
sym =
lookup_symbol (name, (const struct block *) NULL,
- VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL);
+ VAR_DOMAIN, (int *) NULL);
if (sym)
{
write_exp_elt_opcode (OP_VAR_VALUE);
msymbol = lookup_minimal_symbol (name, NULL, NULL);
if (msymbol != NULL)
- {
- write_exp_msymbol (msymbol,
- lookup_function_type (builtin_type_int),
- builtin_type_int);
- }
+ write_exp_msymbol (msymbol);
+ else if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
else
- if (!have_full_symbols () && !have_partial_symbols ())
- 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);
}
;
else
{
struct minimal_symbol *msymbol;
- register char *arg = copy_name ($1.stoken);
+ char *arg = copy_name ($1.stoken);
msymbol =
lookup_minimal_symbol (arg, NULL, NULL);
if (msymbol != NULL)
- {
- write_exp_msymbol (msymbol,
- lookup_function_type (builtin_type_int),
- builtin_type_int);
- }
+ write_exp_msymbol (msymbol);
else if (!have_full_symbols () && !have_partial_symbols ())
error ("No symbol table is loaded. Use the \"file\" command.");
else
func_mod: '(' ')'
{ $$ = 0; }
| '(' nonempty_typelist ')'
- { free ((PTR)$2); $$ = 0; }
+ { free ($2); $$ = 0; }
;
-/* We used to try to recognize more pointer to member types here, but
+/* We used to try to recognize pointer to member types here, but
that didn't work (shift/reduce conflicts meant that these rules never
got executed). The problem is that
int (foo::bar::baz::bizzle)
is a pointer to member type. Stroustrup loses again! */
type : ptype
- | typebase COLONCOLON '*'
- { $$ = lookup_member_type (builtin_type_int, $1); }
;
typebase /* Implements (approximately): (type-qualifier)* type-specifier */
: TYPENAME
{ $$ = $1.type; }
| INT_KEYWORD
- { $$ = builtin_type_int; }
+ { $$ = parse_type->builtin_int; }
| LONG
- { $$ = builtin_type_long; }
+ { $$ = parse_type->builtin_long; }
| SHORT
- { $$ = builtin_type_short; }
+ { $$ = parse_type->builtin_short; }
| LONG INT_KEYWORD
- { $$ = builtin_type_long; }
+ { $$ = parse_type->builtin_long; }
| LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = builtin_type_long; }
+ { $$ = parse_type->builtin_long; }
| LONG SIGNED_KEYWORD
- { $$ = builtin_type_long; }
+ { $$ = parse_type->builtin_long; }
| SIGNED_KEYWORD LONG INT_KEYWORD
- { $$ = builtin_type_long; }
+ { $$ = parse_type->builtin_long; }
| UNSIGNED LONG INT_KEYWORD
- { $$ = builtin_type_unsigned_long; }
+ { $$ = parse_type->builtin_unsigned_long; }
| LONG UNSIGNED INT_KEYWORD
- { $$ = builtin_type_unsigned_long; }
+ { $$ = parse_type->builtin_unsigned_long; }
| LONG UNSIGNED
- { $$ = builtin_type_unsigned_long; }
+ { $$ = parse_type->builtin_unsigned_long; }
| LONG LONG
- { $$ = builtin_type_long_long; }
+ { $$ = parse_type->builtin_long_long; }
| LONG LONG INT_KEYWORD
- { $$ = builtin_type_long_long; }
+ { $$ = parse_type->builtin_long_long; }
| LONG LONG SIGNED_KEYWORD INT_KEYWORD
- { $$ = builtin_type_long_long; }
+ { $$ = parse_type->builtin_long_long; }
| LONG LONG SIGNED_KEYWORD
- { $$ = builtin_type_long_long; }
+ { $$ = parse_type->builtin_long_long; }
| SIGNED_KEYWORD LONG LONG
- { $$ = builtin_type_long_long; }
+ { $$ = parse_type->builtin_long_long; }
+ | SIGNED_KEYWORD LONG LONG INT_KEYWORD
+ { $$ = parse_type->builtin_long_long; }
| UNSIGNED LONG LONG
- { $$ = builtin_type_unsigned_long_long; }
+ { $$ = parse_type->builtin_unsigned_long_long; }
| UNSIGNED LONG LONG INT_KEYWORD
- { $$ = builtin_type_unsigned_long_long; }
+ { $$ = parse_type->builtin_unsigned_long_long; }
| LONG LONG UNSIGNED
- { $$ = builtin_type_unsigned_long_long; }
+ { $$ = parse_type->builtin_unsigned_long_long; }
| LONG LONG UNSIGNED INT_KEYWORD
- { $$ = builtin_type_unsigned_long_long; }
- | SIGNED_KEYWORD LONG LONG
- { $$ = lookup_signed_typename ("long long"); }
- | SIGNED_KEYWORD LONG LONG INT_KEYWORD
- { $$ = lookup_signed_typename ("long long"); }
+ { $$ = parse_type->builtin_unsigned_long_long; }
| SHORT INT_KEYWORD
- { $$ = builtin_type_short; }
+ { $$ = parse_type->builtin_short; }
| SHORT SIGNED_KEYWORD INT_KEYWORD
- { $$ = builtin_type_short; }
+ { $$ = parse_type->builtin_short; }
| SHORT SIGNED_KEYWORD
- { $$ = builtin_type_short; }
+ { $$ = parse_type->builtin_short; }
| UNSIGNED SHORT INT_KEYWORD
- { $$ = builtin_type_unsigned_short; }
+ { $$ = parse_type->builtin_unsigned_short; }
| SHORT UNSIGNED
- { $$ = builtin_type_unsigned_short; }
+ { $$ = parse_type->builtin_unsigned_short; }
| SHORT UNSIGNED INT_KEYWORD
- { $$ = builtin_type_unsigned_short; }
+ { $$ = parse_type->builtin_unsigned_short; }
| DOUBLE_KEYWORD
- { $$ = builtin_type_double; }
+ { $$ = parse_type->builtin_double; }
| LONG DOUBLE_KEYWORD
- { $$ = builtin_type_long_double; }
+ { $$ = parse_type->builtin_long_double; }
| STRUCT name
{ $$ = lookup_struct (copy_name ($2),
expression_context_block); }
| UNSIGNED typename
{ $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); }
| UNSIGNED
- { $$ = builtin_type_unsigned_int; }
+ { $$ = parse_type->builtin_unsigned_int; }
| SIGNED_KEYWORD typename
{ $$ = lookup_signed_typename (TYPE_NAME($2.type)); }
| SIGNED_KEYWORD
- { $$ = builtin_type_int; }
+ { $$ = parse_type->builtin_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 = builtin_type_int;
+ $$.type = parse_type->builtin_int;
}
| LONG
{
$$.stoken.ptr = "long";
$$.stoken.length = 4;
- $$.type = builtin_type_long;
+ $$.type = parse_type->builtin_long;
}
| SHORT
{
$$.stoken.ptr = "short";
$$.stoken.length = 5;
- $$.type = builtin_type_short;
+ $$.type = parse_type->builtin_short;
}
;
static int
parse_number (p, len, parsed_float, putithere)
- register char *p;
- register int len;
+ char *p;
+ 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. */
- register LONGEST n = 0;
- register LONGEST prevn = 0;
+ LONGEST n = 0;
+ LONGEST prevn = 0;
ULONGEST un;
- register int i = 0;
- register int c;
- register int base = input_radix;
+ int i = 0;
+ int c;
+ int base = input_radix;
int unsigned_p = 0;
/* Number of "L" suffixes encountered. */
if (parsed_float)
{
/* It's a float since it contains a point or an exponent. */
- char c;
- int num = 0; /* number of tokens scanned by scanf */
- char saved_char = p[len];
+ char *s;
+ int num; /* number of tokens scanned by scanf */
+ char saved_char;
- p[len] = 0; /* null-terminate the token */
- if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
- num = sscanf (p, "%g%c", (float *) &putithere->typed_val_float.dval,&c);
- else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
- num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval,&c);
- else
+ /* If it ends at "df", "dd" or "dl", take it as type of decimal floating
+ point. Return DECFLOAT. */
+
+ if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
{
-#ifdef SCANF_HAS_LONG_DOUBLE
- num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval,&c);
-#else
- /* Scan it into a double, then assign it to the long double.
- This at least wins with values representable in the range
- of doubles. */
- double temp;
- num = sscanf (p, "%lg%c", &temp,&c);
- putithere->typed_val_float.dval = temp;
-#endif
+ p[len - 2] = '\0';
+ putithere->typed_val_decfloat.type
+ = parse_type->builtin_decfloat;
+ decimal_from_string (putithere->typed_val_decfloat.val, 4, p);
+ p[len - 2] = 'd';
+ return DECFLOAT;
}
+
+ if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd')
+ {
+ p[len - 2] = '\0';
+ putithere->typed_val_decfloat.type
+ = parse_type->builtin_decdouble;
+ decimal_from_string (putithere->typed_val_decfloat.val, 8, p);
+ p[len - 2] = 'd';
+ return DECFLOAT;
+ }
+
+ if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l')
+ {
+ p[len - 2] = '\0';
+ putithere->typed_val_decfloat.type
+ = parse_type->builtin_declong;
+ decimal_from_string (putithere->typed_val_decfloat.val, 16, p);
+ p[len - 2] = 'd';
+ 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) /* check scanf found ONLY a float ... */
- return ERROR;
- /* See if it has `f' or `l' suffix (float or long double). */
-
- c = tolower (p[len - 1]);
-
- if (c == 'f')
- putithere->typed_val_float.type = builtin_type_float;
- else if (c == 'l')
- putithere->typed_val_float.type = builtin_type_long_double;
- else if (isdigit (c) || c == '.')
- putithere->typed_val_float.type = builtin_type_double;
- else
- return ERROR;
+ 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);
return FLOAT;
}
shift it right and see whether anything remains. Note that we
can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one
operation, because many compilers will warn about such a shift
- (which always produces a zero result). Sometimes TARGET_INT_BIT
- or TARGET_LONG_BIT will be that big, sometimes not. To deal with
+ (which always produces a zero result). Sometimes gdbarch_int_bit
+ or gdbarch_long_bit will be that big, sometimes not. To deal with
the case where it is we just always shift the value more than
once, with fewer bits each time. */
un = (ULONGEST)n >> 2;
if (long_p == 0
- && (un >> (TARGET_INT_BIT - 2)) == 0)
+ && (un >> (gdbarch_int_bit (parse_gdbarch) - 2)) == 0)
{
- high_bit = ((ULONGEST)1) << (TARGET_INT_BIT-1);
+ high_bit = ((ULONGEST)1) << (gdbarch_int_bit (parse_gdbarch) - 1);
/* A large decimal (not hex or octal) constant (between INT_MAX
and UINT_MAX) is a long or unsigned long, according to ANSI,
int. This probably should be fixed. GCC gives a warning on
such constants. */
- unsigned_type = builtin_type_unsigned_int;
- signed_type = builtin_type_int;
+ unsigned_type = parse_type->builtin_unsigned_int;
+ signed_type = parse_type->builtin_int;
}
else if (long_p <= 1
- && (un >> (TARGET_LONG_BIT - 2)) == 0)
+ && (un >> (gdbarch_long_bit (parse_gdbarch) - 2)) == 0)
{
- high_bit = ((ULONGEST)1) << (TARGET_LONG_BIT-1);
- unsigned_type = builtin_type_unsigned_long;
- signed_type = builtin_type_long;
+ high_bit = ((ULONGEST)1) << (gdbarch_long_bit (parse_gdbarch) - 1);
+ unsigned_type = parse_type->builtin_unsigned_long;
+ signed_type = parse_type->builtin_long;
}
else
{
int shift;
- if (sizeof (ULONGEST) * HOST_CHAR_BIT < TARGET_LONG_LONG_BIT)
+ if (sizeof (ULONGEST) * HOST_CHAR_BIT
+ < gdbarch_long_long_bit (parse_gdbarch))
/* A long long does not fit in a LONGEST. */
shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
else
- shift = (TARGET_LONG_LONG_BIT - 1);
+ shift = (gdbarch_long_long_bit (parse_gdbarch) - 1);
high_bit = (ULONGEST) 1 << shift;
- unsigned_type = builtin_type_unsigned_long_long;
- signed_type = builtin_type_long_long;
+ unsigned_type = parse_type->builtin_unsigned_long_long;
+ signed_type = parse_type->builtin_long_long;
}
putithere->typed_val_int.val = n;
{">=", GEQ, BINOP_END}
};
+/* This is set if a NAME token appeared at the very end of the input
+ string, with no whitespace separating the name from the EOF. This
+ is used only when parsing to do field name completion. */
+static int saw_name_at_eof;
+
+/* This is set if the previously-returned token was a structure
+ operator -- either '.' or ARROW. This is used only when parsing to
+ do field name completion. */
+static int last_was_structop;
+
/* Read one token, getting characters through lexptr. */
static int
int tempbufindex;
static char *tempbuf;
static int tempbufsize;
- struct symbol * sym_class = NULL;
char * token_string = NULL;
int class_prefix = 0;
- int unquoted_expr;
-
+ int saw_structop = last_was_structop;
+
+ last_was_structop = 0;
+
retry:
/* Check if this is a macro invocation that we need to expand. */
}
prev_lexptr = lexptr;
- unquoted_expr = 1;
tokstart = lexptr;
/* See if it is a special token of length 3. */
for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
- if (STREQN (tokstart, tokentab3[i].operator, 3))
+ if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
{
lexptr += 3;
yylval.opcode = tokentab3[i].opcode;
/* See if it is a special token of length 2. */
for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
- if (STREQN (tokstart, tokentab2[i].operator, 2))
+ if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
{
lexptr += 2;
yylval.opcode = tokentab2[i].opcode;
+ if (in_parse_field && tokentab2[i].token == ARROW)
+ last_was_structop = 1;
return tokentab2[i].token;
}
case 0:
/* If we were just scanning the result of a macro expansion,
then we need to resume scanning the original text.
+ If we're parsing for field name completion, and the previous
+ token allows such completion, return a COMPLETE token.
Otherwise, we were already scanning the original text, and
we're really done. */
if (scanning_macro_expansion ())
finished_macro_expansion ();
goto retry;
}
+ else if (saw_name_at_eof)
+ {
+ saw_name_at_eof = 0;
+ return COMPLETE;
+ }
+ else if (saw_structop)
+ return COMPLETE;
else
return 0;
c = parse_escape (&lexptr);
else if (c == '\'')
error ("Empty character constant.");
+ else if (! host_char_to_target (c, &c))
+ {
+ int toklen = lexptr - tokstart + 1;
+ char *tok = alloca (toklen + 1);
+ memcpy (tok, tokstart, toklen);
+ tok[toklen] = '\0';
+ error ("There is no character corresponding to %s in the target "
+ "character set `%s'.", tok, target_charset ());
+ }
yylval.typed_val_int.val = c;
- yylval.typed_val_int.type = builtin_type_char;
+ yylval.typed_val_int.type = parse_type->builtin_char;
c = *lexptr++;
if (c != '\'')
if (namelen > 2)
{
lexptr = tokstart + namelen;
- unquoted_expr = 0;
if (lexptr[-1] != '\'')
error ("Unmatched single quote.");
namelen -= 2;
case '.':
/* Might be a floating point number. */
if (lexptr[1] < '0' || lexptr[1] > '9')
- goto symbol; /* Nope, must be a symbol. */
+ {
+ if (in_parse_field)
+ last_was_structop = 1;
+ goto symbol; /* Nope, must be a symbol. */
+ }
/* FALL THRU into number case. */
case '0':
{
/* It's a number. */
int got_dot = 0, got_e = 0, toktype;
- register char *p = tokstart;
+ char *p = tokstart;
int hex = input_radix > 10;
if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
tempbufindex = 0;
do {
+ char *char_start_pos = tokptr;
+
/* Grow the static temp buffer if necessary, including allocating
the first one on demand. */
if (tempbufindex + 1 >= tempbufsize)
tempbuf[tempbufindex++] = c;
break;
default:
- tempbuf[tempbufindex++] = *tokptr++;
+ c = *tokptr++;
+ if (! host_char_to_target (c, &c))
+ {
+ int len = tokptr - char_start_pos;
+ char *copy = alloca (len + 1);
+ memcpy (copy, char_start_pos, len);
+ copy[len] = '\0';
+
+ error ("There is no character corresponding to `%s' "
+ "in the target character set `%s'.",
+ copy, target_charset ());
+ }
+ tempbuf[tempbufindex++] = c;
break;
}
} while ((*tokptr != '"') && (*tokptr != '\0'));
switch (namelen)
{
case 8:
- if (STREQN (tokstart, "unsigned", 8))
+ if (strncmp (tokstart, "unsigned", 8) == 0)
return UNSIGNED;
- if (current_language->la_language == language_cplus
- && STREQN (tokstart, "template", 8))
+ if (parse_language->la_language == language_cplus
+ && strncmp (tokstart, "template", 8) == 0)
return TEMPLATE;
- if (STREQN (tokstart, "volatile", 8))
+ if (strncmp (tokstart, "volatile", 8) == 0)
return VOLATILE_KEYWORD;
break;
case 6:
- if (STREQN (tokstart, "struct", 6))
+ if (strncmp (tokstart, "struct", 6) == 0)
return STRUCT;
- if (STREQN (tokstart, "signed", 6))
+ if (strncmp (tokstart, "signed", 6) == 0)
return SIGNED_KEYWORD;
- if (STREQN (tokstart, "sizeof", 6))
+ if (strncmp (tokstart, "sizeof", 6) == 0)
return SIZEOF;
- if (STREQN (tokstart, "double", 6))
+ if (strncmp (tokstart, "double", 6) == 0)
return DOUBLE_KEYWORD;
break;
case 5:
- if (current_language->la_language == language_cplus)
+ if (parse_language->la_language == language_cplus)
{
- if (STREQN (tokstart, "false", 5))
+ if (strncmp (tokstart, "false", 5) == 0)
return FALSEKEYWORD;
- if (STREQN (tokstart, "class", 5))
+ if (strncmp (tokstart, "class", 5) == 0)
return CLASS;
}
- if (STREQN (tokstart, "union", 5))
+ if (strncmp (tokstart, "union", 5) == 0)
return UNION;
- if (STREQN (tokstart, "short", 5))
+ if (strncmp (tokstart, "short", 5) == 0)
return SHORT;
- if (STREQN (tokstart, "const", 5))
+ if (strncmp (tokstart, "const", 5) == 0)
return CONST_KEYWORD;
break;
case 4:
- if (STREQN (tokstart, "enum", 4))
+ if (strncmp (tokstart, "enum", 4) == 0)
return ENUM;
- if (STREQN (tokstart, "long", 4))
+ if (strncmp (tokstart, "long", 4) == 0)
return LONG;
- if (current_language->la_language == language_cplus)
+ if (parse_language->la_language == language_cplus)
{
- if (STREQN (tokstart, "true", 4))
+ if (strncmp (tokstart, "true", 4) == 0)
return TRUEKEYWORD;
-
- if (STREQN (tokstart, "this", 4))
- {
- static const char this_name[] =
- { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
-
- if (lookup_symbol (this_name, expression_context_block,
- VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL))
- return THIS;
- }
}
break;
case 3:
- if (STREQN (tokstart, "int", 3))
+ if (strncmp (tokstart, "int", 3) == 0)
return INT_KEYWORD;
break;
default:
return VARIABLE;
}
- /* Look ahead and see if we can consume more of the input
- string to get a reasonable class/namespace spec or a
- fully-qualified name. This is a kludge to get around the
- HP aCC compiler's generation of symbol names with embedded
- colons for namespace and nested classes. */
- if (unquoted_expr)
- {
- /* Only do it if not inside single quotes */
- sym_class = parse_nested_classes_for_hpacc (yylval.sval.ptr, yylval.sval.length,
- &token_string, &class_prefix, &lexptr);
- if (sym_class)
- {
- /* Replace the current token with the bigger one we found */
- yylval.sval.ptr = token_string;
- yylval.sval.length = strlen (token_string);
- }
- }
-
/* 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
int hextype;
sym = lookup_symbol (tmp, expression_context_block,
- VAR_NAMESPACE,
- current_language->la_language == language_cplus
- ? &is_a_field_of_this : (int *) NULL,
- (struct symtab **) NULL);
+ 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_TYPEDEF)
{
-#if 1
- /* Despite the following flaw, we need to keep this code enabled.
- Because we can get called from check_stub_method, if we don't
- handle nested types then it screws many operations in any
- program which uses nested types. */
- /* In "A::x", if x is a member function of A and there happens
- to be a type (nested or not, since the stabs don't make that
- distinction) named x, then this code incorrectly thinks we
- are dealing with nested types rather than a member function. */
-
- char *p;
- char *namestart;
- struct symbol *best_sym;
-
- /* Look ahead to detect nested types. This probably should be
- done in the grammar, but trying seemed to introduce a lot
- of shift/reduce and reduce/reduce conflicts. It's possible
- that it could be done, though. Or perhaps a non-grammar, but
- less ad hoc, approach would work well. */
-
- /* Since we do not currently have any way of distinguishing
- a nested type from a non-nested one (the stabs don't tell
- us whether a type is nested), we just ignore the
- containing type. */
-
- p = lexptr;
- best_sym = sym;
- while (1)
- {
- /* Skip whitespace. */
- while (*p == ' ' || *p == '\t' || *p == '\n')
- ++p;
- if (*p == ':' && p[1] == ':')
- {
- /* Skip the `::'. */
- p += 2;
- /* Skip whitespace. */
- while (*p == ' ' || *p == '\t' || *p == '\n')
- ++p;
- namestart = p;
- while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
- || (*p >= 'a' && *p <= 'z')
- || (*p >= 'A' && *p <= 'Z'))
- ++p;
- if (p != namestart)
- {
- struct symbol *cur_sym;
- /* As big as the whole rest of the expression, which is
- at least big enough. */
- char *ncopy = alloca (strlen (tmp)+strlen (namestart)+3);
- char *tmp1;
-
- tmp1 = ncopy;
- memcpy (tmp1, tmp, strlen (tmp));
- tmp1 += strlen (tmp);
- memcpy (tmp1, "::", 2);
- tmp1 += 2;
- memcpy (tmp1, namestart, p - namestart);
- tmp1[p - namestart] = '\0';
- cur_sym = lookup_symbol (ncopy, expression_context_block,
- VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL);
- if (cur_sym)
- {
- if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF)
- {
- best_sym = cur_sym;
- lexptr = p;
- }
- else
- break;
- }
- else
- break;
- }
- else
- break;
- }
- else
- break;
- }
-
- yylval.tsym.type = SYMBOL_TYPE (best_sym);
-#else /* not 0 */
+ /* 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);
-#endif /* not 0 */
return TYPENAME;
}
- if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
+ yylval.tsym.type
+ = language_lookup_primitive_type_by_name (parse_language,
+ parse_gdbarch, tmp);
+ if (yylval.tsym.type != NULL)
return TYPENAME;
/* Input names that aren't symbols but ARE valid hex numbers,
/* 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;
}
}
+int
+c_parse (void)
+{
+ last_was_structop = 0;
+ saw_name_at_eof = 0;
+ return yyparse ();
+}
+
void
yyerror (msg)
char *msg;