* expr.h (expr_build_uconstant): Add prototype.
authorDoug Evans <dje@google.com>
Wed, 25 Mar 1998 22:03:19 +0000 (22:03 +0000)
committerDoug Evans <dje@google.com>
Wed, 25 Mar 1998 22:03:19 +0000 (22:03 +0000)
(expr_build_unary,expr_build_binary): Add prototypes.
* expr.c (expr_build_uconstant): New function.
(expr_build_unary,expr_build_binary): New functions.

gas/ChangeLog
gas/expr.c

index c40837e0ccee6cc2e53d42222004695fb6f538a9..6287213cf2e17ea499b7e31fd8dcd6657d1b1393 100644 (file)
@@ -1,3 +1,10 @@
+Wed Mar 25 13:44:18 1998  Doug Evans  <devans@canuck.cygnus.com>
+
+       * expr.h (expr_build_uconstant): Add prototype.
+       (expr_build_unary,expr_build_binary): Add prototypes.
+       * expr.c (expr_build_uconstant): New function.
+       (expr_build_unary,expr_build_binary): New functions.
+
 Wed Mar 25 13:10:42 1998  Bruno Haible  <bruno@linuix.mathematik.uni-karlsruhe.de>
 
         * gasp.c (IS*): Cast argument to unsigned char, not unsigned int.
index 73f334f2af9ef5c6c1ed390fddab174434fc9674..34fe7fba69e811c269a588ae21c0bc0f734d90f4 100644 (file)
@@ -1,5 +1,5 @@
 /* expr.c -operands, expressions-
-   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
+   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997, 1998
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -28,6 +28,7 @@
 
 #include <ctype.h>
 #include <string.h>
+#define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
 #include "obstack.h"
@@ -121,6 +122,62 @@ expr_symbol_where (sym, pfile, pline)
   return 0;
 }
 \f
+/* Utilities for building expressions.
+   Since complex expressions are recorded as symbols for use in other
+   expressions these return a symbolS * and not an expressionS *.
+   These explicitly do not take an "add_number" argument.  */
+/* ??? For completeness' sake one might want expr_build_symbol.
+   It would just return its argument.  */
+
+/* Build an expression for an unsigned constant.
+   The corresponding one for signed constants is missing because
+   there's currently no need for it.  One could add an unsigned_p flag
+   but that seems more clumsy.  */
+
+symbolS *
+expr_build_uconstant (value)
+     offsetT value;
+{
+  expressionS e;
+
+  e.X_op = O_constant;
+  e.X_add_number = value;
+  e.X_unsigned = 1;
+  return make_expr_symbol (&e);
+}
+
+/* Build an expression for OP s1.  */
+
+symbolS *
+expr_build_unary (op, s1)
+     operatorT op;
+     symbolS *s1;
+{
+  expressionS e;
+
+  e.X_op = op;
+  e.X_add_symbol = s1;
+  e.X_add_number = 0;
+  return make_expr_symbol (&e);
+}
+
+/* Build an expression for s1 OP s2.  */
+
+symbolS *
+expr_build_binary (op, s1, s2)
+     operatorT op;
+     symbolS *s1;
+     symbolS *s2;
+{
+  expressionS e;
+
+  e.X_op = op;
+  e.X_add_symbol = s1;
+  e.X_op_symbol = s2;
+  e.X_add_number = 0;
+  return make_expr_symbol (&e);
+}
+\f
 /*
  * Build any floating-point literal here.
  * Also build any bignum literal here.
@@ -171,6 +228,32 @@ floating_constant (expressionP)
   expressionP->X_add_number = -1;
 }
 
+static valueT 
+generic_bignum_to_int32 () 
+{
+  valueT number =
+          ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+          | (generic_bignum[0] & LITTLENUM_MASK);
+  number &= 0xffffffff;
+  return number;
+}
+
+#ifdef BFD64
+static valueT 
+generic_bignum_to_int64 () 
+{
+  valueT number = 
+          ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK)
+                << LITTLENUM_NUMBER_OF_BITS)
+               | ((valueT) generic_bignum[2] & LITTLENUM_MASK))
+              << LITTLENUM_NUMBER_OF_BITS)
+             | ((valueT) generic_bignum[1] & LITTLENUM_MASK))
+            << LITTLENUM_NUMBER_OF_BITS)
+           | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
+  return number;
+}
+#endif
+
 static void
 integer_constant (radix, expressionP)
      int radix;
@@ -286,7 +369,83 @@ integer_constant (radix, expressionP)
   /* c contains character after number. */
   /* input_line_pointer->char after c. */
   small = (input_line_pointer - start - 1) < too_many_digits;
-  if (!small)
+
+  if (radix == 16 && c == '_') 
+    {
+      /* This is literal of the form 0x333_0_12345678_1.
+         This example is equivalent to 0x00000333000000001234567800000001.  */
+
+      int num_little_digits = 0;
+      int i;
+      input_line_pointer = start;      /*->1st digit. */
+
+      know (LITTLENUM_NUMBER_OF_BITS == 16);
+
+      for (c = '_'; c == '_'; num_little_digits+=2)
+       {
+
+         /* Convert one 64-bit word. */
+         int ndigit = 0; 
+         number = 0;
+         for (c = *input_line_pointer++;
+              (digit = hex_value (c)) < maxdig;
+              c = *(input_line_pointer++))
+           {
+             number = number * radix + digit;
+             ndigit++;
+           }
+
+         /* Check for 8 digit per word max.  */
+         if (ndigit > 8) 
+           as_bad ("An bignum with underscores may not have more than 8 hex digits in any word.");
+
+         /* Add this chunk to the bignum.  Shift things down 2 little digits.*/
+         know (LITTLENUM_NUMBER_OF_BITS == 16);
+         for (i = min (num_little_digits + 1, SIZE_OF_LARGE_NUMBER - 1); i >= 2; i--)
+           generic_bignum[i] = generic_bignum[i-2];
+
+         /* Add the new digits as the least significant new ones. */
+         generic_bignum[0] = number & 0xffffffff;
+         generic_bignum[1] = number >> 16;
+       }
+
+      /* Again, c is char after number, input_line_pointer->after c. */
+
+      if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1)
+       num_little_digits = SIZE_OF_LARGE_NUMBER - 1;
+
+      assert (num_little_digits >= 4);
+
+      if (num_little_digits != 8)
+       as_bad ("A bignum with underscores must have exactly 4 words.");
+
+      /* We might have some leading zeros.  These can be trimmed to give
+       * us a change to fit this constant into a small number.
+       */
+      while (generic_bignum[num_little_digits-1] == 0 && num_little_digits > 1)
+       num_little_digits--;
+       
+      if (num_little_digits <= 2)
+       {
+         /* will fit into 32 bits. */
+         number = generic_bignum_to_int32 ();
+         small = 1;
+       }
+#ifdef BFD64
+      else if (num_little_digits <= 4)
+       {
+         /* Will fit into 64 bits.  */
+         number = generic_bignum_to_int64 ();
+         small = 1;
+       }
+#endif
+      else
+       {
+         small = 0;
+         number = num_little_digits; /* number of littlenums in the bignum. */
+       }
+    }
+  else if (!small)
     {
       /*
        * we saw a lot of digits. manufacture a bignum the hard way.
@@ -331,24 +490,14 @@ integer_constant (radix, expressionP)
       if (leader < generic_bignum + 2)
        {
          /* will fit into 32 bits. */
-         number =
-           ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
-           | (generic_bignum[0] & LITTLENUM_MASK);
-         number &= 0xffffffff
+         number = generic_bignum_to_int32 ();
          small = 1;
        }
 #ifdef BFD64
       else if (leader < generic_bignum + 4)
        {
          /* Will fit into 64 bits.  */
-         number = 
-           ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK)
-                 << LITTLENUM_NUMBER_OF_BITS)
-                | ((valueT) generic_bignum[2] & LITTLENUM_MASK))
-               << LITTLENUM_NUMBER_OF_BITS)
-              | ((valueT) generic_bignum[1] & LITTLENUM_MASK))
-             << LITTLENUM_NUMBER_OF_BITS)
-            | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
+         number = generic_bignum_to_int64 ();
          small = 1;
        }
 #endif
@@ -1395,7 +1544,7 @@ operator ()
     }
 
   /*NOTREACHED*/
-}      
+}
 
 /* Parse an expression.  */