mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
edd079d9f6
When parsing floating-point literals, the language parsers currently use parse_float or some equivalent routine to parse the input string into a DOUBLEST, which is then stored within a OP_DOUBLE expression node. When evaluating the expression, the OP_DOUBLE is finally converted into a value in target format. On the other hand, *decimal* floating-point literals are parsed directly into target format and stored that way in a OP_DECFLOAT expression node. In order to eliminate the DOUBLEST, this patch therefore unifies the handling of binary and decimal floating- point literals and stores them both in target format within a new OP_FLOAT expression node, replacing both OP_DOUBLE and OP_DECFLOAT. In order to store literals in target format, the parse_float routine needs to know the type of the literal. All parsers therefore need to be changed to determine the appropriate type (e.g. by detecting suffixes) *before* calling parse_float, instead of after it as today. However, this change is mostly straightforward -- again, this is already done for decimal FP today. The core of the literal parsing is moved into a new routine floatformat_from_string, mirroring floatformat_to_string. The parse_float routine now calls either floatformat_from_string or decimal_from_sting, allowing it to handle any type of FP literal. All language parsers need to be updated. Some notes on specific changes to the various languages: - C: Decimal FP is now handled in parse_float, and no longer needs to be handled specially. - D: Straightforward. - Fortran: Still used a hard-coded "atof", also replaced by parse_float now. Continues to always use builtin_real_s8 as the type of literal, even though this is probably wrong. - Go: This used to handle "f" and "l" suffixes, even though the Go language actually doesn't support those. I kept this support for now -- maybe revisit later. Note the the GDB test suite for some reason actually *verifies* that GDB supports those unsupported suffixes ... - Pascal: Likewise -- this handles suffixes that are not supported in the language standard. - Modula-2: Like Fortran, used to use "atof". - Rust: Mostly straightforward, except for a unit-testing hitch. The code use to set a special "unit_testing" flag which would cause "rust_type" to always return NULL. This makes it not possible to encode a literal into target format (which type?). The reason for this flag appears to have been that during unit testing, there is no "rust_parser" context set up, which means no "gdbarch" is available to use its types. To fix this, I removed the unit_testing flag, and instead simply just set up a dummy rust_parser context during unit testing. - Ada: This used to check sizeof (DOUBLEST) to determine which type to use for floating-point literal. This seems questionable to begin with (since DOUBLEST is quite unrelated to target formats), and in any case we need to get rid of DOUBLEST. I'm now simply always using the largest type (builtin_long_double). gdb/ChangeLog: 2017-10-25 Ulrich Weigand <uweigand@de.ibm.com> * doublest.c (floatformat_from_string): New function. * doublest.h (floatformat_from_string): Add prototype. * std-operator.def (OP_DOUBLE, OP_DECFLOAT): Remove, replace by ... (OP_FLOAT): ... this. * expression.h: Do not include "doublest.h". (union exp_element): Replace doubleconst and decfloatconst by new element floatconst. * ada-lang.c (resolve_subexp): Handle OP_FLOAT instead of OP_DOUBLE. (ada_evaluate_subexp): Likewise. * eval.c (evaluate_subexp_standard): Handle OP_FLOAT instead of OP_DOUBLE and OP_DECFLOAT. * expprint.c (print_subexp_standard): Likewise. (dump_subexp_body_standard): Likewise. * breakpoint.c (watchpoint_exp_is_const): Likewise. * parse.c: Include "dfp.h". (write_exp_elt_dblcst, write_exp_elt_decfloatcst): Remove. (write_exp_elt_floatcst): New function. (operator_length_standard): Handle OP_FLOAT instead of OP_DOUBLE and OP_DECFLOAT. (operator_check_standard): Likewise. (parse_float): Do not accept suffix. Take type as input. Return bool. Return target format buffer instead of host DOUBLEST. Use floatformat_from_string and decimal_from_string to parse either binary or decimal floating-point types. (parse_c_float): Remove. * parser-defs.h: Do not include "doublest.h". (write_exp_elt_dblcst, write_exp_elt_decfloatcst): Remove. (write_exp_elt_floatcst): Add prototype. (parse_float): Update prototype. (parse_c_float): Remove. * c-exp.y: Do not include "dfp.h". (typed_val_float): Use byte buffer instead of DOUBLEST. (typed_val_decfloat): Remove. (DECFLOAT): Remove. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Update to new parse_float interface. Parse suffixes and determine type before calling parse_float. Handle decimal and binary FP types the same way. * d-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST. (FLOAT_LITERAL): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Update to new parse_float interface. Parse suffixes and determine type before calling parse_float. * f-exp.y: Replace dval by typed_val_float. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Use parse_float instead of atof. * go-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST. (parse_go_float): Remove. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Call parse_float instead of parse_go_float. Parse suffixes and determine type before calling parse_float. * p-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Update to new parse_float interface. Parse suffixes and determine type before calling parse_float. * m2-exp.y: Replace dval by byte buffer val. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. (parse_number): Call parse_float instead of atof. * rust-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST. (lex_number): Call parse_float instead of strtod. (ast_dliteral): Use OP_FLOAT instead of OP_DOUBLE. (convert_ast_to_expression): Handle OP_FLOAT instead of OP_DOUBLE. Use write_exp_elt_floatcst. (unit_testing): Remove static variable. (rust_type): Do not check unit_testing. (rust_lex_tests): Do not set uint_testing. Set up dummy rust_parser. * ada-exp.y (type_float, type_double): Remove. (typed_val_float): Use byte buffer instead of DOUBLEST. (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst. * ada-lex.l (processReal): Use parse_float instead of sscanf.
1156 lines
32 KiB
C
1156 lines
32 KiB
C
/* Print in infix form a struct expression.
|
|
|
|
Copyright (C) 1986-2017 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "symtab.h"
|
|
#include "gdbtypes.h"
|
|
#include "expression.h"
|
|
#include "value.h"
|
|
#include "language.h"
|
|
#include "parser-defs.h"
|
|
#include "user-regs.h" /* For user_reg_map_regnum_to_name. */
|
|
#include "target.h"
|
|
#include "block.h"
|
|
#include "objfiles.h"
|
|
#include "valprint.h"
|
|
|
|
#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->la_exp_desc->print_subexp (exp, pos, stream, prec);
|
|
}
|
|
|
|
/* 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->la_op_print_tab;
|
|
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 (type_name_no_tag (exp->elts[pc + 1].type), 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
|
|
&& SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)) != NULL)
|
|
{
|
|
fputs_filtered (SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)), stream);
|
|
fputs_filtered ("::", stream);
|
|
}
|
|
fputs_filtered (SYMBOL_PRINT_NAME (exp->elts[pc + 2].symbol), stream);
|
|
}
|
|
return;
|
|
|
|
case OP_VAR_MSYM_VALUE:
|
|
{
|
|
(*pos) += 3;
|
|
fputs_filtered (MSYMBOL_PRINT_NAME (exp->elts[pc + 2].msymbol), 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",
|
|
SYMBOL_PRINT_NAME (exp->elts[pc + 1].symbol));
|
|
}
|
|
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:
|
|
(*pos) += 2;
|
|
nargs = longest_to_int (exp->elts[pc + 1].longconst);
|
|
print_subexp (exp, pos, stream, PREC_SUFFIX);
|
|
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 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);
|
|
LA_PRINT_STRING (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);
|
|
LA_PRINT_STRING (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. */
|
|
char *selector;
|
|
|
|
(*pos) += 3;
|
|
nargs = longest_to_int (exp->elts[pc + 2].longconst);
|
|
fprintf_unfiltered (stream, "[");
|
|
print_subexp (exp, pos, stream, PREC_SUFFIX);
|
|
if (0 == target_read_string (exp->elts[pc + 1].longconst,
|
|
&selector, 1024, NULL))
|
|
{
|
|
error (_("bad selector"));
|
|
return;
|
|
}
|
|
if (nargs)
|
|
{
|
|
char *s, *nextS;
|
|
|
|
s = (char *) alloca (strlen (selector) + 1);
|
|
strcpy (s, selector);
|
|
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);
|
|
}
|
|
fprintf_unfiltered (stream, "]");
|
|
/* "selector" was malloc'd by target_read_string. Free it. */
|
|
xfree (selector);
|
|
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);
|
|
LA_PRINT_STRING (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 (TYPE_CODE (exp->elts[pc + 1].type) == 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->la_name_of_this)
|
|
fputs_filtered (exp->language_defn->la_name_of_this, stream);
|
|
else
|
|
fprintf_filtered (stream, _("<language %s has no 'this'>"),
|
|
exp->language_defn->la_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_type range_type;
|
|
|
|
range_type = (enum range_type)
|
|
longest_to_int (exp->elts[pc + 1].longconst);
|
|
*pos += 2;
|
|
|
|
fputs_filtered ("RANGE(", stream);
|
|
if (range_type == HIGH_BOUND_DEFAULT
|
|
|| range_type == NONE_BOUND_DEFAULT)
|
|
print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
|
|
fputs_filtered ("..", stream);
|
|
if (range_type == LOW_BOUND_DEFAULT
|
|
|| range_type == NONE_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->la_op_print_tab;
|
|
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);
|
|
|
|
/* Name for OPCODE, when it appears in expression EXP. */
|
|
|
|
const char *
|
|
op_name (struct expression *exp, enum exp_opcode opcode)
|
|
{
|
|
return exp->language_defn->la_exp_desc->op_name (opcode);
|
|
}
|
|
|
|
/* Default name for the standard operator OPCODE (i.e., one defined in
|
|
the definition of enum exp_opcode). */
|
|
|
|
const char *
|
|
op_name_standard (enum exp_opcode opcode)
|
|
{
|
|
switch (opcode)
|
|
{
|
|
default:
|
|
{
|
|
static char buf[30];
|
|
|
|
xsnprintf (buf, sizeof (buf), "<unknown %d>", opcode);
|
|
return buf;
|
|
}
|
|
#define OP(name) \
|
|
case name: \
|
|
return #name ;
|
|
#include "std-operator.def"
|
|
#undef OP
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
|
|
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->la_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, 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, 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->la_exp_desc->dump_subexp_body (exp, stream, 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_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)",
|
|
SYMBOL_PRINT_NAME (exp->elts[elt + 1].symbol));
|
|
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)",
|
|
MSYMBOL_PRINT_NAME (exp->elts[elt + 1].msymbol));
|
|
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)",
|
|
SYMBOL_PRINT_NAME (exp->elts[elt].symbol));
|
|
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:
|
|
{
|
|
int i, nargs;
|
|
|
|
nargs = longest_to_int (exp->elts[elt].longconst);
|
|
|
|
fprintf_filtered (stream, "Number of args: %d", nargs);
|
|
elt += 2;
|
|
|
|
for (i = 1; i <= nargs + 1; i++)
|
|
elt = dump_subexp (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_type range_type;
|
|
|
|
range_type = (enum range_type)
|
|
longest_to_int (exp->elts[elt].longconst);
|
|
elt += 2;
|
|
|
|
switch (range_type)
|
|
{
|
|
case BOTH_BOUND_DEFAULT:
|
|
fputs_filtered ("Range '..'", stream);
|
|
break;
|
|
case LOW_BOUND_DEFAULT:
|
|
fputs_filtered ("Range '..EXP'", stream);
|
|
break;
|
|
case HIGH_BOUND_DEFAULT:
|
|
fputs_filtered ("Range 'EXP..'", stream);
|
|
break;
|
|
case NONE_BOUND_DEFAULT:
|
|
fputs_filtered ("Range 'EXP..EXP'", stream);
|
|
break;
|
|
default:
|
|
fputs_filtered ("Invalid Range!", stream);
|
|
break;
|
|
}
|
|
|
|
if (range_type == HIGH_BOUND_DEFAULT
|
|
|| range_type == NONE_BOUND_DEFAULT)
|
|
elt = dump_subexp (exp, stream, elt);
|
|
if (range_type == LOW_BOUND_DEFAULT
|
|
|| range_type == NONE_BOUND_DEFAULT)
|
|
elt = dump_subexp (exp, stream, elt);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
case OP_NULL:
|
|
case MULTI_SUBSCRIPT:
|
|
case OP_F77_UNDETERMINED_ARGLIST:
|
|
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;
|
|
|
|
fprintf_filtered (stream, "Dump of expression @ ");
|
|
gdb_print_host_address (exp, stream);
|
|
fputs_filtered (", after conversion to prefix form:\nExpression: `", stream);
|
|
print_expression (exp, stream);
|
|
fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
|
|
exp->language_defn->la_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);
|
|
}
|