2001-10-24 Chris Demetriou <cgd@broadcom.com>
[deliverable/binutils-gdb.git] / gas / expr.c
index 1e785b2f277e5ca917c0cdf880eeccb190d03c65..74c49d9c7bf721aec4ea2ba9f690f9b38eb3196d 100644 (file)
@@ -1,5 +1,6 @@
 /* expr.c -operands, expressions-
 /* expr.c -operands, expressions-
-   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
    (It also gives smaller files to re-compile.)
    Here, "operand"s are of expressions, not instructions.  */
 
    (It also gives smaller files to re-compile.)
    Here, "operand"s are of expressions, not instructions.  */
 
-#include <ctype.h>
 #include <string.h>
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
 #include <string.h>
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
+#include "safe-ctype.h"
 #include "obstack.h"
 
 static void floating_constant PARAMS ((expressionS * expressionP));
 #include "obstack.h"
 
 static void floating_constant PARAMS ((expressionS * expressionP));
@@ -41,15 +42,14 @@ static void mri_char_constant PARAMS ((expressionS *));
 static void current_location PARAMS ((expressionS *));
 static void clean_up_expression PARAMS ((expressionS * expressionP));
 static segT operand PARAMS ((expressionS *));
 static void current_location PARAMS ((expressionS *));
 static void clean_up_expression PARAMS ((expressionS * expressionP));
 static segT operand PARAMS ((expressionS *));
-static operatorT operator PARAMS ((void));
+static operatorT operator PARAMS ((int *));
 
 extern const char EXP_CHARS[], FLT_CHARS[];
 
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
 
 
 extern const char EXP_CHARS[], FLT_CHARS[];
 
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
 
-struct expr_symbol_line
-{
+struct expr_symbol_line {
   struct expr_symbol_line *next;
   symbolS *sym;
   char *file;
   struct expr_symbol_line *next;
   symbolS *sym;
   char *file;
@@ -81,9 +81,9 @@ make_expr_symbol (expressionP)
          generic_floating_point_number or generic_bignum, and we are
          going to lose it if we haven't already.  */
       if (expressionP->X_add_number > 0)
          generic_floating_point_number or generic_bignum, and we are
          going to lose it if we haven't already.  */
       if (expressionP->X_add_number > 0)
-       as_bad (_("bignum invalid; zero assumed"));
+       as_bad (_("bignum invalid"));
       else
       else
-       as_bad (_("floating point number invalid; zero assumed"));
+       as_bad (_("floating point number invalid"));
       zero.X_op = O_constant;
       zero.X_add_number = 0;
       zero.X_unsigned = 0;
       zero.X_op = O_constant;
       zero.X_add_number = 0;
       zero.X_unsigned = 0;
@@ -105,7 +105,7 @@ make_expr_symbol (expressionP)
   symbol_set_value_expression (symbolP, expressionP);
 
   if (expressionP->X_op == O_constant)
   symbol_set_value_expression (symbolP, expressionP);
 
   if (expressionP->X_op == O_constant)
-    resolve_symbol_value (symbolP, 1);
+    resolve_symbol_value (symbolP);
 
   n = (struct expr_symbol_line *) xmalloc (sizeof *n);
   n->sym = symbolP;
 
   n = (struct expr_symbol_line *) xmalloc (sizeof *n);
   n->sym = symbolP;
@@ -217,13 +217,13 @@ expr_build_dot ()
    and never write into the early words, thus they'll always be zero.
    I hate Dean's floating-point code.  Bleh.  */
 LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6];
    and never write into the early words, thus they'll always be zero.
    I hate Dean's floating-point code.  Bleh.  */
 LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6];
-FLONUM_TYPE generic_floating_point_number =
-{
-  &generic_bignum[6],          /* Low.  (JF: Was 0)  */
-  &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* High.  JF: (added +6)  */
-  0,                           /* Leader.  */
-  0,                           /* Exponent.  */
-  0                            /* Sign.  */
+
+FLONUM_TYPE generic_floating_point_number = {
+  &generic_bignum[6],          /* low.  (JF: Was 0)  */
+  &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* high.  JF: (added +6)  */
+  0,                           /* leader.  */
+  0,                           /* exponent.  */
+  0                            /* sign.  */
 };
 
 /* If nonzero, we've been asked to assemble nan, +inf or -inf.  */
 };
 
 /* If nonzero, we've been asked to assemble nan, +inf or -inf.  */
@@ -243,11 +243,12 @@ floating_constant (expressionP)
     {
       if (error_code == ERROR_EXPONENT_OVERFLOW)
        {
     {
       if (error_code == ERROR_EXPONENT_OVERFLOW)
        {
-         as_bad (_("bad floating-point constant: exponent overflow, probably assembling junk"));
+         as_bad (_("bad floating-point constant: exponent overflow"));
        }
       else
        {
        }
       else
        {
-         as_bad (_("bad floating-point constant: unknown error code=%d."), error_code);
+         as_bad (_("bad floating-point constant: unknown error code=%d"),
+                 error_code);
        }
     }
   expressionP->X_op = O_big;
        }
     }
   expressionP->X_op = O_big;
@@ -330,9 +331,7 @@ integer_constant (radix, expressionP)
       /* In MRI mode, the number may have a suffix indicating the
          radix.  For that matter, it might actually be a floating
          point constant.  */
       /* In MRI mode, the number may have a suffix indicating the
          radix.  For that matter, it might actually be a floating
          point constant.  */
-      for (suffix = input_line_pointer;
-          isalnum ((unsigned char) *suffix);
-          suffix++)
+      for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++)
        {
          if (*suffix == 'e' || *suffix == 'E')
            flt = 1;
        {
          if (*suffix == 'e' || *suffix == 'E')
            flt = 1;
@@ -346,8 +345,7 @@ integer_constant (radix, expressionP)
       else
        {
          c = *--suffix;
       else
        {
          c = *--suffix;
-         if (islower ((unsigned char) c))
-           c = toupper (c);
+         c = TOUPPER (c);
          if (c == 'B')
            radix = 2;
          else if (c == 'D')
          if (c == 'B')
            radix = 2;
          else if (c == 'D')
@@ -427,7 +425,7 @@ integer_constant (radix, expressionP)
 
          /* Check for 8 digit per word max.  */
          if (ndigit > 8)
 
          /* Check for 8 digit per word max.  */
          if (ndigit > 8)
-           as_bad (_("A bignum with underscores may not have more than 8 hex digits in any word."));
+           as_bad (_("a 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.  */
 
          /* Add this chunk to the bignum.
             Shift things down 2 little digits.  */
@@ -450,7 +448,7 @@ integer_constant (radix, expressionP)
       assert (num_little_digits >= 4);
 
       if (num_little_digits != 8)
       assert (num_little_digits >= 4);
 
       if (num_little_digits != 8)
-       as_bad (_("A bignum with underscores must have exactly 4 words."));
+       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.  */
 
       /* We might have some leading zeros.  These can be trimmed to give
         us a change to fit this constant into a small number.  */
@@ -573,7 +571,7 @@ integer_constant (radix, expressionP)
              /* Either not seen or not defined.  */
              /* @@ Should print out the original string instead of
                 the parsed number.  */
              /* Either not seen or not defined.  */
              /* @@ Should print out the original string instead of
                 the parsed number.  */
-             as_bad (_("backw. ref to unknown label \"%d:\", 0 assumed."),
+             as_bad (_("backward ref to unknown label \"%d:\""),
                      (int) number);
              expressionP->X_op = O_constant;
            }
                      (int) number);
              expressionP->X_op = O_constant;
            }
@@ -632,12 +630,12 @@ integer_constant (radix, expressionP)
          number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1);
 #endif
          expressionP->X_add_number = number;
          number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1);
 #endif
          expressionP->X_add_number = number;
-         input_line_pointer--; /* Rstore following character.  */
+         input_line_pointer--; /* Restore following character.  */
        }                       /* Really just a number.  */
     }
   else
     {
        }                       /* Really just a number.  */
     }
   else
     {
-      /* not a small number */
+      /* Not a small number.  */
       expressionP->X_op = O_big;
       expressionP->X_add_number = number;      /* Number of littlenums.  */
       input_line_pointer--;    /* -> char following number.  */
       expressionP->X_op = O_big;
       expressionP->X_add_number = number;      /* Number of littlenums.  */
       input_line_pointer--;    /* -> char following number.  */
@@ -696,7 +694,7 @@ mri_char_constant (expressionP)
 
   if (i < 0)
     {
 
   if (i < 0)
     {
-      as_bad (_("Character constant too large"));
+      as_bad (_("character constant too large"));
       i = 0;
     }
 
       i = 0;
     }
 
@@ -761,7 +759,7 @@ current_location (expressionp)
 /* In: Input_line_pointer points to 1st char of operand, which may
        be a space.
 
 /* In: Input_line_pointer points to 1st char of operand, which may
        be a space.
 
-   Out:        A expressionS.
+   Out:        An expressionS.
        The operand may have been empty: in this case X_op == O_absent.
        Input_line_pointer->(next non-blank) char after operand.  */
 
        The operand may have been empty: in this case X_op == O_absent.
        Input_line_pointer->(next non-blank) char after operand.  */
 
@@ -785,7 +783,7 @@ operand (expressionP)
   /* Digits, assume it is a bignum.  */
 
   SKIP_WHITESPACE ();          /* Leading whitespace is part of operand.  */
   /* Digits, assume it is a bignum.  */
 
   SKIP_WHITESPACE ();          /* Leading whitespace is part of operand.  */
-  c = *input_line_pointer++;   /* input_line_pointer->past char in c.  */
+  c = *input_line_pointer++;   /* input_line_pointer -> past char in c.  */
 
   if (is_end_of_line[(unsigned char) c])
     goto eol;
 
   if (is_end_of_line[(unsigned char) c])
     goto eol;
@@ -810,6 +808,9 @@ operand (expressionP)
 
 #ifdef LITERAL_PREFIXDOLLAR_HEX
     case '$':
 
 #ifdef LITERAL_PREFIXDOLLAR_HEX
     case '$':
+      /* $L is the start of a local label, not a hex constant.  */
+      if (* input_line_pointer == 'L')
+      goto isname;
       integer_constant (16, expressionP);
       break;
 #endif
       integer_constant (16, expressionP);
       break;
 #endif
@@ -858,8 +859,7 @@ operand (expressionP)
            {
              input_line_pointer++;
              floating_constant (expressionP);
            {
              input_line_pointer++;
              floating_constant (expressionP);
-             expressionP->X_add_number =
-               -(isupper ((unsigned char) c) ? tolower (c) : c);
+             expressionP->X_add_number = - TOLOWER (c);
            }
          else
            {
            }
          else
            {
@@ -981,8 +981,7 @@ operand (expressionP)
        case 'G':
          input_line_pointer++;
          floating_constant (expressionP);
        case 'G':
          input_line_pointer++;
          floating_constant (expressionP);
-         expressionP->X_add_number =
-           -(isupper ((unsigned char) c) ? tolower (c) : c);
+         expressionP->X_add_number = - TOLOWER (c);
          break;
 
        case '$':
          break;
 
        case '$':
@@ -1010,7 +1009,7 @@ operand (expressionP)
 #ifdef RELAX_PAREN_GROUPING
          if (c != '(')
 #endif
 #ifdef RELAX_PAREN_GROUPING
          if (c != '(')
 #endif
-           as_bad (_("Missing '%c' assumed"), c == '(' ? ')' : ']');
+           as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
        }
       else
        input_line_pointer++;
        }
       else
        input_line_pointer++;
@@ -1069,7 +1068,7 @@ operand (expressionP)
            /* input_line_pointer -> char after operand.  */
            if (c == '-')
              {
            /* input_line_pointer -> char after operand.  */
            if (c == '-')
              {
-               expressionP->X_add_number = -expressionP->X_add_number;
+               expressionP->X_add_number = - expressionP->X_add_number;
                /* Notice: '-' may overflow: no warning is given.
                   This is compatible with other people's
                   assemblers.  Sigh.  */
                /* Notice: '-' may overflow: no warning is given.
                   This is compatible with other people's
                   assemblers.  Sigh.  */
@@ -1231,7 +1230,7 @@ operand (expressionP)
              specially in certain contexts.  If a name always has a
              specific value, it can often be handled by simply
              entering it in the symbol table.  */
              specially in certain contexts.  If a name always has a
              specific value, it can often be handled by simply
              entering it in the symbol table.  */
-         if (md_parse_name (name, expressionP))
+         if (md_parse_name (name, expressionP, &c))
            {
              *input_line_pointer = c;
              break;
            {
              *input_line_pointer = c;
              break;
@@ -1304,7 +1303,7 @@ operand (expressionP)
        {
          /* Let the target try to parse it.  Success is indicated by changing
             the X_op field to something other than O_absent and pointing
        {
          /* Let the target try to parse it.  Success is indicated by changing
             the X_op field to something other than O_absent and pointing
-            input_line_pointer passed the expression.  If it can't parse the
+            input_line_pointer past the expression.  If it can't parse the
             expression, X_op and input_line_pointer should be unchanged.  */
          expressionP->X_op = O_absent;
          --input_line_pointer;
             expression, X_op and input_line_pointer should be unchanged.  */
          expressionP->X_op = O_absent;
          --input_line_pointer;
@@ -1312,7 +1311,7 @@ operand (expressionP)
          if (expressionP->X_op == O_absent)
            {
              ++input_line_pointer;
          if (expressionP->X_op == O_absent)
            {
              ++input_line_pointer;
-             as_bad (_("Bad expression"));
+             as_bad (_("bad expression"));
              expressionP->X_op = O_constant;
              expressionP->X_add_number = 0;
            }
              expressionP->X_op = O_constant;
              expressionP->X_add_number = 0;
            }
@@ -1343,7 +1342,7 @@ operand (expressionP)
 \f
 /* Internal.  Simplify a struct expression for use by expr ().  */
 
 \f
 /* Internal.  Simplify a struct expression for use by expr ().  */
 
-/* In: address of a expressionS.
+/* In: address of an expressionS.
        The X_op field of the expressionS may only take certain values.
        Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
 
        The X_op field of the expressionS may only take certain values.
        Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
 
@@ -1400,7 +1399,7 @@ clean_up_expression (expressionP)
    Unary operators and parenthetical expressions are treated as operands.
    As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
 
    Unary operators and parenthetical expressions are treated as operands.
    As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
 
-   We used to do a aho/ullman shift-reduce parser, but the logic got so
+   We used to do an aho/ullman shift-reduce parser, but the logic got so
    warped that I flushed it and wrote a recursive-descent parser instead.
    Now things are stable, would anybody like to write a fast parser?
    Most expressions are either register (which does not even reach here)
    warped that I flushed it and wrote a recursive-descent parser instead.
    Now things are stable, would anybody like to write a fast parser?
    Most expressions are either register (which does not even reach here)
@@ -1418,9 +1417,8 @@ clean_up_expression (expressionP)
 #undef __
 #define __ O_illegal
 
 #undef __
 #define __ O_illegal
 
-static const operatorT op_encoding[256] =
-{                              /* Maps ASCII -> operators.  */
-
+/* Maps ASCII -> operators.  */
+static const operatorT op_encoding[256] = {
   __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
   __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
 
   __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
   __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
 
@@ -1457,22 +1455,21 @@ static const operatorT op_encoding[256] =
    0   operand, (expression)
    1   ||
    2   &&
    0   operand, (expression)
    1   ||
    2   &&
-   3   = <> < <= >= >
+   3   == <> < <= >= >
    4   + -
    5   used for * / % in MRI mode
    6   & ^ ! |
    7   * / % << >>
    8   unary - unary ~
 */
    4   + -
    5   used for * / % in MRI mode
    6   & ^ ! |
    7   * / % << >>
    8   unary - unary ~
 */
-static operator_rankT op_rank[] =
-{
+static operator_rankT op_rank[] = {
   0,   /* O_illegal */
   0,   /* O_absent */
   0,   /* O_constant */
   0,   /* O_symbol */
   0,   /* O_symbol_rva */
   0,   /* O_register */
   0,   /* O_illegal */
   0,   /* O_absent */
   0,   /* O_constant */
   0,   /* O_symbol */
   0,   /* O_symbol_rva */
   0,   /* O_register */
-  0,   /* O_bit */
+  0,   /* O_big */
   9,   /* O_uminus */
   9,   /* O_bit_not */
   9,   /* O_logical_not */
   9,   /* O_uminus */
   9,   /* O_bit_not */
   9,   /* O_logical_not */
@@ -1520,8 +1517,8 @@ static operator_rankT op_rank[] =
    mode.  Also, MRI uses a different bit_not operator, and this fixes
    that as well.  */
 
    mode.  Also, MRI uses a different bit_not operator, and this fixes
    that as well.  */
 
-#define STANDARD_MUL_PRECEDENCE (7)
-#define MRI_MUL_PRECEDENCE (5)
+#define STANDARD_MUL_PRECEDENCE 8
+#define MRI_MUL_PRECEDENCE 6
 
 void
 expr_set_precedence ()
 
 void
 expr_set_precedence ()
@@ -1555,17 +1552,19 @@ expr_begin ()
   }
 }
 \f
   }
 }
 \f
-/* Return the encoding for the operator at INPUT_LINE_POINTER.
-   Advance INPUT_LINE_POINTER to the last character in the operator
-   (i.e., don't change it for a single character operator).  */
+/* Return the encoding for the operator at INPUT_LINE_POINTER, and
+   sets NUM_CHARS to the number of characters in the operator.
+   Does not advance INPUT_LINE_POINTER.  */
 
 static inline operatorT
 
 static inline operatorT
-operator ()
+operator (num_chars)
+     int *num_chars;
 {
   int c;
   operatorT ret;
 
   c = *input_line_pointer & 0xff;
 {
   int c;
   operatorT ret;
 
   c = *input_line_pointer & 0xff;
+  *num_chars = 1;
 
   if (is_end_of_line[c])
     return O_illegal;
 
   if (is_end_of_line[c])
     return O_illegal;
@@ -1590,14 +1589,14 @@ operator ()
          ret = O_le;
          break;
        }
          ret = O_le;
          break;
        }
-      ++input_line_pointer;
+      *num_chars = 2;
       return ret;
 
     case '=':
       if (input_line_pointer[1] != '=')
        return op_encoding[c];
 
       return ret;
 
     case '=':
       if (input_line_pointer[1] != '=')
        return op_encoding[c];
 
-      ++input_line_pointer;
+      *num_chars = 2;
       return O_eq;
 
     case '>':
       return O_eq;
 
     case '>':
@@ -1612,7 +1611,7 @@ operator ()
          ret = O_ge;
          break;
        }
          ret = O_ge;
          break;
        }
-      ++input_line_pointer;
+      *num_chars = 2;
       return ret;
 
     case '!':
       return ret;
 
     case '!':
@@ -1623,21 +1622,21 @@ operator ()
            return O_bit_inclusive_or;
          return op_encoding[c];
        }
            return O_bit_inclusive_or;
          return op_encoding[c];
        }
-      ++input_line_pointer;
+      *num_chars = 2;
       return O_bit_exclusive_or;
 
     case '|':
       if (input_line_pointer[1] != '|')
        return op_encoding[c];
 
       return O_bit_exclusive_or;
 
     case '|':
       if (input_line_pointer[1] != '|')
        return op_encoding[c];
 
-      ++input_line_pointer;
+      *num_chars = 2;
       return O_logical_or;
 
     case '&':
       if (input_line_pointer[1] != '&')
        return op_encoding[c];
 
       return O_logical_or;
 
     case '&':
       if (input_line_pointer[1] != '&')
        return op_encoding[c];
 
-      ++input_line_pointer;
+      *num_chars = 2;
       return O_logical_and;
     }
 
       return O_logical_and;
     }
 
@@ -1656,6 +1655,7 @@ expr (rankarg, resultP)
   expressionS right;
   operatorT op_left;
   operatorT op_right;
   expressionS right;
   operatorT op_left;
   operatorT op_right;
+  int op_chars;
 
   know (rank >= 0);
 
 
   know (rank >= 0);
 
@@ -1664,12 +1664,12 @@ expr (rankarg, resultP)
   /* operand () gobbles spaces.  */
   know (*input_line_pointer != ' ');
 
   /* operand () gobbles spaces.  */
   know (*input_line_pointer != ' ');
 
-  op_left = operator ();
+  op_left = operator (&op_chars);
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
       segT rightseg;
 
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
       segT rightseg;
 
-      input_line_pointer++;    /* -> after 1st character of operator.  */
+      input_line_pointer += op_chars;  /* -> after operator.  */
 
       rightseg = expr (op_rank[(int) op_left], &right);
       if (right.X_op == O_absent)
 
       rightseg = expr (op_rank[(int) op_left], &right);
       if (right.X_op == O_absent)
@@ -1694,22 +1694,7 @@ expr (rankarg, resultP)
            }
        }
 
            }
        }
 
-      if (retval == undefined_section)
-       {
-         if (SEG_NORMAL (rightseg))
-           retval = rightseg;
-       }
-      else if (! SEG_NORMAL (retval))
-       retval = rightseg;
-      else if (SEG_NORMAL (rightseg)
-              && retval != rightseg
-#ifdef DIFF_EXPR_OK
-              && op_left != O_subtract
-#endif
-              )
-       as_bad (_("operation combines symbols in different segments"));
-
-      op_right = operator ();
+      op_right = operator (&op_chars);
 
       know (op_right == O_illegal
            || op_rank[(int) op_right] <= op_rank[(int) op_left]);
 
       know (op_right == O_illegal
            || op_rank[(int) op_right] <= op_rank[(int) op_left]);
@@ -1764,8 +1749,7 @@ expr (rankarg, resultP)
               && resultP->X_op == O_symbol
               && (symbol_get_frag (right.X_add_symbol)
                   == symbol_get_frag (resultP->X_add_symbol))
               && resultP->X_op == O_symbol
               && (symbol_get_frag (right.X_add_symbol)
                   == symbol_get_frag (resultP->X_add_symbol))
-              && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol)))
-
+              && SEG_NORMAL (rightseg))
        {
          resultP->X_add_number -= right.X_add_number;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
        {
          resultP->X_add_number -= right.X_add_number;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
@@ -1817,27 +1801,27 @@ expr (rankarg, resultP)
            case O_subtract:            resultP->X_add_number -= v; break;
            case O_eq:
              resultP->X_add_number =
            case O_subtract:            resultP->X_add_number -= v; break;
            case O_eq:
              resultP->X_add_number =
-               resultP->X_add_number == v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
              break;
            case O_ne:
              resultP->X_add_number =
              break;
            case O_ne:
              resultP->X_add_number =
-               resultP->X_add_number != v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number != v ? ~ (offsetT) 0 : 0;
              break;
            case O_lt:
              resultP->X_add_number =
              break;
            case O_lt:
              resultP->X_add_number =
-               resultP->X_add_number < v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number <  v ? ~ (offsetT) 0 : 0;
              break;
            case O_le:
              resultP->X_add_number =
              break;
            case O_le:
              resultP->X_add_number =
-               resultP->X_add_number <= v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number <= v ? ~ (offsetT) 0 : 0;
              break;
            case O_ge:
              resultP->X_add_number =
              break;
            case O_ge:
              resultP->X_add_number =
-               resultP->X_add_number >= v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number >= v ? ~ (offsetT) 0 : 0;
              break;
            case O_gt:
              resultP->X_add_number =
              break;
            case O_gt:
              resultP->X_add_number =
-               resultP->X_add_number > v ? ~(offsetT) 0 : 0;
+               resultP->X_add_number >  v ? ~ (offsetT) 0 : 0;
              break;
            case O_logical_and:
              resultP->X_add_number = resultP->X_add_number && v;
              break;
            case O_logical_and:
              resultP->X_add_number = resultP->X_add_number && v;
@@ -1860,7 +1844,14 @@ expr (rankarg, resultP)
          if (op_left == O_add)
            resultP->X_add_number += right.X_add_number;
          else if (op_left == O_subtract)
          if (op_left == O_add)
            resultP->X_add_number += right.X_add_number;
          else if (op_left == O_subtract)
-           resultP->X_add_number -= right.X_add_number;
+           {
+             resultP->X_add_number -= right.X_add_number;
+             if (retval == rightseg && SEG_NORMAL (retval))
+               {
+                 retval = absolute_section;
+                 rightseg = absolute_section;
+               }
+           }
        }
       else
        {
        }
       else
        {
@@ -1872,6 +1863,21 @@ expr (rankarg, resultP)
          resultP->X_unsigned = 1;
        }
 
          resultP->X_unsigned = 1;
        }
 
+      if (retval != rightseg)
+       {
+         if (! SEG_NORMAL (retval))
+           {
+             if (retval != undefined_section || SEG_NORMAL (rightseg))
+               retval = rightseg;
+           }
+         else if (SEG_NORMAL (rightseg)
+#ifdef DIFF_EXPR_OK
+                  && op_left != O_subtract
+#endif
+                  )
+           as_bad (_("operation combines symbols in different segments"));
+       }
+
       op_left = op_right;
     }                          /* While next operator is >= this rank.  */
 
       op_left = op_right;
     }                          /* While next operator is >= this rank.  */
 
This page took 0.030599 seconds and 4 git commands to generate.