aboutsummaryrefslogtreecommitdiff
path: root/gdb/valarith.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/valarith.c')
-rw-r--r--gdb/valarith.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/gdb/valarith.c b/gdb/valarith.c
new file mode 100644
index 0000000..03bc1e1
--- /dev/null
+++ b/gdb/valarith.c
@@ -0,0 +1,365 @@
+/* Perform arithmetic and other operations on values, for GDB.
+ Copyright (C) 1986 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "initialize.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+START_FILE
+
+value
+value_add (arg1, arg2)
+ value arg1, arg2;
+{
+ register value val, valint, valptr;
+ register int len;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ 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)
+ {
+ valptr = arg1;
+ valint = arg2;
+ }
+ else
+ {
+ valptr = arg2;
+ valint = arg1;
+ }
+ len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr)));
+ if (len == 0) len = 1; /* For (void *) */
+ val = value_from_long (builtin_type_long,
+ value_as_long (valptr)
+ + (len * value_as_long (valint)));
+ VALUE_TYPE (val) = VALUE_TYPE (valptr);
+ return val;
+ }
+
+ return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+value
+value_sub (arg1, arg2)
+ value arg1, arg2;
+{
+ register value val;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ val = value_from_long (builtin_type_long,
+ value_as_long (arg1)
+ - TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) * value_as_long (arg2));
+ VALUE_TYPE (val) = VALUE_TYPE (arg1);
+ return val;
+ }
+
+ 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 val;
+ }
+
+ return value_binop (arg1, arg2, BINOP_SUB);
+}
+
+/* Return the value of ARRAY[IDX]. */
+
+value
+value_subscript (array, idx)
+ value array, idx;
+{
+ return value_ind (value_add (array, idx));
+}
+
+/* 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
+value_binop (arg1, arg2, op)
+ value arg1, arg2;
+ int op;
+{
+ register value val;
+
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ 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)
+ {
+ double v1, v2, v;
+ v1 = value_as_double (arg1);
+ v2 = value_as_double (arg2);
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ default:
+ error ("Integer-only operation on floating point number.");
+ }
+
+ val = allocate_value (builtin_type_double);
+ *(double *) VALUE_CONTENTS (val) = v;
+ }
+ else
+ {
+ long v1, v2, v;
+ v1 = value_as_long (arg1);
+ v2 = value_as_long (arg2);
+
+ switch (op)
+ {
+ case BINOP_ADD:
+ v = v1 + v2;
+ break;
+
+ case BINOP_SUB:
+ v = v1 - v2;
+ break;
+
+ case BINOP_MUL:
+ v = v1 * v2;
+ break;
+
+ case BINOP_DIV:
+ v = v1 / v2;
+ break;
+
+ case BINOP_REM:
+ v = v1 % v2;
+ break;
+
+ case BINOP_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_LOGAND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_LOGIOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_LOGXOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_OR:
+ v = v1 || v2;
+ break;
+
+ default:
+ error ("Invalid binary operation on numbers.");
+ }
+
+ val = allocate_value (builtin_type_long);
+ *(long *) VALUE_CONTENTS (val) = v;
+ }
+
+ return val;
+}
+
+/* Simulate the C operator ! -- return 1 if ARG1 contains zeros. */
+
+int
+value_zerop (arg1)
+ value arg1;
+{
+ register int len;
+ register char *p;
+
+ COERCE_ARRAY (arg1);
+
+ len = TYPE_LENGTH (VALUE_TYPE (arg1));
+ p = VALUE_CONTENTS (arg1);
+
+ while (--len >= 0)
+ {
+ if (*p++)
+ break;
+ }
+
+ return len < 0;
+}
+
+/* Simulate the C operator == by returning a 1
+ iff ARG1 and ARG2 have equal contents. */
+
+int
+value_equal (arg1, arg2)
+ register value arg1, arg2;
+
+{
+ register int len;
+ register char *p1, *p2;
+ enum type_code code1;
+ enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (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 value_as_long (arg1) == value_as_long (arg2);
+ else if (code1 == code2
+ && ((len = TYPE_LENGTH (VALUE_TYPE (arg1)))
+ == TYPE_LENGTH (VALUE_TYPE (arg2))))
+ {
+ p1 = VALUE_CONTENTS (arg1);
+ p2 = VALUE_CONTENTS (arg2);
+ while (--len >= 0)
+ {
+ if (*p1++ != *p2++)
+ break;
+ }
+ return len < 0;
+ }
+ else
+ error ("Invalid type combination in equality test.");
+}
+
+/* Simulate the C operator < by returning 1
+ iff ARG1's contents are less than ARG2's. */
+
+int
+value_less (arg1, arg2)
+ register value arg1, arg2;
+{
+ register enum type_code code1;
+ register enum type_code code2;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (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 || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_PTR || code2 == TYPE_CODE_INT))
+ return value_as_long (arg1) < value_as_long (arg2);
+ else
+ error ("Invalid type combination in ordering comparison.");
+}
+
+/* The unary operators - and ~. Both free the argument ARG1. */
+
+value
+value_neg (arg1)
+ register value arg1;
+{
+ register struct type *type;
+
+ COERCE_ENUM (arg1);
+
+ 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));
+ else
+ error ("Argument to negate operation not a number.");
+}
+
+value
+value_lognot (arg1)
+ register value arg1;
+{
+ COERCE_ENUM (arg1);
+
+ 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));
+}
+
+static
+initialize ()
+{
+}
+
+END_FILE