/* YACC parser for C expressions, for GDB.
- Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994
+ Free Software Foundation, Inc.
This file is part of GDB.
%{
#include "defs.h"
+#include <string.h>
#include "expression.h"
-#include "parser-defs.h"
#include "value.h"
+#include "parser-defs.h"
#include "language.h"
#include "c-lang.h"
+#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 */
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
as well as gratuitiously global symbol names, so we can have multiple
%union
{
LONGEST lval;
- unsigned LONGEST ulval;
struct {
LONGEST val;
struct type *type;
parse_number PARAMS ((char *, int, int, YYSTYPE *));
%}
-%type <voidval> exp exp1 type_exp start variable qualified_name
+%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> rcurly
%type <tval> type typebase
%type <tvec> nonempty_typelist
/* %type <bval> block */
write_exp_elt_opcode (OP_FUNCALL); }
;
+lcurly : '{'
+ { start_arglist (); }
+ ;
+
arglist :
;
{ arglist_len++; }
;
-exp : '{' type '}' exp %prec UNARY
+rcurly : '}'
+ { $$ = end_arglist () - 1; }
+ ;
+exp : lcurly arglist rcurly %prec ARROW
+ { write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) $3);
+ 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 : STRING
- { write_exp_elt_opcode (OP_STRING);
- write_exp_string ($1);
- write_exp_elt_opcode (OP_STRING); }
+ { /* 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.
+ There is no such thing in C as a completely empty
+ string. */
+ char *sp = $1.ptr; int count = $1.length;
+ while (count-- > 0)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_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_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); }
;
/* C++. */
block : block COLONCOLON name
{ struct symbol *tem
= lookup_symbol (copy_name ($3), $1,
- VAR_NAMESPACE, 0, NULL);
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) 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, 0, NULL);
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
if (sym == 0)
error ("No symbol \"%s\" in specified context.",
copy_name ($3));
write_exp_elt_opcode (OP_VAR_VALUE);
+ /* block_found is set by lookup_symbol. */
+ write_exp_elt_block (block_found);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE); }
;
struct minimal_symbol *msymbol;
sym =
- lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL);
+ lookup_symbol (name, (const struct block *) NULL,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
if (sym)
{
write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE);
break;
(struct objfile *) NULL);
if (msymbol != NULL)
{
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_int);
- write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_opcode (UNOP_MEMVAL);
- if (msymbol -> type == mst_data ||
- msymbol -> type == mst_bss)
- write_exp_elt_type (builtin_type_int);
- else if (msymbol -> type == mst_text)
- write_exp_elt_type (lookup_function_type (builtin_type_int));
- else
- write_exp_elt_type (builtin_type_char);
- write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_msymbol (msymbol,
+ lookup_function_type (builtin_type_int),
+ builtin_type_int);
}
else
if (!have_full_symbols () && !have_partial_symbols ())
if (sym)
{
- switch (SYMBOL_CLASS (sym))
+ if (symbol_read_needs_frame (sym))
{
- case LOC_REGISTER:
- case LOC_ARG:
- case LOC_REF_ARG:
- case LOC_REGPARM:
- case LOC_LOCAL:
- case LOC_LOCAL_ARG:
if (innermost_block == 0 ||
contained_in (block_found,
innermost_block))
innermost_block = block_found;
- case LOC_UNDEF:
- case LOC_CONST:
- case LOC_STATIC:
- case LOC_TYPEDEF:
- case LOC_LABEL:
- case LOC_BLOCK:
- case LOC_CONST_BYTES:
-
- /* In this case the expression can
- be evaluated regardless of what
- frame we are in, so there is no
- need to check for the
- innermost_block. These cases are
- listed so that gcc -Wall will
- report types that may not have
- been considered. */
-
- break;
}
+
write_exp_elt_opcode (OP_VAR_VALUE);
+ /* We want to use the selected frame, not
+ another more inner frame which happens to
+ be in the same block. */
+ write_exp_elt_block (NULL);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE);
}
(struct objfile *) NULL);
if (msymbol != NULL)
{
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_int);
- write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_opcode (UNOP_MEMVAL);
- if (msymbol -> type == mst_data ||
- msymbol -> type == mst_bss)
- write_exp_elt_type (builtin_type_int);
- else if (msymbol -> type == mst_text)
- write_exp_elt_type (lookup_function_type (builtin_type_int));
- else
- write_exp_elt_type (builtin_type_char);
- write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_msymbol (msymbol,
+ lookup_function_type (builtin_type_int),
+ builtin_type_int);
}
else if (!have_full_symbols () && !have_partial_symbols ())
error ("No symbol table is loaded. Use the \"file\" command.");
ptype : typebase
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ before the type is currently handled in the typebase rule.
+ The reason for recognizing these here (shift/reduce conflicts)
+ might be obsolete now that some pointer to member rules have
+ been deleted. */
+ | typebase CONST_KEYWORD
+ | typebase VOLATILE_KEYWORD
| typebase abs_decl
- {
- /* This is where the interesting stuff happens. */
- int done = 0;
- int array_size;
- struct type *follow_type = $1;
- struct type *range_type;
-
- while (!done)
- switch (pop_type ())
- {
- case tp_end:
- done = 1;
- break;
- case tp_pointer:
- follow_type = lookup_pointer_type (follow_type);
- break;
- case tp_reference:
- follow_type = lookup_reference_type (follow_type);
- break;
- case tp_array:
- array_size = pop_type_int ();
- if (array_size != -1)
- {
- range_type =
- create_range_type ((struct type *) NULL,
- builtin_type_int, 0,
- array_size - 1);
- follow_type =
- create_array_type ((struct type *) NULL,
- follow_type, range_type);
- }
- else
- follow_type = lookup_pointer_type (follow_type);
- break;
- case tp_function:
- follow_type = lookup_function_type (follow_type);
- break;
- }
- $$ = follow_type;
- }
+ { $$ = follow_types ($1); }
+ | typebase CONST_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
+ | typebase VOLATILE_KEYWORD abs_decl
+ { $$ = follow_types ($1); }
;
abs_decl: '*'
push_type (tp_array);
$$ = 0;
}
+
| direct_abs_decl func_mod
{ push_type (tp_function); }
| func_mod
{ free ((PTR)$2); $$ = 0; }
;
+/* We used to try to recognize more 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 function type but
+ 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); }
- | type '(' typebase COLONCOLON '*' ')'
- { $$ = lookup_member_type ($1, $3); }
- | type '(' typebase COLONCOLON '*' ')' '(' ')'
- { $$ = lookup_member_type
- (lookup_function_type ($1), $3); }
- | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
- { $$ = lookup_member_type
- (lookup_function_type ($1), $3);
- free ((PTR)$8); }
;
typebase /* Implements (approximately): (type-qualifier)* type-specifier */
{ $$ = lookup_template_type(copy_name($2), $4,
expression_context_block);
}
- /* "const" and "volatile" are curently ignored. */
+ /* "const" and "volatile" are curently ignored. A type qualifier
+ after the type is handled in the ptype rule. I think these could
+ be too. */
| CONST_KEYWORD typebase { $$ = $2; }
| VOLATILE_KEYWORD typebase { $$ = $2; }
;
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;
- register int i;
+ unsigned LONGEST un;
+
+ register int i = 0;
register int c;
register int base = input_radix;
int unsigned_p = 0;
+
+ /* Number of "L" suffixes encountered. */
int long_p = 0;
- LONGEST high_bit;
+
+ /* We have found a "L" or "U" suffix. */
+ int found_suffix = 0;
+
+ unsigned LONGEST high_bit;
struct type *signed_type;
struct type *unsigned_type;
if (c != 'l' && c != 'u')
n *= base;
if (c >= '0' && c <= '9')
- n += i = c - '0';
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - '0';
+ }
else
{
if (base > 10 && c >= 'a' && c <= 'f')
- n += i = c - 'a' + 10;
- else if (len == 0 && c == 'l')
- long_p = 1;
- else if (len == 0 && c == 'u')
- unsigned_p = 1;
+ {
+ if (found_suffix)
+ return ERROR;
+ n += i = c - 'a' + 10;
+ }
+ else if (c == 'l')
+ {
+ ++long_p;
+ found_suffix = 1;
+ }
+ else if (c == 'u')
+ {
+ unsigned_p = 1;
+ found_suffix = 1;
+ }
else
return ERROR; /* Char not a digit */
}
return ERROR; /* Invalid digit in this base */
/* Portably test for overflow (only works for nonzero values, so make
- a second check for zero). */
- if((prevn >= n) && n != 0)
- unsigned_p=1; /* Try something unsigned */
- /* If range checking enabled, portably test for unsigned overflow. */
- if(RANGE_CHECK && n!=0)
- {
- if((unsigned_p && (unsigned)prevn >= (unsigned)n))
- range_error("Overflow on numeric constant.");
- }
- prevn=n;
+ a second check for zero). FIXME: Can't we just make n and prevn
+ unsigned and avoid this? */
+ if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+ unsigned_p = 1; /* Try something unsigned */
+
+ /* Portably test for unsigned overflow.
+ FIXME: This check is wrong; for example it doesn't find overflow
+ on 0x123456789 when LONGEST is 32 bits. */
+ if (c != 'l' && c != 'u' && n != 0)
+ {
+ if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n))
+ error ("Numeric constant too large.");
+ }
+ prevn = n;
}
-
- /* If the number is too big to be an int, or it's got an l suffix
- then it's a long. Work out if this has to be a long by
- shifting right and and seeing if anything remains, and the
- target int size is different to the target long size. */
- if ((TARGET_INT_BIT != TARGET_LONG_BIT && (n >> TARGET_INT_BIT)) || long_p)
- {
- high_bit = ((LONGEST)1) << (TARGET_LONG_BIT-1);
- unsigned_type = builtin_type_unsigned_long;
- signed_type = builtin_type_long;
- }
- else
- {
- high_bit = ((LONGEST)1) << (TARGET_INT_BIT-1);
- unsigned_type = builtin_type_unsigned_int;
- signed_type = builtin_type_int;
- }
+ /* An integer constant is an int, a long, or a long long. An L
+ suffix forces it to be long; an LL suffix forces it to be long
+ long. If not forced to a larger size, it gets the first type of
+ the above that it fits in. To figure out whether it fits, we
+ 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
+ the case where it is we just always shift the value more than
+ once, with fewer bits each time. */
+
+ un = (unsigned LONGEST)n >> 2;
+ if (long_p == 0
+ && (un >> (TARGET_INT_BIT - 2)) == 0)
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1);
+
+ /* A large decimal (not hex or octal) constant (between INT_MAX
+ and UINT_MAX) is a long or unsigned long, according to ANSI,
+ never an unsigned int, but this code treats it as unsigned
+ int. This probably should be fixed. GCC gives a warning on
+ such constants. */
+
+ unsigned_type = builtin_type_unsigned_int;
+ signed_type = builtin_type_int;
+ }
+ else if (long_p <= 1
+ && (un >> (TARGET_LONG_BIT - 2)) == 0)
+ {
+ high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1);
+ unsigned_type = builtin_type_unsigned_long;
+ signed_type = builtin_type_long;
+ }
+ else
+ {
+ high_bit = (((unsigned LONGEST)1)
+ << (TARGET_LONG_LONG_BIT - 32 - 1)
+ << 16
+ << 16);
+ if (high_bit == 0)
+ /* A long long does not fit in a LONGEST. */
+ high_bit =
+ (unsigned LONGEST)1 << (sizeof (LONGEST) * HOST_CHAR_BIT - 1);
+ unsigned_type = builtin_type_unsigned_long_long;
+ signed_type = builtin_type_long_long;
+ }
putithere->typed_val.val = n;
if (unsigned_p || (n & high_bit))
{
- putithere->typed_val.type = unsigned_type;
+ putithere->typed_val.type = unsigned_type;
}
else
{
- putithere->typed_val.type = signed_type;
+ putithere->typed_val.type = signed_type;
}
return INT;
if (namelen > 2)
{
lexptr = tokstart + namelen;
+ if (lexptr[-1] != '\'')
+ error ("Unmatched single quote.");
namelen -= 2;
tokstart++;
goto tryname;
for (;; ++p)
{
+ /* This test includes !hex because 'e' is a valid hex digit
+ and thus does not indicate a floating point number when
+ the radix is hex. */
if (!hex && !got_e && (*p == 'e' || *p == 'E'))
got_dot = got_e = 1;
- else if (!hex && !got_dot && *p == '.')
+ /* This test does not include !hex, because a '.' always indicates
+ a decimal floating point number regardless of the radix. */
+ else if (!got_dot && *p == '.')
got_dot = 1;
else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
&& (*p == '-' || *p == '+'))
{ CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
if (lookup_symbol (this_name, expression_context_block,
- VAR_NAMESPACE, 0, NULL))
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL))
return THIS;
}
break;
sym = lookup_symbol (tmp, expression_context_block,
VAR_NAMESPACE,
current_language->la_language == language_cplus
- ? &is_a_field_of_this : NULL,
- NULL);
+ ? &is_a_field_of_this : (int *) NULL,
+ (struct symtab **) 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) ||
- lookup_partial_symtab (tmp))
+ lookup_symtab (tmp))
{
yylval.ssym.sym = sym;
yylval.ssym.is_a_field_of_this = is_a_field_of_this;
}
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 *tmp = alloca (strlen (namestart)+1);
+
+ memcpy (tmp, namestart, p - namestart);
+ tmp[p - namestart] = '\0';
+ cur_sym = lookup_symbol (tmp, 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 */
yylval.tsym.type = SYMBOL_TYPE (sym);
+#endif /* not 0 */
return TYPENAME;
}
if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
yyerror (msg)
char *msg;
{
- error (msg ? msg : "Invalid syntax in expression.");
+ error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
}