aboutsummaryrefslogtreecommitdiff
path: root/gdb/expread.y
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/expread.y')
-rw-r--r--gdb/expread.y460
1 files changed, 367 insertions, 93 deletions
diff --git a/gdb/expread.y b/gdb/expread.y
index fd6caa9..8af164e 100644
--- a/gdb/expread.y
+++ b/gdb/expread.y
@@ -1,22 +1,21 @@
/* Parse C expressions for GDB.
- Copyright (C) 1986 Free Software Foundation, Inc.
-
-GDB is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY. No author or distributor accepts responsibility to anyone
-for the consequences of using it or for whether it serves any
-particular purpose or works at all, unless he says so in writing.
-Refer to the GDB General Public License for full details.
-
-Everyone is granted permission to copy, modify and redistribute GDB,
-but only under the conditions described in the GDB General Public
-License. A copy of this license is supposed to have been given to you
-along with GDB so you can know your rights and responsibilities. It
-should be in a file named COPYING. Among other things, the copyright
-notice and this notice must be preserved on all copies.
-
-In other words, go ahead and share GDB, but don't try to stop
-anyone else from sharing it farther. Help stamp out software hoarding!
-*/
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Parse a C expression from text in a string,
and return the result as a struct expression pointer.
@@ -35,6 +34,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
#include "expression.h"
#include <stdio.h>
+#include <a.out.h>
static struct expression *expout;
static int expout_size;
@@ -43,6 +43,12 @@ static int expout_ptr;
static int yylex ();
static void yyerror ();
static void write_exp_elt ();
+static void write_exp_elt_opcode ();
+static void write_exp_elt_sym ();
+static void write_exp_elt_longcst ();
+static void write_exp_elt_dblcst ();
+static void write_exp_elt_type ();
+static void write_exp_elt_intern ();
static void write_exp_string ();
static void start_arglist ();
static int end_arglist ();
@@ -83,6 +89,19 @@ struct stoken
char *ptr;
int length;
};
+
+/* For parsing of complicated types.
+ An array should be preceded in the list by the size of the array. */
+enum type_pieces
+ {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function};
+static enum type_pieces *type_stack;
+static int type_stack_depth, type_stack_size;
+
+static void push_type ();
+static enum type_pieces pop_type ();
+
+/* Allow debugging of parsing. */
+#define YYDEBUG 1
%}
/* Although the yacc "value" of an expression is not used,
@@ -91,7 +110,8 @@ struct stoken
%union
{
- long lval;
+ LONGEST lval;
+ unsigned LONGEST ulval;
double dval;
struct symbol *sym;
struct type *tval;
@@ -110,7 +130,13 @@ struct stoken
%type <tvec> nonempty_typelist
%type <bval> block
+/* Fancy type parsing. */
+%type <voidval> func_mod direct_abs_decl abs_decl
+%type <tval> ptype
+%type <lval> array_mod
+
%token <lval> INT CHAR
+%token <ulval> UINT
%token <dval> FLOAT
/* Both NAME and TYPENAME tokens represent symbols in the input,
@@ -122,11 +148,15 @@ struct stoken
Contexts where this distinction is not important can use the
nonterminal "name", which matches either NAME or TYPENAME. */
-%token <sval> NAME TYPENAME STRING
-%type <sval> name
+%token <sval> NAME TYPENAME BLOCKNAME STRING
+%type <sval> name name_not_typename typename
%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token SIGNED LONG SHORT INT_KEYWORD
+
%token <lval> LAST REGNAME
%token <ivar> VARIABLE
@@ -139,6 +169,7 @@ struct stoken
%left ','
%left ABOVE_COMMA
%right '=' ASSIGN_MODIFY
+%right '?'
%left OR
%left AND
%left '|'
@@ -147,11 +178,11 @@ struct stoken
%left EQUAL NOTEQUAL
%left '<' '>' LEQ GEQ
%left LSH RSH
+%left '@'
%left '+' '-'
%left '*' '/' '%'
-%left '@'
%right UNARY INCREMENT DECREMENT
-%right ARROW '.' '['
+%right ARROW '.' '[' '('
%left COLONCOLON
%%
@@ -232,9 +263,9 @@ exp : exp '('
/* This is to save the value of arglist_len
being accumulated by an outer function call. */
{ start_arglist (); }
- arglist ')'
+ arglist ')' %prec ARROW
{ write_exp_elt_opcode (OP_FUNCALL);
- write_exp_elt_longcst (end_arglist ());
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
write_exp_elt_opcode (OP_FUNCALL); }
;
@@ -343,7 +374,7 @@ exp : exp OR exp
{ write_exp_elt_opcode (BINOP_OR); }
;
-exp : exp '?' exp ':' exp
+exp : exp '?' exp ':' exp %prec '?'
{ write_exp_elt_opcode (TERNOP_COND); }
;
@@ -359,15 +390,30 @@ exp : exp ASSIGN_MODIFY exp
exp : INT
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (builtin_type_long);
- write_exp_elt_longcst ($1);
+ if ($1 == (int) $1 || $1 == (unsigned int) $1)
+ write_exp_elt_type (builtin_type_int);
+ else
+ write_exp_elt_type (BUILTIN_TYPE_LONGEST);
+ write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LONG); }
;
+exp : UINT
+ {
+ write_exp_elt_opcode (OP_LONG);
+ if ($1 == (unsigned int) $1)
+ write_exp_elt_type (builtin_type_unsigned_int);
+ else
+ write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG);
+ }
+ ;
+
exp : CHAR
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_char);
- write_exp_elt_longcst ($1);
+ write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LONG); }
;
@@ -383,13 +429,13 @@ exp : variable
exp : LAST
{ write_exp_elt_opcode (OP_LAST);
- write_exp_elt_longcst ($1);
+ write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LAST); }
;
exp : REGNAME
{ write_exp_elt_opcode (OP_REGISTER);
- write_exp_elt_longcst ($1);
+ write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_REGISTER); }
;
@@ -399,10 +445,10 @@ exp : VARIABLE
write_exp_elt_opcode (OP_INTERNALVAR); }
;
-exp : SIZEOF '(' type ')'
+exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
- write_exp_elt_longcst ((long) TYPE_LENGTH ($3));
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
;
@@ -420,7 +466,7 @@ exp : THIS
/* end of C++. */
-block : name
+block : BLOCKNAME
{
struct symtab *tem = lookup_symtab (copy_name ($1));
struct symbol *sym;
@@ -494,12 +540,21 @@ variable: typebase COLONCOLON name
if (i < misc_function_count)
{
+ enum misc_function_type mft =
+ (enum misc_function_type)
+ misc_function_vector[i].type;
+
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
- write_exp_elt_longcst (misc_function_vector[i].address);
+ write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (UNOP_MEMVAL);
- write_exp_elt_type (builtin_type_char);
+ if (mft == mf_data || mft == mf_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (mft == mf_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);
}
else
@@ -511,7 +566,7 @@ variable: typebase COLONCOLON name
}
;
-variable: NAME
+variable: name_not_typename
{ struct symbol *sym;
int is_a_field_of_this;
@@ -560,12 +615,21 @@ variable: NAME
if (i < misc_function_count)
{
+ enum misc_function_type mft =
+ (enum misc_function_type)
+ misc_function_vector[i].type;
+
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
- write_exp_elt_longcst (misc_function_vector[i].address);
+ write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (UNOP_MEMVAL);
- write_exp_elt_type (builtin_type_char);
+ if (mft == mf_data || mft == mf_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (mft == mf_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);
}
else if (symtab_list == 0
@@ -578,19 +642,90 @@ variable: NAME
}
;
-type : typebase
- | type '*'
- { $$ = lookup_pointer_type ($1); }
- | type '&'
- { $$ = lookup_reference_type ($1); }
+
+ptype : typebase
+ | typebase abs_decl
+ {
+ /* This is where the interesting stuff happens. */
+ int done = 0;
+ int array_size;
+ struct type *follow_type = $1;
+
+ 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 = (int) pop_type ();
+ if (array_size != -1)
+ follow_type = create_array_type (follow_type,
+ array_size);
+ else
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_function:
+ follow_type = lookup_function_type (follow_type);
+ break;
+ }
+ $$ = follow_type;
+ }
+ ;
+
+abs_decl: '*'
+ { push_type (tp_pointer); $$ = 0; }
+ | '*' abs_decl
+ { push_type (tp_pointer); $$ = $2; }
+ | direct_abs_decl
+ ;
+
+direct_abs_decl: '(' abs_decl ')'
+ { $$ = $2; }
+ | direct_abs_decl array_mod
+ {
+ push_type ((enum type_pieces) $2);
+ push_type (tp_array);
+ }
+ | array_mod
+ {
+ push_type ((enum type_pieces) $1);
+ push_type (tp_array);
+ $$ = 0;
+ }
+ | direct_abs_decl func_mod
+ { push_type (tp_function); }
+ | func_mod
+ { push_type (tp_function); }
+ ;
+
+array_mod: '[' ']'
+ { $$ = -1; }
+ | '[' INT ']'
+ { $$ = $2; }
+ ;
+
+func_mod: '(' ')'
+ { $$ = 0; }
+ ;
+
+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)); }
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3); }
| type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
- { $$ = lookup_member_type (lookup_function_type ($1));
+ { $$ = lookup_member_type
+ (lookup_function_type ($1), $3);
free ($8); }
;
@@ -598,6 +733,20 @@ typebase
: TYPENAME
{ $$ = lookup_typename (copy_name ($1),
expression_context_block, 0); }
+ | INT_KEYWORD
+ { $$ = builtin_type_int; }
+ | LONG
+ { $$ = builtin_type_long; }
+ | SHORT
+ { $$ = builtin_type_short; }
+ | LONG INT_KEYWORD
+ { $$ = builtin_type_long; }
+ | UNSIGNED LONG INT_KEYWORD
+ { $$ = builtin_type_unsigned_long; }
+ | SHORT INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | UNSIGNED SHORT INT_KEYWORD
+ { $$ = builtin_type_unsigned_short; }
| STRUCT name
{ $$ = lookup_struct (copy_name ($2),
expression_context_block); }
@@ -607,8 +756,33 @@ typebase
| ENUM name
{ $$ = lookup_enum (copy_name ($2),
expression_context_block); }
- | UNSIGNED name
+ | UNSIGNED typename
{ $$ = lookup_unsigned_typename (copy_name ($2)); }
+ | UNSIGNED
+ { $$ = builtin_type_unsigned_int; }
+ | SIGNED typename
+ { $$ = lookup_typename (copy_name ($2),
+ expression_context_block, 0); }
+ | SIGNED
+ { $$ = builtin_type_int; }
+ ;
+
+typename: TYPENAME
+ | INT_KEYWORD
+ {
+ $$.ptr = "int";
+ $$.length = 3;
+ }
+ | LONG
+ {
+ $$.ptr = "long";
+ $$.length = 4;
+ }
+ | SHORT
+ {
+ $$.ptr = "short";
+ $$.length = 5;
+ }
;
nonempty_typelist
@@ -625,8 +799,14 @@ nonempty_typelist
;
name : NAME
+ | BLOCKNAME
| TYPENAME
;
+
+name_not_typename : NAME
+ | BLOCKNAME
+ ;
+
%%
/* Begin counting arguments for a function call,
@@ -782,7 +962,7 @@ write_exp_string (str)
}
bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
- write_exp_elt_longcst (len);
+ write_exp_elt_longcst ((LONGEST) len);
}
/* During parsing of a C expression, the pointer to the next character
@@ -820,11 +1000,12 @@ parse_number (olen)
int olen;
{
register char *p = lexptr;
- register long n = 0;
+ register LONGEST n = 0;
register int c;
register int base = 10;
register int len = olen;
char *err_copy;
+ int unsigned_p = 0;
extern double atof ();
@@ -850,7 +1031,7 @@ parse_number (olen)
{
c = *p++;
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
- if (c != 'l')
+ if (c != 'l' && c != 'u')
n *= base;
if (c >= '0' && c <= '9')
n += c - '0';
@@ -860,6 +1041,16 @@ parse_number (olen)
n += c - 'a' + 10;
else if (len == 0 && c == 'l')
;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else if (base == 10 && len != 0 && (c == 'e' || c == 'E'))
+ {
+ /* Scientific notation, where we are unlucky enough not
+ to have a '.' in the string. */
+ yylval.dval = atof (lexptr);
+ lexptr += olen;
+ return FLOAT;
+ }
else
{
err_copy = (char *) alloca (olen + 1);
@@ -871,8 +1062,16 @@ parse_number (olen)
}
lexptr = p;
- yylval.lval = n;
- return INT;
+ if (unsigned_p)
+ {
+ yylval.ulval = n;
+ return UINT;
+ }
+ else
+ {
+ yylval.lval = n;
+ return INT;
+ }
}
struct token
@@ -1006,6 +1205,11 @@ yylex ()
lexptr++;
return c;
+ case '.':
+ /* Might be a floating point number. */
+ if (lexptr[1] >= '0' && lexptr[1] <= '9')
+ break; /* Falls into number code. */
+
case '+':
case '-':
case '*':
@@ -1021,7 +1225,6 @@ yylex ()
case '>':
case '[':
case ']':
- case '.':
case '?':
case ':':
case '=':
@@ -1047,29 +1250,47 @@ yylex ()
lexptr += namelen + 1;
return STRING;
}
- if (c >= '0' && c <= '9')
+
+ /* Is it a number? */
+ /* Note: We have already dealt with the case of the token '.'.
+ See case '.' above. */
+ if ((c >= '0' && c <= '9') || c == '.')
{
- /* It's a number */
- for (namelen = 0;
- c = tokstart[namelen],
- (c == '_' || c == '$' || c == '.' || (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- namelen++)
- ;
- return parse_number (namelen);
+ /* It's a number. */
+ int got_dot = 0, got_e = 0;
+ register char *p = tokstart;
+ int hex = c == '0' && (p[1] == 'x' || p[1] == 'X');
+ if (hex)
+ p += 2;
+ for (;; ++p)
+ {
+ if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ else if (!hex && !got_dot && *p == '.')
+ got_dot = 1;
+ else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+ && (*p == '-' || *p == '+'))
+ /* This is the sign of the exponent, not the end of the
+ number. */
+ continue;
+ else if (*p < '0' || *p > '9'
+ && (!hex || ((*p < 'a' || *p > 'f')
+ && (*p < 'A' || *p > 'F'))))
+ break;
+ }
+ return parse_number (p - tokstart);
}
if (!(c == '_' || c == '$'
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
error ("Invalid token in expression.");
- /* It is a name. See how long it is. */
-
- for (namelen = 0;
- c = tokstart[namelen],
+ /* It's a name. See how long it is. */
+ namelen = 0;
+ for (c = tokstart[namelen];
(c == '_' || c == '$' || (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- namelen++)
+ c = tokstart[++namelen])
;
/* The token "if" terminates the expression and is NOT
@@ -1134,36 +1355,45 @@ yylex ()
return REGNAME;
}
}
- if (namelen == 6 && !strncmp (tokstart, "struct", 6))
- {
- return STRUCT;
- }
- if (namelen == 5)
+ /* Catch specific keywords. Should be done with a data structure. */
+ switch (namelen)
{
+ case 8:
+ if (!strncmp (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ break;
+ case 6:
+ if (!strncmp (tokstart, "struct", 6))
+ return STRUCT;
+ if (!strncmp (tokstart, "signed", 6))
+ return SIGNED;
+ if (!strncmp (tokstart, "sizeof", 6))
+ return SIZEOF;
+ break;
+ case 5:
if (!strncmp (tokstart, "union", 5))
- {
- return UNION;
- }
- }
- if (namelen == 4)
- {
+ return UNION;
+ if (!strncmp (tokstart, "short", 5))
+ return SHORT;
+ break;
+ case 4:
if (!strncmp (tokstart, "enum", 4))
- {
- return ENUM;
- }
+ return ENUM;
+ if (!strncmp (tokstart, "long", 4))
+ return LONG;
if (!strncmp (tokstart, "this", 4)
&& lookup_symbol ("$this", expression_context_block,
VAR_NAMESPACE, 0))
return THIS;
+ break;
+ case 3:
+ if (!strncmp (tokstart, "int", 3))
+ return INT_KEYWORD;
+ break;
+ default:
+ break;
}
- if (namelen == 6 && !strncmp (tokstart, "sizeof", 6))
- {
- return SIZEOF;
- }
- if (namelen == 8 && !strncmp (tokstart, "unsigned", 6))
- {
- return UNSIGNED;
- }
+
yylval.sval.ptr = tokstart;
yylval.sval.length = namelen;
@@ -1175,12 +1405,25 @@ yylex ()
return VARIABLE;
}
- /* Use token-type TYPENAME for symbols that happen to be defined
+ /* 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. */
- if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
- return TYPENAME;
- return NAME;
+ {
+ char *tmp = copy_name (yylval.sval);
+ struct symbol *sym;
+
+ if (lookup_partial_symtab (tmp))
+ return BLOCKNAME;
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, 0);
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ return BLOCKNAME;
+ if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
+ return TYPENAME;
+ return NAME;
+ }
}
static void
@@ -1443,6 +1686,7 @@ parse_c_1 (stringptr, block, comma)
lexptr = *stringptr;
paren_depth = 0;
+ type_stack_depth = 0;
comma_terminates = comma;
@@ -1487,3 +1731,33 @@ parse_c_expression (string)
error ("Junk after end of expression.");
return exp;
}
+
+static void
+push_type (tp)
+ enum type_pieces tp;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (enum type_pieces *)
+ xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces));
+ }
+ type_stack[type_stack_depth++] = tp;
+}
+
+static enum type_pieces
+pop_type ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth];
+ return tp_end;
+}
+
+void
+_initialize_expread ()
+{
+ type_stack_size = 80;
+ type_stack_depth = 0;
+ type_stack = (enum type_pieces *)
+ xmalloc (type_stack_size * sizeof (enum type_pieces));
+}