Switch to GPLv3
[deliverable/binutils-gdb.git] / gas / expr.c
index c601b0af6986e89312ffcc6c2e018f2b328003ef..b88328502eebdddbd2250ebdb38c628dcbebb024 100644 (file)
@@ -1,13 +1,13 @@
 /* expr.c -operands, expressions-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -25,7 +25,6 @@
    (It also gives smaller files to re-compile.)
    Here, "operand"s are of expressions, not instructions.  */
 
-#include <string.h>
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
@@ -1003,11 +1002,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
     case '-':
     case '+':
       {
-       /* Do not accept ++e or --e as +(+e) or -(-e)
-          Disabled, since the preprocessor removes whitespace.  */
-       if (0 && (c == '-' || c == '+') && *input_line_pointer == c)
-         goto target_op;
-       
        operand (expressionP, mode);
        if (expressionP->X_op == O_constant)
          {
@@ -1291,7 +1285,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
        }
       else
        {
-       target_op:
          /* 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 past the expression.  If it can't parse the
@@ -1552,11 +1545,7 @@ operator (int *num_chars)
 
     case '+':
     case '-':
-      /* Do not allow a++b and a--b to be a + (+b) and a - (-b)
-        Disabled, since the preprocessor removes whitespace.  */
-      if (1 || input_line_pointer[1] != c)
-       return op_encoding[c];
-      return O_illegal;
+      return op_encoding[c];
 
     case '<':
       switch (input_line_pointer[1])
@@ -1647,7 +1636,7 @@ expr (int rankarg,                /* Larger # is higher rank.  */
   operatorT op_right;
   int op_chars;
 
-  know (rank >= 0);
+  know (rankarg >= 0);
 
   /* Save the value of dot for the fixup code.  */
   if (rank == 0)
@@ -1662,6 +1651,7 @@ expr (int rankarg,                /* Larger # is higher rank.  */
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
       segT rightseg;
+      bfd_vma frag_off;
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
@@ -1741,12 +1731,15 @@ expr (int rankarg,              /* Larger # is higher rank.  */
       else if (op_left == O_subtract
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
-              && (symbol_get_frag (right.X_add_symbol)
-                  == symbol_get_frag (resultP->X_add_symbol))
+              && retval == rightseg
               && (SEG_NORMAL (rightseg)
-                  || right.X_add_symbol == resultP->X_add_symbol))
+                  || right.X_add_symbol == resultP->X_add_symbol)
+              && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
+                                      symbol_get_frag (right.X_add_symbol),
+                                      &frag_off))
        {
          resultP->X_add_number -= right.X_add_number;
+         resultP->X_add_number -= frag_off / OCTETS_PER_BYTE;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
                                    - S_GET_VALUE (right.X_add_symbol));
          resultP->X_op = O_constant;
@@ -1792,7 +1785,9 @@ expr (int rankarg,                /* Larger # is higher rank.  */
            case O_bit_or_not:          resultP->X_add_number |= ~v; break;
            case O_bit_exclusive_or:    resultP->X_add_number ^= v; break;
            case O_bit_and:             resultP->X_add_number &= v; break;
-           case O_add:                 resultP->X_add_number += v; break;
+             /* Constant + constant (O_add) is handled by the
+                previous if statement for constant + X, so is omitted
+                here.  */
            case O_subtract:            resultP->X_add_number -= v; break;
            case O_eq:
              resultP->X_add_number =
@@ -1900,6 +1895,7 @@ resolve_expression (expressionS *expressionP)
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
+  bfd_vma frag_off;
 
   switch (op)
     {
@@ -1913,7 +1909,7 @@ resolve_expression (expressionS *expressionP)
 
     case O_symbol:
     case O_symbol_rva:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
        return 0;
 
       break;
@@ -1921,7 +1917,7 @@ resolve_expression (expressionS *expressionP)
     case O_uminus:
     case O_bit_not:
     case O_logical_not:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
        return 0;
 
       if (seg_left != absolute_section)
@@ -1955,8 +1951,8 @@ resolve_expression (expressionS *expressionP)
     case O_gt:
     case O_logical_and:
     case O_logical_or:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)
-         || !snapshot_symbol (op_symbol, &right, &seg_right, &frag_right))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)
+         || !snapshot_symbol (&op_symbol, &right, &seg_right, &frag_right))
        return 0;
 
       /* Simplify addition or subtraction of a constant by folding the
@@ -1974,7 +1970,7 @@ resolve_expression (expressionS *expressionP)
              final_val += left;
              left = right;
              seg_left = seg_right;
-             expressionP->X_add_symbol = expressionP->X_op_symbol;
+             add_symbol = op_symbol;
              op = O_symbol;
              break;
            }
@@ -1991,21 +1987,86 @@ resolve_expression (expressionS *expressionP)
 
       /* Equality and non-equality tests are permitted on anything.
         Subtraction, and other comparison operators are permitted if
-        both operands are in the same section.  Otherwise, both
-        operands must be absolute.  We already handled the case of
-        addition or subtraction of a constant above.  */
+        both operands are in the same section.
+        Shifts by constant zero are permitted on anything.
+        Multiplies, bit-ors, and bit-ands with constant zero are
+        permitted on anything.
+        Multiplies and divides by constant one are permitted on
+        anything.
+        Binary operations with both operands being the same register
+        or undefined symbol are permitted if the result doesn't depend
+        on the input value.
+        Otherwise, both operands must be absolute.  We already handled
+        the case of addition or subtraction of a constant above.  */
+      frag_off = 0;
       if (!(seg_left == absolute_section
               && seg_right == absolute_section)
          && !(op == O_eq || op == O_ne)
          && !((op == O_subtract
                || op == O_lt || op == O_le || op == O_ge || op == O_gt)
               && seg_left == seg_right
-              && (finalize_syms || frag_left == frag_right)
-              && ((seg_left != undefined_section
-                   && seg_left != reg_section)
-                  || add_symbol == op_symbol)))
-       return 0;
+              && (finalize_syms
+                  || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
+              && (seg_left != reg_section || left == right)
+              && (seg_left != undefined_section || add_symbol == op_symbol)))
+       {
+         if ((seg_left == absolute_section && left == 0)
+             || (seg_right == absolute_section && right == 0))
+           {
+             if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
+               {
+                 if (seg_right != absolute_section || right != 0)
+                   {
+                     seg_left = seg_right;
+                     left = right;
+                     add_symbol = op_symbol;
+                   }
+                 op = O_symbol;
+                 break;
+               }
+             else if (op == O_left_shift || op == O_right_shift)
+               {
+                 if (seg_left != absolute_section || left != 0)
+                   {
+                     op = O_symbol;
+                     break;
+                   }
+               }
+             else if (op != O_multiply
+                      && op != O_bit_or_not && op != O_bit_and)
+               return 0;
+           }
+         else if (op == O_multiply
+                  && seg_left == absolute_section && left == 1)
+           {
+             seg_left = seg_right;
+             left = right;
+             add_symbol = op_symbol;
+             op = O_symbol;
+             break;
+           }
+         else if ((op == O_multiply || op == O_divide)
+                  && seg_right == absolute_section && right == 1)
+           {
+             op = O_symbol;
+             break;
+           }
+         else if (left != right
+                  || ((seg_left != reg_section || seg_right != reg_section)
+                      && (seg_left != undefined_section
+                          || seg_right != undefined_section
+                          || add_symbol != op_symbol)))
+           return 0;
+         else if (op == O_bit_and || op == O_bit_inclusive_or)
+           {
+             op = O_symbol;
+             break;
+           }
+         else if (op != O_bit_exclusive_or && op != O_bit_or_not)
+           return 0;
+       }
 
+      right += frag_off / OCTETS_PER_BYTE;
       switch (op)
        {
        case O_add:                     left += right; break;
@@ -2032,8 +2093,7 @@ resolve_expression (expressionS *expressionP)
          left = (left == right
                  && seg_left == seg_right
                  && (finalize_syms || frag_left == frag_right)
-                 && ((seg_left != undefined_section
-                      && seg_left != reg_section)
+                 && (seg_left != undefined_section
                      || add_symbol == op_symbol)
                  ? ~ (valueT) 0 : 0);
          if (op == O_ne)
@@ -2066,6 +2126,9 @@ resolve_expression (expressionS *expressionP)
        op = O_constant;
       else if (seg_left == reg_section && final_val == 0)
        op = O_register;
+      else if (add_symbol != expressionP->X_add_symbol)
+       final_val += left;
+      expressionP->X_add_symbol = add_symbol;
     }
   expressionP->X_op = op;
 
This page took 0.046608 seconds and 4 git commands to generate.