#include <ctype.h>
#include "defs.h"
#include "gdb_string.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "frame.h"
#include "expression.h"
#include "value.h"
#include "command.h"
#include "language.h"
#include "parser-defs.h"
#include "gdbcmd.h"
#include "symfile.h"
#include "inferior.h"
#include "doublest.h"
#include "gdb_assert.h"
#include "block.h"
const struct exp_descriptor exp_descriptor_standard =
{
print_subexp_standard,
operator_length_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_standard
};
struct expression *expout;
int expout_size;
int expout_ptr;
struct block *expression_context_block;
CORE_ADDR expression_context_pc;
struct block *innermost_block;
int arglist_len;
union type_stack_elt *type_stack;
int type_stack_depth, type_stack_size;
char *lexptr;
char *prev_lexptr;
int paren_depth;
int comma_terminates;
char *namecopy;
size_t namecopy_size;
static int expressiondebug = 0;
static void
show_expressiondebug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Expression debugging is %s.\n"), value);
}
static void free_funcalls (void *ignore);
static void prefixify_expression (struct expression *);
static void prefixify_subexp (struct expression *, struct expression *, int,
int);
static struct expression *parse_exp_in_context (char **, struct block *, int,
int);
void _initialize_parse (void);
struct funcall
{
struct funcall *next;
int arglist_len;
};
static struct funcall *funcall_chain;
void
start_arglist (void)
{
struct funcall *new;
new = (struct funcall *) xmalloc (sizeof (struct funcall));
new->next = funcall_chain;
new->arglist_len = arglist_len;
arglist_len = 0;
funcall_chain = new;
}
int
end_arglist (void)
{
int val = arglist_len;
struct funcall *call = funcall_chain;
funcall_chain = call->next;
arglist_len = call->arglist_len;
xfree (call);
return val;
}
static void
free_funcalls (void *ignore)
{
struct funcall *call, *next;
for (call = funcall_chain; call; call = next)
{
next = call->next;
xfree (call);
}
}
void
write_exp_elt (union exp_element expelt)
{
if (expout_ptr >= expout_size)
{
expout_size *= 2;
expout = (struct expression *)
xrealloc ((char *) expout, sizeof (struct expression)
+ EXP_ELEM_TO_BYTES (expout_size));
}
expout->elts[expout_ptr++] = expelt;
}
void
write_exp_elt_opcode (enum exp_opcode expelt)
{
union exp_element tmp;
tmp.opcode = expelt;
write_exp_elt (tmp);
}
void
write_exp_elt_sym (struct symbol *expelt)
{
union exp_element tmp;
tmp.symbol = expelt;
write_exp_elt (tmp);
}
void
write_exp_elt_block (struct block *b)
{
union exp_element tmp;
tmp.block = b;
write_exp_elt (tmp);
}
void
write_exp_elt_longcst (LONGEST expelt)
{
union exp_element tmp;
tmp.longconst = expelt;
write_exp_elt (tmp);
}
void
write_exp_elt_dblcst (DOUBLEST expelt)
{
union exp_element tmp;
tmp.doubleconst = expelt;
write_exp_elt (tmp);
}
void
write_exp_elt_type (struct type *expelt)
{
union exp_element tmp;
tmp.type = expelt;
write_exp_elt (tmp);
}
void
write_exp_elt_intern (struct internalvar *expelt)
{
union exp_element tmp;
tmp.internalvar = expelt;
write_exp_elt (tmp);
}
void
write_exp_string (struct stoken str)
{
int len = str.length;
int lenelt;
char *strdata;
lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1);
if ((expout_ptr + lenelt) >= expout_size)
{
expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
expout = (struct expression *)
xrealloc ((char *) expout, (sizeof (struct expression)
+ EXP_ELEM_TO_BYTES (expout_size)));
}
write_exp_elt_longcst ((LONGEST) len);
strdata = (char *) &expout->elts[expout_ptr];
memcpy (strdata, str.ptr, len);
*(strdata + len) = '\0';
expout_ptr += lenelt - 2;
write_exp_elt_longcst ((LONGEST) len);
}
void
write_exp_bitstring (struct stoken str)
{
int bits = str.length;
int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
int lenelt;
char *strdata;
lenelt = 2 + BYTES_TO_EXP_ELEM (len);
if ((expout_ptr + lenelt) >= expout_size)
{
expout_size = max (expout_size * 2, expout_ptr + lenelt + 10);
expout = (struct expression *)
xrealloc ((char *) expout, (sizeof (struct expression)
+ EXP_ELEM_TO_BYTES (expout_size)));
}
write_exp_elt_longcst ((LONGEST) bits);
strdata = (char *) &expout->elts[expout_ptr];
memcpy (strdata, str.ptr, len);
expout_ptr += lenelt - 2;
write_exp_elt_longcst ((LONGEST) bits);
}
struct type *msym_text_symbol_type;
struct type *msym_data_symbol_type;
struct type *msym_unknown_symbol_type;
void
write_exp_msymbol (struct minimal_symbol *msymbol,
struct type *text_symbol_type,
struct type *data_symbol_type)
{
CORE_ADDR addr;
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_CORE_ADDR);
addr = SYMBOL_VALUE_ADDRESS (msymbol);
if (overlay_debugging)
addr = symbol_overlayed_address (addr, SYMBOL_BFD_SECTION (msymbol));
write_exp_elt_longcst ((LONGEST) addr);
write_exp_elt_opcode (OP_LONG);
write_exp_elt_opcode (UNOP_MEMVAL);
switch (msymbol->type)
{
case mst_text:
case mst_file_text:
case mst_solib_trampoline:
write_exp_elt_type (msym_text_symbol_type);
break;
case mst_data:
case mst_file_data:
case mst_bss:
case mst_file_bss:
write_exp_elt_type (msym_data_symbol_type);
break;
default:
write_exp_elt_type (msym_unknown_symbol_type);
break;
}
write_exp_elt_opcode (UNOP_MEMVAL);
}
void
write_dollar_variable (struct stoken str)
{
struct symbol *sym = NULL;
struct minimal_symbol *msym = NULL;
int negate = 0;
int i = 1;
if (str.length >= 2 && str.ptr[1] == '$')
{
negate = 1;
i = 2;
}
if (i == str.length)
{
i = -negate;
goto handle_last;
}
for (; i < str.length; i++)
if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9'))
break;
if (i == str.length)
{
i = atoi (str.ptr + 1 + negate);
if (negate)
i = -i;
goto handle_last;
}
i = frame_map_name_to_regnum (deprecated_selected_frame,
str.ptr + 1, str.length - 1);
if (i >= 0)
goto handle_register;
sym = lookup_symbol (copy_name (str), (struct block *) NULL,
VAR_DOMAIN, (int *) NULL, (struct symtab **) NULL);
if (sym)
{
write_exp_elt_opcode (OP_VAR_VALUE);
write_exp_elt_block (block_found);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE);
return;
}
msym = lookup_minimal_symbol (copy_name (str), NULL, NULL);
if (msym)
{
write_exp_msymbol (msym,
lookup_function_type (builtin_type_int),
builtin_type_int);
return;
}
write_exp_elt_opcode (OP_INTERNALVAR);
write_exp_elt_intern (lookup_internalvar (copy_name (str) + 1));
write_exp_elt_opcode (OP_INTERNALVAR);
return;
handle_last:
write_exp_elt_opcode (OP_LAST);
write_exp_elt_longcst ((LONGEST) i);
write_exp_elt_opcode (OP_LAST);
return;
handle_register:
write_exp_elt_opcode (OP_REGISTER);
write_exp_elt_longcst (i);
write_exp_elt_opcode (OP_REGISTER);
return;
}
static const char coloncolon[2] =
{':', ':'};
struct symbol *
parse_nested_classes_for_hpacc (char *name, int len, char **token,
int *class_prefix, char **argptr)
{
char *p;
char *start, *end;
char *prefix = NULL;
char *tmp;
struct symbol *sym_class = NULL;
struct symbol *sym_var = NULL;
struct type *t;
int prefix_len = 0;
int done = 0;
char *q;
if (!deprecated_hp_som_som_object_present)
return (struct symbol *) NULL;
p = name;
while (*p && (*p == ' ' || *p == '\t'))
p++;
if (p[0] == ':' && p[1] == ':')
p += 2;
while (*p && (*p == ' ' || *p == '\t'))
p++;
while (1)
{
start = p;
if (!(isalpha (*p) || *p == '$' || *p == '_'))
return (struct symbol *) NULL;
p++;
while (*p && (isalnum (*p) || *p == '$' || *p == '_'))
p++;
if (*p == '<')
{
q = find_template_name_end (p);
if (q)
p = q;
}
end = p;
while (*p && (*p == ' ' || *p == '\t'))
p++;
if (p[0] == ':' && p[1] == ':')
p += 2;
while (*p && (*p == ' ' || *p == '\t'))
p++;
if (!*p || !(isalpha (*p) || *p == '$' || *p == '_'))
done = 1;
tmp = (char *) alloca (prefix_len + end - start + 3);
if (prefix)
{
memcpy (tmp, prefix, prefix_len);
memcpy (tmp + prefix_len, coloncolon, 2);
memcpy (tmp + prefix_len + 2, start, end - start);
tmp[prefix_len + 2 + end - start] = '\000';
}
else
{
memcpy (tmp, start, end - start);
tmp[end - start] = '\000';
}
prefix = tmp;
prefix_len = strlen (prefix);
if (!done)
{
sym_class = lookup_symbol (prefix, 0, STRUCT_DOMAIN,
0, (struct symtab **) NULL);
}
else
{
sym_var = lookup_symbol (prefix, 0, VAR_DOMAIN,
0, (struct symtab **) NULL);
if (!sym_var)
sym_class = lookup_symbol (prefix, 0, STRUCT_DOMAIN,
0, (struct symtab **) NULL);
}
if (sym_var ||
(sym_class &&
(t = check_typedef (SYMBOL_TYPE (sym_class)),
(TYPE_CODE (t) == TYPE_CODE_STRUCT
|| TYPE_CODE (t) == TYPE_CODE_UNION))))
{
*token = (char *) xmalloc (prefix_len + 1);
memcpy (*token, prefix, prefix_len);
(*token)[prefix_len] = '\000';
break;
}
if (done)
return (struct symbol *) NULL;
}
if (sym_var)
*class_prefix = 0;
else
*class_prefix = 1;
if (argptr)
*argptr = done ? p : end;
return sym_var ? sym_var : sym_class;
}
char *
find_template_name_end (char *p)
{
int depth = 1;
int just_seen_right = 0;
int just_seen_colon = 0;
int just_seen_space = 0;
if (!p || (*p != '<'))
return 0;
while (*++p)
{
switch (*p)
{
case '\'':
case '\"':
case '{':
case '}':
return 0;
case '<':
depth++;
if (just_seen_colon || just_seen_right || just_seen_space)
return 0;
break;
case '>':
if (just_seen_colon || just_seen_right)
return 0;
just_seen_right = 1;
if (--depth == 0)
return ++p;
break;
case ':':
if (just_seen_space || (just_seen_colon > 1))
return 0;
just_seen_colon++;
break;
case ' ':
break;
default:
if (!((*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z') ||
(*p >= '0' && *p <= '9') ||
(*p == '_') || (*p == ',') ||
(*p == '&') || (*p == '*') ||
(*p == '(') || (*p == ')') ||
(*p == '[') || (*p == ']')))
return 0;
}
if (*p != ' ')
just_seen_space = 0;
if (*p != ':')
just_seen_colon = 0;
if (*p != '>')
just_seen_right = 0;
}
return 0;
}
char *
copy_name (struct stoken token)
{
if (namecopy_size < token.length + 1)
{
namecopy_size = token.length + 1;
namecopy = xrealloc (namecopy, token.length + 1);
}
memcpy (namecopy, token.ptr, token.length);
namecopy[token.length] = 0;
return namecopy;
}
static void
prefixify_expression (struct expression *expr)
{
int len =
sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
struct expression *temp;
int inpos = expr->nelts, outpos = 0;
temp = (struct expression *) alloca (len);
memcpy (temp, expr, len);
prefixify_subexp (temp, expr, inpos, outpos);
}
int
length_of_subexp (struct expression *expr, int endpos)
{
int oplen, args;
operator_length (expr, endpos, &oplen, &args);
while (args > 0)
{
oplen += length_of_subexp (expr, endpos - oplen);
args--;
}
return oplen;
}
void
operator_length (struct expression *expr, int endpos, int *oplenp, int *argsp)
{
expr->language_defn->la_exp_desc->operator_length (expr, endpos,
oplenp, argsp);
}
void
operator_length_standard (struct expression *expr, int endpos,
int *oplenp, int *argsp)
{
int oplen = 1;
int args = 0;
int i;
if (endpos < 1)
error (_("?error in operator_length_standard"));
i = (int) expr->elts[endpos - 1].opcode;
switch (i)
{
case OP_SCOPE:
oplen = longest_to_int (expr->elts[endpos - 2].longconst);
oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
break;
case OP_LONG:
case OP_DOUBLE:
case OP_VAR_VALUE:
oplen = 4;
break;
case OP_TYPE:
case OP_BOOL:
case OP_LAST:
case OP_REGISTER:
case OP_INTERNALVAR:
oplen = 3;
break;
case OP_COMPLEX:
oplen = 1;
args = 2;
break;
case OP_FUNCALL:
case OP_F77_UNDETERMINED_ARGLIST:
oplen = 3;
args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
break;
case OP_OBJC_MSGCALL:
oplen = 4;
args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
break;
case UNOP_MAX:
case UNOP_MIN:
oplen = 3;
break;
case BINOP_VAL:
case UNOP_CAST:
case UNOP_MEMVAL:
oplen = 3;
args = 1;
break;
case UNOP_ABS:
case UNOP_CAP:
case UNOP_CHR:
case UNOP_FLOAT:
case UNOP_HIGH:
case UNOP_ODD:
case UNOP_ORD:
case UNOP_TRUNC:
oplen = 1;
args = 1;
break;
case OP_LABELED:
case STRUCTOP_STRUCT:
case STRUCTOP_PTR:
args = 1;
case OP_M2_STRING:
case OP_STRING:
case OP_OBJC_NSSTRING:
case OP_OBJC_SELECTOR:
case OP_NAME:
case OP_EXPRSTRING:
oplen = longest_to_int (expr->elts[endpos - 2].longconst);
oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
break;
case OP_BITSTRING:
oplen = longest_to_int (expr->elts[endpos - 2].longconst);
oplen = (oplen + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
oplen = 4 + BYTES_TO_EXP_ELEM (oplen);
break;
case OP_ARRAY:
oplen = 4;
args = longest_to_int (expr->elts[endpos - 2].longconst);
args -= longest_to_int (expr->elts[endpos - 3].longconst);
args += 1;
break;
case TERNOP_COND:
case TERNOP_SLICE:
case TERNOP_SLICE_COUNT:
args = 3;
break;
case MULTI_SUBSCRIPT:
oplen = 3;
args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
break;
case BINOP_ASSIGN_MODIFY:
oplen = 3;
args = 2;
break;
case OP_THIS:
case OP_OBJC_SELF:
oplen = 2;
break;
default:
args = 1 + (i < (int) BINOP_END);
}
*oplenp = oplen;
*argsp = args;
}
static void
prefixify_subexp (struct expression *inexpr,
struct expression *outexpr, int inend, int outbeg)
{
int oplen;
int args;
int i;
int *arglens;
operator_length (inexpr, inend, &oplen, &args);
inend -= oplen;
memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend],
EXP_ELEM_TO_BYTES (oplen));
outbeg += oplen;
arglens = (int *) alloca (args * sizeof (int));
for (i = args - 1; i >= 0; i--)
{
oplen = length_of_subexp (inexpr, inend);
arglens[i] = oplen;
inend -= oplen;
}
for (i = 0; i < args; i++)
{
oplen = arglens[i];
inend += oplen;
prefixify_subexp (inexpr, outexpr, inend, outbeg);
outbeg += oplen;
}
}
struct expression *
parse_exp_1 (char **stringptr, struct block *block, int comma)
{
return parse_exp_in_context (stringptr, block, comma, 0);
}
static struct expression *
parse_exp_in_context (char **stringptr, struct block *block, int comma,
int void_context_p)
{
struct cleanup *old_chain;
struct cleanup *hook_stop_chain;
lexptr = *stringptr;
prev_lexptr = NULL;
paren_depth = 0;
type_stack_depth = 0;
comma_terminates = comma;
if (lexptr == 0 || *lexptr == 0)
error_no_arg (_("expression to compute"));
old_chain = make_cleanup (free_funcalls, 0 );
funcall_chain = 0;
if (block)
{
expression_context_block = block;
expression_context_pc = BLOCK_LOWEST_PC (block);
}
else
expression_context_block = get_selected_block (&expression_context_pc);
expout_size = 10;
expout_ptr = 0;
expout = (struct expression *)
xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size));
expout->language_defn = current_language;
make_cleanup (free_current_contents, &expout);
hook_stop_chain = make_cleanup_suppress_hook_stop ();
innermost_block = NULL;
if (current_language->la_parser ())
current_language->la_error (NULL);
do_cleanups (hook_stop_chain);
discard_cleanups (old_chain);
expout->nelts = expout_ptr;
expout = (struct expression *)
xrealloc ((char *) expout,
sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_ptr));;
if (expressiondebug)
dump_raw_expression (expout, gdb_stdlog,
"before conversion to prefix form");
prefixify_expression (expout);
current_language->la_post_parser (&expout, void_context_p);
if (expressiondebug)
dump_prefix_expression (expout, gdb_stdlog);
*stringptr = lexptr;
return expout;
}
struct expression *
parse_expression (char *string)
{
struct expression *exp;
exp = parse_exp_1 (&string, 0, 0);
if (*string)
error (_("Junk after end of expression."));
return exp;
}
struct expression *
parse_expression_in_context (char *string, int void_context_p)
{
struct expression *exp;
exp = parse_exp_in_context (&string, 0, 0, void_context_p);
if (*string != '\000')
error (_("Junk after end of expression."));
return exp;
}
void
null_post_parser (struct expression **exp, int void_context_p)
{
}
static void
check_type_stack_depth (void)
{
if (type_stack_depth == type_stack_size)
{
type_stack_size *= 2;
type_stack = (union type_stack_elt *)
xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack));
}
}
void
push_type (enum type_pieces tp)
{
check_type_stack_depth ();
type_stack[type_stack_depth++].piece = tp;
}
void
push_type_int (int n)
{
check_type_stack_depth ();
type_stack[type_stack_depth++].int_val = n;
}
void
push_type_address_space (char *string)
{
push_type_int (address_space_name_to_int (string));
}
enum type_pieces
pop_type (void)
{
if (type_stack_depth)
return type_stack[--type_stack_depth].piece;
return tp_end;
}
int
pop_type_int (void)
{
if (type_stack_depth)
return type_stack[--type_stack_depth].int_val;
return 0;
}
struct type *
follow_types (struct type *follow_type)
{
int done = 0;
int make_const = 0;
int make_volatile = 0;
int make_addr_space = 0;
int array_size;
struct type *range_type;
while (!done)
switch (pop_type ())
{
case tp_end:
done = 1;
if (make_const)
follow_type = make_cv_type (make_const,
TYPE_VOLATILE (follow_type),
follow_type, 0);
if (make_volatile)
follow_type = make_cv_type (TYPE_CONST (follow_type),
make_volatile,
follow_type, 0);
if (make_addr_space)
follow_type = make_type_with_address_space (follow_type,
make_addr_space);
make_const = make_volatile = 0;
make_addr_space = 0;
break;
case tp_const:
make_const = 1;
break;
case tp_volatile:
make_volatile = 1;
break;
case tp_space_identifier:
make_addr_space = pop_type_int ();
break;
case tp_pointer:
follow_type = lookup_pointer_type (follow_type);
if (make_const)
follow_type = make_cv_type (make_const,
TYPE_VOLATILE (follow_type),
follow_type, 0);
if (make_volatile)
follow_type = make_cv_type (TYPE_CONST (follow_type),
make_volatile,
follow_type, 0);
if (make_addr_space)
follow_type = make_type_with_address_space (follow_type,
make_addr_space);
make_const = make_volatile = 0;
make_addr_space = 0;
break;
case tp_reference:
follow_type = lookup_reference_type (follow_type);
if (make_const)
follow_type = make_cv_type (make_const,
TYPE_VOLATILE (follow_type),
follow_type, 0);
if (make_volatile)
follow_type = make_cv_type (TYPE_CONST (follow_type),
make_volatile,
follow_type, 0);
if (make_addr_space)
follow_type = make_type_with_address_space (follow_type,
make_addr_space);
make_const = make_volatile = 0;
make_addr_space = 0;
break;
case tp_array:
array_size = pop_type_int ();
range_type =
create_range_type ((struct type *) NULL,
builtin_type_int, 0,
array_size >= 0 ? array_size - 1 : 0);
follow_type =
create_array_type ((struct type *) NULL,
follow_type, range_type);
if (array_size < 0)
TYPE_ARRAY_UPPER_BOUND_TYPE (follow_type)
= BOUND_CANNOT_BE_DETERMINED;
break;
case tp_function:
follow_type = lookup_function_type (follow_type);
break;
}
return follow_type;
}
static void build_parse (void);
static void
build_parse (void)
{
msym_text_symbol_type =
init_type (TYPE_CODE_FUNC, 1, 0, "<text variable, no debug info>", NULL);
TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_error;
msym_data_symbol_type =
init_type (TYPE_CODE_ERROR, 0, 0,
"<data variable, no debug info>", NULL);
msym_unknown_symbol_type =
init_type (TYPE_CODE_ERROR, 0, 0,
"<variable (not text or data), no debug info>",
NULL);
}
void
parser_fprintf (FILE *x, const char *y, ...)
{
va_list args;
va_start (args, y);
if (x == stderr)
vfprintf_unfiltered (gdb_stderr, y, args);
else
{
fprintf_unfiltered (gdb_stderr, " Unknown FILE used.\n");
vfprintf_unfiltered (gdb_stderr, y, args);
}
va_end (args);
}
void
_initialize_parse (void)
{
type_stack_size = 80;
type_stack_depth = 0;
type_stack = (union type_stack_elt *)
xmalloc (type_stack_size * sizeof (*type_stack));
build_parse ();
DEPRECATED_REGISTER_GDBARCH_SWAP (msym_text_symbol_type);
DEPRECATED_REGISTER_GDBARCH_SWAP (msym_data_symbol_type);
DEPRECATED_REGISTER_GDBARCH_SWAP (msym_unknown_symbol_type);
deprecated_register_gdbarch_swap (NULL, 0, build_parse);
add_setshow_zinteger_cmd ("expression", class_maintenance,
&expressiondebug, _("\
Set expression debugging."), _("\
Show expression debugging."), _("\
When non-zero, the internal representation of expressions will be printed."),
NULL,
show_expressiondebug,
&setdebuglist, &showdebuglist);
}