[GOLD] PowerPC relaxation corner case
[platform/upstream/binutils.git] / gas / cond.c
index 025ca51..3b9b450 100644 (file)
@@ -1,12 +1,11 @@
 /* cond.c - conditional assembly pseudo-ops, and .include
 /* cond.c - conditional assembly pseudo-ops, and .include
-   Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 98, 99, 2000
-   Free Software Foundation, Inc.
+   Copyright (C) 1990-2014 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,
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include "as.h"
 
 #include "as.h"
+#include "sb.h"
 #include "macro.h"
 
 #include "obstack.h"
 
 #include "macro.h"
 
 #include "obstack.h"
 
-/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */
+/* This is allocated to grow and shrink as .ifdef/.endif pairs are
+   scanned.  */
 struct obstack cond_obstack;
 
 struct obstack cond_obstack;
 
-struct file_line
-{
+struct file_line {
   char *file;
   unsigned int line;
 };
   char *file;
   unsigned int line;
 };
@@ -36,8 +36,7 @@ struct file_line
 /* We push one of these structures for each .if, and pop it at the
    .endif.  */
 
 /* We push one of these structures for each .if, and pop it at the
    .endif.  */
 
-struct conditional_frame
-{
+struct conditional_frame {
   /* The source file & line number of the "if".  */
   struct file_line if_file_line;
   /* The source file & line of the "else".  */
   /* The source file & line number of the "if".  */
   struct file_line if_file_line;
   /* The source file & line of the "else".  */
@@ -48,26 +47,34 @@ struct conditional_frame
   int else_seen;
   /* Whether we are currently ignoring input.  */
   int ignoring;
   int else_seen;
   /* Whether we are currently ignoring input.  */
   int ignoring;
-  /* Whether a conditional at a higher level is ignoring input.  */
+  /* Whether a conditional at a higher level is ignoring input.
+     Set also when a branch of an "if .. elseif .." tree has matched
+     to prevent further matches.  */
   int dead_tree;
   /* Macro nesting level at which this conditional was created.  */
   int macro_nest;
 };
 
   int dead_tree;
   /* Macro nesting level at which this conditional was created.  */
   int macro_nest;
 };
 
-static void initialize_cframe PARAMS ((struct conditional_frame *cframe));
-static char *get_mri_string PARAMS ((int, int *));
+static void initialize_cframe (struct conditional_frame *cframe);
+static char *get_mri_string (int, int *);
 
 static struct conditional_frame *current_cframe = NULL;
 
 
 static struct conditional_frame *current_cframe = NULL;
 
-void 
-s_ifdef (arg)
-     int arg;
+/* Performs the .ifdef (test_defined == 1) and
+   the .ifndef (test_defined == 0) pseudo op.  */
+
+void
+s_ifdef (int test_defined)
 {
 {
-  register char *name;         /* points to name of symbol */
-  register symbolS *symbolP;   /* Points to symbol */
+  /* Points to name of symbol.  */
+  char *name;
+  /* Points to symbol.  */
+  symbolS *symbolP;
   struct conditional_frame cframe;
   struct conditional_frame cframe;
+  char c;
 
 
-  SKIP_WHITESPACE ();          /* Leading whitespace is part of operand. */
+  /* Leading whitespace is part of operand.  */
+  SKIP_WHITESPACE ();
   name = input_line_pointer;
 
   if (!is_name_beginner (*name))
   name = input_line_pointer;
 
   if (!is_name_beginner (*name))
@@ -75,34 +82,47 @@ s_ifdef (arg)
       as_bad (_("invalid identifier for \".ifdef\""));
       obstack_1grow (&cond_obstack, 0);
       ignore_rest_of_line ();
       as_bad (_("invalid identifier for \".ifdef\""));
       obstack_1grow (&cond_obstack, 0);
       ignore_rest_of_line ();
+      return;
     }
     }
+
+  c = get_symbol_end ();
+  symbolP = symbol_find (name);
+  *input_line_pointer = c;
+
+  initialize_cframe (&cframe);
+
+  if (cframe.dead_tree)
+    cframe.ignoring = 1;
   else
     {
   else
     {
-      char c;
+      int is_defined;
 
 
-      c = get_symbol_end ();
-      symbolP = symbol_find (name);
-      *input_line_pointer = c;
+      /* Use the same definition of 'defined' as .equiv so that a symbol
+        which has been referenced but not yet given a value/address is
+        considered to be undefined.  */
+      is_defined =
+       symbolP != NULL
+       && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
+       && S_GET_SEGMENT (symbolP) != reg_section;
 
 
-      initialize_cframe (&cframe);
-      cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg);
-      current_cframe = ((struct conditional_frame *)
-                       obstack_copy (&cond_obstack, &cframe,
-                                     sizeof (cframe)));
+      cframe.ignoring = ! (test_defined ^ is_defined);
+    }
 
 
-      if (LISTING_SKIP_COND ()
-         && cframe.ignoring
-         && (cframe.previous_cframe == NULL
-             || ! cframe.previous_cframe->ignoring))
-       listing_list (2);
+  current_cframe = ((struct conditional_frame *)
+                   obstack_copy (&cond_obstack, &cframe,
+                                 sizeof (cframe)));
 
 
-      demand_empty_rest_of_line ();
-    }                          /* if a valid identifyer name */
-}                              /* s_ifdef() */
+  if (LISTING_SKIP_COND ()
+      && cframe.ignoring
+      && (cframe.previous_cframe == NULL
+         || ! cframe.previous_cframe->ignoring))
+    listing_list (2);
 
 
-void 
-s_if (arg)
-     int arg;
+  demand_empty_rest_of_line ();
+}
+
+void
+s_if (int arg)
 {
   expressionS operand;
   struct conditional_frame cframe;
 {
   expressionS operand;
   struct conditional_frame cframe;
@@ -113,7 +133,8 @@ s_if (arg)
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
   if (flag_mri)
     stop = mri_comment_field (&stopc);
 
-  SKIP_WHITESPACE ();          /* Leading whitespace is part of operand. */
+  /* Leading whitespace is part of operand.  */
+  SKIP_WHITESPACE ();
 
   if (current_cframe != NULL && current_cframe->ignoring)
     {
 
   if (current_cframe != NULL && current_cframe->ignoring)
     {
@@ -123,7 +144,7 @@ s_if (arg)
     }
   else
     {
     }
   else
     {
-      expression (&operand);
+      expression_and_evaluate (&operand);
       if (operand.X_op != O_constant)
        as_bad (_("non-constant expression in \".if\" statement"));
     }
       if (operand.X_op != O_constant)
        as_bad (_("non-constant expression in \".if\" statement"));
     }
@@ -158,14 +179,46 @@ s_if (arg)
     mri_comment_end (stop, stopc);
 
   demand_empty_rest_of_line ();
     mri_comment_end (stop, stopc);
 
   demand_empty_rest_of_line ();
-}                              /* s_if() */
+}
+
+/* Performs the .ifb (test_blank == 1) and
+   the .ifnb (test_blank == 0) pseudo op.  */
+
+void
+s_ifb (int test_blank)
+{
+  struct conditional_frame cframe;
+
+  initialize_cframe (&cframe);
+
+  if (cframe.dead_tree)
+    cframe.ignoring = 1;
+  else
+    {
+      int is_eol;
+
+      SKIP_WHITESPACE ();
+      is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
+      cframe.ignoring = (test_blank == !is_eol);
+    }
+
+  current_cframe = ((struct conditional_frame *)
+                   obstack_copy (&cond_obstack, &cframe,
+                                 sizeof (cframe)));
+
+  if (LISTING_SKIP_COND ()
+      && cframe.ignoring
+      && (cframe.previous_cframe == NULL
+         || ! cframe.previous_cframe->ignoring))
+    listing_list (2);
+
+  ignore_rest_of_line ();
+}
 
 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
 
 static char *
 
 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
 
 static char *
-get_mri_string (terminator, len)
-     int terminator;
-     int *len;
+get_mri_string (int terminator, int *len)
 {
   char *ret;
   char *s;
 {
   char *ret;
   char *s;
@@ -205,8 +258,7 @@ get_mri_string (terminator, len)
 /* The MRI IFC and IFNC pseudo-ops.  */
 
 void
 /* The MRI IFC and IFNC pseudo-ops.  */
 
 void
-s_ifc (arg)
-     int arg;
+s_ifc (int arg)
 {
   char *stop = NULL;
   char stopc;
 {
   char *stop = NULL;
   char stopc;
@@ -246,89 +298,83 @@ s_ifc (arg)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-void 
-s_elseif (arg)
-     int arg;
+void
+s_elseif (int arg)
 {
 {
-  expressionS operand;
-  int t;
-
   if (current_cframe == NULL)
     {
   if (current_cframe == NULL)
     {
-      as_bad (_("\".elseif\" without matching \".if\" - ignored"));
-
+      as_bad (_("\".elseif\" without matching \".if\""));
     }
   else if (current_cframe->else_seen)
     {
     }
   else if (current_cframe->else_seen)
     {
-      as_bad (_("\".elseif\" after \".else\" - ignored"));
+      as_bad (_("\".elseif\" after \".else\""));
       as_bad_where (current_cframe->else_file_line.file,
                    current_cframe->else_file_line.line,
       as_bad_where (current_cframe->else_file_line.file,
                    current_cframe->else_file_line.line,
-                   _("here is the previous \"else\""));
+                   _("here is the previous \".else\""));
       as_bad_where (current_cframe->if_file_line.file,
                    current_cframe->if_file_line.line,
       as_bad_where (current_cframe->if_file_line.file,
                    current_cframe->if_file_line.line,
-                   _("here is the previous \"if\""));
+                   _("here is the previous \".if\""));
     }
   else
     {
       as_where (&current_cframe->else_file_line.file,
                &current_cframe->else_file_line.line);
 
     }
   else
     {
       as_where (&current_cframe->else_file_line.file,
                &current_cframe->else_file_line.line);
 
-      if (!current_cframe->dead_tree)
-       {
-         current_cframe->ignoring = !current_cframe->ignoring;
-         if (LISTING_SKIP_COND ())
-           {
-             if (! current_cframe->ignoring)
-               listing_list (1);
-             else
-               listing_list (2);
-           }
-       }                       /* if not a dead tree */
-    }                          /* if error else do it */
-
-
-  SKIP_WHITESPACE ();          /* Leading whitespace is part of operand. */
+      current_cframe->dead_tree |= !current_cframe->ignoring;
+      current_cframe->ignoring = current_cframe->dead_tree;
+    }
 
 
-  if (current_cframe != NULL && current_cframe->ignoring)
+  if (current_cframe == NULL || current_cframe->ignoring)
     {
     {
-      operand.X_add_number = 0;
       while (! is_end_of_line[(unsigned char) *input_line_pointer])
        ++input_line_pointer;
       while (! is_end_of_line[(unsigned char) *input_line_pointer])
        ++input_line_pointer;
+
+      if (current_cframe == NULL)
+       return;
     }
   else
     {
     }
   else
     {
-      expression (&operand);
+      expressionS operand;
+      int t;
+
+      /* Leading whitespace is part of operand.  */
+      SKIP_WHITESPACE ();
+
+      expression_and_evaluate (&operand);
       if (operand.X_op != O_constant)
        as_bad (_("non-constant expression in \".elseif\" statement"));
       if (operand.X_op != O_constant)
        as_bad (_("non-constant expression in \".elseif\" statement"));
-    }
-  
-  switch ((operatorT) arg)
-    {
-    case O_eq: t = operand.X_add_number == 0; break;
-    case O_ne: t = operand.X_add_number != 0; break;
-    case O_lt: t = operand.X_add_number < 0; break;
-    case O_le: t = operand.X_add_number <= 0; break;
-    case O_ge: t = operand.X_add_number >= 0; break;
-    case O_gt: t = operand.X_add_number > 0; break;
-    default:
-      abort ();
-      return;
-    }
 
 
-  current_cframe->ignoring = current_cframe->dead_tree || ! t;
+      switch ((operatorT) arg)
+       {
+       case O_eq: t = operand.X_add_number == 0; break;
+       case O_ne: t = operand.X_add_number != 0; break;
+       case O_lt: t = operand.X_add_number < 0; break;
+       case O_le: t = operand.X_add_number <= 0; break;
+       case O_ge: t = operand.X_add_number >= 0; break;
+       case O_gt: t = operand.X_add_number > 0; break;
+       default:
+         abort ();
+         return;
+       }
+
+      current_cframe->ignoring = current_cframe->dead_tree || ! t;
+    }
 
   if (LISTING_SKIP_COND ()
 
   if (LISTING_SKIP_COND ()
-      && current_cframe->ignoring
       && (current_cframe->previous_cframe == NULL
          || ! current_cframe->previous_cframe->ignoring))
       && (current_cframe->previous_cframe == NULL
          || ! current_cframe->previous_cframe->ignoring))
-    listing_list (2);
+    {
+      if (! current_cframe->ignoring)
+       listing_list (1);
+      else
+       listing_list (2);
+    }
 
   demand_empty_rest_of_line ();
 }
 
 
   demand_empty_rest_of_line ();
 }
 
-void 
-s_endif (arg)
-     int arg ATTRIBUTE_UNUSED;
+void
+s_endif (int arg ATTRIBUTE_UNUSED)
 {
   struct conditional_frame *hold;
 
 {
   struct conditional_frame *hold;
 
@@ -356,46 +402,45 @@ s_endif (arg)
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
-}                              /* s_endif() */
+}
 
 
-void 
-s_else (arg)
-     int arg ATTRIBUTE_UNUSED;
+void
+s_else (int arg ATTRIBUTE_UNUSED)
 {
   if (current_cframe == NULL)
     {
 {
   if (current_cframe == NULL)
     {
-      as_bad (_(".else without matching .if - ignored"));
-
+      as_bad (_("\".else\" without matching \".if\""));
     }
   else if (current_cframe->else_seen)
     {
     }
   else if (current_cframe->else_seen)
     {
-      as_bad (_("duplicate \"else\" - ignored"));
+      as_bad (_("duplicate \".else\""));
       as_bad_where (current_cframe->else_file_line.file,
                    current_cframe->else_file_line.line,
       as_bad_where (current_cframe->else_file_line.file,
                    current_cframe->else_file_line.line,
-                   _("here is the previous \"else\""));
+                   _("here is the previous \".else\""));
       as_bad_where (current_cframe->if_file_line.file,
                    current_cframe->if_file_line.line,
       as_bad_where (current_cframe->if_file_line.file,
                    current_cframe->if_file_line.line,
-                   _("here is the previous \"if\""));
+                   _("here is the previous \".if\""));
     }
   else
     {
       as_where (&current_cframe->else_file_line.file,
                &current_cframe->else_file_line.line);
 
     }
   else
     {
       as_where (&current_cframe->else_file_line.file,
                &current_cframe->else_file_line.line);
 
-      if (!current_cframe->dead_tree)
+      current_cframe->ignoring =
+       current_cframe->dead_tree | !current_cframe->ignoring;
+
+      if (LISTING_SKIP_COND ()
+         && (current_cframe->previous_cframe == NULL
+             || ! current_cframe->previous_cframe->ignoring))
        {
        {
-         current_cframe->ignoring = !current_cframe->ignoring;
-         if (LISTING_SKIP_COND ())
-           {
-             if (! current_cframe->ignoring)
-               listing_list (1);
-             else
-               listing_list (2);
-           }
-       }                       /* if not a dead tree */
+         if (! current_cframe->ignoring)
+           listing_list (1);
+         else
+           listing_list (2);
+       }
 
       current_cframe->else_seen = 1;
 
       current_cframe->else_seen = 1;
-    }                          /* if error else do it */
+    }
 
   if (flag_mri)
     {
 
   if (flag_mri)
     {
@@ -404,11 +449,10 @@ s_else (arg)
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
-}                              /* s_else() */
+}
 
 
-void 
-s_ifeqs (arg)
-     int arg;
+void
+s_ifeqs (int arg)
 {
   char *s1, *s2;
   int len1, len2;
 {
   char *s1, *s2;
   int len1, len2;
@@ -443,10 +487,10 @@ s_ifeqs (arg)
     listing_list (2);
 
   demand_empty_rest_of_line ();
     listing_list (2);
 
   demand_empty_rest_of_line ();
-}                              /* s_ifeqs() */
+}
 
 
-int 
-ignore_input ()
+int
+ignore_input (void)
 {
   char *s;
 
 {
   char *s;
 
@@ -477,11 +521,10 @@ ignore_input ()
     return 0;
 
   return (current_cframe != NULL) && (current_cframe->ignoring);
     return 0;
 
   return (current_cframe != NULL) && (current_cframe->ignoring);
-}                              /* ignore_input() */
+}
 
 
-static void 
-initialize_cframe (cframe)
-     struct conditional_frame *cframe;
+static void
+initialize_cframe (struct conditional_frame *cframe)
 {
   memset (cframe, 0, sizeof (*cframe));
   as_where (&cframe->if_file_line.file,
 {
   memset (cframe, 0, sizeof (*cframe));
   as_where (&cframe->if_file_line.file,
@@ -497,8 +540,7 @@ initialize_cframe (cframe)
    negative, we are being called at the of the input files.  */
 
 void
    negative, we are being called at the of the input files.  */
 
 void
-cond_finish_check (nest)
-     int nest;
+cond_finish_check (int nest)
 {
   if (current_cframe != NULL && current_cframe->macro_nest >= nest)
     {
 {
   if (current_cframe != NULL && current_cframe->macro_nest >= nest)
     {
@@ -521,8 +563,7 @@ cond_finish_check (nest)
    nested, and just pop them off the stack.  */
 
 void
    nested, and just pop them off the stack.  */
 
 void
-cond_exit_macro (nest)
-     int nest;
+cond_exit_macro (int nest)
 {
   while (current_cframe != NULL && current_cframe->macro_nest >= nest)
     {
 {
   while (current_cframe != NULL && current_cframe->macro_nest >= nest)
     {
@@ -533,5 +574,3 @@ cond_exit_macro (nest)
       obstack_free (&cond_obstack, hold);
     }
 }
       obstack_free (&cond_obstack, hold);
     }
 }
-
-/* end of cond.c */