#include "typeprint.h"
#include "cp-abi.h"
#include "type-stack.h"
+#include "target-float.h"
#define parse_type(ps) builtin_type (ps->gdbarch ())
%type <voidval> exp exp1 type_exp start variable qualified_name lcurly function_method
%type <lval> rcurly
-%type <tval> type typebase
+%type <tval> type typebase scalar_type
%type <tvec> nonempty_typelist func_mod parameter_typelist
/* %type <bval> block */
%type <type_stack> ptr_operator_ts abs_decl direct_abs_decl
-%token <typed_val_int> INT
-%token <typed_val_float> FLOAT
+%token <typed_val_int> INT COMPLEX_INT
+%token <typed_val_float> FLOAT COMPLEX_FLOAT
/* Both NAME and TYPENAME tokens represent symbols in the input,
and both convey their data as strings.
legal basetypes. */
%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD
%token RESTRICT ATOMIC
+%token FLOAT_KEYWORD COMPLEX
%token <sval> DOLLAR_VARIABLE
write_exp_elt_opcode (pstate, OP_LONG); }
;
+exp : COMPLEX_INT
+ {
+ write_exp_elt_opcode (pstate, OP_LONG);
+ write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
+ write_exp_elt_longcst (pstate, 0);
+ write_exp_elt_opcode (pstate, OP_LONG);
+ write_exp_elt_opcode (pstate, OP_LONG);
+ write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
+ write_exp_elt_longcst (pstate, (LONGEST) ($1.val));
+ write_exp_elt_opcode (pstate, OP_LONG);
+ write_exp_elt_opcode (pstate, OP_COMPLEX);
+ write_exp_elt_type (pstate, $1.type);
+ write_exp_elt_opcode (pstate, OP_COMPLEX);
+ }
+ ;
+
exp : CHAR
{
struct stoken_vector vec;
write_exp_elt_opcode (pstate, OP_FLOAT); }
;
+exp : COMPLEX_FLOAT
+ {
+ struct type *underlying
+ = TYPE_TARGET_TYPE ($1.type);
+
+ write_exp_elt_opcode (pstate, OP_FLOAT);
+ write_exp_elt_type (pstate, underlying);
+ gdb_byte val[16];
+ target_float_from_host_double (val, underlying, 0);
+ write_exp_elt_floatcst (pstate, val);
+ write_exp_elt_opcode (pstate, OP_FLOAT);
+ write_exp_elt_opcode (pstate, OP_FLOAT);
+ write_exp_elt_type (pstate, underlying);
+ write_exp_elt_floatcst (pstate, $1.val);
+ write_exp_elt_opcode (pstate, OP_FLOAT);
+ write_exp_elt_opcode (pstate, OP_COMPLEX);
+ write_exp_elt_type (pstate, $1.type);
+ write_exp_elt_opcode (pstate, OP_COMPLEX);
+ }
+ ;
+
exp : variable
;
type : ptype
;
-/* Implements (approximately): (type-qualifier)* type-specifier.
+/* A helper production that recognizes scalar types that can validly
+ be used with _Complex. */
- When type-specifier is only ever a single word, like 'float' then these
- arrive as pre-built TYPENAME tokens thanks to the classify_name
- function. However, when a type-specifier can contain multiple words,
- for example 'double' can appear as just 'double' or 'long double', and
- similarly 'long' can appear as just 'long' or in 'long double', then
- these type-specifiers are parsed into their own tokens in the function
- lex_one_token and the ident_tokens array. These separate tokens are all
- recognised here. */
-typebase
- : TYPENAME
- { $$ = $1.type; }
- | INT_KEYWORD
+scalar_type:
+ INT_KEYWORD
{ $$ = lookup_signed_typename (pstate->language (),
"int"); }
| LONG
"double",
NULL,
0); }
+ | FLOAT_KEYWORD
+ { $$ = lookup_typename (pstate->language (),
+ "float",
+ NULL,
+ 0); }
| LONG DOUBLE_KEYWORD
{ $$ = lookup_typename (pstate->language (),
"long double",
NULL,
0); }
+ | UNSIGNED type_name
+ { $$ = lookup_unsigned_typename (pstate->language (),
+ $2.type->name ()); }
+ | UNSIGNED
+ { $$ = lookup_unsigned_typename (pstate->language (),
+ "int"); }
+ | SIGNED_KEYWORD type_name
+ { $$ = lookup_signed_typename (pstate->language (),
+ $2.type->name ()); }
+ | SIGNED_KEYWORD
+ { $$ = lookup_signed_typename (pstate->language (),
+ "int"); }
+ ;
+
+/* Implements (approximately): (type-qualifier)* type-specifier.
+
+ When type-specifier is only ever a single word, like 'float' then these
+ arrive as pre-built TYPENAME tokens thanks to the classify_name
+ function. However, when a type-specifier can contain multiple words,
+ for example 'double' can appear as just 'double' or 'long double', and
+ similarly 'long' can appear as just 'long' or in 'long double', then
+ these type-specifiers are parsed into their own tokens in the function
+ lex_one_token and the ident_tokens array. These separate tokens are all
+ recognised here. */
+typebase
+ : TYPENAME
+ { $$ = $1.type; }
+ | scalar_type
+ { $$ = $1; }
+ | COMPLEX scalar_type
+ {
+ $$ = init_complex_type (nullptr, $2);
+ }
| STRUCT name
{ $$
= lookup_struct (copy_name ($2).c_str (),
$2.length);
$$ = NULL;
}
- | UNSIGNED type_name
- { $$ = lookup_unsigned_typename (pstate->language (),
- TYPE_NAME($2.type)); }
- | UNSIGNED
- { $$ = lookup_unsigned_typename (pstate->language (),
- "int"); }
- | SIGNED_KEYWORD type_name
- { $$ = lookup_signed_typename (pstate->language (),
- TYPE_NAME($2.type)); }
- | SIGNED_KEYWORD
- { $$ = lookup_signed_typename (pstate->language (),
- "int"); }
/* It appears that this rule for templates is never
reduced; template recognition happens by lookahead
in the token processing code in yylex. */
c_print_type ($2, NULL, &buf, -1, 0,
&type_print_raw_options);
+ std::string name = std::move (buf.string ());
/* This also needs canonicalization. */
- std::string canon
- = cp_canonicalize_string (buf.c_str ());
- if (canon.empty ())
- canon = std::move (buf.string ());
- $$ = operator_stoken ((" " + canon).c_str ());
+ gdb::unique_xmalloc_ptr<char> canon
+ = cp_canonicalize_string (name.c_str ());
+ if (canon != nullptr)
+ name = canon.get ();
+ $$ = operator_stoken ((" " + name).c_str ());
}
;
match the 'name' rule to appear as fields within a struct. The example
that initially motivated this was the RISC-V target which models the
floating point registers as a union with fields called 'float' and
- 'double'. The 'float' string becomes a TYPENAME token and can appear
- anywhere a 'name' can, however 'double' is its own token,
- DOUBLE_KEYWORD, and doesn't match the 'name' rule.*/
+ 'double'. */
field_name
: name
| DOUBLE_KEYWORD { $$ = typename_stoken ("double"); }
+ | FLOAT_KEYWORD { $$ = typename_stoken ("float"); }
| INT_KEYWORD { $$ = typename_stoken ("int"); }
| LONG { $$ = typename_stoken ("long"); }
| SHORT { $$ = typename_stoken ("short"); }
static int
type_aggregate_p (struct type *type)
{
- return (TYPE_CODE (type) == TYPE_CODE_STRUCT
- || TYPE_CODE (type) == TYPE_CODE_UNION
- || TYPE_CODE (type) == TYPE_CODE_NAMESPACE
- || (TYPE_CODE (type) == TYPE_CODE_ENUM
+ return (type->code () == TYPE_CODE_STRUCT
+ || type->code () == TYPE_CODE_UNION
+ || type->code () == TYPE_CODE_NAMESPACE
+ || (type->code () == TYPE_CODE_ENUM
&& TYPE_DECLARED_CLASS (type)));
}
for (ix = 0; ix < params->size (); ++ix)
{
type = (*params)[ix];
- if (type != NULL && TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID)
+ if (type != NULL && check_typedef (type)->code () == TYPE_CODE_VOID)
{
if (ix == 0)
{
/* Number of "L" suffixes encountered. */
int long_p = 0;
- /* We have found a "L" or "U" suffix. */
+ /* Imaginary number. */
+ bool imaginary_p = false;
+
+ /* We have found a "L" or "U" (or "i") suffix. */
int found_suffix = 0;
ULONGEST high_bit;
if (parsed_float)
{
+ if (len >= 1 && p[len - 1] == 'i')
+ {
+ imaginary_p = true;
+ --len;
+ }
+
/* Handle suffixes for decimal floating-point: "df", "dd" or "dl". */
if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
{
putithere->typed_val_float.type,
putithere->typed_val_float.val))
return ERROR;
- return FLOAT;
+
+ if (imaginary_p)
+ putithere->typed_val_float.type
+ = init_complex_type (nullptr, putithere->typed_val_float.type);
+
+ return imaginary_p ? COMPLEX_FLOAT : FLOAT;
}
/* Handle base-switching prefixes 0x, 0t, 0d, 0 */
c = *p++;
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
- if (c != 'l' && c != 'u')
+ if (c != 'l' && c != 'u' && c != 'i')
n *= base;
if (c >= '0' && c <= '9')
{
unsigned_p = 1;
found_suffix = 1;
}
+ else if (c == 'i')
+ {
+ imaginary_p = true;
+ found_suffix = 1;
+ }
else
return ERROR; /* Char not a digit */
}
/* Portably test for overflow (only works for nonzero values, so make
a second check for zero). FIXME: Can't we just make n and prevn
unsigned and avoid this? */
- if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+ if (c != 'l' && c != 'u' && c != 'i' && (prevn >= n) && n != 0)
unsigned_p = 1; /* Try something unsigned */
/* Portably test for unsigned overflow.
FIXME: This check is wrong; for example it doesn't find overflow
on 0x123456789 when LONGEST is 32 bits. */
- if (c != 'l' && c != 'u' && n != 0)
+ if (c != 'l' && c != 'u' && c != 'i' && n != 0)
{
if (unsigned_p && prevn >= n)
error (_("Numeric constant too large."));
putithere->typed_val_int.type = signed_type;
}
- return INT;
+ if (imaginary_p)
+ putithere->typed_val_int.type
+ = init_complex_type (nullptr, putithere->typed_val_int.type);
+
+ return imaginary_p ? COMPLEX_INT : INT;
}
/* Temporary obstack used for holding strings. */
/* Identifier-like tokens. Only type-specifiers than can appear in
multi-word type names (for example 'double' can appear in 'long
double') need to be listed here. type-specifiers that are only ever
- single word (like 'float') are handled by the classify_name function. */
+ single word (like 'char') are handled by the classify_name function. */
static const struct token ident_tokens[] =
{
{"unsigned", UNSIGNED, OP_NULL, 0},
{"_Alignof", ALIGNOF, OP_NULL, 0},
{"alignof", ALIGNOF, OP_NULL, FLAG_CXX},
{"double", DOUBLE_KEYWORD, OP_NULL, 0},
+ {"float", FLOAT_KEYWORD, OP_NULL, 0},
{"false", FALSEKEYWORD, OP_NULL, FLAG_CXX},
{"class", CLASS, OP_NULL, FLAG_CXX},
{"union", UNION, OP_NULL, 0},
{"_Atomic", ATOMIC, OP_NULL, 0},
{"enum", ENUM, OP_NULL, 0},
{"long", LONG, OP_NULL, 0},
+ {"_Complex", COMPLEX, OP_NULL, 0},
+ {"__complex__", COMPLEX, OP_NULL, 0},
+
{"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
{"int", INT_KEYWORD, OP_NULL, 0},
{"new", NEW, OP_NULL, FLAG_CXX},
if ((tokentab2[i].flags & FLAG_CXX) != 0
&& par_state->language ()->la_language != language_cplus)
break;
- gdb_assert ((tokentab3[i].flags & FLAG_C) == 0);
+ gdb_assert ((tokentab2[i].flags & FLAG_C) == 0);
pstate->lexptr += 2;
yylval.opcode = tokentab2[i].opcode;