Fix pthread_setname_np build error
[deliverable/binutils-gdb.git] / gas / expr.c
index 69f0aaccdb64b42da016bf5ad54aa08b35c3b22f..16c89343a71b23ad3befd1d9ccb5c74765b286b7 100644 (file)
@@ -1,13 +1,11 @@
 /* expr.c -operands, expressions-
 /* expr.c -operands, expressions-
-   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 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
 
    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,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    (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 <string.h>
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
 #include "safe-ctype.h"
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
 #include "safe-ctype.h"
-#include "obstack.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+bfd_boolean literal_prefix_dollar_hex = FALSE;
 
 static void floating_constant (expressionS * expressionP);
 static valueT generic_bignum_to_int32 (void);
 
 static void floating_constant (expressionS * expressionP);
 static valueT generic_bignum_to_int32 (void);
@@ -39,12 +44,9 @@ static valueT generic_bignum_to_int64 (void);
 #endif
 static void integer_constant (int radix, expressionS * expressionP);
 static void mri_char_constant (expressionS *);
 #endif
 static void integer_constant (int radix, expressionS * expressionP);
 static void mri_char_constant (expressionS *);
-static void current_location (expressionS *);
 static void clean_up_expression (expressionS * expressionP);
 static segT operand (expressionS *, enum expr_mode);
 static void clean_up_expression (expressionS * expressionP);
 static segT operand (expressionS *, enum expr_mode);
-static operatorT operator (int *);
-
-extern const char EXP_CHARS[], FLT_CHARS[];
+static operatorT operatorf (int *);
 
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
 
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
@@ -52,7 +54,7 @@ extern const char EXP_CHARS[], FLT_CHARS[];
 struct expr_symbol_line {
   struct expr_symbol_line *next;
   symbolS *sym;
 struct expr_symbol_line {
   struct expr_symbol_line *next;
   symbolS *sym;
-  char *file;
+  const char *file;
   unsigned int line;
 };
 
   unsigned int line;
 };
 
@@ -85,6 +87,7 @@ make_expr_symbol (expressionS *expressionP)
       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;
+      zero.X_extrabit = 0;
       clean_up_expression (&zero);
       expressionP = &zero;
     }
       clean_up_expression (&zero);
       expressionP = &zero;
     }
@@ -96,16 +99,18 @@ make_expr_symbol (expressionS *expressionP)
   symbolP = symbol_create (FAKE_LABEL_NAME,
                           (expressionP->X_op == O_constant
                            ? absolute_section
   symbolP = symbol_create (FAKE_LABEL_NAME,
                           (expressionP->X_op == O_constant
                            ? absolute_section
-                           : expr_section),
+                           : expressionP->X_op == O_register
+                             ? reg_section
+                             : expr_section),
                           0, &zero_address_frag);
   symbol_set_value_expression (symbolP, expressionP);
 
   if (expressionP->X_op == O_constant)
     resolve_symbol_value (symbolP);
 
                           0, &zero_address_frag);
   symbol_set_value_expression (symbolP, expressionP);
 
   if (expressionP->X_op == O_constant)
     resolve_symbol_value (symbolP);
 
-  n = (struct expr_symbol_line *) xmalloc (sizeof *n);
+  n = XNEW (struct expr_symbol_line);
   n->sym = symbolP;
   n->sym = symbolP;
-  as_where (&n->file, &n->line);
+  n->file = as_where (&n->line);
   n->next = expr_symbol_lines;
   expr_symbol_lines = n;
 
   n->next = expr_symbol_lines;
   expr_symbol_lines = n;
 
@@ -117,9 +122,9 @@ make_expr_symbol (expressionS *expressionP)
    the symbol.  */
 
 int
    the symbol.  */
 
 int
-expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline)
+expr_symbol_where (symbolS *sym, const char **pfile, unsigned int *pline)
 {
 {
-  register struct expr_symbol_line *l;
+  struct expr_symbol_line *l;
 
   for (l = expr_symbol_lines; l != NULL; l = l->next)
     {
 
   for (l = expr_symbol_lines; l != NULL; l = l->next)
     {
@@ -154,6 +159,7 @@ expr_build_uconstant (offsetT value)
   e.X_op = O_constant;
   e.X_add_number = value;
   e.X_unsigned = 1;
   e.X_op = O_constant;
   e.X_add_number = value;
   e.X_unsigned = 1;
+  e.X_extrabit = 0;
   return make_expr_symbol (&e);
 }
 
   return make_expr_symbol (&e);
 }
 
@@ -165,7 +171,7 @@ expr_build_dot (void)
   expressionS e;
 
   current_location (&e);
   expressionS e;
 
   current_location (&e);
-  return make_expr_symbol (&e);
+  return symbol_clone_if_forward_ref (make_expr_symbol (&e));
 }
 \f
 /* Build any floating-point literal here.
 }
 \f
 /* Build any floating-point literal here.
@@ -279,6 +285,12 @@ integer_constant (int radix, expressionS *expressionP)
 #define valuesize 32
 #endif
 
 #define valuesize 32
 #endif
 
+  if (is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      expressionP->X_op = O_absent;
+      return;
+    }
+
   if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
     {
       int flt = 0;
   if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
     {
       int flt = 0;
@@ -403,7 +415,7 @@ integer_constant (int radix, expressionS *expressionP)
       if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1)
        num_little_digits = SIZE_OF_LARGE_NUMBER - 1;
 
       if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1)
        num_little_digits = SIZE_OF_LARGE_NUMBER - 1;
 
-      assert (num_little_digits >= 4);
+      gas_assert (num_little_digits >= 4);
 
       if (num_little_digits != 8)
        as_bad (_("a bignum with underscores must have exactly 4 words"));
 
       if (num_little_digits != 8)
        as_bad (_("a bignum with underscores must have exactly 4 words"));
@@ -498,6 +510,21 @@ integer_constant (int radix, expressionS *expressionP)
       && input_line_pointer - 1 == suffix)
     c = *input_line_pointer++;
 
       && input_line_pointer - 1 == suffix)
     c = *input_line_pointer++;
 
+#ifndef tc_allow_U_suffix
+#define tc_allow_U_suffix 1
+#endif
+  /* PR 19910: Look for, and ignore, a U suffix to the number.  */
+  if (tc_allow_U_suffix && (c == 'U' || c == 'u'))
+    c = * input_line_pointer++;
+
+#ifndef tc_allow_L_suffix
+#define tc_allow_L_suffix 1
+#endif
+  /* PR 20732: Look for, and ignore, a L or LL suffix to the number.  */
+  if (tc_allow_L_suffix)
+    while (c == 'L' || c == 'l')
+      c = * input_line_pointer++;
+
   if (small)
     {
       /* Here with number, in correct radix. c is the next char.
   if (small)
     {
       /* Here with number, in correct radix. c is the next char.
@@ -687,7 +714,7 @@ mri_char_constant (expressionS *expressionP)
 /* Return an expression representing the current location.  This
    handles the magic symbol `.'.  */
 
 /* Return an expression representing the current location.  This
    handles the magic symbol `.'.  */
 
-static void
+void
 current_location (expressionS *expressionp)
 {
   if (now_seg == absolute_section)
 current_location (expressionS *expressionp)
 {
   if (now_seg == absolute_section)
@@ -698,7 +725,7 @@ current_location (expressionS *expressionp)
   else
     {
       expressionp->X_op = O_symbol;
   else
     {
       expressionp->X_op = O_symbol;
-      expressionp->X_add_symbol = symbol_temp_new_now ();
+      expressionp->X_add_symbol = &dot_symbol;
       expressionp->X_add_number = 0;
     }
 }
       expressionp->X_add_number = 0;
     }
 }
@@ -725,6 +752,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
      something like ``.quad 0x80000000'' is not sign extended even
      though it appears negative if valueT is 32 bits.  */
   expressionP->X_unsigned = 1;
      something like ``.quad 0x80000000'' is not sign extended even
      though it appears negative if valueT is 32 bits.  */
   expressionP->X_unsigned = 1;
+  expressionP->X_extrabit = 0;
 
   /* Digits, assume it is a bignum.  */
 
 
   /* Digits, assume it is a bignum.  */
 
@@ -752,15 +780,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
                        expressionP);
       break;
 
                        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
-
 #ifdef LITERAL_PREFIXPERCENT_BIN
     case '%':
       integer_constant (2, expressionP);
 #ifdef LITERAL_PREFIXPERCENT_BIN
     case '%':
       integer_constant (2, expressionP);
@@ -825,32 +844,28 @@ operand (expressionS *expressionP, enum expr_mode mode)
          break;
 
        case 'b':
          break;
 
        case 'b':
-         if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX))
+         if (LOCAL_LABELS_FB && !flag_m68k_mri
+             && input_line_pointer[1] != '0'
+             && input_line_pointer[1] != '1')
            {
            {
-             /* This code used to check for '+' and '-' here, and, in
-                some conditions, fall through to call
-                integer_constant.  However, that didn't make sense,
-                as integer_constant only accepts digits.  */
-             /* Some of our code elsewhere does permit digits greater
-                than the expected base; for consistency, do the same
-                here.  */
-             if (input_line_pointer[1] < '0'
-                 || input_line_pointer[1] > '9')
-               {
-                 /* Parse this as a back reference to label 0.  */
-                 input_line_pointer--;
-                 integer_constant (10, expressionP);
-                 break;
-               }
-             /* Otherwise, parse this as a binary number.  */
+             /* Parse this as a back reference to label 0.  */
+             input_line_pointer--;
+             integer_constant (10, expressionP);
+             break;
            }
            }
+         /* Otherwise, parse this as a binary number.  */
          /* Fall through.  */
        case 'B':
          /* Fall through.  */
        case 'B':
-         input_line_pointer++;
+         if (input_line_pointer[1] == '0'
+             || input_line_pointer[1] == '1')
+           {
+             input_line_pointer++;
+             integer_constant (2, expressionP);
+             break;
+           }
          if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
          if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
-           goto default_case;
-         integer_constant (2, expressionP);
-         break;
+           input_line_pointer++;
+         goto default_case;
 
        case '0':
        case '1':
 
        case '0':
        case '1':
@@ -868,48 +883,35 @@ operand (expressionS *expressionP, enum expr_mode mode)
        case 'f':
          if (LOCAL_LABELS_FB)
            {
        case 'f':
          if (LOCAL_LABELS_FB)
            {
+             int is_label = 1;
+
              /* If it says "0f" and it could possibly be a floating point
                 number, make it one.  Otherwise, make it a local label,
                 and try to deal with parsing the rest later.  */
              /* If it says "0f" and it could possibly be a floating point
                 number, make it one.  Otherwise, make it a local label,
                 and try to deal with parsing the rest later.  */
-             if (!input_line_pointer[1]
-                 || (is_end_of_line[0xff & input_line_pointer[1]])
-                 || strchr (FLT_CHARS, 'f') == NULL)
-               goto is_0f_label;
-             {
-               char *cp = input_line_pointer + 1;
-               int r = atof_generic (&cp, ".", EXP_CHARS,
-                                     &generic_floating_point_number);
-               switch (r)
-                 {
-                 case 0:
-                 case ERROR_EXPONENT_OVERFLOW:
-                   if (*cp == 'f' || *cp == 'b')
-                     /* Looks like a difference expression.  */
-                     goto is_0f_label;
-                   else if (cp == input_line_pointer + 1)
-                     /* No characters has been accepted -- looks like
-                        end of operand.  */
-                     goto is_0f_label;
-                   else
-                     goto is_0f_float;
-                 default:
-                   as_fatal (_("expr.c(operand): bad atof_generic return val %d"),
-                             r);
-                 }
-             }
-
-             /* Okay, now we've sorted it out.  We resume at one of these
-                two labels, depending on what we've decided we're probably
-                looking at.  */
-           is_0f_label:
-             input_line_pointer--;
-             integer_constant (10, expressionP);
-             break;
-
-           is_0f_float:
-             /* Fall through.  */
-             ;
+             if (!is_end_of_line[(unsigned char) input_line_pointer[1]]
+                 && strchr (FLT_CHARS, 'f') != NULL)
+               {
+                 char *cp = input_line_pointer + 1;
+
+                 atof_generic (&cp, ".", EXP_CHARS,
+                               &generic_floating_point_number);
+
+                 /* Was nothing parsed, or does it look like an
+                    expression?  */
+                 is_label = (cp == input_line_pointer + 1
+                             || (cp == input_line_pointer + 2
+                                 && (cp[-1] == '-' || cp[-1] == '+'))
+                             || *cp == 'f'
+                             || *cp == 'b');
+               }
+             if (is_label)
+               {
+                 input_line_pointer--;
+                 integer_constant (10, expressionP);
+                 break;
+               }
            }
            }
+         /* Fall through.  */
 
        case 'd':
        case 'D':
 
        case 'd':
        case 'D':
@@ -942,19 +944,27 @@ operand (expressionS *expressionP, enum expr_mode mode)
 
       break;
 
 
       break;
 
-    case '(':
 #ifndef NEED_INDEX_OPERATOR
     case '[':
 #ifndef NEED_INDEX_OPERATOR
     case '[':
+# ifdef md_need_index_operator
+      if (md_need_index_operator())
+       goto de_fault;
+# endif
 #endif
 #endif
+      /* Fall through.  */
+    case '(':
       /* Didn't begin with digit & not a name.  */
       /* Didn't begin with digit & not a name.  */
-      if (mode != expr_defer)
-       segment = expression (expressionP);
-      else
-       segment = deferred_expression (expressionP);
+      segment = expr (0, expressionP, mode);
       /* expression () will pass trailing whitespace.  */
       if ((c == '(' && *input_line_pointer != ')')
          || (c == '[' && *input_line_pointer != ']'))
       /* expression () will pass trailing whitespace.  */
       if ((c == '(' && *input_line_pointer != ')')
          || (c == '[' && *input_line_pointer != ']'))
-       as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
+       {
+         if (* input_line_pointer)
+           as_bad (_("found '%c', expected: '%c'"),
+                   * input_line_pointer, c == '(' ? ')' : ']');
+         else
+           as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
+       }           
       else
        input_line_pointer++;
       SKIP_WHITESPACE ();
       else
        input_line_pointer++;
       SKIP_WHITESPACE ();
@@ -971,8 +981,8 @@ operand (expressionS *expressionP, enum expr_mode mode)
       if (! flag_m68k_mri || *input_line_pointer != '\'')
        goto de_fault;
       ++input_line_pointer;
       if (! flag_m68k_mri || *input_line_pointer != '\'')
        goto de_fault;
       ++input_line_pointer;
-      /* Fall through.  */
 #endif
 #endif
+      /* Fall through.  */
     case '\'':
       if (! flag_m68k_mri)
        {
     case '\'':
       if (! flag_m68k_mri)
        {
@@ -993,32 +1003,34 @@ operand (expressionS *expressionP, enum expr_mode mode)
       /* Double quote is the bitwise not operator in MRI mode.  */
       if (! flag_m68k_mri)
        goto de_fault;
       /* Double quote is the bitwise not operator in MRI mode.  */
       if (! flag_m68k_mri)
        goto de_fault;
-      /* Fall through.  */
 #endif
 #endif
+      /* Fall through.  */
     case '~':
       /* '~' is permitted to start a label on the Delta.  */
       if (is_name_beginner (c))
        goto isname;
     case '~':
       /* '~' is permitted to start a label on the Delta.  */
       if (is_name_beginner (c))
        goto isname;
+      /* Fall through.  */
     case '!':
     case '-':
     case '+':
       {
     case '!':
     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;
-       
+#ifdef md_operator
+      unary:
+#endif
        operand (expressionP, mode);
        if (expressionP->X_op == O_constant)
          {
            /* input_line_pointer -> char after operand.  */
            if (c == '-')
              {
        operand (expressionP, mode);
        if (expressionP->X_op == O_constant)
          {
            /* input_line_pointer -> char after operand.  */
            if (c == '-')
              {
-               expressionP->X_add_number = - expressionP->X_add_number;
+               expressionP->X_add_number
+                 = - (addressT) expressionP->X_add_number;
                /* Notice: '-' may overflow: no warning is given.
                   This is compatible with other people's
                   assemblers.  Sigh.  */
                expressionP->X_unsigned = 0;
                /* Notice: '-' may overflow: no warning is given.
                   This is compatible with other people's
                   assemblers.  Sigh.  */
                expressionP->X_unsigned = 0;
+               if (expressionP->X_add_number)
+                 expressionP->X_extrabit ^= 1;
              }
            else if (c == '~' || c == '"')
              expressionP->X_add_number = ~ expressionP->X_add_number;
              }
            else if (c == '~' || c == '"')
              expressionP->X_add_number = ~ expressionP->X_add_number;
@@ -1046,6 +1058,15 @@ operand (expressionS *expressionP, enum expr_mode mode)
              {
                for (i = 0; i < expressionP->X_add_number; ++i)
                  generic_bignum[i] = ~generic_bignum[i];
              {
                for (i = 0; i < expressionP->X_add_number; ++i)
                  generic_bignum[i] = ~generic_bignum[i];
+
+               /* Extend the bignum to at least the size of .octa.  */
+               if (expressionP->X_add_number < SIZE_OF_LARGE_NUMBER)
+                 {
+                   expressionP->X_add_number = SIZE_OF_LARGE_NUMBER;
+                   for (; i < expressionP->X_add_number; ++i)
+                     generic_bignum[i] = ~(LITTLENUM_TYPE) 0;
+                 }
+
                if (c == '-')
                  for (i = 0; i < expressionP->X_add_number; ++i)
                    {
                if (c == '-')
                  for (i = 0; i < expressionP->X_add_number; ++i)
                    {
@@ -1056,14 +1077,13 @@ operand (expressionS *expressionP, enum expr_mode mode)
              }
            else if (c == '!')
              {
              }
            else if (c == '!')
              {
-               int nonzero = 0;
                for (i = 0; i < expressionP->X_add_number; ++i)
                for (i = 0; i < expressionP->X_add_number; ++i)
-                 {
-                   if (generic_bignum[i])
-                     nonzero = 1;
-                   generic_bignum[i] = 0;
-                 }
-               generic_bignum[0] = nonzero;
+                 if (generic_bignum[i] != 0)
+                   break;
+               expressionP->X_add_number = i >= expressionP->X_add_number;
+               expressionP->X_op = O_constant;
+               expressionP->X_unsigned = 1;
+               expressionP->X_extrabit = 0;
              }
          }
        else if (expressionP->X_op != O_illegal
              }
          }
        else if (expressionP->X_op != O_illegal
@@ -1087,7 +1107,21 @@ operand (expressionS *expressionP, enum expr_mode mode)
       }
       break;
 
       }
       break;
 
-#if defined (DOLLAR_DOT) || defined (TC_M68K)
+#if !defined (DOLLAR_DOT) && !defined (TC_M68K)
+    case '$':
+      if (literal_prefix_dollar_hex)
+       {
+         /* $L is the start of a local label, not a hex constant.  */
+         if (* input_line_pointer == 'L')
+               goto isname;
+         integer_constant (16, expressionP);
+       }
+      else
+       {
+         goto isname;
+       }
+      break;
+#else
     case '$':
       /* '$' is the program counter when in MRI mode, or when
         DOLLAR_DOT is defined.  */
     case '$':
       /* '$' is the program counter when in MRI mode, or when
         DOLLAR_DOT is defined.  */
@@ -1127,6 +1161,10 @@ operand (expressionS *expressionP, enum expr_mode mode)
                   || input_line_pointer[1] == 'T');
          input_line_pointer += start ? 8 : 7;
          SKIP_WHITESPACE ();
                   || input_line_pointer[1] == 'T');
          input_line_pointer += start ? 8 : 7;
          SKIP_WHITESPACE ();
+
+         /* Cover for the as_bad () invocations below.  */
+         expressionP->X_op = O_absent;
+
          if (*input_line_pointer != '(')
            as_bad (_("syntax error in .startof. or .sizeof."));
          else
          if (*input_line_pointer != '(')
            as_bad (_("syntax error in .startof. or .sizeof."));
          else
@@ -1135,14 +1173,20 @@ operand (expressionS *expressionP, enum expr_mode mode)
 
              ++input_line_pointer;
              SKIP_WHITESPACE ();
 
              ++input_line_pointer;
              SKIP_WHITESPACE ();
-             name = input_line_pointer;
-             c = get_symbol_end ();
+             c = get_symbol_name (& name);
+             if (! *name)
+               {
+                 as_bad (_("expected symbol name"));
+                 (void) restore_line_pointer (c);
+                 if (c != ')')
+                   ignore_rest_of_line ();
+                 else
+                   ++input_line_pointer;
+                 break;
+               }
 
 
-             buf = (char *) xmalloc (strlen (name) + 10);
-             if (start)
-               sprintf (buf, ".startof.%s", name);
-             else
-               sprintf (buf, ".sizeof.%s", name);
+             buf = concat (start ? ".startof." : ".sizeof.", name,
+                           (char *) NULL);
              symbolP = symbol_make (buf);
              free (buf);
 
              symbolP = symbol_make (buf);
              free (buf);
 
@@ -1151,7 +1195,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
              expressionP->X_add_number = 0;
 
              *input_line_pointer = c;
              expressionP->X_add_number = 0;
 
              *input_line_pointer = c;
-             SKIP_WHITESPACE ();
+             SKIP_WHITESPACE_AFTER_NAME ();
              if (*input_line_pointer != ')')
                as_bad (_("syntax error in .startof. or .sizeof."));
              else
              if (*input_line_pointer != ')')
                as_bad (_("syntax error in .startof. or .sizeof."));
              else
@@ -1204,16 +1248,54 @@ operand (expressionS *expressionP, enum expr_mode mode)
 #endif
 
     default:
 #endif
 
     default:
-#ifdef TC_M68K
+#if defined(md_need_index_operator) || defined(TC_M68K)
     de_fault:
 #endif
     de_fault:
 #endif
-      if (is_name_beginner (c))        /* Here if did not begin with a digit.  */
+      if (is_name_beginner (c) || c == '"')    /* Here if did not begin with a digit.  */
        {
          /* Identifier begins here.
             This is kludged for speed, so code is repeated.  */
        isname:
        {
          /* Identifier begins here.
             This is kludged for speed, so code is repeated.  */
        isname:
-         name = --input_line_pointer;
-         c = get_symbol_end ();
+         -- input_line_pointer;
+         c = get_symbol_name (&name);
+
+#ifdef md_operator
+         {
+           operatorT op = md_operator (name, 1, &c);
+
+           switch (op)
+             {
+             case O_uminus:
+               restore_line_pointer (c);
+               c = '-';
+               goto unary;
+             case O_bit_not:
+               restore_line_pointer (c);
+               c = '~';
+               goto unary;
+             case O_logical_not:
+               restore_line_pointer (c);
+               c = '!';
+               goto unary;
+             case O_illegal:
+               as_bad (_("invalid use of operator \"%s\""), name);
+               break;
+             default:
+               break;
+             }
+
+           if (op != O_absent && op != O_illegal)
+             {
+               restore_line_pointer (c);
+               expr (9, expressionP, mode);
+               expressionP->X_add_symbol = make_expr_symbol (expressionP);
+               expressionP->X_op_symbol = NULL;
+               expressionP->X_add_number = 0;
+               expressionP->X_op = op;
+               break;
+             }
+         }
+#endif
 
 #ifdef md_parse_name
          /* This is a hook for the backend to parse certain names
 
 #ifdef md_parse_name
          /* This is a hook for the backend to parse certain names
@@ -1222,46 +1304,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
             entering it in the symbol table.  */
          if (md_parse_name (name, expressionP, mode, &c))
            {
             entering it in the symbol table.  */
          if (md_parse_name (name, expressionP, mode, &c))
            {
-             *input_line_pointer = c;
-             break;
-           }
-#endif
-
-#ifdef TC_I960
-         /* The MRI i960 assembler permits
-                lda sizeof code,g13
-            FIXME: This should use md_parse_name.  */
-         if (flag_mri
-             && (strcasecmp (name, "sizeof") == 0
-                 || strcasecmp (name, "startof") == 0))
-           {
-             int start;
-             char *buf;
-
-             start = (name[1] == 't'
-                      || name[1] == 'T');
-
-             *input_line_pointer = c;
-             SKIP_WHITESPACE ();
-
-             name = input_line_pointer;
-             c = get_symbol_end ();
-
-             buf = (char *) xmalloc (strlen (name) + 10);
-             if (start)
-               sprintf (buf, ".startof.%s", name);
-             else
-               sprintf (buf, ".sizeof.%s", name);
-             symbolP = symbol_make (buf);
-             free (buf);
-
-             expressionP->X_op = O_symbol;
-             expressionP->X_add_symbol = symbolP;
-             expressionP->X_add_number = 0;
-
-             *input_line_pointer = c;
-             SKIP_WHITESPACE ();
-
+             restore_line_pointer (c);
              break;
            }
 #endif
              break;
            }
 #endif
@@ -1271,7 +1314,9 @@ operand (expressionS *expressionP, enum expr_mode mode)
          /* If we have an absolute symbol or a reg, then we know its
             value now.  */
          segment = S_GET_SEGMENT (symbolP);
          /* If we have an absolute symbol or a reg, then we know its
             value now.  */
          segment = S_GET_SEGMENT (symbolP);
-         if (mode != expr_defer && segment == absolute_section)
+         if (mode != expr_defer
+             && segment == absolute_section
+             && !S_FORCE_RELOC (symbolP, 0))
            {
              expressionP->X_op = O_constant;
              expressionP->X_add_number = S_GET_VALUE (symbolP);
            {
              expressionP->X_op = O_constant;
              expressionP->X_add_number = S_GET_VALUE (symbolP);
@@ -1287,11 +1332,11 @@ operand (expressionS *expressionP, enum expr_mode mode)
              expressionP->X_add_symbol = symbolP;
              expressionP->X_add_number = 0;
            }
              expressionP->X_add_symbol = symbolP;
              expressionP->X_add_number = 0;
            }
-         *input_line_pointer = c;
+
+         restore_line_pointer (c);
        }
       else
        {
        }
       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
          /* 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
@@ -1313,15 +1358,20 @@ operand (expressionS *expressionP, enum expr_mode mode)
   /* It is more 'efficient' to clean up the expressionS when they are
      created.  Doing it here saves lines of code.  */
   clean_up_expression (expressionP);
   /* It is more 'efficient' to clean up the expressionS when they are
      created.  Doing it here saves lines of code.  */
   clean_up_expression (expressionP);
-  SKIP_WHITESPACE ();          /* -> 1st char after operand.  */
+  SKIP_ALL_WHITESPACE ();              /* -> 1st char after operand.  */
   know (*input_line_pointer != ' ');
 
   /* The PA port needs this information.  */
   if (expressionP->X_add_symbol)
     symbol_mark_used (expressionP->X_add_symbol);
 
   know (*input_line_pointer != ' ');
 
   /* The PA port needs this information.  */
   if (expressionP->X_add_symbol)
     symbol_mark_used (expressionP->X_add_symbol);
 
-  expressionP->X_add_symbol = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
-  expressionP->X_op_symbol = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+  if (mode != expr_defer)
+    {
+      expressionP->X_add_symbol
+       = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
+      expressionP->X_op_symbol
+       = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+    }
 
   switch (expressionP->X_op)
     {
 
   switch (expressionP->X_op)
     {
@@ -1439,7 +1489,7 @@ static const operatorT op_encoding[256] = {
    7   * / % << >>
    8   unary - unary ~
 */
    7   * / % << >>
    8   unary - unary ~
 */
-static operator_rankT op_rank[] = {
+static operator_rankT op_rank[O_max] = {
   0,   /* O_illegal */
   0,   /* O_absent */
   0,   /* O_constant */
   0,   /* O_illegal */
   0,   /* O_absent */
   0,   /* O_constant */
@@ -1470,22 +1520,6 @@ static operator_rankT op_rank[] = {
   3,   /* O_logical_and */
   2,   /* O_logical_or */
   1,   /* O_index */
   3,   /* O_logical_and */
   2,   /* O_logical_or */
   1,   /* O_index */
-  0,   /* O_md1 */
-  0,   /* O_md2 */
-  0,   /* O_md3 */
-  0,   /* O_md4 */
-  0,   /* O_md5 */
-  0,   /* O_md6 */
-  0,   /* O_md7 */
-  0,   /* O_md8 */
-  0,   /* O_md9 */
-  0,   /* O_md10 */
-  0,   /* O_md11 */
-  0,   /* O_md12 */
-  0,   /* O_md13 */
-  0,   /* O_md14 */
-  0,   /* O_md15 */
-  0,   /* O_md16 */
 };
 
 /* Unfortunately, in MRI mode for the m68k, multiplication and
 };
 
 /* Unfortunately, in MRI mode for the m68k, multiplication and
@@ -1514,6 +1548,13 @@ expr_set_precedence (void)
     }
 }
 
     }
 }
 
+void
+expr_set_rank (operatorT op, operator_rankT rank)
+{
+  gas_assert (op >= O_md1 && op < ARRAY_SIZE (op_rank));
+  op_rank[op] = rank;
+}
+
 /* Initialize the expression parser.  */
 
 void
 /* Initialize the expression parser.  */
 
 void
@@ -1525,7 +1566,7 @@ expr_begin (void)
   {
     expressionS e;
     e.X_op = O_max;
   {
     expressionS e;
     e.X_op = O_max;
-    assert (e.X_op == O_max);
+    gas_assert (e.X_op == O_max);
   }
 }
 \f
   }
 }
 \f
@@ -1534,7 +1575,7 @@ expr_begin (void)
    Does not advance INPUT_LINE_POINTER.  */
 
 static inline operatorT
    Does not advance INPUT_LINE_POINTER.  */
 
 static inline operatorT
-operator (int *num_chars)
+operatorf (int *num_chars)
 {
   int c;
   operatorT ret;
 {
   int c;
   operatorT ret;
@@ -1545,18 +1586,54 @@ operator (int *num_chars)
   if (is_end_of_line[c])
     return O_illegal;
 
   if (is_end_of_line[c])
     return O_illegal;
 
+#ifdef md_operator
+  if (is_name_beginner (c))
+    {
+      char *name;
+      char ec = get_symbol_name (& name);
+
+      ret = md_operator (name, 2, &ec);
+      switch (ret)
+       {
+       case O_absent:
+         *input_line_pointer = ec;
+         input_line_pointer = name;
+         break;
+       case O_uminus:
+       case O_bit_not:
+       case O_logical_not:
+         as_bad (_("invalid use of operator \"%s\""), name);
+         ret = O_illegal;
+         /* FALLTHROUGH */
+       default:
+         *input_line_pointer = ec;
+         *num_chars = input_line_pointer - name;
+         input_line_pointer = name;
+         return ret;
+       }
+    }
+#endif
+
   switch (c)
     {
     default:
   switch (c)
     {
     default:
-      return op_encoding[c];
+      ret = op_encoding[c];
+#ifdef md_operator
+      if (ret == O_illegal)
+       {
+         char *start = input_line_pointer;
+
+         ret = md_operator (NULL, 2, NULL);
+         if (ret != O_illegal)
+           *num_chars = input_line_pointer - start;
+         input_line_pointer = start;
+       }
+#endif
+      return ret;
 
     case '+':
     case '-':
 
     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])
 
     case '<':
       switch (input_line_pointer[1])
@@ -1633,6 +1710,42 @@ operator (int *num_chars)
   /* NOTREACHED  */
 }
 
   /* NOTREACHED  */
 }
 
+/* Implement "word-size + 1 bit" addition for
+   {resultP->X_extrabit:resultP->X_add_number} + {rhs_highbit:amount}.  This
+   is used so that the full range of unsigned word values and the full range of
+   signed word values can be represented in an O_constant expression, which is
+   useful e.g. for .sleb128 directives.  */
+
+void
+add_to_result (expressionS *resultP, offsetT amount, int rhs_highbit)
+{
+  valueT ures = resultP->X_add_number;
+  valueT uamount = amount;
+
+  resultP->X_add_number += amount;
+
+  resultP->X_extrabit ^= rhs_highbit;
+
+  if (ures + uamount < ures)
+    resultP->X_extrabit ^= 1;
+}
+
+/* Similarly, for subtraction.  */
+
+void
+subtract_from_result (expressionS *resultP, offsetT amount, int rhs_highbit)
+{
+  valueT ures = resultP->X_add_number;
+  valueT uamount = amount;
+
+  resultP->X_add_number -= amount;
+
+  resultP->X_extrabit ^= rhs_highbit;
+
+  if (ures < uamount)
+    resultP->X_extrabit ^= 1;
+}
+
 /* Parse an expression.  */
 
 segT
 /* Parse an expression.  */
 
 segT
@@ -1647,25 +1760,29 @@ expr (int rankarg,              /* Larger # is higher rank.  */
   operatorT op_right;
   int op_chars;
 
   operatorT op_right;
   int op_chars;
 
-  know (rank >= 0);
+  know (rankarg >= 0);
 
   /* Save the value of dot for the fixup code.  */
   if (rank == 0)
 
   /* Save the value of dot for the fixup code.  */
   if (rank == 0)
-    dot_value = frag_now_fix ();
+    {
+      dot_value = frag_now_fix ();
+      dot_frag = frag_now;
+    }
 
   retval = operand (resultP, mode);
 
   /* operand () gobbles spaces.  */
   know (*input_line_pointer != ' ');
 
 
   retval = operand (resultP, mode);
 
   /* operand () gobbles spaces.  */
   know (*input_line_pointer != ' ');
 
-  op_left = operator (&op_chars);
+  op_left = operatorf (&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;
-      bfd_vma frag_off;
+      offsetT frag_off;
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
+      right.X_md = 0;
       rightseg = expr (op_rank[(int) op_left], &right, mode);
       if (right.X_op == O_absent)
        {
       rightseg = expr (op_rank[(int) op_left], &right, mode);
       if (right.X_op == O_absent)
        {
@@ -1689,12 +1806,16 @@ expr (int rankarg,              /* Larger # is higher rank.  */
            }
        }
 
            }
        }
 
-      op_right = operator (&op_chars);
+      op_right = operatorf (&op_chars);
 
 
-      know (op_right == O_illegal
+      know (op_right == O_illegal || op_left == O_index
            || op_rank[(int) op_right] <= op_rank[(int) op_left]);
            || op_rank[(int) op_right] <= op_rank[(int) op_left]);
-      know ((int) op_left >= (int) O_multiply
-           && (int) op_left <= (int) O_index);
+      know ((int) op_left >= (int) O_multiply);
+#ifndef md_operator
+      know ((int) op_left <= (int) O_index);
+#else
+      know ((int) op_left < (int) O_max);
+#endif
 
       /* input_line_pointer->after right-hand quantity.  */
       /* left-hand quantity in resultP.  */
 
       /* input_line_pointer->after right-hand quantity.  */
       /* left-hand quantity in resultP.  */
@@ -1724,6 +1845,13 @@ expr (int rankarg,               /* Larger # is higher rank.  */
          right.X_op_symbol = NULL;
        }
 
          right.X_op_symbol = NULL;
        }
 
+      if (mode == expr_defer
+         && ((resultP->X_add_symbol != NULL
+              && S_IS_FORWARD_REF (resultP->X_add_symbol))
+             || (right.X_add_symbol != NULL
+                 && S_IS_FORWARD_REF (right.X_add_symbol))))
+       goto general;
+
       /* Optimize common cases.  */
 #ifdef md_optimize_expr
       if (md_optimize_expr (resultP, op_left, &right))
       /* Optimize common cases.  */
 #ifdef md_optimize_expr
       if (md_optimize_expr (resultP, op_left, &right))
@@ -1733,41 +1861,53 @@ expr (int rankarg,              /* Larger # is higher rank.  */
        }
       else
 #endif
        }
       else
 #endif
-      if (op_left == O_add && right.X_op == O_constant)
+#ifndef md_register_arithmetic
+# define md_register_arithmetic 1
+#endif
+      if (op_left == O_add && right.X_op == O_constant
+         && (md_register_arithmetic || resultP->X_op != O_register))
        {
          /* X + constant.  */
        {
          /* X + constant.  */
-         resultP->X_add_number += right.X_add_number;
+         add_to_result (resultP, right.X_add_number, right.X_extrabit);
        }
       /* This case comes up in PIC code.  */
       else if (op_left == O_subtract
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
               && retval == rightseg
        }
       /* This case comes up in PIC code.  */
       else if (op_left == O_subtract
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
               && retval == rightseg
-              && (SEG_NORMAL (rightseg)
+#ifdef md_allow_local_subtract
+              && md_allow_local_subtract (resultP, & right, rightseg)
+#endif
+              && ((SEG_NORMAL (rightseg)
+                   && !S_FORCE_RELOC (resultP->X_add_symbol, 0)
+                   && !S_FORCE_RELOC (right.X_add_symbol, 0))
                   || 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))
        {
                   || 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));
+         offsetT symval_diff = S_GET_VALUE (resultP->X_add_symbol)
+                               - S_GET_VALUE (right.X_add_symbol);
+         subtract_from_result (resultP, right.X_add_number, right.X_extrabit);
+         subtract_from_result (resultP, frag_off / OCTETS_PER_BYTE, 0);
+         add_to_result (resultP, symval_diff, symval_diff < 0);
          resultP->X_op = O_constant;
          resultP->X_add_symbol = 0;
        }
          resultP->X_op = O_constant;
          resultP->X_add_symbol = 0;
        }
-      else if (op_left == O_subtract && right.X_op == O_constant)
+      else if (op_left == O_subtract && right.X_op == O_constant
+              && (md_register_arithmetic || resultP->X_op != O_register))
        {
          /* X - constant.  */
        {
          /* X - constant.  */
-         resultP->X_add_number -= right.X_add_number;
+         subtract_from_result (resultP, right.X_add_number, right.X_extrabit);
        }
        }
-      else if (op_left == O_add && resultP->X_op == O_constant)
+      else if (op_left == O_add && resultP->X_op == O_constant
+              && (md_register_arithmetic || right.X_op != O_register))
        {
          /* Constant + X.  */
          resultP->X_op = right.X_op;
          resultP->X_add_symbol = right.X_add_symbol;
          resultP->X_op_symbol = right.X_op_symbol;
        {
          /* Constant + X.  */
          resultP->X_op = right.X_op;
          resultP->X_add_symbol = right.X_add_symbol;
          resultP->X_op_symbol = right.X_op_symbol;
-         resultP->X_add_number += right.X_add_number;
+         add_to_result (resultP, right.X_add_number, right.X_extrabit);
          retval = rightseg;
        }
       else if (resultP->X_op == O_constant && right.X_op == O_constant)
          retval = rightseg;
        }
       else if (resultP->X_op == O_constant && right.X_op == O_constant)
@@ -1779,9 +1919,17 @@ expr (int rankarg,               /* Larger # is higher rank.  */
              as_warn (_("division by zero"));
              v = 1;
            }
              as_warn (_("division by zero"));
              v = 1;
            }
+         if ((valueT) v >= sizeof(valueT) * CHAR_BIT
+             && (op_left == O_left_shift || op_left == O_right_shift))
+           {
+             as_warn_value_out_of_range (_("shift count"), v, 0,
+                                         sizeof(valueT) * CHAR_BIT - 1,
+                                         NULL, 0);
+             resultP->X_add_number = v = 0;
+           }
          switch (op_left)
            {
          switch (op_left)
            {
-           default:                    abort ();
+           default:                    goto general;
            case O_multiply:            resultP->X_add_number *= v; break;
            case O_divide:              resultP->X_add_number /= v; break;
            case O_modulus:             resultP->X_add_number %= v; break;
            case O_multiply:            resultP->X_add_number *= v; break;
            case O_divide:              resultP->X_add_number /= v; break;
            case O_modulus:             resultP->X_add_number %= v; break;
@@ -1796,8 +1944,12 @@ 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_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;
-           case O_subtract:            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:
+             subtract_from_result (resultP, v, 0);
+             break;
            case O_eq:
              resultP->X_add_number =
                resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
            case O_eq:
              resultP->X_add_number =
                resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
@@ -1841,11 +1993,15 @@ expr (int rankarg,              /* Larger # is higher rank.  */
          resultP->X_op = op_left;
          resultP->X_op_symbol = right.X_add_symbol;
          if (op_left == O_add)
          resultP->X_op = op_left;
          resultP->X_op_symbol = right.X_add_symbol;
          if (op_left == O_add)
-           resultP->X_add_number += right.X_add_number;
+           add_to_result (resultP, right.X_add_number, right.X_extrabit);
          else if (op_left == O_subtract)
            {
          else if (op_left == O_subtract)
            {
-             resultP->X_add_number -= right.X_add_number;
-             if (retval == rightseg && SEG_NORMAL (retval))
+             subtract_from_result (resultP, right.X_add_number,
+                                   right.X_extrabit);
+             if (retval == rightseg
+                 && SEG_NORMAL (retval)
+                 && !S_FORCE_RELOC (resultP->X_add_symbol, 0)
+                 && !S_FORCE_RELOC (right.X_add_symbol, 0))
                {
                  retval = absolute_section;
                  rightseg = absolute_section;
                {
                  retval = absolute_section;
                  rightseg = absolute_section;
@@ -1854,26 +2010,39 @@ expr (int rankarg,              /* Larger # is higher rank.  */
        }
       else
        {
        }
       else
        {
+        general:
          /* The general case.  */
          resultP->X_add_symbol = make_expr_symbol (resultP);
          resultP->X_op_symbol = make_expr_symbol (&right);
          resultP->X_op = op_left;
          resultP->X_add_number = 0;
          resultP->X_unsigned = 1;
          /* The general case.  */
          resultP->X_add_symbol = make_expr_symbol (resultP);
          resultP->X_op_symbol = make_expr_symbol (&right);
          resultP->X_op = op_left;
          resultP->X_add_number = 0;
          resultP->X_unsigned = 1;
+         resultP->X_extrabit = 0;
        }
 
       if (retval != rightseg)
        {
        }
 
       if (retval != rightseg)
        {
-         if (! SEG_NORMAL (retval))
-           {
-             if (retval != undefined_section || SEG_NORMAL (rightseg))
-               retval = rightseg;
-           }
-         else if (SEG_NORMAL (rightseg)
+         if (retval == undefined_section)
+           ;
+         else if (rightseg == undefined_section)
+           retval = rightseg;
+         else if (retval == expr_section)
+           ;
+         else if (rightseg == expr_section)
+           retval = rightseg;
+         else if (retval == reg_section)
+           ;
+         else if (rightseg == reg_section)
+           retval = rightseg;
+         else if (rightseg == absolute_section)
+           ;
+         else if (retval == absolute_section)
+           retval = rightseg;
 #ifdef DIFF_EXPR_OK
 #ifdef DIFF_EXPR_OK
-                  && op_left != O_subtract
+         else if (op_left == O_subtract)
+           ;
 #endif
 #endif
-                  )
+         else
            as_bad (_("operation combines symbols in different segments"));
        }
 
            as_bad (_("operation combines symbols in different segments"));
        }
 
@@ -1899,12 +2068,13 @@ resolve_expression (expressionS *expressionP)
   /* Help out with CSE.  */
   valueT final_val = expressionP->X_add_number;
   symbolS *add_symbol = expressionP->X_add_symbol;
   /* Help out with CSE.  */
   valueT final_val = expressionP->X_add_number;
   symbolS *add_symbol = expressionP->X_add_symbol;
+  symbolS *orig_add_symbol = add_symbol;
   symbolS *op_symbol = expressionP->X_op_symbol;
   operatorT op = expressionP->X_op;
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
   symbolS *op_symbol = expressionP->X_op_symbol;
   operatorT op = expressionP->X_op;
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
-  bfd_vma frag_off;
+  offsetT frag_off;
 
   switch (op)
     {
 
   switch (op)
     {
@@ -1980,6 +2150,7 @@ resolve_expression (expressionS *expressionP)
              left = right;
              seg_left = seg_right;
              add_symbol = op_symbol;
              left = right;
              seg_left = seg_right;
              add_symbol = op_symbol;
+             orig_add_symbol = expressionP->X_op_symbol;
              op = O_symbol;
              break;
            }
              op = O_symbol;
              break;
            }
@@ -2015,7 +2186,10 @@ resolve_expression (expressionS *expressionP)
                || op == O_lt || op == O_le || op == O_ge || op == O_gt)
               && seg_left == seg_right
               && (finalize_syms
                || op == O_lt || op == O_le || op == O_ge || op == O_gt)
               && seg_left == seg_right
               && (finalize_syms
-                  || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
+                  || frag_offset_fixed_p (frag_left, frag_right, &frag_off)
+                  || (op == O_gt
+                      && frag_gtoffset_p (left, frag_left,
+                                          right, frag_right, &frag_off)))
               && (seg_left != reg_section || left == right)
               && (seg_left != undefined_section || add_symbol == op_symbol)))
        {
               && (seg_left != reg_section || left == right)
               && (seg_left != undefined_section || add_symbol == op_symbol)))
        {
@@ -2024,18 +2198,19 @@ resolve_expression (expressionS *expressionP)
            {
              if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
                {
            {
              if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
                {
-                 if (seg_right != absolute_section || right != 0)
+                 if (!(seg_right == absolute_section && right == 0))
                    {
                      seg_left = seg_right;
                      left = right;
                      add_symbol = op_symbol;
                    {
                      seg_left = seg_right;
                      left = right;
                      add_symbol = op_symbol;
+                     orig_add_symbol = expressionP->X_op_symbol;
                    }
                  op = O_symbol;
                  break;
                }
              else if (op == O_left_shift || op == O_right_shift)
                {
                    }
                  op = O_symbol;
                  break;
                }
              else if (op == O_left_shift || op == O_right_shift)
                {
-                 if (seg_left != absolute_section || left != 0)
+                 if (!(seg_left == absolute_section && left == 0))
                    {
                      op = O_symbol;
                      break;
                    {
                      op = O_symbol;
                      break;
@@ -2051,6 +2226,7 @@ resolve_expression (expressionS *expressionP)
              seg_left = seg_right;
              left = right;
              add_symbol = op_symbol;
              seg_left = seg_right;
              left = right;
              add_symbol = op_symbol;
+             orig_add_symbol = expressionP->X_op_symbol;
              op = O_symbol;
              break;
            }
              op = O_symbol;
              break;
            }
@@ -2060,11 +2236,11 @@ resolve_expression (expressionS *expressionP)
              op = O_symbol;
              break;
            }
              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)))
+         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)
            {
            return 0;
          else if (op == O_bit_and || op == O_bit_inclusive_or)
            {
@@ -2135,7 +2311,7 @@ resolve_expression (expressionS *expressionP)
        op = O_constant;
       else if (seg_left == reg_section && final_val == 0)
        op = O_register;
        op = O_constant;
       else if (seg_left == reg_section && final_val == 0)
        op = O_register;
-      else if (add_symbol != expressionP->X_add_symbol)
+      else if (!symbol_same_p (add_symbol, orig_add_symbol))
        final_val += left;
       expressionP->X_add_symbol = add_symbol;
     }
        final_val += left;
       expressionP->X_add_symbol = add_symbol;
     }
@@ -2152,31 +2328,63 @@ resolve_expression (expressionS *expressionP)
    expr.c is just a branch office read.c anyway, and putting it
    here lessens the crowd at read.c.
 
    expr.c is just a branch office read.c anyway, and putting it
    here lessens the crowd at read.c.
 
-   Assume input_line_pointer is at start of symbol name.
+   Assume input_line_pointer is at start of symbol name, or the
+    start of a double quote enclosed symbol name.
    Advance input_line_pointer past symbol name.
    Advance input_line_pointer past symbol name.
-   Turn that character into a '\0', returning its former value.
+   Turn that character into a '\0', returning its former value,
+    which may be the closing double quote.
    This allows a string compare (RMS wants symbol names to be strings)
    This allows a string compare (RMS wants symbol names to be strings)
-   of the symbol name.
+    of the symbol name.
    There will always be a char following symbol name, because all good
    lines end in end-of-line.  */
 
 char
    There will always be a char following symbol name, because all good
    lines end in end-of-line.  */
 
 char
-get_symbol_end (void)
+get_symbol_name (char ** ilp_return)
 {
   char c;
 
 {
   char c;
 
-  /* We accept \001 in a name in case this is being called with a
+  * ilp_return = input_line_pointer;
+  /* We accept FAKE_LABEL_CHAR in a name in case this is being called with a
      constructed string.  */
      constructed string.  */
-  if (is_name_beginner (c = *input_line_pointer++) || c == '\001')
+  if (is_name_beginner (c = *input_line_pointer++)
+      || (input_from_string && c == FAKE_LABEL_CHAR))
     {
       while (is_part_of_name (c = *input_line_pointer++)
     {
       while (is_part_of_name (c = *input_line_pointer++)
-            || c == '\001')
+            || (input_from_string && c == FAKE_LABEL_CHAR))
        ;
       if (is_name_ender (c))
        c = *input_line_pointer++;
     }
        ;
       if (is_name_ender (c))
        c = *input_line_pointer++;
     }
+  else if (c == '"')
+    {
+      bfd_boolean backslash_seen;
+
+      * ilp_return = input_line_pointer;
+      do
+       {
+         backslash_seen = c == '\\';
+         c = * input_line_pointer ++;
+       }
+      while (c != 0 && (c != '"' || backslash_seen));
+
+      if (c == 0)
+       as_warn (_("missing closing '\"'"));
+    }
   *--input_line_pointer = 0;
   *--input_line_pointer = 0;
-  return (c);
+  return c;
+}
+
+/* Replace the NUL character pointed to by input_line_pointer
+   with C.  If C is \" then advance past it.  Return the character
+   now pointed to by input_line_pointer.  */
+
+char
+restore_line_pointer (char c)
+{
+  * input_line_pointer = c;
+  if (c == '"')
+    c = * ++ input_line_pointer;
+  return c;
 }
 
 unsigned int
 }
 
 unsigned int
This page took 0.04178 seconds and 4 git commands to generate.