* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
static char sccsid
[] = "@(#)valarith.c 6.3 (Berkeley) 5/8/91";
/* Perform arithmetic and other operations on values, for GDB.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB 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 1, or (at your option)
GDB 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 GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
value
value_subscripted_rvalue ();
register value val
, valint
, valptr
;
if ((TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_PTR
|| TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_PTR
)
(TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_INT
|| TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_INT
))
/* Exactly one argument is a pointer, and one is an integer. */
if (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_PTR
)
len
= TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr
)));
if (len
== 0) len
= 1; /* For (void *) */
val
= value_from_long (builtin_type_long
,
+ (len
* value_as_long (valint
)));
VALUE_TYPE (val
) = VALUE_TYPE (valptr
);
return value_binop (arg1
, arg2
, BINOP_ADD
);
if (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_PTR
TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_INT
)
val
= value_from_long (builtin_type_long
,
- TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1
))) * value_as_long (arg2
));
VALUE_TYPE (val
) = VALUE_TYPE (arg1
);
if (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_PTR
VALUE_TYPE (arg1
) == VALUE_TYPE (arg2
))
val
= value_from_long (builtin_type_long
,
(value_as_long (arg1
) - value_as_long (arg2
))
/ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1
))));
return value_binop (arg1
, arg2
, BINOP_SUB
);
/* Return the value of ARRAY[IDX]. */
value_subscript (array
, idx
)
if (TYPE_CODE (VALUE_TYPE (array
)) == TYPE_CODE_ARRAY
&& VALUE_LVAL (array
) != lval_memory
)
return value_subscripted_rvalue (array
, idx
);
return value_ind (value_add (array
, idx
));
/* Return the value of EXPR[IDX], expr an aggregate rvalue
(eg, a vector register) */
value_subscripted_rvalue (array
, idx
)
struct type
*elt_type
= TYPE_TARGET_TYPE (VALUE_TYPE (array
));
int elt_size
= TYPE_LENGTH (elt_type
);
int elt_offs
= elt_size
* value_as_long (idx
);
if (elt_offs
>= TYPE_LENGTH (VALUE_TYPE (array
)))
error ("no such vector element");
if (TYPE_CODE (elt_type
) == TYPE_CODE_FLT
)
if (elt_size
== sizeof (float))
v
= value_from_double (elt_type
, (double) *(float *)
(VALUE_CONTENTS (array
) + elt_offs
));
v
= value_from_double (elt_type
, *(double *)
(VALUE_CONTENTS (array
) + elt_offs
));
union {int i
; char c
;} test
;
offs
= sizeof (LONGEST
) - elt_size
;
v
= value_from_long (elt_type
, *(LONGEST
*)
(VALUE_CONTENTS (array
) + elt_offs
- offs
));
if (VALUE_LVAL (array
) == lval_internalvar
)
VALUE_LVAL (v
) = lval_internalvar_component
;
VALUE_LVAL (v
) = not_lval
;
VALUE_ADDRESS (v
) = VALUE_ADDRESS (array
);
VALUE_OFFSET (v
) = VALUE_OFFSET (array
) + elt_offs
;
VALUE_BITSIZE (v
) = elt_size
* 8;
/* Check to see if either argument is a structure. This is called so
we know whether to go ahead with the normal binop or look for a
user defined function instead.
For now, we do not overload the `=' operator. */
binop_user_defined_p (op
, arg1
, arg2
)
return (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_STRUCT
|| TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_STRUCT
|| (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1
))) == TYPE_CODE_STRUCT
)
|| (TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2
))) == TYPE_CODE_STRUCT
));
/* Check to see if argument is a structure. This is called so
we know whether to go ahead with the normal unop or look for a
user defined function instead.
For now, we do not overload the `&' operator. */
int unop_user_defined_p (op
, arg1
)
return (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_STRUCT
|| (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1
))) == TYPE_CODE_STRUCT
));
/* We know either arg1 or arg2 is a structure, so try to find the right
user defined function. Create an argument vector that calls
arg1.operator @ (arg1,arg2) and return that value (where '@' is any
binary operator which is legal for GNU C++). */
value_x_binop (arg1
, arg2
, op
, otherop
)
/* now we know that what we have to do is construct our
arg vector and find the right function to call it with. */
if (TYPE_CODE (VALUE_TYPE (arg1
)) != TYPE_CODE_STRUCT
)
error ("friend functions not implemented yet");
argvec
= (value
*) alloca (sizeof (value
) * 4);
argvec
[1] = value_addr (arg1
);
/* make the right function name up */
strcpy(tstr
, "operator __");
case BINOP_ADD
: strcpy(ptr
,"+"); break;
case BINOP_SUB
: strcpy(ptr
,"-"); break;
case BINOP_MUL
: strcpy(ptr
,"*"); break;
case BINOP_DIV
: strcpy(ptr
,"/"); break;
case BINOP_REM
: strcpy(ptr
,"%"); break;
case BINOP_LSH
: strcpy(ptr
,"<<"); break;
case BINOP_RSH
: strcpy(ptr
,">>"); break;
case BINOP_LOGAND
: strcpy(ptr
,"&"); break;
case BINOP_LOGIOR
: strcpy(ptr
,"|"); break;
case BINOP_LOGXOR
: strcpy(ptr
,"^"); break;
case BINOP_AND
: strcpy(ptr
,"&&"); break;
case BINOP_OR
: strcpy(ptr
,"||"); break;
case BINOP_MIN
: strcpy(ptr
,"<?"); break;
case BINOP_MAX
: strcpy(ptr
,">?"); break;
case BINOP_ASSIGN
: strcpy(ptr
,"="); break;
case BINOP_ASSIGN_MODIFY
:
case BINOP_ADD
: strcpy(ptr
,"+="); break;
case BINOP_SUB
: strcpy(ptr
,"-="); break;
case BINOP_MUL
: strcpy(ptr
,"*="); break;
case BINOP_DIV
: strcpy(ptr
,"/="); break;
case BINOP_REM
: strcpy(ptr
,"%="); break;
case BINOP_LOGAND
: strcpy(ptr
,"&="); break;
case BINOP_LOGIOR
: strcpy(ptr
,"|="); break;
case BINOP_LOGXOR
: strcpy(ptr
,"^="); break;
error ("Invalid binary operation specified.");
case BINOP_SUBSCRIPT
: strcpy(ptr
,"[]"); break;
case BINOP_EQUAL
: strcpy(ptr
,"=="); break;
case BINOP_NOTEQUAL
: strcpy(ptr
,"!="); break;
case BINOP_LESS
: strcpy(ptr
,"<"); break;
case BINOP_GTR
: strcpy(ptr
,">"); break;
case BINOP_GEQ
: strcpy(ptr
,">="); break;
case BINOP_LEQ
: strcpy(ptr
,"<="); break;
error ("Invalid binary operation specified.");
argvec
[0] = value_struct_elt (arg1
, argvec
+1, tstr
, &static_memfuncp
, "structure");
return call_function (argvec
[0], 2 - static_memfuncp
, argvec
+ 1);
error ("member function %s not found", tstr
);
/* We know that arg1 is a structure, so try to find a unary user
defined operator that matches the operator in question.
Create an argument vector that calls arg1.operator @ (arg1)
and return that value (where '@' is (almost) any unary operator which
is legal for GNU C++). */
/* now we know that what we have to do is construct our
arg vector and find the right function to call it with. */
if (TYPE_CODE (VALUE_TYPE (arg1
)) != TYPE_CODE_STRUCT
)
error ("friend functions not implemented yet");
argvec
= (value
*) alloca (sizeof (value
) * 3);
argvec
[1] = value_addr (arg1
);
/* make the right function name up */
strcpy(tstr
,"operator __");
case UNOP_PREINCREMENT
: strcpy(ptr
,"++"); break;
case UNOP_PREDECREMENT
: strcpy(ptr
,"++"); break;
case UNOP_POSTINCREMENT
: strcpy(ptr
,"++"); break;
case UNOP_POSTDECREMENT
: strcpy(ptr
,"++"); break;
case UNOP_ZEROP
: strcpy(ptr
,"!"); break;
case UNOP_LOGNOT
: strcpy(ptr
,"~"); break;
case UNOP_NEG
: strcpy(ptr
,"-"); break;
error ("Invalid binary operation specified.");
argvec
[0] = value_struct_elt (arg1
, argvec
+1, tstr
, &static_memfuncp
, "structure");
return call_function (argvec
[0], 1 - static_memfuncp
, argvec
+ 1);
error ("member function %s not found", tstr
);
/* Perform a binary operation on two integers or two floats.
Does not support addition and subtraction on pointers;
use value_add or value_sub if you want to handle those possibilities. */
value_binop (arg1
, arg2
, op
)
if ((TYPE_CODE (VALUE_TYPE (arg1
)) != TYPE_CODE_FLT
TYPE_CODE (VALUE_TYPE (arg1
)) != TYPE_CODE_INT
)
(TYPE_CODE (VALUE_TYPE (arg2
)) != TYPE_CODE_FLT
TYPE_CODE (VALUE_TYPE (arg2
)) != TYPE_CODE_INT
))
error ("Argument to arithmetic operation not a number.");
if (TYPE_CODE (VALUE_TYPE (arg1
)) == TYPE_CODE_FLT
TYPE_CODE (VALUE_TYPE (arg2
)) == TYPE_CODE_FLT
)
v1
= value_as_double (arg1
);
v2
= value_as_double (arg2
);
error ("Integer-only operation on floating point number.");
val
= allocate_value (builtin_type_double
);
*(double *) VALUE_CONTENTS (val
) = v
;
/* Integral operations here. */
/* Should we promote to unsigned longest? */
if ((TYPE_UNSIGNED (VALUE_TYPE (arg1
))
|| TYPE_UNSIGNED (VALUE_TYPE (arg2
)))
&& (TYPE_LENGTH (VALUE_TYPE (arg1
)) >= sizeof (unsigned LONGEST
)
|| TYPE_LENGTH (VALUE_TYPE (arg2
)) >= sizeof (unsigned LONGEST
)))
unsigned LONGEST v1
, v2
, v
;
v1
= (unsigned LONGEST
) value_as_long (arg1
);
v2
= (unsigned LONGEST
) value_as_long (arg2
);
error ("Invalid binary operation on numbers.");
val
= allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST
);
*(unsigned LONGEST
*) VALUE_CONTENTS (val
) = v
;
v1
= value_as_long (arg1
);
v2
= value_as_long (arg2
);
error ("Invalid binary operation on numbers.");
val
= allocate_value (BUILTIN_TYPE_LONGEST
);
*(LONGEST
*) VALUE_CONTENTS (val
) = v
;
/* Simulate the C operator ! -- return 1 if ARG1 contains zeros. */
len
= TYPE_LENGTH (VALUE_TYPE (arg1
));
p
= VALUE_CONTENTS (arg1
);
/* Simulate the C operator == by returning a 1
iff ARG1 and ARG2 have equal contents. */
register value arg1
, arg2
;
code1
= TYPE_CODE (VALUE_TYPE (arg1
));
code2
= TYPE_CODE (VALUE_TYPE (arg2
));
if (code1
== TYPE_CODE_INT
&& code2
== TYPE_CODE_INT
)
return value_as_long (arg1
) == value_as_long (arg2
);
else if ((code1
== TYPE_CODE_FLT
|| code1
== TYPE_CODE_INT
)
&& (code2
== TYPE_CODE_FLT
|| code2
== TYPE_CODE_INT
))
return value_as_double (arg1
) == value_as_double (arg2
);
else if ((code1
== TYPE_CODE_PTR
&& code2
== TYPE_CODE_INT
)
|| (code2
== TYPE_CODE_PTR
&& code1
== TYPE_CODE_INT
))
return (char *) value_as_long (arg1
) == (char *) value_as_long (arg2
);
&& ((len
= TYPE_LENGTH (VALUE_TYPE (arg1
)))
== TYPE_LENGTH (VALUE_TYPE (arg2
))))
p1
= VALUE_CONTENTS (arg1
);
p2
= VALUE_CONTENTS (arg2
);
error ("Invalid type combination in equality test.");
/* Simulate the C operator < by returning 1
iff ARG1's contents are less than ARG2's. */
register value arg1
, arg2
;
register enum type_code code1
;
register enum type_code code2
;
code1
= TYPE_CODE (VALUE_TYPE (arg1
));
code2
= TYPE_CODE (VALUE_TYPE (arg2
));
if (code1
== TYPE_CODE_INT
&& code2
== TYPE_CODE_INT
)
return value_as_long (arg1
) < value_as_long (arg2
);
else if ((code1
== TYPE_CODE_FLT
|| code1
== TYPE_CODE_INT
)
&& (code2
== TYPE_CODE_FLT
|| code2
== TYPE_CODE_INT
))
return value_as_double (arg1
) < value_as_double (arg2
);
else if ((code1
== TYPE_CODE_PTR
|| code1
== TYPE_CODE_INT
)
&& (code2
== TYPE_CODE_PTR
|| code2
== TYPE_CODE_INT
))
return (char *) value_as_long (arg1
) < (char *) value_as_long (arg2
);
error ("Invalid type combination in ordering comparison.");
/* The unary operators - and ~. Both free the argument ARG1. */
register struct type
*type
;
type
= VALUE_TYPE (arg1
);
if (TYPE_CODE (type
) == TYPE_CODE_FLT
)
return value_from_double (type
, - value_as_double (arg1
));
else if (TYPE_CODE (type
) == TYPE_CODE_INT
)
return value_from_long (type
, - value_as_long (arg1
));
error ("Argument to negate operation not a number.");
if (TYPE_CODE (VALUE_TYPE (arg1
)) != TYPE_CODE_INT
)
error ("Argument to complement operation not an integer.");
return value_from_long (VALUE_TYPE (arg1
), ~ value_as_long (arg1
));