[190/203] Remove union exp_element

Message ID 20210101214723.1784144-191-tom@tromey.com
State Superseded
Headers show
Series
  • Refactor expressions
Related show

Commit Message

Tom Tromey Jan. 1, 2021, 9:47 p.m.
This removes union exp_element functions that either create such
elements or walk them.  struct expression no longer holds
exp_elements.  A couple of language_defn methods are also removed, as
they are obsolete.

Note that this patch also removes the print_expression code.  The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled.  Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous.  So, I have not
reimplemented this feature.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* value.h (evaluate_subexp_with_coercion): Don't declare.
	* parse.c (exp_descriptor_standard): Remove.
	(expr_builder::expr_builder, expr_builder::release): Update.
	(expression::expression): Remove size_t parameter.
	(expression::~expression): Simplify.
	(expression::resize): Remove.
	(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
	(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
	(write_exp_elt_longcst, write_exp_elt_floatcst)
	(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
	(write_exp_string_vector, write_exp_bitstring): Remove.
	* p-lang.h (class pascal_language) <opcode_print_table,
	op_print_tab>: Remove.
	* p-lang.c (pascal_language::op_print_tab): Remove.
	* opencl-lang.c (class opencl_language) <opcode_print_table>:
	Remove.
	* objc-lang.c (objc_op_print_tab): Remove.
	(class objc_language) <opcode_print_table>: Remove.
	* m2-lang.h (class m2_language) <opcode_print_table,
	op_print_tab>: Remove.
	* m2-lang.c (m2_language::op_print_tab): Remove.
	* language.h (struct language_defn) <post_parser, expression_ops,
	opcode_print_table>: Remove.
	* language.c (language_defn::expression_ops)
	(auto_or_unknown_language::opcode_print_table): Remove.
	* go-lang.h (class go_language) <expression_ops,
	opcode_print_table, op_print_tab>: Remove.
	* go-lang.c (go_language::expression_ops): Remove.
	(go_language::op_print_tab): Remove.
	* f-lang.h (class f_language) <opcode_print_table>: Remove
	<op_print_tab>: Remove.
	* f-lang.c (f_language::op_print_tab): Remove.
	* expression.h (union exp_element): Remove.
	(struct expression): Remove size_t parameter from constructor.
	<resize>: Remove.
	<first_opcode>: Update.
	<nelts, elts>: Remove.
	(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
	(evaluate_subexp_standard, print_expression, op_string)
	(dump_raw_expression): Don't declare.
	* expprint.c (print_expression, print_subexp)
	(print_subexp_funcall, print_subexp_standard, op_string)
	(dump_raw_expression, dump_subexp, dump_subexp_body)
	(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
	(dump_prefix_expression): Update.
	* eval.c (evaluate_subexp, evaluate_expression, evaluate_type):
	Update.
	(evaluate_subexpression_type): Remove.
	(fetch_subexp_value): Remove "pc" parameter.  Update.
	(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
	(evaluate_subexp_standard, evaluate_subexp_for_address)
	(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
	(evaluate_subexp_for_cast): Remove.
	(parse_and_eval_type): Update.
	* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
	* d-lang.c (d_op_print_tab): Remove.
	(class d_language) <opcode_print_table>: Remove.
	* c-lang.h (c_op_print_tab): Don't declare.
	* c-lang.c (c_op_print_tab): Remove.
	(class c_language, class cplus_language, class asm_language, class
	minimal_language) <opcode_print_table>: Remove.
	* breakpoint.c (update_watchpoint, watchpoint_check)
	(watchpoint_exp_is_const, watch_command_1): Update.
	* ax-gdb.h (union exp_element): Don't declare.
	* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
	(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
	(gen_expr_binop_rest): Remove.
	(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
	* ada-lang.c (ada_op_print_tab): Remove.
	(class ada_language) <post_parser, opcode_print_table>: Remove.
---
 gdb/ChangeLog       |   73 ++
 gdb/ada-lang.c      |   58 --
 gdb/ax-gdb.c        |  735 +------------------
 gdb/ax-gdb.h        |    1 -
 gdb/breakpoint.c    |  118 +---
 gdb/c-lang.c        |   59 --
 gdb/c-lang.h        |    2 -
 gdb/d-lang.c        |   43 --
 gdb/dtrace-probe.c  |   10 +-
 gdb/eval.c          | 1629 +------------------------------------------
 gdb/expprint.c      | 1110 +----------------------------
 gdb/expression.h    |   58 +-
 gdb/f-lang.c        |   28 -
 gdb/f-lang.h        |    9 -
 gdb/go-lang.c       |   46 --
 gdb/go-lang.h       |   16 -
 gdb/language.c      |   20 -
 gdb/language.h      |   20 -
 gdb/m2-lang.c       |   37 -
 gdb/m2-lang.h       |    9 -
 gdb/objc-lang.c     |   43 --
 gdb/opencl-lang.c   |    5 -
 gdb/p-lang.c        |   34 -
 gdb/p-lang.h        |    9 -
 gdb/parse.c         |  971 +-------------------------
 gdb/parser-defs.h   |  179 -----
 gdb/ppc-linux-nat.c |   25 +-
 gdb/printcmd.c      |    8 +-
 gdb/rust-lang.h     |    5 -
 gdb/stap-probe.c    |    7 +-
 gdb/tracepoint.c    |   56 +-
 gdb/value.c         |   30 +-
 gdb/value.h         |   14 +-
 33 files changed, 151 insertions(+), 5316 deletions(-)

-- 
2.26.2

Patch

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index c7d9540798d..e7bfe9967e9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12901,43 +12901,6 @@  info_exceptions_command (const char *regexp, int from_tty)
     printf_filtered ("%s: %s\n", info.name, paddress (gdbarch, info.addr));
 }
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-static const struct op_print ada_op_print_tab[] = {
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"or else", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"and then", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"and", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"&", BINOP_CONCAT, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"rem", BINOP_REM, PREC_MUL, 0},
-  {"mod", BINOP_MOD, PREC_MUL, 0},
-  {"**", BINOP_EXP, PREC_REPEAT, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"not ", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"not ", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"abs ", UNOP_ABS, PREC_PREFIX, 0},
-  {".all", UNOP_IND, PREC_SUFFIX, 1},
-  {"'access", UNOP_ADDR, PREC_SUFFIX, 1},
-  {"'size", OP_ATR_SIZE, PREC_SUFFIX, 1},
-  {NULL, OP_NULL, PREC_SUFFIX, 0}
-};
 
 				/* Language vector */
 
@@ -13519,22 +13482,6 @@  class ada_language : public language_defn
     return ada_parse (ps);
   }
 
-  /* See language.h.
-
-     Same as evaluate_type (*EXP), but resolves ambiguous symbol references
-     (marked by OP_VAR_VALUE nodes in which the symbol has an undefined
-     namespace) and converts operators that are user-defined into
-     appropriate function calls.  If CONTEXT_TYPE is non-null, it provides
-     a preferred result type [at the moment, only type void has any
-     effect---causing procedures to be preferred over functions in calls].
-     A null CONTEXT_TYPE indicates that a non-void return type is
-     preferred.  May change (expand) *EXP.  */
-
-  void post_parser (expression_up *expp, struct parser_state *ps)
-    const override
-  {
-  }
-
   /* See language.h.  */
 
   void emitchar (int ch, struct type *chtype,
@@ -13597,11 +13544,6 @@  class ada_language : public language_defn
   const struct lang_varobj_ops *varobj_ops () const override
   { return &ada_varobj_ops; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return ada_op_print_tab; }
-
 protected:
   /* See language.h.  */
 
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index d2f50bbec7b..788be528d1b 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -70,14 +70,9 @@ 
 /* Prototypes for local functions.  */
 
 /* There's a standard order to the arguments of these functions:
-   union exp_element ** --- pointer into expression
    struct agent_expr * --- agent expression buffer to generate code into
    struct axs_value * --- describes value left on top of stack  */
 
-static struct value *const_var_ref (struct symbol *var);
-static struct value *const_expr (union exp_element **pc);
-static struct value *maybe_const_expr (union exp_element **pc);
-
 static void gen_traced_pop (struct agent_expr *, struct axs_value *);
 
 static void gen_sign_extend (struct agent_expr *, struct type *);
@@ -148,123 +143,13 @@  static void gen_struct_ref (struct agent_expr *ax,
 			    const char *operand_name);
 static void gen_static_field (struct agent_expr *ax, struct axs_value *value,
 			      struct type *type, int fieldno);
-static void gen_repeat (struct expression *exp, union exp_element **pc,
-			struct agent_expr *ax, struct axs_value *value);
-static void gen_sizeof (struct expression *exp, union exp_element **pc,
-			struct agent_expr *ax, struct axs_value *value,
-			struct type *size_type);
-static void gen_expr_binop_rest (struct expression *exp,
-				 enum exp_opcode op, union exp_element **pc,
-				 struct agent_expr *ax,
-				 struct axs_value *value,
-				 struct axs_value *value1,
-				 struct axs_value *value2);
 static void gen_expr_binop_rest (struct expression *exp,
 				 enum exp_opcode op,
 				 struct agent_expr *ax,
 				 struct axs_value *value,
 				 struct axs_value *value1,
 				 struct axs_value *value2);
-
-
-/* Detecting constant expressions.  */
-
-/* If the variable reference at *PC is a constant, return its value.
-   Otherwise, return zero.
-
-   Hey, Wally!  How can a variable reference be a constant?
-
-   Well, Beav, this function really handles the OP_VAR_VALUE operator,
-   not specifically variable references.  GDB uses OP_VAR_VALUE to
-   refer to any kind of symbolic reference: function names, enum
-   elements, and goto labels are all handled through the OP_VAR_VALUE
-   operator, even though they're constants.  It makes sense given the
-   situation.
-
-   Gee, Wally, don'cha wonder sometimes if data representations that
-   subvert commonly accepted definitions of terms in favor of heavily
-   context-specific interpretations are really just a tool of the
-   programming hegemony to preserve their power and exclude the
-   proletariat?  */
-
-static struct value *
-const_var_ref (struct symbol *var)
-{
-  struct type *type = SYMBOL_TYPE (var);
-
-  switch (SYMBOL_CLASS (var))
-    {
-    case LOC_CONST:
-      return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var));
-
-    case LOC_LABEL:
-      return value_from_pointer (type, (CORE_ADDR) SYMBOL_VALUE_ADDRESS (var));
-
-    default:
-      return 0;
-    }
-}
-
-
-/* If the expression starting at *PC has a constant value, return it.
-   Otherwise, return zero.  If we return a value, then *PC will be
-   advanced to the end of it.  If we return zero, *PC could be
-   anywhere.  */
-static struct value *
-const_expr (union exp_element **pc)
-{
-  enum exp_opcode op = (*pc)->opcode;
-  struct value *v1;
-
-  switch (op)
-    {
-    case OP_LONG:
-      {
-	struct type *type = (*pc)[1].type;
-	LONGEST k = (*pc)[2].longconst;
-
-	(*pc) += 4;
-	return value_from_longest (type, k);
-      }
-
-    case OP_VAR_VALUE:
-      {
-	struct value *v = const_var_ref ((*pc)[2].symbol);
-
-	(*pc) += 4;
-	return v;
-      }
-
-      /* We could add more operators in here.  */
-
-    case UNOP_NEG:
-      (*pc)++;
-      v1 = const_expr (pc);
-      if (v1)
-	return value_neg (v1);
-      else
-	return 0;
-
-    default:
-      return 0;
-    }
-}
 
-
-/* Like const_expr, but guarantee also that *PC is undisturbed if the
-   expression is not constant.  */
-static struct value *
-maybe_const_expr (union exp_element **pc)
-{
-  union exp_element *tentative_pc = *pc;
-  struct value *v = const_expr (&tentative_pc);
-
-  /* If we got a value, then update the real PC.  */
-  if (v)
-    *pc = tentative_pc;
-
-  return v;
-}
 
 
 /* Generating bytecode from GDB expressions: general assumptions */
@@ -1691,592 +1576,8 @@  gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
   return 0;
 }
 
-/* Generate code for GDB's magical `repeat' operator.
-   LVALUE @ INT creates an array INT elements long, and whose elements
-   have the same type as LVALUE, located in memory so that LVALUE is
-   its first element.  For example, argv[0]@argc gives you the array
-   of command-line arguments.
-
-   Unfortunately, because we have to know the types before we actually
-   have a value for the expression, we can't implement this perfectly
-   without changing the type system, having values that occupy two
-   stack slots, doing weird things with sizeof, etc.  So we require
-   the right operand to be a constant expression.  */
-static void
-gen_repeat (struct expression *exp, union exp_element **pc,
-	    struct agent_expr *ax, struct axs_value *value)
-{
-  struct axs_value value1;
-
-  /* We don't want to turn this into an rvalue, so no conversions
-     here.  */
-  gen_expr (exp, pc, ax, &value1);
-  if (value1.kind != axs_lvalue_memory)
-    error (_("Left operand of `@' must be an object in memory."));
-
-  /* Evaluate the length; it had better be a constant.  */
-  {
-    struct value *v = const_expr (pc);
-    int length;
-
-    if (!v)
-      error (_("Right operand of `@' must be a "
-	       "constant, in agent expressions."));
-    if (value_type (v)->code () != TYPE_CODE_INT)
-      error (_("Right operand of `@' must be an integer."));
-    length = value_as_long (v);
-    if (length <= 0)
-      error (_("Right operand of `@' must be positive."));
-
-    /* The top of the stack is already the address of the object, so
-       all we need to do is frob the type of the lvalue.  */
-    {
-      /* FIXME-type-allocation: need a way to free this type when we are
-	 done with it.  */
-      struct type *array
-	= lookup_array_range_type (value1.type, 0, length - 1);
-
-      value->kind = axs_lvalue_memory;
-      value->type = array;
-    }
-  }
-}
-
-
-/* Emit code for the `sizeof' operator.
-   *PC should point at the start of the operand expression; we advance it
-   to the first instruction after the operand.  */
-static void
-gen_sizeof (struct expression *exp, union exp_element **pc,
-	    struct agent_expr *ax, struct axs_value *value,
-	    struct type *size_type)
-{
-  /* We don't care about the value of the operand expression; we only
-     care about its type.  However, in the current arrangement, the
-     only way to find an expression's type is to generate code for it.
-     So we generate code for the operand, and then throw it away,
-     replacing it with code that simply pushes its size.  */
-  int start = ax->len;
-
-  gen_expr (exp, pc, ax, value);
-
-  /* Throw away the code we just generated.  */
-  ax->len = start;
-
-  ax_const_l (ax, TYPE_LENGTH (value->type));
-  value->kind = axs_rvalue;
-  value->type = size_type;
-}
 
 
-/* Generate bytecode for a cast to TO_TYPE.  Advance *PC over the
-   subexpression.  */
-
-static void
-gen_expr_for_cast (struct expression *exp, union exp_element **pc,
-		   struct agent_expr *ax, struct axs_value *value,
-		   struct type *to_type)
-{
-  enum exp_opcode op = (*pc)[0].opcode;
-
-  /* Don't let symbols be handled with gen_expr because that throws an
-     "unknown type" error for no-debug data symbols.  Instead, we want
-     the cast to reinterpret such symbols.  */
-  if (op == OP_VAR_MSYM_VALUE || op == OP_VAR_VALUE)
-    {
-      if (op == OP_VAR_VALUE)
-	{
-	  gen_var_ref (ax, value, (*pc)[2].symbol);
-
-	  if (value->optimized_out)
-	    error (_("`%s' has been optimized out, cannot use"),
-		   (*pc)[2].symbol->print_name ());
-	}
-      else
-	gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-      if (value->type->code () == TYPE_CODE_ERROR)
-	value->type = to_type;
-      (*pc) += 4;
-    }
-  else
-    gen_expr (exp, pc, ax, value);
-  gen_cast (ax, value, to_type);
-}
-
-/* Generating bytecode from GDB expressions: general recursive thingy  */
-
-/* XXX: i18n */
-/* A gen_expr function written by a Gen-X'er guy.
-   Append code for the subexpression of EXPR starting at *POS_P to AX.  */
-void
-gen_expr (struct expression *exp, union exp_element **pc,
-	  struct agent_expr *ax, struct axs_value *value)
-{
-  /* Used to hold the descriptions of operand expressions.  */
-  struct axs_value value1, value2, value3;
-  enum exp_opcode op = (*pc)[0].opcode, op2;
-  int if1, go1, if2, go2, end;
-  struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
-
-  /* If we're looking at a constant expression, just push its value.  */
-  {
-    struct value *v = maybe_const_expr (pc);
-
-    if (v)
-      {
-	ax_const_l (ax, value_as_long (v));
-	value->kind = axs_rvalue;
-	value->type = check_typedef (value_type (v));
-	return;
-      }
-  }
-
-  /* Otherwise, go ahead and generate code for it.  */
-  switch (op)
-    {
-      /* Binary arithmetic operators.  */
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_SUBSCRIPT:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
-      break;
-
-    case BINOP_LOGICAL_AND:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      go1 = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      go2 = ax_goto (ax, aop_goto);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, go1, ax->len);
-      ax_label (ax, go2, ax->len);
-      ax_const_l (ax, 0);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case BINOP_LOGICAL_OR:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      ax_const_l (ax, 0);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case TERNOP_COND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      /* For (A ? B : C), it's easiest to generate subexpression
-	 bytecodes in order, but if_goto jumps on true, so we invert
-	 the sense of A.  Then we can do B by dropping through, and
-	 jump to do C.  */
-      gen_logical_not (ax, &value1, int_type);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value3);
-      gen_usual_unary (ax, &value3);
-      ax_label (ax, end, ax->len);
-      /* This is arbitrary - what if B and C are incompatible types? */
-      value->type = value2.type;
-      value->kind = value2.kind;
-      break;
-
-    case BINOP_ASSIGN:
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-	{
-	  const char *name = internalvar_name ((*pc)[1].internalvar);
-	  struct trace_state_variable *tsv;
-
-	  (*pc) += 3;
-	  gen_expr (exp, pc, ax, value);
-	  tsv = find_trace_state_variable (name);
-	  if (tsv)
-	    {
-	      ax_tsv (ax, aop_setv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	    }
-	  else
-	    error (_("$%s is not a trace state variable, "
-		     "may not assign to it"), name);
-	}
-      else
-	error (_("May only assign to trace state variables"));
-      break;
-
-    case BINOP_ASSIGN_MODIFY:
-      (*pc)++;
-      op2 = (*pc)[0].opcode;
-      (*pc)++;
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-	{
-	  const char *name = internalvar_name ((*pc)[1].internalvar);
-	  struct trace_state_variable *tsv;
-
-	  (*pc) += 3;
-	  tsv = find_trace_state_variable (name);
-	  if (tsv)
-	    {
-	      /* The tsv will be the left half of the binary operation.  */
-	      ax_tsv (ax, aop_getv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	      /* Trace state variables are always 64-bit integers.  */
-	      value1.kind = axs_rvalue;
-	      value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
-	      /* Now do right half of expression.  */
-	      gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2);
-	      /* We have a result of the binary op, set the tsv.  */
-	      ax_tsv (ax, aop_setv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	    }
-	  else
-	    error (_("$%s is not a trace state variable, "
-		     "may not assign to it"), name);
-	}
-      else
-	error (_("May only assign to trace state variables"));
-      break;
-
-      /* Note that we need to be a little subtle about generating code
-	 for comma.  In C, we can do some optimizations here because
-	 we know the left operand is only being evaluated for effect.
-	 However, if the tracing kludge is in effect, then we always
-	 need to evaluate the left hand side fully, so that all the
-	 variables it mentions get traced.  */
-    case BINOP_COMMA:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      /* Don't just dispose of the left operand.  We might be tracing,
-	 in which case we want to emit code to trace it if it's an
-	 lvalue.  */
-      gen_traced_pop (ax, &value1);
-      gen_expr (exp, pc, ax, value);
-      /* It's the consumer's responsibility to trace the right operand.  */
-      break;
-
-    case OP_LONG:		/* some integer constant */
-      {
-	struct type *type = (*pc)[1].type;
-	LONGEST k = (*pc)[2].longconst;
-
-	(*pc) += 4;
-	gen_int_literal (ax, value, k, type);
-      }
-      break;
-
-    case OP_VAR_VALUE:
-      gen_var_ref (ax, value, (*pc)[2].symbol);
-
-      if (value->optimized_out)
-	error (_("`%s' has been optimized out, cannot use"),
-	       (*pc)[2].symbol->print_name ());
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-	error_unknown_type ((*pc)[2].symbol->print_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_VAR_MSYM_VALUE:
-      gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-	error_unknown_type ((*pc)[2].msymbol->linkage_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_REGISTER:
-      {
-	const char *name = &(*pc)[2].string;
-	int reg;
-
-	(*pc) += 4 + BYTES_TO_EXP_ELEM ((*pc)[1].longconst + 1);
-	reg = user_reg_map_name_to_regnum (ax->gdbarch, name, strlen (name));
-	if (reg == -1)
-	  internal_error (__FILE__, __LINE__,
-			  _("Register $%s not available"), name);
-	/* No support for tracing user registers yet.  */
-	if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
-	  error (_("'%s' is a user-register; "
-		   "GDB cannot yet trace user-register contents."),
-		 name);
-	value->kind = axs_lvalue_register;
-	value->u.reg = reg;
-	value->type = register_type (ax->gdbarch, reg);
-      }
-      break;
-
-    case OP_INTERNALVAR:
-      {
-	struct internalvar *var = (*pc)[1].internalvar;
-	const char *name = internalvar_name (var);
-	struct trace_state_variable *tsv;
-
-	(*pc) += 3;
-	tsv = find_trace_state_variable (name);
-	if (tsv)
-	  {
-	    ax_tsv (ax, aop_getv, tsv->number);
-	    if (ax->tracing)
-	      ax_tsv (ax, aop_tracev, tsv->number);
-	    /* Trace state variables are always 64-bit integers.  */
-	    value->kind = axs_rvalue;
-	    value->type = builtin_type (ax->gdbarch)->builtin_long_long;
-	  }
-	else if (! compile_internalvar_to_ax (var, ax, value))
-	  error (_("$%s is not a trace state variable; GDB agent "
-		   "expressions cannot use convenience variables."), name);
-      }
-      break;
-
-      /* Weirdo operator: see comments for gen_repeat for details.  */
-    case BINOP_REPEAT:
-      /* Note that gen_repeat handles its own argument evaluation.  */
-      (*pc)++;
-      gen_repeat (exp, pc, ax, value);
-      break;
-
-    case UNOP_CAST:
-      {
-	struct type *type = (*pc)[1].type;
-
-	(*pc) += 3;
-	gen_expr_for_cast (exp, pc, ax, value, type);
-      }
-      break;
-
-    case UNOP_CAST_TYPE:
-      {
-	int offset;
-	struct value *val;
-	struct type *type;
-
-	++*pc;
-	offset = *pc - exp->elts;
-	val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
-	type = value_type (val);
-	*pc = &exp->elts[offset];
-	gen_expr_for_cast (exp, pc, ax, value, type);
-      }
-      break;
-
-    case UNOP_MEMVAL:
-      {
-	struct type *type = check_typedef ((*pc)[1].type);
-
-	(*pc) += 3;
-	gen_expr (exp, pc, ax, value);
-
-	/* If we have an axs_rvalue or an axs_lvalue_memory, then we
-	   already have the right value on the stack.  For
-	   axs_lvalue_register, we must convert.  */
-	if (value->kind == axs_lvalue_register)
-	  require_rvalue (ax, value);
-
-	value->type = type;
-	value->kind = axs_lvalue_memory;
-      }
-      break;
-
-    case UNOP_MEMVAL_TYPE:
-      {
-	int offset;
-	struct value *val;
-	struct type *type;
-
-	++*pc;
-	offset = *pc - exp->elts;
-	val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
-	type = value_type (val);
-	*pc = &exp->elts[offset];
-
-	gen_expr (exp, pc, ax, value);
-
-	/* If we have an axs_rvalue or an axs_lvalue_memory, then we
-	   already have the right value on the stack.  For
-	   axs_lvalue_register, we must convert.  */
-	if (value->kind == axs_lvalue_register)
-	  require_rvalue (ax, value);
-
-	value->type = type;
-	value->kind = axs_lvalue_memory;
-      }
-      break;
-
-    case UNOP_PLUS:
-      (*pc)++;
-      /* + FOO is equivalent to 0 + FOO, which can be optimized.  */
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      break;
-      
-    case UNOP_NEG:
-      (*pc)++;
-      /* -FOO is equivalent to 0 - FOO.  */
-      gen_int_literal (ax, &value1, 0,
-		       builtin_type (ax->gdbarch)->builtin_int);
-      gen_usual_unary (ax, &value1);	/* shouldn't do much */
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      gen_usual_arithmetic (ax, &value1, &value2);
-      gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
-      break;
-
-    case UNOP_LOGICAL_NOT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_logical_not (ax, value, int_type);
-      break;
-
-    case UNOP_COMPLEMENT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_integral_promotions (ax, value);
-      gen_complement (ax, value);
-      break;
-
-    case UNOP_IND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      if (!pointer_type (value->type))
-	error (_("Argument of unary `*' is not a pointer."));
-      gen_deref (value);
-      break;
-
-    case UNOP_ADDR:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_address_of (value);
-      break;
-
-    case UNOP_SIZEOF:
-      (*pc)++;
-      /* Notice that gen_sizeof handles its own operand, unlike most
-	 of the other unary operator functions.  This is because we
-	 have to throw away the code we generate.  */
-      gen_sizeof (exp, pc, ax, value,
-		  builtin_type (ax->gdbarch)->builtin_int);
-      break;
-
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      {
-	int length = (*pc)[1].longconst;
-	const char *name = &(*pc)[2].string;
-
-	(*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
-	gen_expr (exp, pc, ax, value);
-	if (op == STRUCTOP_STRUCT)
-	  gen_struct_ref (ax, value, name, ".", "structure or union");
-	else if (op == STRUCTOP_PTR)
-	  gen_struct_ref (ax, value, name, "->",
-			  "pointer to a structure or union");
-	else
-	  /* If this `if' chain doesn't handle it, then the case list
-	     shouldn't mention it, and we shouldn't be here.  */
-	  internal_error (__FILE__, __LINE__,
-			  _("gen_expr: unhandled struct case"));
-      }
-      break;
-
-    case OP_THIS:
-      {
-	struct symbol *sym, *func;
-	const struct block *b;
-	const struct language_defn *lang;
-
-	b = block_for_pc (ax->scope);
-	func = block_linkage_function (b);
-	lang = language_def (func->language ());
-
-	sym = lookup_language_this (lang, b).symbol;
-	if (!sym)
-	  error (_("no `%s' found"), lang->name_of_this ());
-
-	gen_var_ref (ax, value, sym);
-
-	if (value->optimized_out)
-	  error (_("`%s' has been optimized out, cannot use"),
-		 sym->print_name ());
-
-	(*pc) += 2;
-      }
-      break;
-
-    case OP_SCOPE:
-      {
-	struct type *type = (*pc)[1].type;
-	int length = longest_to_int ((*pc)[2].longconst);
-	const char *name = &(*pc)[3].string;
-	int found;
-
-	found = gen_aggregate_elt_ref (ax, value, type, name);
-	if (!found)
-	  error (_("There is no field named %s"), name);
-	(*pc) += 5 + BYTES_TO_EXP_ELEM (length + 1);
-      }
-      break;
-
-    case OP_TYPE:
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      error (_("Attempt to use a type name as an expression."));
-
-    default:
-      error (_("Unsupported operator %s (%d) in expression."),
-	     op_name (op), op);
-    }
-}
-
 namespace expr
 {
 
@@ -2901,19 +2202,6 @@  gen_expr_binop_rest (struct expression *exp,
     }
 }
 
-/* Variant of gen_expr_binop_rest that first generates the
-   right-hand-side.  */
-
-static void
-gen_expr_binop_rest (struct expression *exp,
-		     enum exp_opcode op, union exp_element **pc,
-		     struct agent_expr *ax, struct axs_value *value,
-		     struct axs_value *value1, struct axs_value *value2)
-{
-  gen_expr (exp, pc, ax, value2);
-  gen_expr_binop_rest (exp, op, ax, value, value1, value2);
-}
-
 /* A helper function that emits a binop based on two operations.  */
 
 void
@@ -3057,17 +2345,12 @@  gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
 		    int trace_string)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 1;
   ax->trace_string = trace_string;
   value.optimized_out = 0;
-  if (expr->op != nullptr)
-    expr->op->generate_ax (expr, ax.get (), &value);
-  else
-    gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   /* Make sure we record the final object, and get rid of it.  */
   gen_traced_pop (ax.get (), &value);
@@ -3089,16 +2372,11 @@  agent_expr_up
 gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 0;
   value.optimized_out = 0;
-  if (expr->op != nullptr)
-    expr->op->generate_ax (expr, ax.get (), &value);
-  else
-    gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   require_rvalue (ax.get (), &value);
 
@@ -3140,7 +2418,6 @@  gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
 	    int nargs, struct expression **exprs)
 {
   agent_expr_up ax (new agent_expr (gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
   int tem;
 
@@ -3152,13 +2429,7 @@  gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
   for (tem = nargs - 1; tem >= 0; --tem)
     {
       value.optimized_out = 0;
-      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);
-	}
+      exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
       require_rvalue (ax.get (), &value);
     }
 
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index 5b7a513ac8e..b143847889b 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -22,7 +22,6 @@ 
 #include "ax.h"  /* For agent_expr_up.  */
 
 struct expression;
-union exp_element;
 
 /* Types and enums */
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1f7716c29f4..67685344eb3 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1898,12 +1898,11 @@  update_watchpoint (struct watchpoint *b, int reparse)
     }
   else if (within_current_scope && b->exp)
     {
-      int pc = 0;
       std::vector<value_ref_ptr> val_chain;
       struct value *v, *result;
       struct program_space *frame_pspace;
 
-      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &v, &result,
+      fetch_subexp_value (b->exp.get (), b->exp->op.get (), &v, &result,
 			  &val_chain, false);
 
       /* Avoid setting b->val if it's already set.  The meaning of
@@ -4945,7 +4944,6 @@  watchpoint_check (bpstat bs)
 	 free_all_values.  We can't call free_all_values because we
 	 might be in the middle of evaluating a function call.  */
 
-      int pc = 0;
       struct value *mark;
       struct value *new_val;
 
@@ -4956,7 +4954,7 @@  watchpoint_check (bpstat bs)
 	return WP_VALUE_CHANGED;
 
       mark = value_mark ();
-      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &new_val,
+      fetch_subexp_value (b->exp.get (), b->exp->op.get (), &new_val,
 			  NULL, NULL, false);
 
       if (b->val_bitsize != 0)
@@ -10058,112 +10056,7 @@  break_range_command (const char *arg, int from_tty)
 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)
-    {
-      int oplenp, argsp;
-
-      /* We are only interested in the descriptor of each element.  */
-      operator_length (exp, i, &oplenp, &argsp);
-      i -= oplenp;
-
-      switch (exp->elts[i].opcode)
-	{
-	case BINOP_ADD:
-	case BINOP_SUB:
-	case BINOP_MUL:
-	case BINOP_DIV:
-	case BINOP_REM:
-	case BINOP_MOD:
-	case BINOP_LSH:
-	case BINOP_RSH:
-	case BINOP_LOGICAL_AND:
-	case BINOP_LOGICAL_OR:
-	case BINOP_BITWISE_AND:
-	case BINOP_BITWISE_IOR:
-	case BINOP_BITWISE_XOR:
-	case BINOP_EQUAL:
-	case BINOP_NOTEQUAL:
-	case BINOP_LESS:
-	case BINOP_GTR:
-	case BINOP_LEQ:
-	case BINOP_GEQ:
-	case BINOP_REPEAT:
-	case BINOP_COMMA:
-	case BINOP_EXP:
-	case BINOP_MIN:
-	case BINOP_MAX:
-	case BINOP_INTDIV:
-	case BINOP_CONCAT:
-	case TERNOP_COND:
-	case TERNOP_SLICE:
-
-	case OP_LONG:
-	case OP_FLOAT:
-	case OP_LAST:
-	case OP_COMPLEX:
-	case OP_STRING:
-	case OP_ARRAY:
-	case OP_TYPE:
-	case OP_TYPEOF:
-	case OP_DECLTYPE:
-	case OP_TYPEID:
-	case OP_NAME:
-	case OP_OBJC_NSSTRING:
-
-	case UNOP_NEG:
-	case UNOP_LOGICAL_NOT:
-	case UNOP_COMPLEMENT:
-	case UNOP_ADDR:
-	case UNOP_HIGH:
-	case UNOP_CAST:
-
-	case UNOP_CAST_TYPE:
-	case UNOP_REINTERPRET_CAST:
-	case UNOP_DYNAMIC_CAST:
-	  /* Unary, binary and ternary operators: We have to check
-	     their operands.  If they are constant, then so is the
-	     result of that operation.  For instance, if A and B are
-	     determined to be constants, then so is "A + B".
-
-	     UNOP_IND is one exception to the rule above, because the
-	     value of *ADDR is not necessarily a constant, even when
-	     ADDR is.  */
-	  break;
-
-	case OP_VAR_VALUE:
-	  /* Check whether the associated symbol is a constant.
-
-	     We use SYMBOL_CLASS rather than TYPE_CONST because it's
-	     possible that a buggy compiler could mark a variable as
-	     constant even when it is not, and TYPE_CONST would return
-	     true in this case, while SYMBOL_CLASS wouldn't.
-
-	     We also have to check for function symbols because they
-	     are always constant.  */
-	  {
-	    struct symbol *s = exp->elts[i + 2].symbol;
-
-	    if (SYMBOL_CLASS (s) != LOC_BLOCK
-		&& SYMBOL_CLASS (s) != LOC_CONST
-		&& SYMBOL_CLASS (s) != LOC_CONST_BYTES)
-	      return false;
-	    break;
-	  }
-
-	/* The default action is to return 0 because we are using
-	   the optimistic approach here: If we don't know something,
-	   then it is not a constant.  */
-	default:
-	  return false;
-	}
-    }
-
-  return true;
+  return exp->op->constant_p ();
 }
 
 /* Watchpoint destructor.  */
@@ -10664,7 +10557,6 @@  watch_command_1 (const char *arg, int accessflag, int from_tty,
   const char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
-  int pc = 0;
   /* Flag to indicate whether we are going to use masks for
      the hardware watchpoint.  */
   bool use_mask = false;
@@ -10781,8 +10673,8 @@  watch_command_1 (const char *arg, int accessflag, int from_tty,
   exp_valid_block = tracker.block ();
   struct value *mark = value_mark ();
   struct value *val_as_value = nullptr;
-  fetch_subexp_value (exp.get (), &pc, exp->op.get (), &val_as_value, &result,
-		      NULL, just_location);
+  fetch_subexp_value (exp.get (), exp->op.get (), &val_as_value, &result, NULL,
+		      just_location);
 
   if (val_as_value != NULL && just_location)
     {
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 90ad90cab4e..5dd27329726 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -741,45 +741,6 @@  c_is_string_type_p (struct type *type)
   return false;
 }
 
-
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-const struct op_print c_op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"alignof ", UNOP_ALIGNOF, PREC_PREFIX, 0},
-  {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-  {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
 
 
 void
@@ -887,11 +848,6 @@  class c_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* Single instance of the C language class.  */
@@ -1066,11 +1022,6 @@  class cplus_language : public language_defn
   const struct lang_varobj_ops *varobj_ops () const override
   { return &cplus_varobj_ops; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
-
 protected:
 
   /* See language.h.  */
@@ -1141,11 +1092,6 @@  class asm_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* The single instance of the ASM language class.  */
@@ -1198,11 +1144,6 @@  class minimal_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* The single instance of the minimal language class.  */
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index a46957d0d84..e09c647fecd 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -106,8 +106,6 @@  extern void c_language_arch_info (struct gdbarch *gdbarch,
 extern void c_emit_char (int c, struct type *type,
 			 struct ui_file *stream, int quoter);
 
-extern const struct op_print c_op_print_tab[];
-
 /* These are in c-typeprint.c: */
 
 extern void c_type_print_base (struct type *, struct ui_file *,
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 4488c10e609..6c9b730cf41 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -57,44 +57,6 @@  d_demangle (const char *symbol, int options)
   return gdb_demangle (symbol, options | DMGL_DLANG);
 }
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-static const struct op_print d_op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_ORDER, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_ORDER, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"~", BINOP_CONCAT, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"^^", BINOP_EXP, PREC_REPEAT, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-  {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
-
 /* Class representing the D language.  */
 
 class d_language : public language_defn
@@ -216,11 +178,6 @@  class d_language : public language_defn
 
   const char *name_of_this () const override
   { return "this"; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return d_op_print_tab; }
 };
 
 /* Single instance of the D language class.  */
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 3fa02ddaebe..cccd3a8bbba 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -725,17 +725,9 @@  dtrace_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
 			     unsigned n)
 {
   struct dtrace_probe_arg *arg;
-  union exp_element *pc;
 
   arg = this->get_arg_by_number (n, expr->gdbarch);
-
-  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);
-    }
+  arg->expr->op->generate_ax (arg->expr.get (), expr, value);
 
   require_rvalue (expr, value);
   value->type = arg->type;
diff --git a/gdb/eval.c b/gdb/eval.c
index bb4e59fe17f..1f87748e80b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -45,34 +45,19 @@ 
 
 /* Prototypes for local functions.  */
 
-static struct value *evaluate_subexp_for_sizeof (struct expression *, int *,
-						 enum noside);
-
-static struct value *evaluate_subexp_for_address (struct expression *,
-						  int *, enum noside);
-
-static value *evaluate_subexp_for_cast (expression *exp, int *pos,
-					enum noside noside,
-					struct type *type);
-
-static struct value *evaluate_struct_tuple (struct value *,
-					    struct expression *, int *,
-					    enum noside, int);
-
-struct value *
+static struct value *
 evaluate_subexp (struct type *expect_type, struct expression *exp,
-		 int *pos, enum noside noside)
+		 enum noside noside)
 {
   struct value *retval;
 
   gdb::optional<enable_thread_stack_temporaries> stack_temporaries;
-  if (*pos == 0 && target_has_execution ()
+  if (target_has_execution ()
       && exp->language_defn->la_language == language_cplus
       && !thread_stack_temporaries_enabled_p (inferior_thread ()))
     stack_temporaries.emplace (inferior_thread ());
 
-  retval = (*exp->language_defn->expression_ops ()->evaluate_exp)
-    (expect_type, exp, pos, noside);
+  return exp->op->evaluate (expect_type, exp, noside);
 
   if (stack_temporaries.has_value ()
       && value_in_thread_stack_temporaries (retval, inferior_thread ()))
@@ -128,12 +113,7 @@  parse_to_comma_and_eval (const char **expp)
 struct value *
 evaluate_expression (struct expression *exp, struct type *expect_type)
 {
-  int pc = 0;
-
-  if (exp->op != nullptr)
-    return exp->op->evaluate (expect_type, exp, EVAL_NORMAL);
-
-  return evaluate_subexp (expect_type, exp, &pc, EVAL_NORMAL);
+  return evaluate_subexp (expect_type, exp, EVAL_NORMAL);
 }
 
 /* Evaluate an expression, avoiding all memory references
@@ -142,23 +122,7 @@  evaluate_expression (struct expression *exp, struct type *expect_type)
 struct value *
 evaluate_type (struct expression *exp)
 {
-  int pc = 0;
-
-  if (exp->op != nullptr)
-    return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
-
-  return evaluate_subexp (nullptr, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
-}
-
-/* Evaluate a subexpression, avoiding all memory references and
-   getting a value whose type alone is correct.  */
-
-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);
+  return evaluate_subexp (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
 }
 
 /* Find the current value of a watchpoint on EXP.  Return the value in
@@ -184,7 +148,7 @@  evaluate_subexpression_type (struct expression *exp, int subexp)
    values will be left on the value chain.  */
 
 void
-fetch_subexp_value (struct expression *exp, int *pc,
+fetch_subexp_value (struct expression *exp,
 		    expr::operation *op,
 		    struct value **valp, struct value **resultp,
 		    std::vector<value_ref_ptr> *val_chain,
@@ -204,10 +168,7 @@  fetch_subexp_value (struct expression *exp, int *pc,
 
   try
     {
-      if (op == nullptr)
-	result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
-      else
-	result = op->evaluate (nullptr, exp, EVAL_NORMAL);
+      result = op->evaluate (nullptr, exp, EVAL_NORMAL);
     }
   catch (const gdb_exception &ex)
     {
@@ -260,91 +221,6 @@  fetch_subexp_value (struct expression *exp, int *pc,
     }
 }
 
-/* Extract a field operation from an expression.  If the subexpression
-   of EXP starting at *SUBEXP is not a structure dereference
-   operation, return NULL.  Otherwise, return the name of the
-   dereferenced field, and advance *SUBEXP to point to the
-   subexpression of the left-hand-side of the dereference.  This is
-   used when completing field names.  */
-
-const char *
-extract_field_op (struct expression *exp, int *subexp)
-{
-  int tem;
-  char *result;
-
-  if (exp->elts[*subexp].opcode != STRUCTOP_STRUCT
-      && exp->elts[*subexp].opcode != STRUCTOP_PTR)
-    return NULL;
-  tem = longest_to_int (exp->elts[*subexp + 1].longconst);
-  result = &exp->elts[*subexp + 2].string;
-  (*subexp) += 1 + 3 + BYTES_TO_EXP_ELEM (tem + 1);
-  return result;
-}
-
-/* This function evaluates brace-initializers (in C/C++) for
-   structure types.  */
-
-static struct value *
-evaluate_struct_tuple (struct value *struct_val,
-		       struct expression *exp,
-		       int *pos, enum noside noside, int nargs)
-{
-  struct type *struct_type = check_typedef (value_type (struct_val));
-  struct type *field_type;
-  int fieldno = -1;
-
-  while (--nargs >= 0)
-    {
-      struct value *val = NULL;
-      int bitpos, bitsize;
-      bfd_byte *addr;
-
-      fieldno++;
-      /* Skip static fields.  */
-      while (fieldno < struct_type->num_fields ()
-	     && field_is_static (&struct_type->field (fieldno)))
-	fieldno++;
-      if (fieldno >= struct_type->num_fields ())
-	error (_("too many initializers"));
-      field_type = struct_type->field (fieldno).type ();
-      if (field_type->code () == TYPE_CODE_UNION
-	  && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0')
-	error (_("don't know which variant you want to set"));
-
-      /* Here, struct_type is the type of the inner struct,
-	 while substruct_type is the type of the inner struct.
-	 These are the same for normal structures, but a variant struct
-	 contains anonymous union fields that contain substruct fields.
-	 The value fieldno is the index of the top-level (normal or
-	 anonymous union) field in struct_field, while the value
-	 subfieldno is the index of the actual real (named inner) field
-	 in substruct_type.  */
-
-      field_type = struct_type->field (fieldno).type ();
-      if (val == 0)
-	val = evaluate_subexp (field_type, exp, pos, noside);
-
-      /* Now actually set the field in struct_val.  */
-
-      /* Assign val to field fieldno.  */
-      if (value_type (val) != field_type)
-	val = value_cast (field_type, val);
-
-      bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno);
-      bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno);
-      addr = value_contents_writeable (struct_val) + bitpos / 8;
-      if (bitsize)
-	modify_field (struct_type, addr,
-		      value_as_long (val), bitpos % 8, bitsize);
-      else
-	memcpy (addr, value_contents (val),
-		TYPE_LENGTH (value_type (val)));
-
-    }
-  return struct_val;
-}
-
 /* Promote value ARG1 as appropriate before performing a unary operation
    on this argument.
    If the result is not appropriate for any particular language then it
@@ -808,412 +684,6 @@  evaluate_subexp_do_call (expression *exp, enum noside noside,
     }
 }
 
-/* Helper for evaluating an OP_FUNCALL.  */
-
-static value *
-evaluate_funcall (type *expect_type, expression *exp, int *pos,
-		  enum noside noside)
-{
-  int tem;
-  int pc2 = 0;
-  value *arg1 = NULL;
-  value *arg2 = NULL;
-  int save_pos1;
-  symbol *function = NULL;
-  char *function_name = NULL;
-  const char *var_func_name = NULL;
-
-  int pc = (*pos);
-  (*pos) += 2;
-
-  exp_opcode op = exp->elts[*pos].opcode;
-  int nargs = longest_to_int (exp->elts[pc].longconst);
-  /* Allocate arg vector, including space for the function to be
-     called in argvec[0], a potential `this', and a terminating
-     NULL.  */
-  value **argvec = (value **) alloca (sizeof (value *) * (nargs + 3));
-  if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
-    {
-      /* First, evaluate the structure into arg2.  */
-      pc2 = (*pos)++;
-
-      if (op == STRUCTOP_MEMBER)
-	{
-	  arg2 = evaluate_subexp_for_address (exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	}
-
-      /* If the function is a virtual function, then the aggregate
-	 value (providing the structure) plays its part by providing
-	 the vtable.  Otherwise, it is just along for the ride: call
-	 the function directly.  */
-
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      type *a1_type = check_typedef (value_type (arg1));
-      if (noside == EVAL_SKIP)
-	tem = 1;  /* Set it to the right arg index so that all
-		     arguments can also be skipped.  */
-      else if (a1_type->code () == TYPE_CODE_METHODPTR)
-	{
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    arg1 = value_zero (TYPE_TARGET_TYPE (a1_type), not_lval);
-	  else
-	    arg1 = cplus_method_ptr_to_value (&arg2, arg1);
-
-	  /* Now, say which argument to start evaluating from.  */
-	  nargs++;
-	  tem = 2;
-	  argvec[1] = arg2;
-	}
-      else if (a1_type->code () == TYPE_CODE_MEMBERPTR)
-	{
-	  struct type *type_ptr
-	    = lookup_pointer_type (TYPE_SELF_TYPE (a1_type));
-	  struct type *target_type_ptr
-	    = lookup_pointer_type (TYPE_TARGET_TYPE (a1_type));
-
-	  /* Now, convert these values to an address.  */
-	  arg2 = value_cast (type_ptr, arg2);
-
-	  long mem_offset = value_as_long (arg1);
-
-	  arg1 = value_from_pointer (target_type_ptr,
-				     value_as_long (arg2) + mem_offset);
-	  arg1 = value_ind (arg1);
-	  tem = 1;
-	}
-      else
-	error (_("Non-pointer-to-member value used in pointer-to-member "
-		 "construct"));
-    }
-  else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
-    {
-      /* Hair for method invocations.  */
-      int tem2;
-
-      nargs++;
-      /* First, evaluate the structure into arg2.  */
-      pc2 = (*pos)++;
-      tem2 = longest_to_int (exp->elts[pc2 + 1].longconst);
-      *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1);
-
-      if (op == STRUCTOP_STRUCT)
-	{
-	  /* If v is a variable in a register, and the user types
-	     v.method (), this will produce an error, because v has no
-	     address.
-
-	     A possible way around this would be to allocate a copy of
-	     the variable on the stack, copy in the contents, call the
-	     function, and copy out the contents.  I.e. convert this
-	     from call by reference to call by copy-return (or
-	     whatever it's called).  However, this does not work
-	     because it is not the same: the method being called could
-	     stash a copy of the address, and then future uses through
-	     that address (after the method returns) would be expected
-	     to use the variable itself, not some copy of it.  */
-	  arg2 = evaluate_subexp_for_address (exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-	  /* Check to see if the operator '->' has been overloaded.
-	     If the operator has been overloaded replace arg2 with the
-	     value returned by the custom operator and continue
-	     evaluation.  */
-	  while (unop_user_defined_p (op, arg2))
-	    {
-	      struct value *value = NULL;
-	      try
-		{
-		  value = value_x_unop (arg2, op, noside);
-		}
-
-	      catch (const gdb_exception_error &except)
-		{
-		  if (except.error == NOT_FOUND_ERROR)
-		    break;
-		  else
-		    throw;
-		}
-
-		arg2 = value;
-	    }
-	}
-      /* Now, say which argument to start evaluating from.  */
-      tem = 2;
-    }
-  else if (op == OP_SCOPE
-	   && overload_resolution
-	   && (exp->language_defn->la_language == language_cplus))
-    {
-      /* Unpack it locally so we can properly handle overload
-	 resolution.  */
-      char *name;
-      int local_tem;
-
-      pc2 = (*pos)++;
-      local_tem = longest_to_int (exp->elts[pc2 + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (local_tem + 1);
-      struct type *type = exp->elts[pc2 + 1].type;
-      name = &exp->elts[pc2 + 3].string;
-
-      function = NULL;
-      function_name = NULL;
-      if (type->code () == TYPE_CODE_NAMESPACE)
-	{
-	  function = cp_lookup_symbol_namespace (type->name (),
-						 name,
-						 get_selected_block (0),
-						 VAR_DOMAIN).symbol;
-	  if (function == NULL)
-	    error (_("No symbol \"%s\" in namespace \"%s\"."),
-		   name, type->name ());
-
-	  tem = 1;
-	  /* arg2 is left as NULL on purpose.  */
-	}
-      else
-	{
-	  gdb_assert (type->code () == TYPE_CODE_STRUCT
-		      || type->code () == TYPE_CODE_UNION);
-	  function_name = name;
-
-	  /* We need a properly typed value for method lookup.  For
-	     static methods arg2 is otherwise unused.  */
-	  arg2 = value_zero (type, lval_memory);
-	  ++nargs;
-	  tem = 2;
-	}
-    }
-  else if (op == OP_ADL_FUNC)
-    {
-      /* Save the function position and move pos so that the arguments
-	 can be evaluated.  */
-      int func_name_len;
-
-      save_pos1 = *pos;
-      tem = 1;
-
-      func_name_len = longest_to_int (exp->elts[save_pos1 + 3].longconst);
-      (*pos) += 6 + BYTES_TO_EXP_ELEM (func_name_len + 1);
-    }
-  else
-    {
-      /* Non-method function call.  */
-      save_pos1 = *pos;
-      tem = 1;
-
-      /* If this is a C++ function wait until overload resolution.  */
-      if (op == OP_VAR_VALUE
-	  && overload_resolution
-	  && (exp->language_defn->la_language == language_cplus))
-	{
-	  (*pos) += 4; /* Skip the evaluation of the symbol.  */
-	  argvec[0] = NULL;
-	}
-      else
-	{
-	  if (op == OP_VAR_MSYM_VALUE)
-	    {
-	      minimal_symbol *msym = exp->elts[*pos + 2].msymbol;
-	      var_func_name = msym->print_name ();
-	    }
-	  else if (op == OP_VAR_VALUE)
-	    {
-	      symbol *sym = exp->elts[*pos + 2].symbol;
-	      var_func_name = sym->print_name ();
-	    }
-
-	  argvec[0] = evaluate_subexp_with_coercion (exp, pos, noside);
-	  type *type = value_type (argvec[0]);
-	  if (type && type->code () == TYPE_CODE_PTR)
-	    type = TYPE_TARGET_TYPE (type);
-	  if (type && type->code () == TYPE_CODE_FUNC)
-	    {
-	      for (; tem <= nargs && tem <= type->num_fields (); tem++)
-		{
-		  argvec[tem] = evaluate_subexp (type->field (tem - 1).type (),
-						 exp, pos, noside);
-		}
-	    }
-	}
-    }
-
-  /* Evaluate arguments (if not already done, e.g., namespace::func()
-     and overload-resolution is off).  */
-  for (; tem <= nargs; tem++)
-    {
-      /* Ensure that array expressions are coerced into pointer
-	 objects.  */
-      argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
-    }
-
-  /* Signal end of arglist.  */
-  argvec[tem] = 0;
-
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
-  if (op == OP_ADL_FUNC)
-    {
-      struct symbol *symp;
-      char *func_name;
-      int  name_len;
-      int string_pc = save_pos1 + 3;
-
-      /* Extract the function name.  */
-      name_len = longest_to_int (exp->elts[string_pc].longconst);
-      func_name = (char *) alloca (name_len + 1);
-      strcpy (func_name, &exp->elts[string_pc + 1].string);
-
-      find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-			   func_name,
-			   NON_METHOD, /* not method */
-			   NULL, NULL, /* pass NULL symbol since
-					  symbol is unknown */
-			   NULL, &symp, NULL, 0, noside);
-
-      /* Now fix the expression being evaluated.  */
-      exp->elts[save_pos1 + 2].symbol = symp;
-      argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1, noside);
-    }
-
-  if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR
-      || (op == OP_SCOPE && function_name != NULL))
-    {
-      int static_memfuncp;
-      char *tstr;
-
-      /* Method invocation: stuff "this" as first parameter.  If the
-	 method turns out to be static we undo this below.  */
-      argvec[1] = arg2;
-
-      if (op != OP_SCOPE)
-	{
-	  /* Name of method from expression.  */
-	  tstr = &exp->elts[pc2 + 2].string;
-	}
-      else
-	tstr = function_name;
-
-      if (overload_resolution && (exp->language_defn->la_language
-				  == language_cplus))
-	{
-	  /* Language is C++, do some overload resolution before
-	     evaluation.  */
-	  struct value *valp = NULL;
-
-	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-				      tstr,
-				      METHOD, /* method */
-				      &arg2,  /* the object */
-				      NULL, &valp, NULL,
-				      &static_memfuncp, 0, noside);
-
-	  if (op == OP_SCOPE && !static_memfuncp)
-	    {
-	      /* For the time being, we don't handle this.  */
-	      error (_("Call to overloaded function %s requires "
-		       "`this' pointer"),
-		     function_name);
-	    }
-	  argvec[1] = arg2;	/* the ``this'' pointer */
-	  argvec[0] = valp;	/* Use the method found after overload
-				   resolution.  */
-	}
-      else
-	/* Non-C++ case -- or no overload resolution.  */
-	{
-	  struct value *temp = arg2;
-
-	  argvec[0] = value_struct_elt (&temp, argvec + 1, tstr,
-					&static_memfuncp,
-					op == STRUCTOP_STRUCT
-					? "structure" : "structure pointer");
-	  /* value_struct_elt updates temp with the correct value of
-	     the ``this'' pointer if necessary, so modify argvec[1] to
-	     reflect any ``this'' changes.  */
-	  arg2
-	    = value_from_longest (lookup_pointer_type(value_type (temp)),
-				  value_address (temp)
-				  + value_embedded_offset (temp));
-	  argvec[1] = arg2;	/* the ``this'' pointer */
-	}
-
-      /* Take out `this' if needed.  */
-      if (static_memfuncp)
-	{
-	  argvec[1] = argvec[0];
-	  nargs--;
-	  argvec++;
-	}
-    }
-  else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
-    {
-      /* Pointer to member.  argvec[1] is already set up.  */
-      argvec[0] = arg1;
-    }
-  else if (op == OP_VAR_VALUE || (op == OP_SCOPE && function != NULL))
-    {
-      /* Non-member function being called.  */
-      /* fn: This can only be done for C++ functions.  A C-style
-	 function in a C++ program, for instance, does not have the
-	 fields that are expected here.  */
-
-      if (overload_resolution && (exp->language_defn->la_language
-				  == language_cplus))
-	{
-	  /* Language is C++, do some overload resolution before
-	     evaluation.  */
-	  struct symbol *symp;
-	  int no_adl = 0;
-
-	  /* If a scope has been specified disable ADL.  */
-	  if (op == OP_SCOPE)
-	    no_adl = 1;
-
-	  if (op == OP_VAR_VALUE)
-	    function = exp->elts[save_pos1+2].symbol;
-
-	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-				      NULL,        /* no need for name */
-				      NON_METHOD,  /* not method */
-				      NULL, function, /* the function */
-				      NULL, &symp, NULL, no_adl, noside);
-
-	  if (op == OP_VAR_VALUE)
-	    {
-	      /* Now fix the expression being evaluated.  */
-	      exp->elts[save_pos1+2].symbol = symp;
-	      argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1,
-							 noside);
-	    }
-	  else
-	    argvec[0] = value_of_variable (symp, get_selected_block (0));
-	}
-      else
-	{
-	  /* Not C++, or no overload resolution allowed.  */
-	  /* Nothing to be done; argvec already correctly set up.  */
-	}
-    }
-  else
-    {
-      /* It is probably a C-style function.  */
-      /* Nothing to be done; argvec already correctly set up.  */
-    }
-
-  return evaluate_subexp_do_call (exp, noside, argvec[0],
-				  gdb::make_array_view (argvec + 1, nargs),
-				  var_func_name, expect_type);
-}
-
 namespace expr
 {
 
@@ -3040,738 +2510,6 @@  array_operation::evaluate (struct type *expect_type,
 
 }
 
-struct value *
-evaluate_subexp_standard (struct type *expect_type,
-			  struct expression *exp, int *pos,
-			  enum noside noside)
-{
-  enum exp_opcode op;
-  int tem, tem2, tem3;
-  int pc, oldpos;
-  struct value *arg1 = NULL;
-  struct value *arg2 = NULL;
-  struct type *type;
-  int nargs;
-  struct value **argvec;
-  int ix;
-  struct type **arg_types;
-
-  pc = (*pos)++;
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case OP_SCOPE:
-      tem = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
-      return eval_op_scope (expect_type, exp, noside,
-			    exp->elts[pc + 1].type,
-			    &exp->elts[pc + 3].string);
-
-    case OP_LONG:
-      (*pos) += 3;
-      return value_from_longest (exp->elts[pc + 1].type,
-				 exp->elts[pc + 2].longconst);
-
-    case OP_FLOAT:
-      (*pos) += 3;
-      return value_from_contents (exp->elts[pc + 1].type,
-				  exp->elts[pc + 2].floatconst);
-
-    case OP_ADL_FUNC:
-    case OP_VAR_VALUE:
-      {
-	(*pos) += 3;
-	symbol *var = exp->elts[pc + 2].symbol;
-	if (SYMBOL_TYPE (var)->code () == TYPE_CODE_ERROR)
-	  error_unknown_type (var->print_name ());
-	if (noside != EVAL_SKIP)
-	    return evaluate_var_value (noside, exp->elts[pc + 1].block, var);
-	else
-	  {
-	    /* Return a dummy value of the correct type when skipping, so
-	       that parent functions know what is to be skipped.  */
-	    return allocate_value (SYMBOL_TYPE (var));
-	  }
-      }
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 3;
-
-	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
-	return eval_op_var_msym_value (expect_type, exp, noside,
-				       msymbol,
-				       exp->elts[pc + 1].objfile);
-      }
-
-    case OP_VAR_ENTRY_VALUE:
-      (*pos) += 2;
-
-      {
-	struct symbol *sym = exp->elts[pc + 1].symbol;
-
-	return eval_op_var_entry_value (expect_type, exp, noside, sym);
-      }
-
-    case OP_FUNC_STATIC_VAR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      {
-	value *func = evaluate_subexp_standard (NULL, exp, pos, noside);
-
-	return eval_op_func_static_var (expect_type, exp, noside, func,
-					&exp->elts[pc + 2].string);
-      }
-
-    case OP_LAST:
-      (*pos) += 2;
-      return
-	access_value_history (longest_to_int (exp->elts[pc + 1].longconst));
-
-    case OP_REGISTER:
-      {
-	const char *name = &exp->elts[pc + 2].string;
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-	return eval_op_register (expect_type, exp, noside, name);
-      }
-    case OP_BOOL:
-      (*pos) += 2;
-      type = language_bool_type (exp->language_defn, exp->gdbarch);
-      return value_from_longest (type, exp->elts[pc + 1].longconst);
-
-    case OP_INTERNALVAR:
-      (*pos) += 2;
-      return value_of_internalvar (exp->gdbarch,
-				   exp->elts[pc + 1].internalvar);
-
-    case OP_STRING:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      return eval_op_string (expect_type, exp, noside, tem,
-			     &exp->elts[pc + 2].string);
-
-    case OP_OBJC_NSSTRING:		/* Objective C Foundation Class
-					   NSString constant.  */
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_nsstring (exp->gdbarch, &exp->elts[pc + 2].string, tem + 1);
-
-    case OP_ARRAY:
-      (*pos) += 3;
-      tem2 = longest_to_int (exp->elts[pc + 1].longconst);
-      tem3 = longest_to_int (exp->elts[pc + 2].longconst);
-      nargs = tem3 - tem2 + 1;
-      type = expect_type ? check_typedef (expect_type) : nullptr;
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_STRUCT)
-	{
-	  struct value *rec = allocate_value (expect_type);
-
-	  memset (value_contents_raw (rec), '\0', TYPE_LENGTH (type));
-	  return evaluate_struct_tuple (rec, exp, pos, noside, nargs);
-	}
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_ARRAY)
-	{
-	  struct type *range_type = type->index_type ();
-	  struct type *element_type = TYPE_TARGET_TYPE (type);
-	  struct value *array = allocate_value (expect_type);
-	  int element_size = TYPE_LENGTH (check_typedef (element_type));
-	  LONGEST low_bound, high_bound, index;
-
-	  if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
-	    {
-	      low_bound = 0;
-	      high_bound = (TYPE_LENGTH (type) / element_size) - 1;
-	    }
-	  index = low_bound;
-	  memset (value_contents_raw (array), 0, TYPE_LENGTH (expect_type));
-	  for (tem = nargs; --nargs >= 0;)
-	    {
-	      struct value *element;
-
-	      element = evaluate_subexp (element_type, exp, pos, noside);
-	      if (value_type (element) != element_type)
-		element = value_cast (element_type, element);
-	      if (index > high_bound)
-		/* To avoid memory corruption.  */
-		error (_("Too many array elements"));
-	      memcpy (value_contents_raw (array)
-		      + (index - low_bound) * element_size,
-		      value_contents (element),
-		      element_size);
-	      index++;
-	    }
-	  return array;
-	}
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_SET)
-	{
-	  struct value *set = allocate_value (expect_type);
-	  gdb_byte *valaddr = value_contents_raw (set);
-	  struct type *element_type = type->index_type ();
-	  struct type *check_type = element_type;
-	  LONGEST low_bound, high_bound;
-
-	  /* Get targettype of elementtype.  */
-	  while (check_type->code () == TYPE_CODE_RANGE
-		 || check_type->code () == TYPE_CODE_TYPEDEF)
-	    check_type = TYPE_TARGET_TYPE (check_type);
-
-	  if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
-	    error (_("(power)set type with unknown size"));
-	  memset (valaddr, '\0', TYPE_LENGTH (type));
-	  for (tem = 0; tem < nargs; tem++)
-	    {
-	      LONGEST range_low, range_high;
-	      struct type *range_low_type, *range_high_type;
-	      struct value *elem_val;
-
-	      elem_val = evaluate_subexp (element_type, exp, pos, noside);
-	      range_low_type = range_high_type = value_type (elem_val);
-	      range_low = range_high = value_as_long (elem_val);
-
-	      /* Check types of elements to avoid mixture of elements from
-		 different types. Also check if type of element is "compatible"
-		 with element type of powerset.  */
-	      if (range_low_type->code () == TYPE_CODE_RANGE)
-		range_low_type = TYPE_TARGET_TYPE (range_low_type);
-	      if (range_high_type->code () == TYPE_CODE_RANGE)
-		range_high_type = TYPE_TARGET_TYPE (range_high_type);
-	      if ((range_low_type->code () != range_high_type->code ())
-		  || (range_low_type->code () == TYPE_CODE_ENUM
-		      && (range_low_type != range_high_type)))
-		/* different element modes.  */
-		error (_("POWERSET tuple elements of different mode"));
-	      if ((check_type->code () != range_low_type->code ())
-		  || (check_type->code () == TYPE_CODE_ENUM
-		      && range_low_type != check_type))
-		error (_("incompatible POWERSET tuple elements"));
-	      if (range_low > range_high)
-		{
-		  warning (_("empty POWERSET tuple range"));
-		  continue;
-		}
-	      if (range_low < low_bound || range_high > high_bound)
-		error (_("POWERSET tuple element out of range"));
-	      range_low -= low_bound;
-	      range_high -= low_bound;
-	      for (; range_low <= range_high; range_low++)
-		{
-		  int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
-
-		  if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
-		    bit_index = TARGET_CHAR_BIT - 1 - bit_index;
-		  valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
-		    |= 1 << bit_index;
-		}
-	    }
-	  return set;
-	}
-
-      argvec = XALLOCAVEC (struct value *, nargs);
-      for (tem = 0; tem < nargs; tem++)
-	{
-	  /* Ensure that array expressions are coerced into pointer
-	     objects.  */
-	  argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
-	}
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_array (tem2, tem3, argvec);
-
-    case TERNOP_SLICE:
-      {
-	struct value *array = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *low = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *upper = evaluate_subexp (nullptr, exp, pos, noside);
-	return eval_op_ternop (expect_type, exp, noside, array, low, upper);
-      }
-
-    case TERNOP_COND:
-      /* Skip third and second args to evaluate the first one.  */
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (value_logical_not (arg1))
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return evaluate_subexp (nullptr, exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return arg2;
-	}
-
-    case OP_OBJC_SELECTOR:
-      {				/* Objective C @selector operator.  */
-	char *sel = &exp->elts[pc + 2].string;
-	int len = longest_to_int (exp->elts[pc + 1].longconst);
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1);
-	if (sel[len] != 0)
-	  sel[len] = 0;		/* Make sure it's terminated.  */
-
-	return eval_op_objc_selector (expect_type, exp, noside, sel);
-      }
-
-    case OP_OBJC_MSGCALL:
-      {				/* Objective C message (method) call.  */
-	CORE_ADDR selector = 0;
-
-	enum noside sub_no_side = EVAL_NORMAL;
-
-	struct value *target = NULL;
-
-	struct type *selector_type = NULL;
-
-	selector = exp->elts[pc + 1].longconst;
-	nargs = exp->elts[pc + 2].longconst;
-	argvec = XALLOCAVEC (struct value *, nargs + 3);
-
-	(*pos) += 3;
-
-	selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
-
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  sub_no_side = EVAL_NORMAL;
-	else
-	  sub_no_side = noside;
-
-	target = evaluate_subexp (selector_type, exp, pos, sub_no_side);
-
-	if (value_as_long (target) == 0)
-	  sub_no_side = EVAL_SKIP;
-	else
-	  sub_no_side = noside;
-
-	/* Now depending on whether we found a symbol for the method,
-	   we will either call the runtime dispatcher or the method
-	   directly.  */
-
-	argvec[0] = nullptr;
-	argvec[1] = nullptr;
-	/* User-supplied arguments.  */
-	for (tem = 0; tem < nargs; tem++)
-	  argvec[tem + 2] = evaluate_subexp_with_coercion (exp, pos,
-							   sub_no_side);
-	argvec[tem + 3] = 0;
-
-	auto call_args = gdb::make_array_view (argvec, nargs + 3);
-
-	return eval_op_objc_msgcall (expect_type, exp, noside, selector,
-				     target, call_args);
-      }
-      break;
-
-    case OP_FUNCALL:
-      return evaluate_funcall (expect_type, exp, pos, noside);
-
-    case OP_COMPLEX:
-      /* We have a complex number, There should be 2 floating 
-	 point numbers that compose it.  */
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      return value_literal_complex (arg1, arg2, exp->elts[pc + 1].type);
-
-    case STRUCTOP_STRUCT:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_structop_struct (expect_type, exp, noside, arg1,
-				      &exp->elts[pc + 2].string);
-
-    case STRUCTOP_PTR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_structop_ptr (expect_type, exp, noside, arg1,
-				   &exp->elts[pc + 2].string);
-
-    case STRUCTOP_MEMBER:
-    case STRUCTOP_MPTR:
-      if (op == STRUCTOP_MEMBER)
-	arg1 = evaluate_subexp_for_address (exp, pos, noside);
-      else
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      return eval_op_member (expect_type, exp, noside, arg1, arg2);
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
-	nargs = longest_to_int (exp->elts[pc + 2].longconst);
-	arg_types = (struct type **) alloca (nargs * sizeof (struct type *));
-	for (ix = 0; ix < nargs; ++ix)
-	  arg_types[ix] = exp->elts[pc + 2 + ix + 1].type;
-
-	fake_method fake_expect_type (flags, nargs, arg_types);
-	*(pos) += 4 + nargs;
-	return evaluate_subexp_standard (fake_expect_type.type (), exp, pos,
-					 noside);
-      }
-
-    case BINOP_CONCAT:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_concat (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_ASSIGN:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      /* Special-case assignments where the left-hand-side is a
-	 convenience variable -- in these, don't bother setting an
-	 expected type.  This avoids a weird case where re-assigning a
-	 string or array to an internal variable could error with "Too
-	 many array elements".  */
-      arg2 = evaluate_subexp (VALUE_LVAL (arg1) == lval_internalvar
-				? nullptr
-				: value_type (arg1),
-			      exp, pos, noside);
-
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else
-	return value_assign (arg1, arg2);
-
-    case BINOP_ASSIGN_MODIFY:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      op = exp->elts[pc + 1].opcode;
-      return eval_binop_assign_modify (expect_type, exp, noside, op,
-				       arg1, arg2);
-
-    case BINOP_ADD:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_add (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_SUB:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_sub (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_EXP:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_INTDIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_binary (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_SUBSCRIPT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_subscript (expect_type, exp, noside, op, arg1, arg2);
-
-    case MULTI_SUBSCRIPT:
-      (*pos) += 2;
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      argvec = XALLOCAVEC (struct value *, nargs);
-      for (ix = 0; ix < nargs; ++ix)
-	argvec[ix] = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_multi_subscript (expect_type, exp, noside, arg1,
-				   gdb::make_array_view (argvec, nargs));
-
-    case BINOP_LOGICAL_AND:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, noside);
-	  return eval_skip_value (exp);
-	}
-
-      oldpos = *pos;
-      arg2 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      *pos = oldpos;
-
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  tem = value_logical_not (arg1);
-	  arg2
-	    = evaluate_subexp (nullptr, exp, pos, (tem ? EVAL_SKIP : noside));
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type,
-			     (LONGEST) (!tem && !value_logical_not (arg2)));
-	}
-
-    case BINOP_LOGICAL_OR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, noside);
-	  return eval_skip_value (exp);
-	}
-
-      oldpos = *pos;
-      arg2 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      *pos = oldpos;
-
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  tem = value_logical_not (arg1);
-	  arg2
-	    = evaluate_subexp (nullptr, exp, pos, (!tem ? EVAL_SKIP : noside));
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type,
-			     (LONGEST) (!tem || !value_logical_not (arg2)));
-	}
-
-    case BINOP_EQUAL:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_equal (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_NOTEQUAL:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_notequal (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_LESS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_less (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_GTR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_gtr (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_GEQ:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_geq (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_LEQ:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_leq (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_REPEAT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_repeat (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_COMMA:
-      evaluate_subexp (nullptr, exp, pos, noside);
-      return evaluate_subexp (nullptr, exp, pos, noside);
-
-    case UNOP_PLUS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_plus (expect_type, exp, noside, op, arg1);
-      
-    case UNOP_NEG:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_neg (expect_type, exp, noside, op, arg1);
-
-    case UNOP_COMPLEMENT:
-      /* C++: check for and handle destructor names.  */
-
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_complement (expect_type, exp, noside, op, arg1);
-
-    case UNOP_LOGICAL_NOT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_lognot (expect_type, exp, noside, op, arg1);
-
-    case UNOP_IND:
-      if (expect_type && expect_type->code () == TYPE_CODE_PTR)
-	expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_ind (expect_type, exp, noside, arg1);
-
-    case UNOP_ADDR:
-      /* C++: check for and handle pointer to members.  */
-
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      else
-	return evaluate_subexp_for_address (exp, pos, noside);
-
-    case UNOP_SIZEOF:
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      return evaluate_subexp_for_sizeof (exp, pos, noside);
-
-    case UNOP_ALIGNOF:
-      arg1 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      return eval_op_alignof (expect_type, exp, noside, arg1);
-
-    case UNOP_CAST:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
-      return evaluate_subexp_for_cast (exp, pos, noside, type);
-
-    case UNOP_CAST_TYPE:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-      return evaluate_subexp_for_cast (exp, pos, noside, type);
-
-    case UNOP_DYNAMIC_CAST:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-      arg1 = evaluate_subexp (type, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_dynamic_cast (type, arg1);
-
-    case UNOP_REINTERPRET_CAST:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-      arg1 = evaluate_subexp (type, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_reinterpret_cast (type, arg1);
-
-    case UNOP_MEMVAL:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_memval (expect_type, exp, noside, arg1,
-			     exp->elts[pc + 1].type);
-
-    case UNOP_MEMVAL_TYPE:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_memval (expect_type, exp, noside, arg1, type);
-
-    case UNOP_PREINCREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_preinc (expect_type, exp, noside, op, arg1);
-
-    case UNOP_PREDECREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_predec (expect_type, exp, noside, op, arg1);
-
-    case UNOP_POSTINCREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_postinc (expect_type, exp, noside, op, arg1);
-
-    case UNOP_POSTDECREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_postdec (expect_type, exp, noside, op, arg1);
-
-    case OP_THIS:
-      (*pos) += 1;
-      return value_of_this (exp->language_defn);
-
-    case OP_TYPE:
-      /* The value is not supposed to be used.  This is here to make it
-	 easier to accommodate expressions that contain types.  */
-      (*pos) += 2;
-      return eval_op_type (expect_type, exp, noside, exp->elts[pc + 1].type);
-
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  enum exp_opcode sub_op = exp->elts[*pos].opcode;
-	  struct value *result;
-
-	  result = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-
-	  /* 'decltype' has special semantics for lvalues.  */
-	  if (op == OP_DECLTYPE
-	      && (sub_op == BINOP_SUBSCRIPT
-		  || sub_op == STRUCTOP_MEMBER
-		  || sub_op == STRUCTOP_MPTR
-		  || sub_op == UNOP_IND
-		  || sub_op == STRUCTOP_STRUCT
-		  || sub_op == STRUCTOP_PTR
-		  || sub_op == OP_SCOPE))
-	    {
-	      type = value_type (result);
-
-	      if (!TYPE_IS_REFERENCE (type))
-		{
-		  type = lookup_lvalue_reference_type (type);
-		  result = allocate_value (type);
-		}
-	    }
-
-	  return result;
-	}
-      else
-	error (_("Attempt to use a type as an expression"));
-
-    case OP_TYPEID:
-      {
-	struct value *result;
-	enum exp_opcode sub_op = exp->elts[*pos].opcode;
-
-	if (sub_op == OP_TYPE || sub_op == OP_DECLTYPE || sub_op == OP_TYPEOF)
-	  result = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	else
-	  result = evaluate_subexp (nullptr, exp, pos, noside);
-
-	if (noside != EVAL_NORMAL)
-	  return allocate_value (cplus_typeid_type (exp->gdbarch));
-
-	return cplus_typeid (result);
-      }
-
-    default:
-      /* Removing this case and compiling with gcc -Wall reveals that
-	 a lot of cases are hitting this case.  Some of these should
-	 probably be removed from expression.h; others are legitimate
-	 expressions which are (apparently) not fully implemented.
-
-	 If there are any cases landing here which mean a user error,
-	 then they should be separate cases, with more descriptive
-	 error messages.  */
-
-      error (_("GDB does not (yet) know how to "
-	       "evaluate that kind of expression"));
-    }
-
-  gdb_assert_not_reached ("missed return?");
-}
 
 /* Helper for evaluate_subexp_for_address.  */
 
@@ -3796,117 +2534,6 @@  evaluate_subexp_for_address_base (struct expression *exp, enum noside noside,
   return value_addr (x);
 }
 
-/* Evaluate a subexpression of EXP, at index *POS,
-   and return the address of that subexpression.
-   Advance *POS over the subexpression.
-   If the subexpression isn't an lvalue, get an error.
-   NOSIDE may be EVAL_AVOID_SIDE_EFFECTS;
-   then only the type of the result need be correct.  */
-
-static struct value *
-evaluate_subexp_for_address (struct expression *exp, int *pos,
-			     enum noside noside)
-{
-  enum exp_opcode op;
-  int pc;
-  struct symbol *var;
-  struct value *x;
-  int tem;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case UNOP_IND:
-      (*pos)++;
-      x = evaluate_subexp (nullptr, exp, pos, noside);
-
-      /* We can't optimize out "&*" if there's a user-defined operator*.  */
-      if (unop_user_defined_p (op, x))
-	{
-	  x = value_x_unop (x, op, noside);
-	  goto default_case_after_eval;
-	}
-
-      return coerce_array (x);
-
-    case UNOP_MEMVAL:
-      (*pos) += 3;
-      return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
-			 evaluate_subexp (nullptr, exp, pos, noside));
-
-    case UNOP_MEMVAL_TYPE:
-      {
-	struct type *type;
-
-	(*pos) += 1;
-	x = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	type = value_type (x);
-	return value_cast (lookup_pointer_type (type),
-			   evaluate_subexp (nullptr, exp, pos, noside));
-      }
-
-    case OP_VAR_VALUE:
-      var = exp->elts[pc + 2].symbol;
-
-      /* C++: The "address" of a reference should yield the address
-       * of the object pointed to.  Let value_addr() deal with it.  */
-      if (TYPE_IS_REFERENCE (SYMBOL_TYPE (var)))
-	goto default_case;
-
-      (*pos) += 4;
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  struct type *type =
-	    lookup_pointer_type (SYMBOL_TYPE (var));
-	  enum address_class sym_class = SYMBOL_CLASS (var);
-
-	  if (sym_class == LOC_CONST
-	      || sym_class == LOC_CONST_BYTES
-	      || sym_class == LOC_REGISTER)
-	    error (_("Attempt to take address of register or constant."));
-
-	  return
-	    value_zero (type, not_lval);
-	}
-      else
-	return address_of_variable (var, exp->elts[pc + 1].block);
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 4;
-
-	value *val = evaluate_var_msym_value (noside,
-					      exp->elts[pc + 1].objfile,
-					      exp->elts[pc + 2].msymbol);
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  {
-	    struct type *type = lookup_pointer_type (value_type (val));
-	    return value_zero (type, not_lval);
-	  }
-	else
-	  return value_addr (val);
-      }
-
-    case OP_SCOPE:
-      tem = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1);
-      x = value_aggregate_elt (exp->elts[pc + 1].type,
-			       &exp->elts[pc + 3].string,
-			       NULL, 1, noside);
-      if (x == NULL)
-	error (_("There is no field named %s"), &exp->elts[pc + 3].string);
-      return x;
-
-    default:
-    default_case:
-      x = evaluate_subexp (nullptr, exp, pos, noside);
-    default_case_after_eval:
-      return evaluate_subexp_for_address_base (exp, noside, x);
-    }
-}
-
 namespace expr
 {
 
@@ -3993,51 +2620,6 @@  unop_memval_type_operation::evaluate_for_address (struct expression *exp,
 
 }
 
-/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
-   When used in contexts where arrays will be coerced anyway, this is
-   equivalent to `evaluate_subexp' but much faster because it avoids
-   actually fetching array contents (perhaps obsolete now that we have
-   value_lazy()).
-
-   Note that we currently only do the coercion for C expressions, where
-   arrays are zero based and the coercion is correct.  For other languages,
-   with nonzero based arrays, coercion loses.  Use CAST_IS_CONVERSION
-   to decide if coercion is appropriate.  */
-
-struct value *
-evaluate_subexp_with_coercion (struct expression *exp,
-			       int *pos, enum noside noside)
-{
-  enum exp_opcode op;
-  int pc;
-  struct value *val;
-  struct symbol *var;
-  struct type *type;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case OP_VAR_VALUE:
-      var = exp->elts[pc + 2].symbol;
-      type = check_typedef (SYMBOL_TYPE (var));
-      if (type->code () == TYPE_CODE_ARRAY
-	  && !type->is_vector ()
-	  && CAST_IS_CONVERSION (exp->language_defn))
-	{
-	  (*pos) += 4;
-	  val = address_of_variable (var, exp->elts[pc + 1].block);
-	  return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
-			     val);
-	}
-      /* FALLTHROUGH */
-
-    default:
-      return evaluate_subexp (nullptr, exp, pos, noside);
-    }
-}
-
 namespace expr
 {
 
@@ -4103,132 +2685,6 @@  evaluate_subexp_for_sizeof_base (struct expression *exp, struct type *type)
   return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
 }
 
-/* Evaluate a subexpression of EXP, at index *POS,
-   and return a value for the size of that subexpression.
-   Advance *POS over the subexpression.  If NOSIDE is EVAL_NORMAL
-   we allow side-effects on the operand if its type is a variable
-   length array.   */
-
-static struct value *
-evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
-			    enum noside noside)
-{
-  /* FIXME: This should be size_t.  */
-  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
-  enum exp_opcode op;
-  int pc;
-  struct type *type;
-  struct value *val;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-      /* This case is handled specially
-	 so that we avoid creating a value for the result type.
-	 If the result type is very big, it's desirable not to
-	 create a value unnecessarily.  */
-    case UNOP_IND:
-      (*pos)++;
-      val = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = check_typedef (value_type (val));
-      if (type->code () != TYPE_CODE_PTR
-	  && !TYPE_IS_REFERENCE (type)
-	  && type->code () != TYPE_CODE_ARRAY)
-	error (_("Attempt to take contents of a non-pointer value."));
-      type = TYPE_TARGET_TYPE (type);
-      if (is_dynamic_type (type))
-	type = value_type (value_ind (val));
-      return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
-
-    case UNOP_MEMVAL:
-      (*pos) += 3;
-      type = exp->elts[pc + 1].type;
-      break;
-
-    case UNOP_MEMVAL_TYPE:
-      (*pos) += 1;
-      val = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (val);
-      break;
-
-    case OP_VAR_VALUE:
-      type = SYMBOL_TYPE (exp->elts[pc + 2].symbol);
-      if (is_dynamic_type (type))
-	{
-	  val = evaluate_subexp (nullptr, exp, pos, EVAL_NORMAL);
-	  type = value_type (val);
-	  if (type->code () == TYPE_CODE_ARRAY)
-	    {
-	      if (type_not_allocated (type) || type_not_associated (type))
-		return value_zero (size_type, not_lval);
-	      else if (is_dynamic_type (type->index_type ())
-		       && type->bounds ()->high.kind () == PROP_UNDEFINED)
-		return allocate_optimized_out_value (size_type);
-	    }
-	}
-      else
-	(*pos) += 4;
-      break;
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 4;
-
-	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
-	value *mval = evaluate_var_msym_value (noside,
-					       exp->elts[pc + 1].objfile,
-					       msymbol);
-
-	type = value_type (mval);
-	if (type->code () == TYPE_CODE_ERROR)
-	  error_unknown_type (msymbol->print_name ());
-
-	return value_from_longest (size_type, TYPE_LENGTH (type));
-      }
-      break;
-
-      /* Deal with the special case if NOSIDE is EVAL_NORMAL and the resulting
-	 type of the subscript is a variable length array type. In this case we
-	 must re-evaluate the right hand side of the subscription to allow
-	 side-effects. */
-    case BINOP_SUBSCRIPT:
-      if (noside == EVAL_NORMAL)
-	{
-	  int npc = (*pos) + 1;
-
-	  val = evaluate_subexp (nullptr, exp, &npc, EVAL_AVOID_SIDE_EFFECTS);
-	  type = check_typedef (value_type (val));
-	  if (type->code () == TYPE_CODE_ARRAY)
-	    {
-	      type = check_typedef (TYPE_TARGET_TYPE (type));
-	      if (type->code () == TYPE_CODE_ARRAY)
-		{
-		  type = type->index_type ();
-		  /* Only re-evaluate the right hand side if the resulting type
-		     is a variable length type.  */
-		  if (type->bounds ()->flag_bound_evaluated)
-		    {
-		      val = evaluate_subexp (nullptr, exp, pos, EVAL_NORMAL);
-		      return value_from_longest
-			(size_type, (LONGEST) TYPE_LENGTH (value_type (val)));
-		    }
-		}
-	    }
-	}
-
-      /* Fall through.  */
-
-    default:
-      val = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (val);
-      break;
-    }
-
-  return evaluate_subexp_for_sizeof_base (exp, type);
-}
-
 namespace expr
 {
 
@@ -4349,61 +2805,6 @@  var_value_operation::evaluate_for_sizeof (struct expression *exp,
 
 }
 
-/* Evaluate a subexpression of EXP, at index *POS, and return a value
-   for that subexpression cast to TO_TYPE.  Advance *POS over the
-   subexpression.  */
-
-static value *
-evaluate_subexp_for_cast (expression *exp, int *pos,
-			  enum noside noside,
-			  struct type *to_type)
-{
-  int pc = *pos;
-
-  /* Don't let symbols be evaluated with evaluate_subexp because that
-     throws an "unknown type" error for no-debug data symbols.
-     Instead, we want the cast to reinterpret the symbol.  */
-  if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE
-      || exp->elts[pc].opcode == OP_VAR_VALUE)
-    {
-      (*pos) += 4;
-
-      value *val;
-      if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE)
-	{
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return value_zero (to_type, not_lval);
-
-	  val = evaluate_var_msym_value (noside,
-					 exp->elts[pc + 1].objfile,
-					 exp->elts[pc + 2].msymbol);
-	}
-      else
-	val = evaluate_var_value (noside,
-				  exp->elts[pc + 1].block,
-				  exp->elts[pc + 2].symbol);
-
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      val = value_cast (to_type, val);
-
-      /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
-      if (VALUE_LVAL (val) == lval_memory)
-	{
-	  if (value_lazy (val))
-	    value_fetch_lazy (val);
-	  VALUE_LVAL (val) = not_lval;
-	}
-      return val;
-    }
-
-  value *val = evaluate_subexp (to_type, exp, pos, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  return value_cast (to_type, val);
-}
-
 namespace expr
 {
 
@@ -4473,15 +2874,9 @@  parse_and_eval_type (const char *p, int length)
   tmp[length + 2] = '0';
   tmp[length + 3] = '\0';
   expression_up expr = parse_expression (tmp);
-  if (expr->first_opcode () != UNOP_CAST)
+  expr::unop_cast_operation *op
+    = dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
+  if (op == nullptr)
     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;
+  return op->get_type ();
 }
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 1a6634a7b7f..5e55e77b5a2 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -36,661 +36,6 @@ 
 
 #include <ctype.h>
 
-void
-print_expression (struct expression *exp, struct ui_file *stream)
-{
-  int pc = 0;
-
-  print_subexp (exp, &pc, stream, PREC_NULL);
-}
-
-/* Print the subexpression of EXP that starts in position POS, on STREAM.
-   PREC is the precedence of the surrounding operator;
-   if the precedence of the main operator of this subexpression is less,
-   parentheses are needed here.  */
-
-void
-print_subexp (struct expression *exp, int *pos,
-	      struct ui_file *stream, enum precedence prec)
-{
-  exp->language_defn->expression_ops ()->print_subexp (exp, pos, stream,
-						       prec);
-}
-
-/* See parser-defs.h.  */
-
-void
-print_subexp_funcall (struct expression *exp, int *pos,
-		      struct ui_file *stream)
-{
-  unsigned nargs = longest_to_int (exp->elts[*pos].longconst);
-  (*pos) += 2;
-  print_subexp (exp, pos, stream, PREC_SUFFIX);
-  fputs_filtered (" (", stream);
-  for (unsigned tem = 0; tem < nargs; tem++)
-    {
-      if (tem != 0)
-	fputs_filtered (", ", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-    }
-  fputs_filtered (")", stream);
-}
-
-/* Standard implementation of print_subexp for use in language_defn
-   vectors.  */
-void
-print_subexp_standard (struct expression *exp, int *pos,
-		       struct ui_file *stream, enum precedence prec)
-{
-  unsigned tem;
-  const struct op_print *op_print_tab;
-  int pc;
-  unsigned nargs;
-  const char *op_str;
-  int assign_modify = 0;
-  enum exp_opcode opcode;
-  enum precedence myprec = PREC_NULL;
-  /* Set to 1 for a right-associative operator.  */
-  int assoc = 0;
-  struct value *val;
-  char *tempstr = NULL;
-
-  op_print_tab = exp->language_defn->opcode_print_table ();
-  pc = (*pos)++;
-  opcode = exp->elts[pc].opcode;
-  switch (opcode)
-    {
-      /* Common ops */
-
-    case OP_TYPE:
-      (*pos) += 2;
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      return;
-
-    case OP_SCOPE:
-      myprec = PREC_PREFIX;
-      assoc = 0;
-      fputs_filtered (exp->elts[pc + 1].type->name (), stream);
-      fputs_filtered ("::", stream);
-      nargs = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1);
-      fputs_filtered (&exp->elts[pc + 3].string, stream);
-      return;
-
-    case OP_LONG:
-      {
-	struct value_print_options opts;
-
-	get_no_prettyformat_print_options (&opts);
-	(*pos) += 3;
-	value_print (value_from_longest (exp->elts[pc + 1].type,
-					 exp->elts[pc + 2].longconst),
-		     stream, &opts);
-      }
-      return;
-
-    case OP_FLOAT:
-      {
-	struct value_print_options opts;
-
-	get_no_prettyformat_print_options (&opts);
-	(*pos) += 3;
-	value_print (value_from_contents (exp->elts[pc + 1].type,
-					  exp->elts[pc + 2].floatconst),
-		     stream, &opts);
-      }
-      return;
-
-    case OP_VAR_VALUE:
-      {
-	const struct block *b;
-
-	(*pos) += 3;
-	b = exp->elts[pc + 1].block;
-	if (b != NULL
-	    && BLOCK_FUNCTION (b) != NULL
-	    && BLOCK_FUNCTION (b)->print_name () != NULL)
-	  {
-	    fputs_filtered (BLOCK_FUNCTION (b)->print_name (), stream);
-	    fputs_filtered ("::", stream);
-	  }
-	fputs_filtered (exp->elts[pc + 2].symbol->print_name (), stream);
-      }
-      return;
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 3;
-	fputs_filtered (exp->elts[pc + 2].msymbol->print_name (), stream);
-      }
-      return;
-
-    case OP_FUNC_STATIC_VAR:
-      {
-	tem = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-	fputs_filtered (&exp->elts[pc + 1].string, stream);
-      }
-      return;
-
-    case OP_VAR_ENTRY_VALUE:
-      {
-	(*pos) += 2;
-	fprintf_filtered (stream, "%s@entry",
-			  exp->elts[pc + 1].symbol->print_name ());
-      }
-      return;
-
-    case OP_LAST:
-      (*pos) += 2;
-      fprintf_filtered (stream, "$%d",
-			longest_to_int (exp->elts[pc + 1].longconst));
-      return;
-
-    case OP_REGISTER:
-      {
-	const char *name = &exp->elts[pc + 2].string;
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-	fprintf_filtered (stream, "$%s", name);
-	return;
-      }
-
-    case OP_BOOL:
-      (*pos) += 2;
-      fprintf_filtered (stream, "%s",
-			longest_to_int (exp->elts[pc + 1].longconst)
-			? "TRUE" : "FALSE");
-      return;
-
-    case OP_INTERNALVAR:
-      (*pos) += 2;
-      fprintf_filtered (stream, "$%s",
-			internalvar_name (exp->elts[pc + 1].internalvar));
-      return;
-
-    case OP_FUNCALL:
-      print_subexp_funcall (exp, pos, stream);
-      return;
-
-    case OP_NAME:
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-    case OP_STRING:
-      {
-	struct value_print_options opts;
-
-	nargs = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-	/* LA_PRINT_STRING will print using the current repeat count threshold.
-	   If necessary, we can temporarily set it to zero, or pass it as an
-	   additional parameter to LA_PRINT_STRING.  -fnf */
-	get_user_print_options (&opts);
-	exp->language_defn
-	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-		      NULL, 0, &opts);
-      }
-      return;
-
-    case OP_OBJC_NSSTRING:	/* Objective-C Foundation Class
-				   NSString constant.  */
-      {
-	struct value_print_options opts;
-
-	nargs = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-	fputs_filtered ("@\"", stream);
-	get_user_print_options (&opts);
-	exp->language_defn
-	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-		      NULL, 0, &opts);
-	fputs_filtered ("\"", stream);
-      }
-      return;
-
-    case OP_OBJC_MSGCALL:
-      {			/* Objective C message (method) call.  */
-	(*pos) += 3;
-	nargs = longest_to_int (exp->elts[pc + 2].longconst);
-	fprintf_unfiltered (stream, "[");
-	print_subexp (exp, pos, stream, PREC_SUFFIX);
-	gdb::unique_xmalloc_ptr<char> selector
-	  = target_read_string (exp->elts[pc + 1].longconst, 1024);
-	if (selector == nullptr)
-	  error (_("bad selector"));
-	if (nargs)
-	  {
-	    char *s, *nextS;
-
-	    s = selector.get ();
-	    for (tem = 0; tem < nargs; tem++)
-	      {
-		nextS = strchr (s, ':');
-		gdb_assert (nextS);	/* Make sure we found ':'.  */
-		*nextS = '\0';
-		fprintf_unfiltered (stream, " %s: ", s);
-		s = nextS + 1;
-		print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	      }
-	  }
-	else
-	  {
-	    fprintf_unfiltered (stream, " %s", selector.get ());
-	  }
-	fprintf_unfiltered (stream, "]");
-	return;
-      }
-
-    case OP_ARRAY:
-      (*pos) += 3;
-      nargs = longest_to_int (exp->elts[pc + 2].longconst);
-      nargs -= longest_to_int (exp->elts[pc + 1].longconst);
-      nargs++;
-      tem = 0;
-      if (exp->elts[pc + 4].opcode == OP_LONG
-	  && exp->elts[pc + 5].type
-	     == builtin_type (exp->gdbarch)->builtin_char
-	  && exp->language_defn->la_language == language_c)
-	{
-	  /* Attempt to print C character arrays using string syntax.
-	     Walk through the args, picking up one character from each
-	     of the OP_LONG expression elements.  If any array element
-	     does not match our expection of what we should find for
-	     a simple string, revert back to array printing.  Note that
-	     the last expression element is an explicit null terminator
-	     byte, which doesn't get printed.  */
-	  tempstr = (char *) alloca (nargs);
-	  pc += 4;
-	  while (tem < nargs)
-	    {
-	      if (exp->elts[pc].opcode != OP_LONG
-		  || exp->elts[pc + 1].type
-		     != builtin_type (exp->gdbarch)->builtin_char)
-		{
-		  /* Not a simple array of char, use regular array
-		     printing.  */
-		  tem = 0;
-		  break;
-		}
-	      else
-		{
-		  tempstr[tem++] =
-		    longest_to_int (exp->elts[pc + 2].longconst);
-		  pc += 4;
-		}
-	    }
-	}
-      if (tem > 0)
-	{
-	  struct value_print_options opts;
-
-	  get_user_print_options (&opts);
-	  exp->language_defn
-	    ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-			(gdb_byte *) tempstr, nargs - 1, NULL, 0, &opts);
-	  (*pos) = pc;
-	}
-      else
-	{
-	  fputs_filtered (" {", stream);
-	  for (tem = 0; tem < nargs; tem++)
-	    {
-	      if (tem != 0)
-		{
-		  fputs_filtered (", ", stream);
-		}
-	      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	    }
-	  fputs_filtered ("}", stream);
-	}
-      return;
-
-    case TERNOP_COND:
-      if ((int) prec > (int) PREC_COMMA)
-	fputs_filtered ("(", stream);
-      /* Print the subexpressions, forcing parentheses
-	 around any binary operations within them.
-	 This is more parentheses than are strictly necessary,
-	 but it looks clearer.  */
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      fputs_filtered (" ? ", stream);
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      fputs_filtered (" : ", stream);
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      if ((int) prec > (int) PREC_COMMA)
-	fputs_filtered (")", stream);
-      return;
-
-    case TERNOP_SLICE:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("(", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered (opcode == TERNOP_SLICE ? " : " : " UP ", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered (")", stream);
-      return;
-
-    case STRUCTOP_STRUCT:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (".", stream);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-      /* Will not occur for Modula-2.  */
-    case STRUCTOP_PTR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("->", stream);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-    case STRUCTOP_MEMBER:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (".*", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case STRUCTOP_MPTR:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("->*", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case BINOP_SUBSCRIPT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("[", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered ("]", stream);
-      return;
-
-    case UNOP_POSTINCREMENT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("++", stream);
-      return;
-
-    case UNOP_POSTDECREMENT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("--", stream);
-      return;
-
-    case UNOP_CAST:
-      (*pos) += 2;
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      fputs_filtered ("(", stream);
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      fputs_filtered (") ", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case UNOP_CAST_TYPE:
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      fputs_filtered ("(", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered (") ", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case UNOP_DYNAMIC_CAST:
-    case UNOP_REINTERPRET_CAST:
-      fputs_filtered (opcode == UNOP_DYNAMIC_CAST ? "dynamic_cast"
-		      : "reinterpret_cast", stream);
-      fputs_filtered ("<", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered ("> (", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered (")", stream);
-      return;
-
-    case UNOP_MEMVAL:
-      (*pos) += 2;
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      if (exp->elts[pc + 1].type->code () == TYPE_CODE_FUNC
-	  && exp->elts[pc + 3].opcode == OP_LONG)
-	{
-	  struct value_print_options opts;
-
-	  /* We have a minimal symbol fn, probably.  It's encoded
-	     as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
-	     Swallow the OP_LONG (including both its opcodes); ignore
-	     its type; print the value in the type of the MEMVAL.  */
-	  (*pos) += 4;
-	  val = value_at_lazy (exp->elts[pc + 1].type,
-			       (CORE_ADDR) exp->elts[pc + 5].longconst);
-	  get_no_prettyformat_print_options (&opts);
-	  value_print (val, stream, &opts);
-	}
-      else
-	{
-	  fputs_filtered ("{", stream);
-	  type_print (exp->elts[pc + 1].type, "", stream, 0);
-	  fputs_filtered ("} ", stream);
-	  print_subexp (exp, pos, stream, PREC_PREFIX);
-	}
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case UNOP_MEMVAL_TYPE:
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      fputs_filtered ("{", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered ("} ", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case BINOP_ASSIGN_MODIFY:
-      opcode = exp->elts[pc + 1].opcode;
-      (*pos) += 2;
-      myprec = PREC_ASSIGN;
-      assoc = 1;
-      assign_modify = 1;
-      op_str = "???";
-      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-	if (op_print_tab[tem].opcode == opcode)
-	  {
-	    op_str = op_print_tab[tem].string;
-	    break;
-	  }
-      if (op_print_tab[tem].opcode != opcode)
-	/* Not found; don't try to keep going because we don't know how
-	   to interpret further elements.  */
-	error (_("Invalid expression"));
-      break;
-
-      /* C++ ops */
-
-    case OP_THIS:
-      ++(*pos);
-      if (exp->language_defn->name_of_this () != NULL)
-	fputs_filtered (exp->language_defn->name_of_this (), stream);
-      else
-	fprintf_styled (stream, metadata_style.style (),
-			_("<language %s has no 'this'>"),
-			exp->language_defn->name ());
-      return;
-
-      /* Modula-2 ops */
-
-    case MULTI_SUBSCRIPT:
-      (*pos) += 2;
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fprintf_unfiltered (stream, " [");
-      for (tem = 0; tem < nargs; tem++)
-	{
-	  if (tem != 0)
-	    fprintf_unfiltered (stream, ", ");
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	}
-      fprintf_unfiltered (stream, "]");
-      return;
-
-    case BINOP_VAL:
-      (*pos) += 2;
-      fprintf_unfiltered (stream, "VAL(");
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      fprintf_unfiltered (stream, ",");
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fprintf_unfiltered (stream, ")");
-      return;
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
-	LONGEST count = exp->elts[pc + 2].longconst;
-
-	/* The FLAGS.  */
-	(*pos)++;
-	/* The COUNT.  */
-	(*pos)++;
-	fputs_unfiltered ("TypeInstance(", stream);
-	while (count-- > 0)
-	  {
-	    type_print (exp->elts[(*pos)++].type, "", stream, 0);
-	    if (count > 0)
-	      fputs_unfiltered (",", stream);
-	  }
-	fputs_unfiltered (",", stream);
-	/* Ending COUNT and ending TYPE_INSTANCE.  */
-	(*pos) += 2;
-	print_subexp (exp, pos, stream, PREC_PREFIX);
-
-	if (flags & TYPE_INSTANCE_FLAG_CONST)
-	  fputs_unfiltered (",const", stream);
-	if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
-	  fputs_unfiltered (",volatile", stream);
-
-	fputs_unfiltered (")", stream);
-	return;
-      }
-
-    case OP_RANGE:
-      {
-	enum range_flag range_flag;
-
-	range_flag = (enum range_flag)
-	  longest_to_int (exp->elts[pc + 1].longconst);
-	*pos += 2;
-
-	if (range_flag & RANGE_HIGH_BOUND_EXCLUSIVE)
-	  fputs_filtered ("EXCLUSIVE_", stream);
-	fputs_filtered ("RANGE(", stream);
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	fputs_filtered ("..", stream);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	fputs_filtered (")", stream);
-	return;
-      }
-
-      /* Default ops */
-
-    default:
-      op_str = "???";
-      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-	if (op_print_tab[tem].opcode == opcode)
-	  {
-	    op_str = op_print_tab[tem].string;
-	    myprec = op_print_tab[tem].precedence;
-	    assoc = op_print_tab[tem].right_assoc;
-	    break;
-	  }
-      if (op_print_tab[tem].opcode != opcode)
-	/* Not found; don't try to keep going because we don't know how
-	   to interpret further elements.  For example, this happens
-	   if opcode is OP_TYPE.  */
-	error (_("Invalid expression"));
-    }
-
-  /* Note that PREC_BUILTIN will always emit parentheses.  */
-  if ((int) myprec < (int) prec)
-    fputs_filtered ("(", stream);
-  if ((int) opcode > (int) BINOP_END)
-    {
-      if (assoc)
-	{
-	  /* Unary postfix operator.  */
-	  print_subexp (exp, pos, stream, PREC_SUFFIX);
-	  fputs_filtered (op_str, stream);
-	}
-      else
-	{
-	  /* Unary prefix operator.  */
-	  fputs_filtered (op_str, stream);
-	  if (myprec == PREC_BUILTIN_FUNCTION)
-	    fputs_filtered ("(", stream);
-	  print_subexp (exp, pos, stream, PREC_PREFIX);
-	  if (myprec == PREC_BUILTIN_FUNCTION)
-	    fputs_filtered (")", stream);
-	}
-    }
-  else
-    {
-      /* Binary operator.  */
-      /* Print left operand.
-	 If operator is right-associative,
-	 increment precedence for this operand.  */
-      print_subexp (exp, pos, stream,
-		    (enum precedence) ((int) myprec + assoc));
-      /* Print the operator itself.  */
-      if (assign_modify)
-	fprintf_filtered (stream, " %s= ", op_str);
-      else if (op_str[0] == ',')
-	fprintf_filtered (stream, "%s ", op_str);
-      else
-	fprintf_filtered (stream, " %s ", op_str);
-      /* Print right operand.
-	 If operator is left-associative,
-	 increment precedence for this operand.  */
-      print_subexp (exp, pos, stream,
-		    (enum precedence) ((int) myprec + !assoc));
-    }
-
-  if ((int) myprec < (int) prec)
-    fputs_filtered (")", stream);
-}
-
-/* Return the operator corresponding to opcode OP as
-   a string.   NULL indicates that the opcode was not found in the
-   current language table.  */
-const char *
-op_string (enum exp_opcode op)
-{
-  int tem;
-  const struct op_print *op_print_tab;
-
-  op_print_tab = current_language->opcode_print_table ();
-  for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-    if (op_print_tab[tem].opcode == op)
-      return op_print_tab[tem].string;
-  return NULL;
-}
-
-/* Support for dumping the raw data from expressions in a human readable
-   form.  */
-
-static int dump_subexp_body (struct expression *exp, struct ui_file *, int);
-
 /* Default name for the standard operator OPCODE (i.e., one defined in
    the definition of enum exp_opcode).  */
 
@@ -714,463 +59,10 @@  op_name (enum exp_opcode opcode)
     }
 }
 
-/* Print a raw dump of expression EXP to STREAM.
-   NOTE, if non-NULL, is printed as extra explanatory text.  */
-
-void
-dump_raw_expression (struct expression *exp, struct ui_file *stream,
-		     const char *note)
-{
-  int elt;
-  char *eltscan;
-  int eltsize;
-
-  if (exp->op != nullptr)
-    return;
-
-  fprintf_filtered (stream, "Dump of expression @ ");
-  gdb_print_host_address (exp, stream);
-  if (note)
-    fprintf_filtered (stream, ", %s:", note);
-  fprintf_filtered (stream, "\n\tLanguage %s, %d elements, %ld bytes each.\n",
-		    exp->language_defn->name (), exp->nelts,
-		    (long) sizeof (union exp_element));
-  fprintf_filtered (stream, "\t%5s  %20s  %16s  %s\n", "Index", "Opcode",
-		    "Hex Value", "String Value");
-  for (elt = 0; elt < exp->nelts; elt++)
-    {
-      fprintf_filtered (stream, "\t%5d  ", elt);
-
-      const char *opcode_name = op_name (exp->elts[elt].opcode);
-      fprintf_filtered (stream, "%20s  ", opcode_name);
-
-      print_longest (stream, 'd', 0, exp->elts[elt].longconst);
-      fprintf_filtered (stream, "  ");
-
-      for (eltscan = (char *) &exp->elts[elt],
-	   eltsize = sizeof (union exp_element);
-	   eltsize-- > 0;
-	   eltscan++)
-	{
-	  fprintf_filtered (stream, "%c",
-			    isprint (*eltscan) ? (*eltscan & 0xFF) : '.');
-	}
-      fprintf_filtered (stream, "\n");
-    }
-}
-
-/* Dump the subexpression of prefix expression EXP whose operator is at
-   position ELT onto STREAM.  Returns the position of the next 
-   subexpression in EXP.  */
-
-int
-dump_subexp (struct expression *exp, struct ui_file *stream, int elt)
-{
-  static int indent = 0;
-  int i;
-
-  fprintf_filtered (stream, "\n");
-  fprintf_filtered (stream, "\t%5d  ", elt);
-
-  for (i = 1; i <= indent; i++)
-    fprintf_filtered (stream, " ");
-  indent += 2;
-
-  fprintf_filtered (stream, "%-20s  ", op_name (exp->elts[elt].opcode));
-
-  elt = dump_subexp_body (exp, stream, elt);
-
-  indent -= 2;
-
-  return elt;
-}
-
-/* Dump the operands of prefix expression EXP whose opcode is at
-   position ELT onto STREAM.  Returns the position of the next 
-   subexpression in EXP.  */
-
-static int
-dump_subexp_body (struct expression *exp, struct ui_file *stream, int elt)
-{
-  return exp->language_defn->expression_ops ()->dump_subexp_body (exp, stream,
-								  elt);
-}
-
-/* See parser-defs.h.  */
-
-int
-dump_subexp_body_funcall (struct expression *exp,
-			  struct ui_file *stream, int elt)
-{
-  int nargs = longest_to_int (exp->elts[elt].longconst);
-  fprintf_filtered (stream, "Number of args: %d", nargs);
-  elt += 2;
-
-  for (int i = 1; i <= nargs + 1; i++)
-    elt = dump_subexp (exp, stream, elt);
-
-  return elt;
-}
-
-/* Default value for subexp_body in exp_descriptor vector.  */
-
-int
-dump_subexp_body_standard (struct expression *exp, 
-			   struct ui_file *stream, int elt)
-{
-  int opcode = exp->elts[elt++].opcode;
-
-  switch (opcode)
-    {
-    case TERNOP_COND:
-    case TERNOP_SLICE:
-      elt = dump_subexp (exp, stream, elt);
-      /* FALL THROUGH */
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_LOGICAL_AND:
-    case BINOP_LOGICAL_OR:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-    case BINOP_REPEAT:
-    case BINOP_ASSIGN:
-    case BINOP_COMMA:
-    case BINOP_SUBSCRIPT:
-    case BINOP_EXP:
-    case BINOP_MIN:
-    case BINOP_MAX:
-    case BINOP_INTDIV:
-    case BINOP_ASSIGN_MODIFY:
-    case BINOP_VAL:
-    case BINOP_CONCAT:
-    case BINOP_END:
-    case STRUCTOP_MEMBER:
-    case STRUCTOP_MPTR:
-      elt = dump_subexp (exp, stream, elt);
-      /* FALL THROUGH */
-    case UNOP_NEG:
-    case UNOP_LOGICAL_NOT:
-    case UNOP_COMPLEMENT:
-    case UNOP_IND:
-    case UNOP_ADDR:
-    case UNOP_PREINCREMENT:
-    case UNOP_POSTINCREMENT:
-    case UNOP_PREDECREMENT:
-    case UNOP_POSTDECREMENT:
-    case UNOP_SIZEOF:
-    case UNOP_ALIGNOF:
-    case UNOP_PLUS:
-    case UNOP_CAP:
-    case UNOP_CHR:
-    case UNOP_ORD:
-    case UNOP_ABS:
-    case UNOP_FLOAT:
-    case UNOP_HIGH:
-    case UNOP_MAX:
-    case UNOP_MIN:
-    case UNOP_ODD:
-    case UNOP_TRUNC:
-      elt = dump_subexp (exp, stream, elt);
-      break;
-    case OP_LONG:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, "), value %ld (0x%lx)",
-			(long) exp->elts[elt + 1].longconst,
-			(long) exp->elts[elt + 1].longconst);
-      elt += 3;
-      break;
-    case OP_FLOAT:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, "), value ");
-      print_floating (exp->elts[elt + 1].floatconst,
-		      exp->elts[elt].type, stream);
-      elt += 3;
-      break;
-    case OP_VAR_VALUE:
-      fprintf_filtered (stream, "Block @");
-      gdb_print_host_address (exp->elts[elt].block, stream);
-      fprintf_filtered (stream, ", symbol @");
-      gdb_print_host_address (exp->elts[elt + 1].symbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt + 1].symbol->print_name ());
-      elt += 3;
-      break;
-    case OP_VAR_MSYM_VALUE:
-      fprintf_filtered (stream, "Objfile @");
-      gdb_print_host_address (exp->elts[elt].objfile, stream);
-      fprintf_filtered (stream, ", msymbol @");
-      gdb_print_host_address (exp->elts[elt + 1].msymbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt + 1].msymbol->print_name ());
-      elt += 3;
-      break;
-    case OP_VAR_ENTRY_VALUE:
-      fprintf_filtered (stream, "Entry value of symbol @");
-      gdb_print_host_address (exp->elts[elt].symbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt].symbol->print_name ());
-      elt += 2;
-      break;
-    case OP_LAST:
-      fprintf_filtered (stream, "History element %ld",
-			(long) exp->elts[elt].longconst);
-      elt += 2;
-      break;
-    case OP_REGISTER:
-      fprintf_filtered (stream, "Register $%s", &exp->elts[elt + 1].string);
-      elt += 3 + BYTES_TO_EXP_ELEM (exp->elts[elt].longconst + 1);
-      break;
-    case OP_INTERNALVAR:
-      fprintf_filtered (stream, "Internal var @");
-      gdb_print_host_address (exp->elts[elt].internalvar, stream);
-      fprintf_filtered (stream, " (%s)",
-			internalvar_name (exp->elts[elt].internalvar));
-      elt += 2;
-      break;
-    case OP_FUNCALL:
-      elt = dump_subexp_body_funcall (exp, stream, elt);
-      break;
-    case OP_ARRAY:
-      {
-	int lower, upper;
-	int i;
-
-	lower = longest_to_int (exp->elts[elt].longconst);
-	upper = longest_to_int (exp->elts[elt + 1].longconst);
-
-	fprintf_filtered (stream, "Bounds [%d:%d]", lower, upper);
-	elt += 3;
-
-	for (i = 1; i <= upper - lower + 1; i++)
-	  elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-    case UNOP_DYNAMIC_CAST:
-    case UNOP_REINTERPRET_CAST:
-    case UNOP_CAST_TYPE:
-    case UNOP_MEMVAL_TYPE:
-      fprintf_filtered (stream, " (");
-      elt = dump_subexp (exp, stream, elt);
-      fprintf_filtered (stream, ")");
-      elt = dump_subexp (exp, stream, elt);
-      break;
-    case UNOP_MEMVAL:
-    case UNOP_CAST:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, ")");
-      elt = dump_subexp (exp, stream, elt + 2);
-      break;
-    case OP_TYPE:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, ")");
-      elt += 2;
-      break;
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      fprintf_filtered (stream, "Typeof (");
-      elt = dump_subexp (exp, stream, elt);
-      fprintf_filtered (stream, ")");
-      break;
-    case OP_TYPEID:
-      fprintf_filtered (stream, "typeid (");
-      elt = dump_subexp (exp, stream, elt);
-      fprintf_filtered (stream, ")");
-      break;
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      {
-	char *elem_name;
-	int len;
-
-	len = longest_to_int (exp->elts[elt].longconst);
-	elem_name = &exp->elts[elt + 1].string;
-
-	fprintf_filtered (stream, "Element name: `%.*s'", len, elem_name);
-	elt = dump_subexp (exp, stream, elt + 3 + BYTES_TO_EXP_ELEM (len + 1));
-      }
-      break;
-    case OP_SCOPE:
-      {
-	char *elem_name;
-	int len;
-
-	fprintf_filtered (stream, "Type @");
-	gdb_print_host_address (exp->elts[elt].type, stream);
-	fprintf_filtered (stream, " (");
-	type_print (exp->elts[elt].type, NULL, stream, 0);
-	fprintf_filtered (stream, ") ");
-
-	len = longest_to_int (exp->elts[elt + 1].longconst);
-	elem_name = &exp->elts[elt + 2].string;
-
-	fprintf_filtered (stream, "Field name: `%.*s'", len, elem_name);
-	elt += 4 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case OP_FUNC_STATIC_VAR:
-      {
-	int len = longest_to_int (exp->elts[elt].longconst);
-	const char *var_name = &exp->elts[elt + 1].string;
-	fprintf_filtered (stream, "Field name: `%.*s'", len, var_name);
-	elt += 3 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[elt++].longconst);
-	LONGEST len = exp->elts[elt++].longconst;
-	fprintf_filtered (stream, "%s TypeInstance: ", plongest (len));
-	while (len-- > 0)
-	  {
-	    fprintf_filtered (stream, "Type @");
-	    gdb_print_host_address (exp->elts[elt].type, stream);
-	    fprintf_filtered (stream, " (");
-	    type_print (exp->elts[elt].type, NULL, stream, 0);
-	    fprintf_filtered (stream, ")");
-	    elt++;
-	    if (len > 0)
-	      fputs_filtered (", ", stream);
-	  }
-
-	fprintf_filtered (stream, " Flags: %s (", hex_string (flags));
-	bool space = false;
-	auto print_one = [&] (const char *mod)
-	  {
-	    if (space)
-	      fputs_filtered (" ", stream);
-	    space = true;
-	    fprintf_filtered (stream, "%s", mod);
-	  };
-	if (flags & TYPE_INSTANCE_FLAG_CONST)
-	  print_one ("const");
-	if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
-	  print_one ("volatile");
-	fprintf_filtered (stream, ")");
-
-	/* Ending LEN and ending TYPE_INSTANCE.  */
-	elt += 2;
-	elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-    case OP_STRING:
-      {
-	LONGEST len = exp->elts[elt].longconst;
-	LONGEST type = exp->elts[elt + 1].longconst;
-
-	fprintf_filtered (stream, "Language-specific string type: %s",
-			  plongest (type));
-
-	/* Skip length.  */
-	elt += 1;
-
-	/* Skip string content. */
-	elt += BYTES_TO_EXP_ELEM (len);
-
-	/* Skip length and ending OP_STRING. */
-	elt += 2;
-      }
-      break;
-    case OP_RANGE:
-      {
-	enum range_flag range_flag;
-
-	range_flag = (enum range_flag)
-	  longest_to_int (exp->elts[elt].longconst);
-	elt += 2;
-
-	if (range_flag & RANGE_HIGH_BOUND_EXCLUSIVE)
-	  fputs_filtered ("Exclusive", stream);
-	fputs_filtered ("Range '", stream);
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  fputs_filtered ("EXP", stream);
-	fputs_filtered ("..", stream);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  fputs_filtered ("EXP", stream);
-	if (range_flag & RANGE_HAS_STRIDE)
-	  fputs_filtered (":EXP", stream);
-	fputs_filtered ("'", stream);
-
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  elt = dump_subexp (exp, stream, elt);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  elt = dump_subexp (exp, stream, elt);
-	if (range_flag & RANGE_HAS_STRIDE)
-	  elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-
-    default:
-    case OP_NULL:
-    case MULTI_SUBSCRIPT:
-    case OP_COMPLEX:
-    case OP_BOOL:
-    case OP_M2_STRING:
-    case OP_THIS:
-    case OP_NAME:
-      fprintf_filtered (stream, "Unknown format");
-    }
-
-  return elt;
-}
-
 void
 dump_prefix_expression (struct expression *exp, struct ui_file *stream)
 {
-  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,
-		    (long) sizeof (union exp_element));
-  fputs_filtered ("\n", stream);
-
-  for (elt = 0; elt < exp->nelts;)
-    elt = dump_subexp (exp, stream, elt);
-  fputs_filtered ("\n", stream);
+  exp->op->dump (stream, 0);
 }
 
 namespace expr
diff --git a/gdb/expression.h b/gdb/expression.h
index f9b7855346e..bca4c6d9fe2 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -40,21 +40,6 @@  enum innermost_block_tracker_type
 DEF_ENUM_FLAGS_TYPE (enum innermost_block_tracker_type,
 		     innermost_block_tracker_types);
 
-/* Definitions for saved C expressions.  */
-
-/* An expression is represented as a vector of union exp_element's.
-   Each exp_element is an opcode, except that some opcodes cause
-   the following exp_element to be treated as a long or double constant
-   or as a variable.  The opcodes are obeyed, using a stack for temporaries.
-   The value is left on the temporary stack at the end.  */
-
-/* When it is necessary to include a string,
-   it can occupy as many exp_elements as it needs.
-   We find the length of the string using strlen,
-   divide to find out how many exp_elements are used up,
-   and skip that many.  Strings, like numbers, are indicated
-   by the preceding opcode.  */
-
 enum exp_opcode : uint8_t
   {
 #define OP(name) name ,
@@ -197,37 +182,17 @@  make_operation (Arg... args)
 
 }
 
-union exp_element
-  {
-    enum exp_opcode opcode;
-    struct symbol *symbol;
-    struct minimal_symbol *msymbol;
-    LONGEST longconst;
-    gdb_byte floatconst[16];
-    /* Really sizeof (union exp_element) characters (or less for the last
-       element of a string).  */
-    char string;
-    struct type *type;
-    struct internalvar *internalvar;
-    const struct block *block;
-    struct objfile *objfile;
-  };
-
 struct expression
 {
-  expression (const struct language_defn *, struct gdbarch *, size_t);
+  expression (const struct language_defn *, struct gdbarch *);
   ~expression ();
   DISABLE_COPY_AND_ASSIGN (expression);
 
-  void resize (size_t);
-
   /* Return the opcode for the outermost sub-expression of this
      expression.  */
   enum exp_opcode first_opcode () const
   {
-    if (op != nullptr)
-      return op->opcode ();
-    return elts[0].opcode;
+    return op->opcode ();
   }
 
   /* Language it was entered in.  */
@@ -235,20 +200,10 @@  struct expression
   /* Architecture it was parsed in.  */
   struct gdbarch *gdbarch;
   expr::operation_up op;
-  int nelts = 0;
-  union exp_element *elts;
 };
 
 typedef std::unique_ptr<expression> expression_up;
 
-/* Macros for converting between number of expression elements and bytes
-   to store that many expression elements.  */
-
-#define EXP_ELEM_TO_BYTES(elements) \
-    ((elements) * sizeof (union exp_element))
-#define BYTES_TO_EXP_ELEM(bytes) \
-    (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element))
-
 /* From parse.c */
 
 class innermost_block_tracker;
@@ -268,9 +223,6 @@  extern expression_up parse_exp_1 (const char **, CORE_ADDR pc,
 
 /* From eval.c */
 
-extern struct value *evaluate_subexp_standard
-  (struct type *, struct expression *, int *, enum noside);
-
 /* Evaluate a function call.  The function to be called is in CALLEE and
    the arguments passed to the function are in ARGVEC.
    FUNCTION_NAME is the name of the function, if known.
@@ -286,14 +238,8 @@  extern struct value *evaluate_subexp_do_call (expression *exp,
 
 /* From expprint.c */
 
-extern void print_expression (struct expression *, struct ui_file *);
-
 extern const char *op_name (enum exp_opcode opcode);
 
-extern const char *op_string (enum exp_opcode);
-
-extern void dump_raw_expression (struct expression *,
-				 struct ui_file *, const char *);
 extern void dump_prefix_expression (struct expression *, struct ui_file *);
 
 /* In an OP_RANGE expression, either bound could be empty, indicating
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index e5b66c7fa3b..f86f961e7bb 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -101,34 +101,6 @@  f_language::get_encoding (struct type *type)
 
 
 
-/* Table of operators and their precedences for printing expressions.  */
-
-const struct op_print f_language::op_print_tab[] =
-{
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"DIV", BINOP_INTDIV, PREC_MUL, 0},
-  {"MOD", BINOP_REM, PREC_MUL, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {".OR.", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {".AND.", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {".NOT.", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {".EQ.", BINOP_EQUAL, PREC_EQUAL, 0},
-  {".NE.", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {".LE.", BINOP_LEQ, PREC_ORDER, 0},
-  {".GE.", BINOP_GEQ, PREC_ORDER, 0},
-  {".GT.", BINOP_GTR, PREC_ORDER, 0},
-  {".LT.", BINOP_LESS, PREC_ORDER, 0},
-  {"**", UNOP_IND, PREC_PREFIX, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {NULL, OP_NULL, PREC_REPEAT, 0}
-};
-
-
 /* Return the number of dimensions for a Fortran array or string.  */
 
 int
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 03b59102139..1ccdd3978ea 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -218,11 +218,6 @@  class f_language : public language_defn
   enum array_ordering array_ordering () const override
   { return array_column_major; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
 protected:
 
   /* See language.h.  */
@@ -231,10 +226,6 @@  class f_language : public language_defn
 	(const lookup_name_info &lookup_name) const override;
 
 private:
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
   /* Return the encoding that should be used for the character type
      TYPE.  */
 
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index eafd868baf4..2a4fb1a35b0 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -386,14 +386,6 @@  go_language::demangle_symbol (const char *mangled_name, int options) const
   return result;
 }
 
-/* See language.h.  */
-
-const struct exp_descriptor *
-go_language::expression_ops () const
-{
-  return &exp_descriptor_c;
-}
-
 /* Given a Go symbol, return its package or NULL if unknown.
    Space for the result is malloc'd, caller must free.  */
 
@@ -452,44 +444,6 @@  go_block_package_name (const struct block *block)
   return NULL;
 }
 
-/* See go-lang.h.
-
-   TODO(dje): &^ ?  */
-
-const struct op_print go_language::op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"^", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"unsafe.Sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"++", UNOP_POSTINCREMENT, PREC_SUFFIX, 0},
-  {"--", UNOP_POSTDECREMENT, PREC_SUFFIX, 0},
-  {NULL, OP_NULL, PREC_SUFFIX, 0}
-};
-
 /* See language.h.  */
 
 void
diff --git a/gdb/go-lang.h b/gdb/go-lang.h
index 71f91803d6f..3495d98d15d 100644
--- a/gdb/go-lang.h
+++ b/gdb/go-lang.h
@@ -134,22 +134,6 @@  class go_language : public language_defn
 
   bool store_sym_names_in_linkage_form_p () const override
   { return true; }
-
-  /* See language.h.  */
-
-  const struct exp_descriptor *expression_ops () const override;
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
-private:
-
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
 };
 
 #endif /* !defined (GO_LANG_H) */
diff --git a/gdb/language.c b/gdb/language.c
index 1770ba1f8e1..8f14e9f9361 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -765,14 +765,6 @@  language_defn::varobj_ops () const
   return &c_varobj_ops;
 }
 
-/* See language.h.  */
-
-const struct exp_descriptor *
-language_defn::expression_ops () const
-{
-  return &exp_descriptor_standard;
-}
-
 /* Parent class for both the "auto" and "unknown" languages.  These two
    pseudo-languages are very similar so merging their implementations like
    this makes sense.  */
@@ -892,18 +884,6 @@  class auto_or_unknown_language : public language_defn
 
   const char *name_of_this () const override
   { return "this"; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  {
-    static const struct op_print unk_op_print_tab[] =
-      {
-	{NULL, OP_NULL, PREC_NULL, 0}
-      };
-
-    return unk_op_print_tab;
-  }
 };
 
 /* Class representing the fake "auto" language.  */
diff --git a/gdb/language.h b/gdb/language.h
index 44dbf3b8e6f..b5518629ff8 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -519,17 +519,6 @@  struct language_defn
 
   virtual int parser (struct parser_state *ps) const;
 
-  /* Given an expression *EXPP created by prefixifying the result of
-     la_parser, perform any remaining processing necessary to complete its
-     translation.  *EXPP may change; la_post_parser is responsible for
-     releasing its previous contents, if necessary.  */
-
-  virtual void post_parser (expression_up *expp, struct parser_state *ps)
-    const
-  {
-    /* By default the post-parser does nothing.  */
-  }
-
   /* Print the character CH (of type CHTYPE) on STREAM as part of the
      contents of a literal string whose delimiter is QUOTER.  */
 
@@ -646,15 +635,6 @@  struct language_defn
 
   virtual const struct lang_varobj_ops *varobj_ops () const;
 
-  /* Definitions related to expression printing, prefixifying, and
-     dumping.  */
-
-  virtual const struct exp_descriptor *expression_ops () const;
-
-  /* Table for printing expressions.  */
-
-  virtual const struct op_print *opcode_print_table () const = 0;
-
 protected:
 
   /* This is the overridable part of the GET_SYMBOL_NAME_MATCHER method.
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 281fa8b9218..a165cf6b603 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -113,43 +113,6 @@  eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
 
 
 
-/* Table of operators and their precedences for printing expressions.  */
-
-const struct op_print m2_language::op_print_tab[] =
-{
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"DIV", BINOP_INTDIV, PREC_MUL, 0},
-  {"MOD", BINOP_REM, PREC_MUL, 0},
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {"^", UNOP_IND, PREC_PREFIX, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"CAP", UNOP_CAP, PREC_BUILTIN_FUNCTION, 0},
-  {"CHR", UNOP_CHR, PREC_BUILTIN_FUNCTION, 0},
-  {"ORD", UNOP_ORD, PREC_BUILTIN_FUNCTION, 0},
-  {"FLOAT", UNOP_FLOAT, PREC_BUILTIN_FUNCTION, 0},
-  {"HIGH", UNOP_HIGH, PREC_BUILTIN_FUNCTION, 0},
-  {"MAX", UNOP_MAX, PREC_BUILTIN_FUNCTION, 0},
-  {"MIN", UNOP_MIN, PREC_BUILTIN_FUNCTION, 0},
-  {"ODD", UNOP_ODD, PREC_BUILTIN_FUNCTION, 0},
-  {"TRUNC", UNOP_TRUNC, PREC_BUILTIN_FUNCTION, 0},
-  {NULL, OP_NULL, PREC_BUILTIN_FUNCTION, 0}
-};
-
-
 /* Single instance of the M2 language.  */
 
 static m2_language m2_language_defn;
diff --git a/gdb/m2-lang.h b/gdb/m2-lang.h
index 20941429ff0..89b9d185b96 100644
--- a/gdb/m2-lang.h
+++ b/gdb/m2-lang.h
@@ -147,15 +147,6 @@  class m2_language : public language_defn
 
   bool range_checking_on_by_default () const override
   { return true; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
-private:
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-  static const struct op_print op_print_tab[];
 };
 
 #endif /* M2_LANG_H */
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index aa0360b6818..4d594a973fb 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -282,44 +282,6 @@  objc_demangle (const char *mangled, int options)
     return NULL;	/* Not an objc mangled name.  */
 }
 
-
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-static const struct op_print objc_op_print_tab[] =
-  {
-    {",",  BINOP_COMMA, PREC_COMMA, 0},
-    {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
-    {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-    {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-    {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-    {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-    {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-    {"<=", BINOP_LEQ, PREC_ORDER, 0},
-    {">=", BINOP_GEQ, PREC_ORDER, 0},
-    {">",  BINOP_GTR, PREC_ORDER, 0},
-    {"<",  BINOP_LESS, PREC_ORDER, 0},
-    {">>", BINOP_RSH, PREC_SHIFT, 0},
-    {"<<", BINOP_LSH, PREC_SHIFT, 0},
-    {"+",  BINOP_ADD, PREC_ADD, 0},
-    {"-",  BINOP_SUB, PREC_ADD, 0},
-    {"*",  BINOP_MUL, PREC_MUL, 0},
-    {"/",  BINOP_DIV, PREC_MUL, 0},
-    {"%",  BINOP_REM, PREC_MUL, 0},
-    {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
-    {"-",  UNOP_NEG, PREC_PREFIX, 0},
-    {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-    {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
-    {"*",  UNOP_IND, PREC_PREFIX, 0},
-    {"&",  UNOP_ADDR, PREC_PREFIX, 0},
-    {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-    {NULL, OP_NULL, PREC_NULL, 0}
-};
-
 /* Class representing the Objective-C language.  */
 
 class objc_language : public language_defn
@@ -421,11 +383,6 @@  class objc_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return objc_op_print_tab; }
 };
 
 /* Single instance of the class representing the Objective-C language.  */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index b283be173c4..c168cd49344 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -973,11 +973,6 @@  class opencl_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* Single instance of the OpenCL language class.  */
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 9654da11a8c..1d8e9408e54 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -185,40 +185,6 @@  pascal_language::printchar (int c, struct type *type,
 
 
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-const struct op_print pascal_language::op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"and", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {"shr", BINOP_RSH, PREC_SHIFT, 0},
-  {"shl", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"div", BINOP_INTDIV, PREC_MUL, 0},
-  {"mod", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"not", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"^", UNOP_IND, PREC_SUFFIX, 1},
-  {"@", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
-
-
 /* See language.h.  */
 
 void pascal_language::language_arch_info
diff --git a/gdb/p-lang.h b/gdb/p-lang.h
index b93451dcaa3..95dca01f22e 100644
--- a/gdb/p-lang.h
+++ b/gdb/p-lang.h
@@ -154,17 +154,8 @@  class pascal_language : public language_defn
   bool range_checking_on_by_default () const override
   { return true; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
 private:
 
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
   /* Print the character C on STREAM as part of the contents of a literal
      string.  IN_QUOTES is reset to 0 if a char is written with #4 notation.  */
 
diff --git a/gdb/parse.c b/gdb/parse.c
index 28ac43f0d16..637a9f3d246 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -52,18 +52,6 @@ 
 #include "gdbsupport/gdb_optional.h"
 #include "c-exp.h"
 
-/* Standard set of definitions for printing, dumping, prefixifying,
- * and evaluating expressions.  */
-
-const struct exp_descriptor exp_descriptor_standard = 
-  {
-    print_subexp_standard,
-    operator_length_standard,
-    operator_check_standard,
-    dump_subexp_body_standard,
-    evaluate_subexp_standard
-  };
-
 static unsigned int expressiondebug = 0;
 static void
 show_expressiondebug (struct ui_file *file, int from_tty,
@@ -84,18 +72,11 @@  show_parserdebug (struct ui_file *file, int from_tty,
 }
 
 
-static int prefixify_subexp (struct expression *, struct expression *, int,
-			     int, int);
-
 static expression_up parse_exp_in_context (const char **, CORE_ADDR,
 					   const struct block *, int,
-					   bool, int *,
-					   innermost_block_tracker *,
+					   bool, innermost_block_tracker *,
 					   expr_completion_state *);
 
-static void increase_expout_size (struct expr_builder *ps, size_t lenelt);
-
-
 /* Documented at it's declaration.  */
 
 void
@@ -114,297 +95,24 @@  innermost_block_tracker::update (const struct block *b,
 
 expr_builder::expr_builder (const struct language_defn *lang,
 			    struct gdbarch *gdbarch)
-  : expout_size (10),
-    expout (new expression (lang, gdbarch, expout_size)),
-    expout_ptr (0)
+  : expout (new expression (lang, gdbarch))
 {
 }
 
 expression_up
 expr_builder::release ()
 {
-  /* Record the actual number of expression elements, and then
-     reallocate the expression memory so that we free up any
-     excess elements.  */
-
-  expout->nelts = expout_ptr;
-  expout->resize (expout_ptr);
-
   return std::move (expout);
 }
 
-expression::expression (const struct language_defn *lang, struct gdbarch *arch,
-			size_t n)
+expression::expression (const struct language_defn *lang, struct gdbarch *arch)
   : language_defn (lang),
-    gdbarch (arch),
-    elts (nullptr)
+    gdbarch (arch)
 {
-  resize (n);
 }
 
 expression::~expression ()
 {
-  xfree (elts);
-}
-
-void
-expression::resize (size_t n)
-{
-  elts = XRESIZEVAR (union exp_element, elts, EXP_ELEM_TO_BYTES (n));
-}
-
-/* This page contains the functions for adding data to the struct expression
-   being constructed.  */
-
-/* Add one element to the end of the expression.  */
-
-/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
-   a register through here.  */
-
-static void
-write_exp_elt (struct expr_builder *ps, const union exp_element *expelt)
-{
-  if (ps->expout_ptr >= ps->expout_size)
-    {
-      ps->expout_size *= 2;
-      ps->expout->resize (ps->expout_size);
-    }
-  ps->expout->elts[ps->expout_ptr++] = *expelt;
-}
-
-void
-write_exp_elt_opcode (struct expr_builder *ps, enum exp_opcode expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.opcode = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_sym (struct expr_builder *ps, struct symbol *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.symbol = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-static void
-write_exp_elt_msym (struct expr_builder *ps, minimal_symbol *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.msymbol = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_block (struct expr_builder *ps, const struct block *b)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.block = b;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_objfile (struct expr_builder *ps, struct objfile *objfile)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.objfile = objfile;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_longcst (struct expr_builder *ps, LONGEST expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.longconst = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_floatcst (struct expr_builder *ps, const gdb_byte expelt[16])
-{
-  union exp_element tmp;
-  int index;
-
-  for (index = 0; index < 16; index++)
-    tmp.floatconst[index] = expelt[index];
-
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_type (struct expr_builder *ps, struct type *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.type = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_intern (struct expr_builder *ps, struct internalvar *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.internalvar = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-/* Add a string constant to the end of the expression.
-
-   String constants are stored by first writing an expression element
-   that contains the length of the string, then stuffing the string
-   constant itself into however many expression elements are needed
-   to hold it, and then writing another expression element that contains
-   the length of the string.  I.e. an expression element at each end of
-   the string records the string length, so you can skip over the 
-   expression elements containing the actual string bytes from either
-   end of the string.  Note that this also allows gdb to handle
-   strings with embedded null bytes, as is required for some languages.
-
-   Don't be fooled by the fact that the string is null byte terminated,
-   this is strictly for the convenience of debugging gdb itself.
-   Gdb does not depend up the string being null terminated, since the
-   actual length is recorded in expression elements at each end of the
-   string.  The null byte is taken into consideration when computing how
-   many expression elements are required to hold the string constant, of
-   course.  */
-
-
-void
-write_exp_string (struct expr_builder *ps, struct stoken str)
-{
-  int len = str.length;
-  size_t lenelt;
-  char *strdata;
-
-  /* Compute the number of expression elements required to hold the string
-     (including a null byte terminator), along with one expression element
-     at each end to record the actual string length (not including the
-     null byte terminator).  */
-
-  lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1);
-
-  increase_expout_size (ps, lenelt);
-
-  /* Write the leading length expression element (which advances the current
-     expression element index), then write the string constant followed by a
-     terminating null byte, and then write the trailing length expression
-     element.  */
-
-  write_exp_elt_longcst (ps, (LONGEST) len);
-  strdata = (char *) &ps->expout->elts[ps->expout_ptr];
-  memcpy (strdata, str.ptr, len);
-  *(strdata + len) = '\0';
-  ps->expout_ptr += lenelt - 2;
-  write_exp_elt_longcst (ps, (LONGEST) len);
-}
-
-/* Add a vector of string constants to the end of the expression.
-
-   This adds an OP_STRING operation, but encodes the contents
-   differently from write_exp_string.  The language is expected to
-   handle evaluation of this expression itself.
-   
-   After the usual OP_STRING header, TYPE is written into the
-   expression as a long constant.  The interpretation of this field is
-   up to the language evaluator.
-   
-   Next, each string in VEC is written.  The length is written as a
-   long constant, followed by the contents of the string.  */
-
-void
-write_exp_string_vector (struct expr_builder *ps, int type,
-			 struct stoken_vector *vec)
-{
-  int i, len;
-  size_t n_slots;
-
-  /* Compute the size.  We compute the size in number of slots to
-     avoid issues with string padding.  */
-  n_slots = 0;
-  for (i = 0; i < vec->len; ++i)
-    {
-      /* One slot for the length of this element, plus the number of
-	 slots needed for this string.  */
-      n_slots += 1 + BYTES_TO_EXP_ELEM (vec->tokens[i].length);
-    }
-
-  /* One more slot for the type of the string.  */
-  ++n_slots;
-
-  /* Now compute a phony string length.  */
-  len = EXP_ELEM_TO_BYTES (n_slots) - 1;
-
-  n_slots += 4;
-  increase_expout_size (ps, n_slots);
-
-  write_exp_elt_opcode (ps, OP_STRING);
-  write_exp_elt_longcst (ps, len);
-  write_exp_elt_longcst (ps, type);
-
-  for (i = 0; i < vec->len; ++i)
-    {
-      write_exp_elt_longcst (ps, vec->tokens[i].length);
-      memcpy (&ps->expout->elts[ps->expout_ptr], vec->tokens[i].ptr,
-	      vec->tokens[i].length);
-      ps->expout_ptr += BYTES_TO_EXP_ELEM (vec->tokens[i].length);
-    }
-
-  write_exp_elt_longcst (ps, len);
-  write_exp_elt_opcode (ps, OP_STRING);
-}
-
-/* Add a bitstring constant to the end of the expression.
-
-   Bitstring constants are stored by first writing an expression element
-   that contains the length of the bitstring (in bits), then stuffing the
-   bitstring constant itself into however many expression elements are
-   needed to hold it, and then writing another expression element that
-   contains the length of the bitstring.  I.e. an expression element at
-   each end of the bitstring records the bitstring length, so you can skip
-   over the expression elements containing the actual bitstring bytes from
-   either end of the bitstring.  */
-
-void
-write_exp_bitstring (struct expr_builder *ps, struct stoken str)
-{
-  int bits = str.length;	/* length in bits */
-  int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
-  size_t lenelt;
-  char *strdata;
-
-  /* Compute the number of expression elements required to hold the bitstring,
-     along with one expression element at each end to record the actual
-     bitstring length in bits.  */
-
-  lenelt = 2 + BYTES_TO_EXP_ELEM (len);
-
-  increase_expout_size (ps, lenelt);
-
-  /* Write the leading length expression element (which advances the current
-     expression element index), then write the bitstring constant, and then
-     write the trailing length expression element.  */
-
-  write_exp_elt_longcst (ps, (LONGEST) bits);
-  strdata = (char *) &ps->expout->elts[ps->expout_ptr];
-  memcpy (strdata, str.ptr, len);
-  ps->expout_ptr += lenelt - 2;
-  write_exp_elt_longcst (ps, (LONGEST) bits);
 }
 
 /* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
@@ -487,31 +195,6 @@  find_minsym_type_and_address (minimal_symbol *msymbol,
     }
 }
 
-/* Add the appropriate elements for a minimal symbol to the end of
-   the expression.  */
-
-void
-write_exp_msymbol (struct expr_builder *ps,
-		   struct bound_minimal_symbol bound_msym)
-{
-  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
-  write_exp_elt_objfile (ps, bound_msym.objfile);
-  write_exp_elt_msym (ps, bound_msym.minsym);
-  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
-}
-
-/* See parser-defs.h.  */
-
-void
-parser_state::mark_struct_expression ()
-{
-  gdb_assert (parse_completion
-	      && (m_completion_state.expout_tag_completion_type
-		  == TYPE_CODE_UNDEF)
-	      && m_completion_state.expout_last_op == nullptr);
-  m_completion_state.expout_last_struct = expout_ptr;
-}
-
 /* See parser-defs.h.  */
 
 void
@@ -519,8 +202,7 @@  parser_state::mark_struct_expression (expr::structop_base_operation *op)
 {
   gdb_assert (parse_completion
 	      && (m_completion_state.expout_tag_completion_type
-		  == TYPE_CODE_UNDEF)
-	      && m_completion_state.expout_last_struct == -1);
+		  == TYPE_CODE_UNDEF));
   m_completion_state.expout_last_op = op;
 }
 
@@ -536,7 +218,6 @@  parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
 	      && (m_completion_state.expout_tag_completion_type
 		  == TYPE_CODE_UNDEF)
 	      && m_completion_state.expout_completion_name == NULL
-	      && m_completion_state.expout_last_struct == -1
 	      && m_completion_state.expout_last_op == nullptr);
   gdb_assert (tag == TYPE_CODE_UNION
 	      || tag == TYPE_CODE_STRUCT
@@ -670,150 +351,6 @@  parser_state::push_dollar (struct stoken str)
 }
 
 
-/* Recognize tokens that start with '$'.  These include:
-
-   $regname     A native register name or a "standard
-   register name".
-
-   $variable    A convenience variable with a name chosen
-   by the user.
-
-   $digits              Value history with index <digits>, starting
-   from the first value which has index 1.
-
-   $$digits     Value history with index <digits> relative
-   to the last value.  I.e. $$0 is the last
-   value, $$1 is the one previous to that, $$2
-   is the one previous to $$1, etc.
-
-   $ | $0 | $$0 The last value in the value history.
-
-   $$           An abbreviation for the second to the last
-   value in the value history, I.e. $$1  */
-
-void
-write_dollar_variable (struct parser_state *ps, struct stoken str)
-{
-  struct block_symbol sym;
-  struct bound_minimal_symbol msym;
-  struct internalvar *isym = NULL;
-  std::string copy;
-
-  /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
-     and $$digits (equivalent to $<-digits> if you could type that).  */
-
-  int negate = 0;
-  int i = 1;
-  /* Double dollar means negate the number and add -1 as well.
-     Thus $$ alone means -1.  */
-  if (str.length >= 2 && str.ptr[1] == '$')
-    {
-      negate = 1;
-      i = 2;
-    }
-  if (i == str.length)
-    {
-      /* Just dollars (one or two).  */
-      i = -negate;
-      goto handle_last;
-    }
-  /* Is the rest of the token digits?  */
-  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;
-    }
-
-  /* Handle tokens that refer to machine registers:
-     $ followed by a register name.  */
-  i = user_reg_map_name_to_regnum (ps->gdbarch (),
-				   str.ptr + 1, str.length - 1);
-  if (i >= 0)
-    goto handle_register;
-
-  /* Any names starting with $ are probably debugger internal variables.  */
-
-  copy = copy_name (str);
-  isym = lookup_only_internalvar (copy.c_str () + 1);
-  if (isym)
-    {
-      write_exp_elt_opcode (ps, OP_INTERNALVAR);
-      write_exp_elt_intern (ps, isym);
-      write_exp_elt_opcode (ps, OP_INTERNALVAR);
-      return;
-    }
-
-  /* On some systems, such as HP-UX and hppa-linux, certain system routines 
-     have names beginning with $ or $$.  Check for those, first.  */
-
-  sym = lookup_symbol (copy.c_str (), NULL, VAR_DOMAIN, NULL);
-  if (sym.symbol)
-    {
-      write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      write_exp_elt_block (ps, sym.block);
-      write_exp_elt_sym (ps, sym.symbol);
-      write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      return;
-    }
-  msym = lookup_bound_minimal_symbol (copy.c_str ());
-  if (msym.minsym)
-    {
-      write_exp_msymbol (ps, msym);
-      return;
-    }
-
-  /* Any other names are assumed to be debugger internal variables.  */
-
-  write_exp_elt_opcode (ps, OP_INTERNALVAR);
-  write_exp_elt_intern (ps, create_internalvar (copy.c_str () + 1));
-  write_exp_elt_opcode (ps, OP_INTERNALVAR);
-  return;
-handle_last:
-  write_exp_elt_opcode (ps, OP_LAST);
-  write_exp_elt_longcst (ps, (LONGEST) i);
-  write_exp_elt_opcode (ps, OP_LAST);
-  return;
-handle_register:
-  write_exp_elt_opcode (ps, OP_REGISTER);
-  str.length--;
-  str.ptr++;
-  write_exp_string (ps, str);
-  write_exp_elt_opcode (ps, OP_REGISTER);
-  ps->block_tracker->update (ps->expression_context_block,
-			     INNERMOST_BLOCK_FOR_REGISTERS);
-  return;
-}
-
-/* See parser-defs.h.  */
-
-void
-write_exp_symbol_reference (struct parser_state *pstate, const char *name,
-			    struct symbol *sym)
-{
-  if (sym != nullptr)
-    {
-      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-      write_exp_elt_block (pstate, NULL);
-      write_exp_elt_sym (pstate, sym);
-      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-    }
-  else
-    {
-      struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name);
-      if (msymbol.minsym != NULL)
-	write_exp_msymbol (pstate, msymbol);
-      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);
-    }
-}
 
 const char *
 find_template_name_end (const char *p)
@@ -891,293 +428,6 @@  copy_name (struct stoken token)
 }
 
 
-/* See comments on parser-defs.h.  */
-
-int
-prefixify_expression (struct expression *expr, int last_struct)
-{
-  gdb_assert (expr->nelts > 0);
-  int len = EXP_ELEM_TO_BYTES (expr->nelts);
-  struct expression temp (expr->language_defn, expr->gdbarch, expr->nelts);
-  int inpos = expr->nelts, outpos = 0;
-
-  /* Copy the original expression into temp.  */
-  memcpy (temp.elts, expr->elts, len);
-
-  return prefixify_subexp (&temp, expr, inpos, outpos, last_struct);
-}
-
-/* Return the number of exp_elements in the postfix subexpression 
-   of EXPR whose operator is at index ENDPOS - 1 in EXPR.  */
-
-static 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;
-}
-
-/* Sets *OPLENP to the length of the operator whose (last) index is 
-   ENDPOS - 1 in EXPR, and sets *ARGSP to the number of arguments that
-   operator takes.  */
-
-void
-operator_length (const struct expression *expr, int endpos, int *oplenp,
-		 int *argsp)
-{
-  expr->language_defn->expression_ops ()->operator_length (expr, endpos,
-							   oplenp, argsp);
-}
-
-/* Default value for operator_length in exp_descriptor vectors.  */
-
-void
-operator_length_standard (const struct expression *expr, int endpos,
-			  int *oplenp, int *argsp)
-{
-  int oplen = 1;
-  int args = 0;
-  enum range_flag range_flag;
-  int i;
-
-  if (endpos < 1)
-    error (_("?error in operator_length_standard"));
-
-  i = (int) expr->elts[endpos - 1].opcode;
-
-  switch (i)
-    {
-      /* C++  */
-    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_FLOAT:
-    case OP_VAR_VALUE:
-    case OP_VAR_MSYM_VALUE:
-      oplen = 4;
-      break;
-
-    case OP_FUNC_STATIC_VAR:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      args = 1;
-      break;
-
-    case OP_TYPE:
-    case OP_BOOL:
-    case OP_LAST:
-    case OP_INTERNALVAR:
-    case OP_VAR_ENTRY_VALUE:
-      oplen = 3;
-      break;
-
-    case OP_COMPLEX:
-      oplen = 3;
-      args = 2;
-      break;
-
-    case OP_FUNCALL:
-      oplen = 3;
-      args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
-      break;
-
-    case TYPE_INSTANCE:
-      oplen = 5 + longest_to_int (expr->elts[endpos - 2].longconst);
-      args = 1;
-      break;
-
-    case OP_OBJC_MSGCALL:	/* Objective C message (method) call.  */
-      oplen = 4;
-      args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
-      break;
-
-    case UNOP_MAX:
-    case UNOP_MIN:
-      oplen = 3;
-      break;
-
-    case UNOP_CAST_TYPE:
-    case UNOP_DYNAMIC_CAST:
-    case UNOP_REINTERPRET_CAST:
-    case UNOP_MEMVAL_TYPE:
-      oplen = 1;
-      args = 2;
-      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:
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-    case OP_TYPEID:
-      oplen = 1;
-      args = 1;
-      break;
-
-    case OP_ADL_FUNC:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      oplen++;
-      oplen++;
-      break;
-
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      args = 1;
-      /* fall through */
-    case OP_REGISTER:
-    case OP_M2_STRING:
-    case OP_STRING:
-    case OP_OBJC_NSSTRING:	/* Objective C Foundation Class
-				   NSString constant.  */
-    case OP_OBJC_SELECTOR:	/* Objective C "@selector" pseudo-op.  */
-    case OP_NAME:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      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:
-      args = 3;
-      break;
-
-      /* Modula-2 */
-    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;
-
-      /* C++ */
-    case OP_THIS:
-      oplen = 2;
-      break;
-
-    case OP_RANGE:
-      oplen = 3;
-      range_flag = (enum range_flag)
-	longest_to_int (expr->elts[endpos - 2].longconst);
-
-      /* Assume the range has 2 arguments (low bound and high bound), then
-	 reduce the argument count if any bounds are set to default.  */
-      args = 2;
-      if (range_flag & RANGE_HAS_STRIDE)
-	++args;
-      if (range_flag & RANGE_LOW_BOUND_DEFAULT)
-	--args;
-      if (range_flag & RANGE_HIGH_BOUND_DEFAULT)
-	--args;
-
-      break;
-
-    default:
-      args = 1 + (i < (int) BINOP_END);
-    }
-
-  *oplenp = oplen;
-  *argsp = args;
-}
-
-/* Copy the subexpression ending just before index INEND in INEXPR
-   into OUTEXPR, starting at index OUTBEG.
-   In the process, convert it from suffix to prefix form.
-   If LAST_STRUCT is -1, then this function always returns -1.
-   Otherwise, it returns the index of the subexpression which is the
-   left-hand-side of the expression at LAST_STRUCT.  */
-
-static int
-prefixify_subexp (struct expression *inexpr,
-		  struct expression *outexpr, int inend, int outbeg,
-		  int last_struct)
-{
-  int oplen;
-  int args;
-  int i;
-  int *arglens;
-  int result = -1;
-
-  operator_length (inexpr, inend, &oplen, &args);
-
-  /* Copy the final operator itself, from the end of the input
-     to the beginning of the output.  */
-  inend -= oplen;
-  memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend],
-	  EXP_ELEM_TO_BYTES (oplen));
-  outbeg += oplen;
-
-  if (last_struct == inend)
-    result = outbeg - oplen;
-
-  /* Find the lengths of the arg subexpressions.  */
-  arglens = (int *) alloca (args * sizeof (int));
-  for (i = args - 1; i >= 0; i--)
-    {
-      oplen = length_of_subexp (inexpr, inend);
-      arglens[i] = oplen;
-      inend -= oplen;
-    }
-
-  /* Now copy each subexpression, preserving the order of
-     the subexpressions, but prefixifying each one.
-     In this loop, inend starts at the beginning of
-     the expression this level is working on
-     and marches forward over the arguments.
-     outbeg does similarly in the output.  */
-  for (i = 0; i < args; i++)
-    {
-      int r;
-
-      oplen = arglens[i];
-      inend += oplen;
-      r = prefixify_subexp (inexpr, outexpr, inend, outbeg, last_struct);
-      if (r != -1)
-	{
-	  /* Return immediately.  We probably have only parsed a
-	     partial expression, so we don't want to try to reverse
-	     the other operands.  */
-	  return r;
-	}
-      outbeg += oplen;
-    }
-
-  return result;
-}
-
 /* Read an expression from the string *STRINGPTR points to,
    parse it, and return a pointer to a struct expression that we malloc.
    Use block BLOCK as the lexical context for variable names;
@@ -1192,26 +442,21 @@  expression_up
 parse_exp_1 (const char **stringptr, CORE_ADDR pc, const struct block *block,
 	     int comma, innermost_block_tracker *tracker)
 {
-  return parse_exp_in_context (stringptr, pc, block, comma, false, NULL,
+  return parse_exp_in_context (stringptr, pc, block, comma, false,
 			       tracker, nullptr);
 }
 
 /* As for parse_exp_1, except that if VOID_CONTEXT_P, then
-   no value is expected from the expression.
-   OUT_SUBEXP is set when attempting to complete a field name; in this
-   case it is set to the index of the subexpression on the
-   left-hand-side of the struct op.  If not doing such completion, it
-   is left untouched.  */
+   no value is expected from the expression.  */
 
 static expression_up
 parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
 		      const struct block *block,
-		      int comma, bool void_context_p, int *out_subexp,
+		      int comma, bool void_context_p,
 		      innermost_block_tracker *tracker,
 		      expr_completion_state *cstate)
 {
   const struct language_defn *lang = NULL;
-  int subexp;
 
   if (*stringptr == 0 || **stringptr == 0)
     error_no_arg (_("expression to compute"));
@@ -1291,30 +536,12 @@  parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
       /* 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->op == nullptr && ps.expout_ptr == 0))
+      if (! ps.parse_completion || ps.expout->op == nullptr)
 	throw;
     }
 
-  /* We have to operate on an "expression *", due to la_post_parser,
-     which explains this funny-looking double release.  */
   expression_up result = ps.release ();
 
-  /* Convert expression from postfix form as generated by yacc
-     parser, to a prefix form.  */
-
-  if (expressiondebug)
-    dump_raw_expression (result.get (), gdb_stdlog,
-			 "before conversion to prefix form");
-
-  if (result->op == nullptr)
-    subexp = prefixify_expression (result.get (),
-				   ps.m_completion_state.expout_last_struct);
-  if (out_subexp)
-    *out_subexp = subexp;
-
-  lang->post_parser (&result, &ps);
-
   if (expressiondebug)
     dump_prefix_expression (result.get (), gdb_stdlog);
 
@@ -1365,14 +592,11 @@  parse_expression_for_completion (const char *string,
 				 enum type_code *code)
 {
   expression_up exp;
-  struct value *val;
-  int subexp;
   expr_completion_state cstate;
 
   try
     {
-      exp = parse_exp_in_context (&string, 0, 0, 0, false, &subexp,
-				  nullptr, &cstate);
+      exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, &cstate);
     }
   catch (const gdb_exception_error &except)
     {
@@ -1389,30 +613,13 @@  parse_expression_for_completion (const char *string,
       return NULL;
     }
 
-  if (cstate.expout_last_op != nullptr)
-    {
-      expr::structop_base_operation *op = cstate.expout_last_op;
-      const std::string &fld = op->get_string ();
-      *name = make_unique_xstrdup (fld.c_str ());
-      return value_type (op->evaluate_lhs (exp.get ()));
-    }
+  if (cstate.expout_last_op == nullptr)
+    return nullptr;
 
-  if (cstate.expout_last_struct == -1)
-    return NULL;
-
-  const char *fieldname = extract_field_op (exp.get (), &subexp);
-  if (fieldname == NULL)
-    {
-      name->reset ();
-      return NULL;
-    }
-
-  name->reset (xstrdup (fieldname));
-  /* This might throw an exception.  If so, we want to let it
-     propagate.  */
-  val = evaluate_subexpression_type (exp.get (), subexp);
-
-  return value_type (val);
+  expr::structop_base_operation *op = cstate.expout_last_op;
+  const std::string &fld = op->get_string ();
+  *name = make_unique_xstrdup (fld.c_str ());
+  return value_type (op->evaluate_lhs (exp.get ()));
 }
 
 /* Parse floating point value P of length LEN.
@@ -1447,132 +654,6 @@  parser_fprintf (FILE *x, const char *y, ...)
   va_end (args);
 }
 
-/* Implementation of the exp_descriptor method operator_check.  */
-
-int
-operator_check_standard (struct expression *exp, int pos,
-			 int (*objfile_func) (struct objfile *objfile,
-					      void *data),
-			 void *data)
-{
-  const union exp_element *const elts = exp->elts;
-  struct type *type = NULL;
-  struct objfile *objfile = NULL;
-
-  /* Extended operators should have been already handled by exp_descriptor
-     iterate method of its specific language.  */
-  gdb_assert (elts[pos].opcode < OP_EXTENDED0);
-
-  /* Track the callers of write_exp_elt_type for this table.  */
-
-  switch (elts[pos].opcode)
-    {
-    case BINOP_VAL:
-    case OP_COMPLEX:
-    case OP_FLOAT:
-    case OP_LONG:
-    case OP_SCOPE:
-    case OP_TYPE:
-    case UNOP_CAST:
-    case UNOP_MAX:
-    case UNOP_MEMVAL:
-    case UNOP_MIN:
-      type = elts[pos + 1].type;
-      break;
-
-    case TYPE_INSTANCE:
-      {
-	LONGEST arg, nargs = elts[pos + 2].longconst;
-
-	for (arg = 0; arg < nargs; arg++)
-	  {
-	    struct type *inst_type = elts[pos + 3 + arg].type;
-	    struct objfile *inst_objfile = TYPE_OBJFILE (inst_type);
-
-	    if (inst_objfile && (*objfile_func) (inst_objfile, data))
-	      return 1;
-	  }
-      }
-      break;
-
-    case OP_VAR_VALUE:
-      {
-	const struct block *const block = elts[pos + 1].block;
-	const struct symbol *const symbol = elts[pos + 2].symbol;
-
-	/* Check objfile where the variable itself is placed.
-	   SYMBOL_OBJ_SECTION (symbol) may be NULL.  */
-	if ((*objfile_func) (symbol_objfile (symbol), data))
-	  return 1;
-
-	/* Check objfile where is placed the code touching the variable.  */
-	objfile = block_objfile (block);
-
-	type = SYMBOL_TYPE (symbol);
-      }
-      break;
-    case OP_VAR_MSYM_VALUE:
-      objfile = elts[pos + 1].objfile;
-      break;
-    }
-
-  /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL.  */
-
-  if (type && TYPE_OBJFILE (type)
-      && (*objfile_func) (TYPE_OBJFILE (type), data))
-    return 1;
-  if (objfile && (*objfile_func) (objfile, data))
-    return 1;
-
-  return 0;
-}
-
-/* Call OBJFILE_FUNC for any objfile found being referenced by EXP.
-   OBJFILE_FUNC is never called with NULL OBJFILE.  OBJFILE_FUNC get
-   passed an arbitrary caller supplied DATA pointer.  If OBJFILE_FUNC
-   returns non-zero value then (any other) non-zero value is immediately
-   returned to the caller.  Otherwise zero is returned after iterating
-   through whole EXP.  */
-
-static int
-exp_iterate (struct expression *exp,
-	     int (*objfile_func) (struct objfile *objfile, void *data),
-	     void *data)
-{
-  int endpos;
-
-  for (endpos = exp->nelts; endpos > 0; )
-    {
-      int pos, args, oplen = 0;
-
-      operator_length (exp, endpos, &oplen, &args);
-      gdb_assert (oplen > 0);
-
-      pos = endpos - oplen;
-      if (exp->language_defn->expression_ops ()->operator_check (exp, pos,
-								 objfile_func,
-								 data))
-	return 1;
-
-      endpos = pos;
-    }
-
-  return 0;
-}
-
-/* Helper for exp_uses_objfile.  */
-
-static int
-exp_uses_objfile_iter (struct objfile *exp_objfile, void *objfile_voidp)
-{
-  struct objfile *objfile = (struct objfile *) objfile_voidp;
-
-  if (exp_objfile->separate_debug_objfile_backlink)
-    exp_objfile = exp_objfile->separate_debug_objfile_backlink;
-
-  return exp_objfile == objfile;
-}
-
 /* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE
    is unloaded), otherwise return 0.  OBJFILE must not be a separate debug info
    file.  */
@@ -1582,25 +663,7 @@  exp_uses_objfile (struct expression *exp, struct objfile *objfile)
 {
   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);
-}
-
-/* Reallocate the `expout' pointer inside PS so that it can accommodate
-   at least LENELT expression elements.  This function does nothing if
-   there is enough room for the elements.  */
-
-static void
-increase_expout_size (struct expr_builder *ps, size_t lenelt)
-{
-  if ((ps->expout_ptr + lenelt) >= ps->expout_size)
-    {
-      ps->expout_size = std::max (ps->expout_size * 2,
-				  ps->expout_ptr + lenelt + 10);
-      ps->expout->resize (ps->expout_size);
-    }
+  return exp->op->uses_objfile (objfile);
 }
 
 void _initialize_parse ();
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 8ddbac2c134..b6cf4a694c7 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -71,29 +71,15 @@  struct expr_builder
     expout->op = std::move (op);
   }
 
-  /* The size of the expression above.  */
-
-  size_t expout_size;
-
   /* The expression related to this parser state.  */
 
   expression_up expout;
-
-  /* The number of elements already in the expression.  This is used
-     to know where to put new elements.  */
-
-  size_t expout_ptr;
 };
 
 /* This is used for expression completion.  */
 
 struct expr_completion_state
 {
-  /* The index of the last struct expression directly before a '.' or
-     '->'.  This is set when parsing and is only used when completing a
-     field name.  It is -1 if no dereference operation was found.  */
-  int expout_last_struct = -1;
-
   /* The last struct expression directly before a '.' or '->'.  This
      is set when parsing and is only used when completing a field
      name.  It is nullptr if no dereference operation was found.  */
@@ -157,11 +143,6 @@  struct parser_state : public expr_builder
     return val;
   }
 
-  /* Mark the current index as the starting location of a structure
-     expression.  This is used when completing on field names.  */
-
-  void mark_struct_expression ();
-
   /* Mark the given operation as the starting location of a structure
      expression.  This is used when completing on field names.  */
 
@@ -376,173 +357,13 @@  struct objc_class_str
     int theclass;
   };
 
-/* Reverse an expression from suffix form (in which it is constructed)
-   to prefix form (in which we can conveniently print or execute it).
-   Ordinarily this always returns -1.  However, if LAST_STRUCT
-   is not -1 (i.e., we are trying to complete a field name), it will
-   return the index of the subexpression which is the left-hand-side
-   of the struct operation at LAST_STRUCT.  */
-
-extern int prefixify_expression (struct expression *expr,
-				 int last_struct = -1);
-
-extern void write_exp_elt_opcode (struct expr_builder *, enum exp_opcode);
-
-extern void write_exp_elt_sym (struct expr_builder *, struct symbol *);
-
-extern void write_exp_elt_longcst (struct expr_builder *, LONGEST);
-
-extern void write_exp_elt_floatcst (struct expr_builder *, const gdb_byte *);
-
-extern void write_exp_elt_type (struct expr_builder *, struct type *);
-
-extern void write_exp_elt_intern (struct expr_builder *, struct internalvar *);
-
-extern void write_exp_string (struct expr_builder *, struct stoken);
-
-void write_exp_string_vector (struct expr_builder *, int type,
-			      struct stoken_vector *vec);
-
-extern void write_exp_bitstring (struct expr_builder *, struct stoken);
-
-extern void write_exp_elt_block (struct expr_builder *, const struct block *);
-
-extern void write_exp_elt_objfile (struct expr_builder *,
-				   struct objfile *objfile);
-
-extern void write_exp_msymbol (struct expr_builder *,
-			       struct bound_minimal_symbol);
-
-extern void write_dollar_variable (struct parser_state *, struct stoken str);
-
-/* Write a reference to a symbol to the expression being built in PS.
-   NAME is the name of the symbol to write; SYM is the symbol.  If SYM
-   is nullptr, a minimal symbol will be searched for and used if
-   available.  Throws an exception if SYM is nullptr and no minimal
-   symbol can be found.  */
-
-extern void write_exp_symbol_reference (struct parser_state *ps,
-					const char *name,
-					struct symbol *sym);
-
 extern const char *find_template_name_end (const char *);
 
 extern std::string copy_name (struct stoken);
 
-extern int dump_subexp (struct expression *, struct ui_file *, int);
-
-extern int dump_subexp_body_standard (struct expression *, 
-				      struct ui_file *, int);
-
-/* Dump (to STREAM) a function call like expression at position ELT in the
-   expression array EXP.  Return a new value for ELT just after the
-   function call expression.  */
-
-extern int dump_subexp_body_funcall (struct expression *exp,
-				     struct ui_file *stream, int elt);
-
-extern void operator_length (const struct expression *, int, int *, int *);
-
-extern void operator_length_standard (const struct expression *, int, int *,
-				      int *);
-
-extern int operator_check_standard (struct expression *exp, int pos,
-				    int (*objfile_func)
-				      (struct objfile *objfile, void *data),
-				    void *data);
-
 extern bool parse_float (const char *p, int len,
 			 const struct type *type, gdb_byte *data);
 
-/* These codes indicate operator precedences for expression printing,
-   least tightly binding first.  */
-/* Adding 1 to a precedence value is done for binary operators,
-   on the operand which is more tightly bound, so that operators
-   of equal precedence within that operand will get parentheses.  */
-/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
-   they are used as the "surrounding precedence" to force
-   various kinds of things to be parenthesized.  */
-enum precedence
-  {
-    PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR,
-    PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR,
-    PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
-    PREC_HYPER, PREC_PREFIX, PREC_SUFFIX, PREC_BUILTIN_FUNCTION
-  };
-
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-struct op_print
-  {
-    const char *string;
-    enum exp_opcode opcode;
-    /* Precedence of operator.  These values are used only by comparisons.  */
-    enum precedence precedence;
-
-    /* For a binary operator:  1 iff right associate.
-       For a unary operator:  1 iff postfix.  */
-    int right_assoc;
-  };
-
-/* Information needed to print, prefixify, and evaluate expressions for 
-   a given language.  */
-
-struct exp_descriptor
-  {
-    /* Print subexpression.  */
-    void (*print_subexp) (struct expression *, int *, struct ui_file *,
-			  enum precedence);
-
-    /* Returns number of exp_elements needed to represent an operator and
-       the number of subexpressions it takes.  */
-    void (*operator_length) (const struct expression*, int, int*, int *);
-
-    /* Call OBJFILE_FUNC for any objfile found being referenced by the
-       single operator of EXP at position POS.  Operator parameters are
-       located at positive (POS + number) offsets in EXP.  OBJFILE_FUNC
-       should never be called with NULL OBJFILE.  OBJFILE_FUNC should
-       get passed an arbitrary caller supplied DATA pointer.  If it
-       returns non-zero value then (any other) non-zero value should be
-       immediately returned to the caller.  Otherwise zero should be
-       returned.  */
-    int (*operator_check) (struct expression *exp, int pos,
-			   int (*objfile_func) (struct objfile *objfile,
-						void *data),
-			   void *data);
-
-    /* Dump the rest of this (prefix) expression after the operator
-       itself has been printed.  See dump_subexp_body_standard in
-       (expprint.c).  */
-    int (*dump_subexp_body) (struct expression *, struct ui_file *, int);
-
-    /* Evaluate an expression.  */
-    struct value *(*evaluate_exp) (struct type *, struct expression *,
-				   int *, enum noside);
-  };
-
-
-/* Default descriptor containing standard definitions of all
-   elements.  */
-extern const struct exp_descriptor exp_descriptor_standard;
-
-/* Functions used by language-specific extended operators to (recursively)
-   print/dump subexpressions.  */
-
-extern void print_subexp (struct expression *, int *, struct ui_file *,
-			  enum precedence);
-
-extern void print_subexp_standard (struct expression *, int *, 
-				   struct ui_file *, enum precedence);
-
-/* Print a function call like expression to STREAM.  This is called as a
-   helper function by which point the expression node identifying this as a
-   function call has already been stripped off and POS should point to the
-   number of function call arguments.  EXP is the object containing the
-   list of expression elements.  */
-
-extern void print_subexp_funcall (struct expression *exp, int *pos,
-				  struct ui_file *stream);
 
 /* Function used to avoid direct calls to fprintf
    in the code generated by the bison parser.  */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 72f0283e4af..f1ba165d540 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -2488,33 +2488,24 @@  ppc_linux_nat_target::check_condition (CORE_ADDR watch_addr,
 				       struct expression *cond,
 				       CORE_ADDR *data_value, int *len)
 {
-  int pc = 1, num_accesses_left, num_accesses_right;
+  int num_accesses_left, num_accesses_right;
   struct value *left_val, *right_val;
   std::vector<value_ref_ptr> left_chain, right_chain;
 
-  if (cond->first_opcode () != BINOP_EQUAL)
+  expr::equal_operation *eqop
+    = dynamic_cast<expr::equal_operation *> (cond->op.get ());
+  if (eqop == nullptr)
     return 0;
+  expr::operation *lhs = eqop->get_lhs ();
+  expr::operation *rhs = eqop->get_rhs ();
 
-  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);
+  fetch_subexp_value (cond, 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, rhs, &right_val, NULL, &right_chain, false);
+  fetch_subexp_value (cond, rhs, &right_val, NULL, &right_chain, false);
   num_accesses_right = num_memory_accesses (right_chain);
 
   if (right_val == NULL || num_accesses_right < 0)
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 5b399489c70..484a2dbf228 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1373,14 +1373,8 @@  set_command (const char *exp, int from_tty)
 {
   expression_up expr = parse_expression (exp);
 
-  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)
+    switch (expr->op->opcode ())
       {
       case UNOP_PREINCREMENT:
       case UNOP_POSTINCREMENT:
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index ec97cac3dae..ea3f974c979 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -209,11 +209,6 @@  class rust_language : public language_defn
   bool range_checking_on_by_default () const override
   { return true; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
-
 private:
 
   /* Helper for value_print_inner, arguments are as for that function.
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 51f04b9e40b..7f09b65f31f 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1416,15 +1416,10 @@  stap_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
 			   unsigned n)
 {
   struct stap_probe_arg *arg;
-  union exp_element *pc;
 
   arg = this->get_arg_by_number (n, expr->gdbarch);
 
-  pc = arg->aexpr->elts;
-  if (arg->aexpr->op != nullptr)
-    arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
-  else
-    gen_expr (arg->aexpr.get (), &pc, expr, value);
+  arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
 
   require_rvalue (expr, value);
   value->type = arg->atype;
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index ec46446c8bf..1530165c350 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -691,15 +691,10 @@  validate_actionline (const char *line, struct breakpoint *b)
 	      if (exp->first_opcode () == OP_VAR_VALUE)
 		{
 		  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;
+		  expr::var_value_operation *vvop
+		    = (dynamic_cast<expr::var_value_operation *>
+		       (exp->op.get ()));
+		  sym = vvop->get_symbol ();
 
 		  if (SYMBOL_CLASS (sym) == LOC_CONST)
 		    {
@@ -1395,16 +1390,10 @@  encode_actions_1 (struct command_line *action,
 		    {
 		    case OP_REGISTER:
 		      {
-			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;
+			expr::register_operation *regop
+			  = (dynamic_cast<expr::register_operation *>
+			     (exp->op.get ()));
+			const char *name = regop->get_name ();
 
 			i = user_reg_map_name_to_regnum (target_gdbarch (),
 							 name, strlen (name));
@@ -1424,16 +1413,10 @@  encode_actions_1 (struct command_line *action,
 			/* 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;
+			expr::unop_memval_operation *memop
+			  = (dynamic_cast<expr::unop_memval_operation *>
+			     (exp->op.get ()));
+			struct type *type = memop->get_type ();
 			/* Initialize the TYPE_LENGTH if it is a typedef.  */
 			check_typedef (type);
 			collect->add_memrange (target_gdbarch (),
@@ -1447,17 +1430,10 @@  encode_actions_1 (struct command_line *action,
 
 		    case OP_VAR_VALUE:
 		      {
-			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;
+			expr::var_value_operation *vvo
+			  = (dynamic_cast<expr::var_value_operation *>
+			     (exp->op.get ()));
+			struct symbol *sym = vvo->get_symbol ();
 			const char *name = sym->natural_name ();
 
 			collect->collect_symbol (sym,
diff --git a/gdb/value.c b/gdb/value.c
index 806c5449052..7a9128df642 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1982,29 +1982,19 @@  init_if_undefined_command (const char* args, int from_tty)
   /* Validate the expression.
      Was the expression an assignment?
      Or even an expression at all?  */
-  if ((expr->nelts == 0 && expr->op == nullptr)
-      || expr->first_opcode () != BINOP_ASSIGN)
+  if (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->op == nullptr)
+  /* Extract the variable from the parsed expression.  */
+  expr::assign_operation *assign
+    = dynamic_cast<expr::assign_operation *> (expr->op.get ());
+  if (assign != 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 ();
-	}
+      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)
diff --git a/gdb/value.h b/gdb/value.h
index 7075a08d653..88995cfeafe 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -916,13 +916,6 @@  extern struct value *evaluate_expression (struct expression *exp,
 
 extern struct value *evaluate_type (struct expression *exp);
 
-extern struct value *evaluate_subexp (struct type *expect_type,
-				      struct expression *exp,
-				      int *pos, enum noside noside);
-
-extern struct value *evaluate_subexpression_type (struct expression *exp,
-						  int subexp);
-
 extern value *evaluate_var_value (enum noside noside, const block *blk,
 				  symbol *var);
 
@@ -933,17 +926,12 @@  extern value *evaluate_var_msym_value (enum noside noside,
 extern value *eval_skip_value (expression *exp);
 
 namespace expr { class operation; };
-extern void fetch_subexp_value (struct expression *exp, int *pc,
+extern void fetch_subexp_value (struct expression *exp,
 				expr::operation *op,
 				struct value **valp, struct value **resultp,
 				std::vector<value_ref_ptr> *val_chain,
 				bool preserve_errors);
 
-extern const char *extract_field_op (struct expression *exp, int *subexp);
-
-extern struct value *evaluate_subexp_with_coercion (struct expression *,
-						    int *, enum noside);
-
 extern struct value *parse_and_eval (const char *exp);
 
 extern struct value *parse_to_comma_and_eval (const char **expp);