2002-09-30 H.J. Lu <hjl@gnu.org>
[deliverable/binutils-gdb.git] / gas / expr.c
index 6d98a3456acc428c7f89f485ea41f6df25142e3d..68c4a788906fb2d7ccaed0ca3e19c3d8f517366d 100644 (file)
@@ -1,6 +1,6 @@
 /* expr.c -operands, expressions-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001
+   1999, 2000, 2001, 2002
    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.  */
 
-#include <ctype.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));
@@ -331,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.  */
-      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;
@@ -347,8 +345,7 @@ integer_constant (radix, expressionP)
       else
        {
          c = *--suffix;
-         if (islower ((unsigned char) c))
-           c = toupper (c);
+         c = TOUPPER (c);
          if (c == 'B')
            radix = 2;
          else if (c == 'D')
@@ -762,7 +759,7 @@ current_location (expressionp)
 /* 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.  */
 
@@ -806,11 +803,14 @@ operand (expressionP)
 
       integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
                        ? 0 : 10,
-                        expressionP);
+                       expressionP);
       break;
 
 #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
@@ -859,8 +859,7 @@ operand (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
            {
@@ -982,8 +981,7 @@ operand (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 '$':
@@ -1344,13 +1342,11 @@ operand (expressionP)
 \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.
 
    Out:        expressionS may have been modified:
-       'foo-foo' symbol references cancelled to 0, which changes X_op
-       from O_subtract to O_constant.
        Unused fields zeroed to help expr ().  */
 
 static void
@@ -1373,23 +1369,6 @@ clean_up_expression (expressionP)
     case O_bit_not:
       expressionP->X_op_symbol = NULL;
       break;
-    case O_subtract:
-      if (expressionP->X_op_symbol == expressionP->X_add_symbol
-         || ((symbol_get_frag (expressionP->X_op_symbol)
-              == symbol_get_frag (expressionP->X_add_symbol))
-             && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol))
-             && (S_GET_VALUE (expressionP->X_op_symbol)
-                 == S_GET_VALUE (expressionP->X_add_symbol))))
-       {
-         addressT diff = (S_GET_VALUE (expressionP->X_add_symbol)
-                          - S_GET_VALUE (expressionP->X_op_symbol));
-
-         expressionP->X_op = O_constant;
-         expressionP->X_add_symbol = NULL;
-         expressionP->X_op_symbol = NULL;
-         expressionP->X_add_number += diff;
-       }
-      break;
     default:
       break;
     }
@@ -1401,7 +1380,7 @@ clean_up_expression (expressionP)
    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)
@@ -1661,6 +1640,10 @@ expr (rankarg, resultP)
 
   know (rank >= 0);
 
+  /* Save the value of dot for the fixup code.  */
+  if (rank == 0)
+    dot_value = frag_now_fix ();
+
   retval = operand (resultP);
 
   /* operand () gobbles spaces.  */
@@ -1696,21 +1679,6 @@ 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_chars);
 
       know (op_right == O_illegal
@@ -1766,8 +1734,8 @@ expr (rankarg, resultP)
               && 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)
+                  || right.X_add_symbol == resultP->X_add_symbol))
        {
          resultP->X_add_number -= right.X_add_number;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
@@ -1862,7 +1830,14 @@ expr (rankarg, resultP)
          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
        {
@@ -1874,6 +1849,21 @@ expr (rankarg, resultP)
          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.  */
 
This page took 0.026664 seconds and 4 git commands to generate.