+2021-03-08 Tom Tromey <tom@tromey.com>
+
+ * ada-exp.h (class ada_var_value_operation) <get_symbol>: Remove;
+ now in superclass.
+ * value.h (fetch_subexp_value): Add "op" parameter.
+ * value.c (init_if_undefined_command): Update.
+ * tracepoint.c (validate_actionline, encode_actions_1): Update.
+ * stap-probe.c (stap_probe::compile_to_ax): Update.
+ * printcmd.c (set_command): Update.
+ * ppc-linux-nat.c (ppc_linux_nat_target::check_condition):
+ Update.
+ * parser-defs.h (struct expr_builder) <set_operation>: New
+ method.
+ * parse.c (parse_exp_in_context, exp_uses_objfile): Update.
+ * expression.h (struct expression) <first_opcode>: Update.
+ <op>: New member.
+ * expprint.c (dump_raw_expression, dump_prefix_expression):
+ Update.
+ * expop.h (class var_value_operation) <get_symbol>: New method.
+ (class register_operation) <get_name>: New method.
+ (class equal_operation): No longer a typedef, now a subclass.
+ (class unop_memval_operation) <get_type>: New method.
+ (class assign_operation) <get_lhs>: New method.
+ (class unop_cast_operation) <get_type>: New method.
+ * eval.c (evaluate_expression, evaluate_type)
+ (evaluate_subexpression_type): Update.
+ (fetch_subexp_value): Add "op" parameter.
+ (parse_and_eval_type): Update.
+ * dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
+ * breakpoint.c (update_watchpoint, watchpoint_check)
+ (watchpoint_exp_is_const, watch_command_1): Update.
+ * ax-gdb.c (gen_trace_for_expr, gen_eval_for_expr, gen_printf):
+ Update.
+
2021-03-08 Tom Tromey <tom@tromey.com>
* ada-lang.c (ada_value_binop): Do not use op_string.
struct expression *exp,
enum noside noside) override;
- symbol *get_symbol () const
- { return std::get<0> (m_storage); }
-
const block *get_block () const
{ return std::get<1> (m_storage); }
ax->tracing = 1;
ax->trace_string = trace_string;
value.optimized_out = 0;
- gen_expr (expr, &pc, ax.get (), &value);
+ if (expr->op != nullptr)
+ expr->op->generate_ax (expr, ax.get (), &value);
+ else
+ gen_expr (expr, &pc, ax.get (), &value);
/* Make sure we record the final object, and get rid of it. */
gen_traced_pop (ax.get (), &value);
pc = expr->elts;
ax->tracing = 0;
value.optimized_out = 0;
- gen_expr (expr, &pc, ax.get (), &value);
+ if (expr->op != nullptr)
+ expr->op->generate_ax (expr, ax.get (), &value);
+ else
+ gen_expr (expr, &pc, ax.get (), &value);
require_rvalue (ax.get (), &value);
for simplicity of collecting them on the target side. */
for (tem = nargs - 1; tem >= 0; --tem)
{
- pc = exprs[tem]->elts;
value.optimized_out = 0;
- gen_expr (exprs[tem], &pc, ax.get (), &value);
+ if (exprs[tem]->op != nullptr)
+ exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
+ else
+ {
+ pc = exprs[tem]->elts;
+ gen_expr (exprs[tem], &pc, ax.get (), &value);
+ }
require_rvalue (ax.get (), &value);
}
struct value *v, *result;
struct program_space *frame_pspace;
- fetch_subexp_value (b->exp.get (), &pc, &v, &result, &val_chain, false);
+ fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &v, &result,
+ &val_chain, false);
/* Avoid setting b->val if it's already set. The meaning of
b->val is 'the last value' user saw, and we should update
return WP_VALUE_CHANGED;
mark = value_mark ();
- fetch_subexp_value (b->exp.get (), &pc, &new_val, NULL, NULL, false);
+ fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &new_val,
+ NULL, NULL, false);
if (b->val_bitsize != 0)
new_val = extract_bitfield_from_watchpoint_value (b, new_val);
static bool
watchpoint_exp_is_const (const struct expression *exp)
{
+ if (exp->op != nullptr)
+ return exp->op->constant_p ();
+
int i = exp->nelts;
while (i > 0)
exp_valid_block = tracker.block ();
struct value *mark = value_mark ();
struct value *val_as_value = nullptr;
- fetch_subexp_value (exp.get (), &pc, &val_as_value, &result, NULL,
- just_location);
+ fetch_subexp_value (exp.get (), &pc, exp->op.get (), &val_as_value, &result,
+ NULL, just_location);
if (val_as_value != NULL && just_location)
{
arg = this->get_arg_by_number (n, expr->gdbarch);
- pc = arg->expr->elts;
- gen_expr (arg->expr.get (), &pc, expr, value);
+ if (arg->expr->op != nullptr)
+ arg->expr->op->generate_ax (arg->expr.get (), expr, value);
+ else
+ {
+ pc = arg->expr->elts;
+ gen_expr (arg->expr.get (), &pc, expr, value);
+ }
require_rvalue (expr, value);
value->type = arg->type;
&& !thread_stack_temporaries_enabled_p (inferior_thread ()))
stack_temporaries.emplace (inferior_thread ());
- int pos = 0;
- struct value *retval = evaluate_subexp (expect_type, this, &pos, noside);
+ struct value *retval;
+ if (op != nullptr)
+ retval = op->evaluate (expect_type, this, noside);
+ else
+ {
+ int pos = 0;
+ retval = evaluate_subexp (expect_type, this, &pos, noside);
+ }
if (stack_temporaries.has_value ()
&& value_in_thread_stack_temporaries (retval, inferior_thread ()))
struct value *
evaluate_subexpression_type (struct expression *exp, int subexp)
{
+ if (exp->op != nullptr)
+ return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
return evaluate_subexp (nullptr, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
}
values will be left on the value chain. */
void
-fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
- struct value **resultp,
+fetch_subexp_value (struct expression *exp, int *pc,
+ expr::operation *op,
+ struct value **valp, struct value **resultp,
std::vector<value_ref_ptr> *val_chain,
bool preserve_errors)
{
try
{
- result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
+ if (op == nullptr)
+ result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
+ else
+ result = op->evaluate (nullptr, exp, EVAL_NORMAL);
}
catch (const gdb_exception &ex)
{
expression_up expr = parse_expression (tmp);
if (expr->first_opcode () != UNOP_CAST)
error (_("Internal error in eval_type."));
+
+ if (expr->op != nullptr)
+ {
+ expr::unop_cast_operation *op
+ = dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
+ return op->get_type ();
+ }
+
return expr->elts[1].type;
}
enum exp_opcode opcode () const override
{ return OP_VAR_VALUE; }
+ /* Return the symbol referenced by this object. */
+ symbol *get_symbol () const
+ {
+ return std::get<0> (m_storage);
+ }
+
protected:
void do_generate_ax (struct expression *exp,
enum exp_opcode opcode () const override
{ return OP_REGISTER; }
+ /* Return the name of the register. */
+ const char *get_name () const
+ {
+ return std::get<0> (m_storage).c_str ();
+ }
+
protected:
void do_generate_ax (struct expression *exp,
}
};
-using equal_operation = comparison_operation<BINOP_EQUAL, eval_op_equal>;
+class equal_operation
+ : public comparison_operation<BINOP_EQUAL, eval_op_equal>
+{
+public:
+
+ using comparison_operation::comparison_operation;
+
+ operation *get_lhs () const
+ {
+ return std::get<0> (m_storage).get ();
+ }
+
+ operation *get_rhs () const
+ {
+ return std::get<1> (m_storage).get ();
+ }
+};
+
using notequal_operation
= comparison_operation<BINOP_NOTEQUAL, eval_op_notequal>;
using less_operation = comparison_operation<BINOP_LESS, eval_op_less>;
enum exp_opcode opcode () const override
{ return UNOP_MEMVAL; }
+ /* Return the type referenced by this object. */
+ struct type *get_type () const
+ {
+ return std::get<1> (m_storage);
+ }
+
protected:
void do_generate_ax (struct expression *exp,
enum exp_opcode opcode () const override
{ return BINOP_ASSIGN; }
+ /* Return the left-hand-side of the assignment. */
+ operation *get_lhs () const
+ {
+ return std::get<0> (m_storage).get ();
+ }
+
protected:
void do_generate_ax (struct expression *exp,
enum exp_opcode opcode () const override
{ return UNOP_CAST; }
+ /* Return the type referenced by this object. */
+ struct type *get_type () const
+ {
+ return std::get<1> (m_storage);
+ }
+
protected:
void do_generate_ax (struct expression *exp,
char *eltscan;
int eltsize;
+ if (exp->op != nullptr)
+ return;
+
fprintf_filtered (stream, "Dump of expression @ ");
gdb_print_host_address (exp, stream);
if (note)
{
int elt;
+ if (exp->op != nullptr)
+ {
+ exp->op->dump (stream, 0);
+ return;
+ }
+
fprintf_filtered (stream, "Dump of expression @ ");
gdb_print_host_address (exp, stream);
fputs_filtered (", after conversion to prefix form:\nExpression: `", stream);
+
+ if (exp->op != nullptr)
+ {
+ exp->op->dump (stream, 0);
+ return;
+ }
+
print_expression (exp, stream);
fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
exp->language_defn->name (), exp->nelts,
expression. */
enum exp_opcode first_opcode () const
{
- return elts[0].opcode;
+ if (op != nullptr)
+ return op->opcode ();
+ return elts[0].opcode;
}
/* Evaluate the expression. EXPECT_TYPE is the context type of the
const struct language_defn *language_defn;
/* Architecture it was parsed in. */
struct gdbarch *gdbarch;
+ expr::operation_up op;
int nelts = 0;
union exp_element *elts;
};
#include "user-regs.h"
#include <algorithm>
#include "gdbsupport/gdb_optional.h"
+#include "c-exp.h"
/* Standard set of definitions for printing, dumping, prefixifying,
* and evaluating expressions. */
expr_completion_state *cstate)
{
const struct language_defn *lang = NULL;
- int subexp;
if (*stringptr == 0 || **stringptr == 0)
error_no_arg (_("expression to compute"));
/* If parsing for completion, allow this to succeed; but if no
expression elements have been written, then there's nothing
to do, so fail. */
- if (! ps.parse_completion || ps.expout_ptr == 0)
+ if (! ps.parse_completion
+ || (ps.expout->op == nullptr && ps.expout_ptr == 0))
throw;
}
dump_raw_expression (result.get (), gdb_stdlog,
"before conversion to prefix form");
- subexp = prefixify_expression (result.get (),
- ps.m_completion_state.expout_last_struct);
- if (out_subexp)
- *out_subexp = subexp;
+ if (result->op == nullptr)
+ {
+ int subexp = prefixify_expression (result.get (),
+ ps.m_completion_state.expout_last_struct);
+ if (out_subexp)
+ *out_subexp = subexp;
- lang->post_parser (&result, &ps);
+ lang->post_parser (&result, &ps);
+ }
+ else
+ result->op->set_outermost ();
if (expressiondebug)
dump_prefix_expression (result.get (), gdb_stdlog);
{
gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
+ if (exp->op != nullptr)
+ return exp->op->uses_objfile (objfile);
+
return exp_iterate (exp, exp_uses_objfile_iter, objfile);
}
return expout->language_defn;
}
+ /* Set the root operation of the expression that is currently being
+ built. */
+ void set_operation (expr::operation_up &&op)
+ {
+ expout->op = std::move (op);
+ }
+
/* The size of the expression above. */
size_t expout_size;
#include "arch/ppc-linux-tdesc.h"
#include "nat/ppc-linux.h"
#include "linux-tdep.h"
+#include "expop.h"
/* Similarly for the hardware watchpoint support. These requests are used
when the PowerPC HWDEBUG ptrace interface is not available. */
struct value *left_val, *right_val;
std::vector<value_ref_ptr> left_chain, right_chain;
- if (cond->elts[0].opcode != BINOP_EQUAL)
+ if (cond->first_opcode () != BINOP_EQUAL)
return 0;
- fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain, false);
+ expr::operation *lhs = nullptr;
+ expr::operation *rhs = nullptr;
+ if (cond->op != nullptr)
+ {
+ expr::equal_operation *eqop
+ = dynamic_cast<expr::equal_operation *> (cond->op.get ());
+ if (eqop != nullptr)
+ {
+ lhs = eqop->get_lhs ();
+ rhs = eqop->get_rhs ();
+ }
+ }
+
+ fetch_subexp_value (cond, &pc, lhs, &left_val, NULL, &left_chain, false);
num_accesses_left = num_memory_accesses (left_chain);
if (left_val == NULL || num_accesses_left < 0)
return 0;
- fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, false);
+ fetch_subexp_value (cond, &pc, rhs, &right_val, NULL, &right_chain, false);
num_accesses_right = num_memory_accesses (right_chain);
if (right_val == NULL || num_accesses_right < 0)
{
expression_up expr = parse_expression (exp);
- if (expr->nelts >= 1)
- switch (expr->elts[0].opcode)
+ enum exp_opcode opcode = OP_NULL;
+ if (expr->op != nullptr)
+ opcode = expr->op->opcode ();
+ else if (expr->nelts >= 1)
+ opcode = expr->elts[0].opcode;
+
+ if (opcode != OP_NULL)
+ switch (opcode)
{
case UNOP_PREINCREMENT:
case UNOP_POSTINCREMENT:
arg = this->get_arg_by_number (n, expr->gdbarch);
pc = arg->aexpr->elts;
- gen_expr (arg->aexpr.get (), &pc, expr, value);
+ if (arg->aexpr->op != nullptr)
+ arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
+ else
+ gen_expr (arg->aexpr.get (), &pc, expr, value);
require_rvalue (expr, value);
value->type = arg->atype;
#include "location.h"
#include <algorithm>
#include "cli/cli-style.h"
+#include "expop.h"
#include <unistd.h>
if (exp->first_opcode () == OP_VAR_VALUE)
{
- if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+ symbol *sym;
+ if (exp->op != nullptr)
+ {
+ expr::var_value_operation *vvop
+ = (dynamic_cast<expr::var_value_operation *>
+ (exp->op.get ()));
+ sym = vvop->get_symbol ();
+ }
+ else
+ sym = exp->elts[2].symbol;
+
+ if (SYMBOL_CLASS (sym) == LOC_CONST)
{
error (_("constant `%s' (value %s) "
"will not be collected."),
- exp->elts[2].symbol->print_name (),
- plongest (SYMBOL_VALUE (exp->elts[2].symbol)));
+ sym->print_name (),
+ plongest (SYMBOL_VALUE (sym)));
}
- else if (SYMBOL_CLASS (exp->elts[2].symbol)
- == LOC_OPTIMIZED_OUT)
+ else if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT)
{
error (_("`%s' is optimized away "
"and cannot be collected."),
- exp->elts[2].symbol->print_name ());
+ sym->print_name ());
}
}
{
case OP_REGISTER:
{
- const char *name = &exp->elts[2].string;
+ const char *name;
+ if (exp->op != nullptr)
+ {
+ expr::register_operation *regop
+ = (dynamic_cast<expr::register_operation *>
+ (exp->op.get ()));
+ name = regop->get_name ();
+ }
+ else
+ name = &exp->elts[2].string;
i = user_reg_map_name_to_regnum (target_gdbarch (),
name, strlen (name));
}
case UNOP_MEMVAL:
- /* Safe because we know it's a simple expression. */
- tempval = evaluate_expression (exp.get ());
- addr = value_address (tempval);
- /* Initialize the TYPE_LENGTH if it is a typedef. */
- check_typedef (exp->elts[1].type);
- collect->add_memrange (target_gdbarch (),
- memrange_absolute, addr,
- TYPE_LENGTH (exp->elts[1].type),
- tloc->address);
- collect->append_exp (std::string (exp_start,
- action_exp));
+ {
+ /* Safe because we know it's a simple expression. */
+ tempval = evaluate_expression (exp.get ());
+ addr = value_address (tempval);
+ struct type *type;
+ if (exp->op != nullptr)
+ {
+ expr::unop_memval_operation *memop
+ = (dynamic_cast<expr::unop_memval_operation *>
+ (exp->op.get ()));
+ type = memop->get_type ();
+ }
+ else
+ type = exp->elts[1].type;
+ /* Initialize the TYPE_LENGTH if it is a typedef. */
+ check_typedef (type);
+ collect->add_memrange (target_gdbarch (),
+ memrange_absolute, addr,
+ TYPE_LENGTH (type),
+ tloc->address);
+ collect->append_exp (std::string (exp_start,
+ action_exp));
+ }
break;
case OP_VAR_VALUE:
{
- struct symbol *sym = exp->elts[2].symbol;
+ struct symbol *sym;
+
+ if (exp->op != nullptr)
+ {
+ expr::var_value_operation *vvo
+ = (dynamic_cast<expr::var_value_operation *>
+ (exp->op.get ()));
+ sym = vvo->get_symbol ();
+ }
+ else
+ sym = exp->elts[2].symbol;
const char *name = sym->natural_name ();
- collect->collect_symbol (exp->elts[2].symbol,
+ collect->collect_symbol (sym,
target_gdbarch (),
frame_reg,
frame_offset,
#include "gdbsupport/selftest.h"
#include "gdbsupport/array-view.h"
#include "cli/cli-style.h"
+#include "expop.h"
/* Definition of a user function. */
struct internal_function
static void
init_if_undefined_command (const char* args, int from_tty)
{
- struct internalvar* intvar;
+ struct internalvar *intvar = nullptr;
/* Parse the expression - this is taken from set_command(). */
expression_up expr = parse_expression (args);
/* Validate the expression.
Was the expression an assignment?
Or even an expression at all? */
- if (expr->nelts == 0 || expr->first_opcode () != BINOP_ASSIGN)
+ if ((expr->nelts == 0 && expr->op == nullptr)
+ || expr->first_opcode () != BINOP_ASSIGN)
error (_("Init-if-undefined requires an assignment expression."));
/* Extract the variable from the parsed expression.
In the case of an assign the lvalue will be in elts[1] and elts[2]. */
- if (expr->elts[1].opcode != OP_INTERNALVAR)
+ if (expr->op == nullptr)
+ {
+ if (expr->elts[1].opcode == OP_INTERNALVAR)
+ intvar = expr->elts[2].internalvar;
+ }
+ else
+ {
+ expr::assign_operation *assign
+ = dynamic_cast<expr::assign_operation *> (expr->op.get ());
+ if (assign != nullptr)
+ {
+ expr::operation *lhs = assign->get_lhs ();
+ expr::internalvar_operation *ivarop
+ = dynamic_cast<expr::internalvar_operation *> (lhs);
+ if (ivarop != nullptr)
+ intvar = ivarop->get_internalvar ();
+ }
+ }
+
+ if (intvar == nullptr)
error (_("The first parameter to init-if-undefined "
"should be a GDB variable."));
- intvar = expr->elts[2].internalvar;
/* Only evaluate the expression if the lvalue is void.
This may still fail if the expression is invalid. */
extern value *eval_skip_value (expression *exp);
+namespace expr { class operation; };
extern void fetch_subexp_value (struct expression *exp, int *pc,
+ expr::operation *op,
struct value **valp, struct value **resultp,
std::vector<value_ref_ptr> *val_chain,
bool preserve_errors);