diff options
-rw-r--r-- | gas/ChangeLog | 7 | ||||
-rw-r--r-- | gas/expr.c | 179 |
2 files changed, 171 insertions, 15 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index c40837e..6287213 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -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. @@ -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; } +/* 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); +} + /* * 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. */ |