Back to index

cell-binutils  2.17cvs20070401
cond.c
Go to the documentation of this file.
00001 /* cond.c - conditional assembly pseudo-ops, and .include
00002    Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
00003    2003, 2006 Free Software Foundation, Inc.
00004 
00005    This file is part of GAS, the GNU Assembler.
00006 
00007    GAS is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    GAS is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with GAS; see the file COPYING.  If not, write to the Free
00019    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 #include "as.h"
00023 #include "sb.h"
00024 #include "macro.h"
00025 
00026 #include "obstack.h"
00027 
00028 /* This is allocated to grow and shrink as .ifdef/.endif pairs are
00029    scanned.  */
00030 struct obstack cond_obstack;
00031 
00032 struct file_line {
00033   char *file;
00034   unsigned int line;
00035 };
00036 
00037 /* We push one of these structures for each .if, and pop it at the
00038    .endif.  */
00039 
00040 struct conditional_frame {
00041   /* The source file & line number of the "if".  */
00042   struct file_line if_file_line;
00043   /* The source file & line of the "else".  */
00044   struct file_line else_file_line;
00045   /* The previous conditional.  */
00046   struct conditional_frame *previous_cframe;
00047   /* Have we seen an else yet?  */
00048   int else_seen;
00049   /* Whether we are currently ignoring input.  */
00050   int ignoring;
00051   /* Whether a conditional at a higher level is ignoring input.
00052      Set also when a branch of an "if .. elseif .." tree has matched
00053      to prevent further matches.  */
00054   int dead_tree;
00055   /* Macro nesting level at which this conditional was created.  */
00056   int macro_nest;
00057 };
00058 
00059 static void initialize_cframe (struct conditional_frame *cframe);
00060 static char *get_mri_string (int, int *);
00061 
00062 static struct conditional_frame *current_cframe = NULL;
00063 
00064 /* Performs the .ifdef (test_defined == 1) and
00065    the .ifndef (test_defined == 0) pseudo op.  */
00066 
00067 void
00068 s_ifdef (int test_defined)
00069 {
00070   /* Points to name of symbol.  */
00071   char *name;
00072   /* Points to symbol.  */
00073   symbolS *symbolP;
00074   struct conditional_frame cframe;
00075   char c;
00076 
00077   /* Leading whitespace is part of operand.  */
00078   SKIP_WHITESPACE ();
00079   name = input_line_pointer;
00080 
00081   if (!is_name_beginner (*name))
00082     {
00083       as_bad (_("invalid identifier for \".ifdef\""));
00084       obstack_1grow (&cond_obstack, 0);
00085       ignore_rest_of_line ();
00086       return;
00087     }
00088 
00089   c = get_symbol_end ();
00090   symbolP = symbol_find (name);
00091   *input_line_pointer = c;
00092 
00093   initialize_cframe (&cframe);
00094   
00095   if (cframe.dead_tree)
00096     cframe.ignoring = 1;
00097   else
00098     {
00099       int is_defined;
00100 
00101       /* Use the same definition of 'defined' as .equiv so that a symbol
00102         which has been referenced but not yet given a value/address is
00103         considered to be undefined.  */
00104       is_defined =
00105        symbolP != NULL
00106        && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
00107        && S_GET_SEGMENT (symbolP) != reg_section;
00108 
00109       cframe.ignoring = ! (test_defined ^ is_defined);
00110     }
00111 
00112   current_cframe = ((struct conditional_frame *)
00113                   obstack_copy (&cond_obstack, &cframe,
00114                               sizeof (cframe)));
00115 
00116   if (LISTING_SKIP_COND ()
00117       && cframe.ignoring
00118       && (cframe.previous_cframe == NULL
00119          || ! cframe.previous_cframe->ignoring))
00120     listing_list (2);
00121 
00122   demand_empty_rest_of_line ();
00123 }
00124 
00125 void
00126 s_if (int arg)
00127 {
00128   expressionS operand;
00129   struct conditional_frame cframe;
00130   int t;
00131   char *stop = NULL;
00132   char stopc;
00133 
00134   if (flag_mri)
00135     stop = mri_comment_field (&stopc);
00136 
00137   /* Leading whitespace is part of operand.  */
00138   SKIP_WHITESPACE ();
00139 
00140   if (current_cframe != NULL && current_cframe->ignoring)
00141     {
00142       operand.X_add_number = 0;
00143       while (! is_end_of_line[(unsigned char) *input_line_pointer])
00144        ++input_line_pointer;
00145     }
00146   else
00147     {
00148       expression_and_evaluate (&operand);
00149       if (operand.X_op != O_constant)
00150        as_bad (_("non-constant expression in \".if\" statement"));
00151     }
00152 
00153   switch ((operatorT) arg)
00154     {
00155     case O_eq: t = operand.X_add_number == 0; break;
00156     case O_ne: t = operand.X_add_number != 0; break;
00157     case O_lt: t = operand.X_add_number < 0; break;
00158     case O_le: t = operand.X_add_number <= 0; break;
00159     case O_ge: t = operand.X_add_number >= 0; break;
00160     case O_gt: t = operand.X_add_number > 0; break;
00161     default:
00162       abort ();
00163       return;
00164     }
00165 
00166   /* If the above error is signaled, this will dispatch
00167      using an undefined result.  No big deal.  */
00168   initialize_cframe (&cframe);
00169   cframe.ignoring = cframe.dead_tree || ! t;
00170   current_cframe = ((struct conditional_frame *)
00171                   obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
00172 
00173   if (LISTING_SKIP_COND ()
00174       && cframe.ignoring
00175       && (cframe.previous_cframe == NULL
00176          || ! cframe.previous_cframe->ignoring))
00177     listing_list (2);
00178 
00179   if (flag_mri)
00180     mri_comment_end (stop, stopc);
00181 
00182   demand_empty_rest_of_line ();
00183 }
00184 
00185 /* Performs the .ifb (test_blank == 1) and
00186    the .ifnb (test_blank == 0) pseudo op.  */
00187 
00188 void
00189 s_ifb (int test_blank)
00190 {
00191   struct conditional_frame cframe;
00192 
00193   initialize_cframe (&cframe);
00194   
00195   if (cframe.dead_tree)
00196     cframe.ignoring = 1;
00197   else
00198     {
00199       int is_eol;
00200 
00201       SKIP_WHITESPACE ();
00202       is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
00203       cframe.ignoring = (test_blank == !is_eol);
00204     }
00205 
00206   current_cframe = ((struct conditional_frame *)
00207                   obstack_copy (&cond_obstack, &cframe,
00208                               sizeof (cframe)));
00209 
00210   if (LISTING_SKIP_COND ()
00211       && cframe.ignoring
00212       && (cframe.previous_cframe == NULL
00213          || ! cframe.previous_cframe->ignoring))
00214     listing_list (2);
00215 
00216   ignore_rest_of_line ();
00217 }
00218 
00219 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
00220 
00221 static char *
00222 get_mri_string (int terminator, int *len)
00223 {
00224   char *ret;
00225   char *s;
00226 
00227   SKIP_WHITESPACE ();
00228   s = ret = input_line_pointer;
00229   if (*input_line_pointer == '\'')
00230     {
00231       ++s;
00232       ++input_line_pointer;
00233       while (! is_end_of_line[(unsigned char) *input_line_pointer])
00234        {
00235          *s++ = *input_line_pointer++;
00236          if (s[-1] == '\'')
00237            {
00238              if (*input_line_pointer != '\'')
00239               break;
00240              ++input_line_pointer;
00241            }
00242        }
00243       SKIP_WHITESPACE ();
00244     }
00245   else
00246     {
00247       while (*input_line_pointer != terminator
00248             && ! is_end_of_line[(unsigned char) *input_line_pointer])
00249        ++input_line_pointer;
00250       s = input_line_pointer;
00251       while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
00252        --s;
00253     }
00254 
00255   *len = s - ret;
00256   return ret;
00257 }
00258 
00259 /* The MRI IFC and IFNC pseudo-ops.  */
00260 
00261 void
00262 s_ifc (int arg)
00263 {
00264   char *stop = NULL;
00265   char stopc;
00266   char *s1, *s2;
00267   int len1, len2;
00268   int res;
00269   struct conditional_frame cframe;
00270 
00271   if (flag_mri)
00272     stop = mri_comment_field (&stopc);
00273 
00274   s1 = get_mri_string (',', &len1);
00275 
00276   if (*input_line_pointer != ',')
00277     as_bad (_("bad format for ifc or ifnc"));
00278   else
00279     ++input_line_pointer;
00280 
00281   s2 = get_mri_string (';', &len2);
00282 
00283   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
00284 
00285   initialize_cframe (&cframe);
00286   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
00287   current_cframe = ((struct conditional_frame *)
00288                   obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
00289 
00290   if (LISTING_SKIP_COND ()
00291       && cframe.ignoring
00292       && (cframe.previous_cframe == NULL
00293          || ! cframe.previous_cframe->ignoring))
00294     listing_list (2);
00295 
00296   if (flag_mri)
00297     mri_comment_end (stop, stopc);
00298 
00299   demand_empty_rest_of_line ();
00300 }
00301 
00302 void
00303 s_elseif (int arg)
00304 {
00305   if (current_cframe == NULL)
00306     {
00307       as_bad (_("\".elseif\" without matching \".if\""));
00308     }
00309   else if (current_cframe->else_seen)
00310     {
00311       as_bad (_("\".elseif\" after \".else\""));
00312       as_bad_where (current_cframe->else_file_line.file,
00313                   current_cframe->else_file_line.line,
00314                   _("here is the previous \"else\""));
00315       as_bad_where (current_cframe->if_file_line.file,
00316                   current_cframe->if_file_line.line,
00317                   _("here is the previous \"if\""));
00318     }
00319   else
00320     {
00321       as_where (&current_cframe->else_file_line.file,
00322               &current_cframe->else_file_line.line);
00323 
00324       current_cframe->dead_tree |= !current_cframe->ignoring;
00325       current_cframe->ignoring = current_cframe->dead_tree;
00326     }
00327 
00328   if (current_cframe == NULL || current_cframe->ignoring)
00329     {
00330       while (! is_end_of_line[(unsigned char) *input_line_pointer])
00331        ++input_line_pointer;
00332 
00333       if (current_cframe == NULL)
00334        return;
00335     }
00336   else
00337     {
00338       expressionS operand;
00339       int t;
00340 
00341       /* Leading whitespace is part of operand.  */
00342       SKIP_WHITESPACE ();
00343 
00344       expression_and_evaluate (&operand);
00345       if (operand.X_op != O_constant)
00346        as_bad (_("non-constant expression in \".elseif\" statement"));
00347 
00348       switch ((operatorT) arg)
00349        {
00350        case O_eq: t = operand.X_add_number == 0; break;
00351        case O_ne: t = operand.X_add_number != 0; break;
00352        case O_lt: t = operand.X_add_number < 0; break;
00353        case O_le: t = operand.X_add_number <= 0; break;
00354        case O_ge: t = operand.X_add_number >= 0; break;
00355        case O_gt: t = operand.X_add_number > 0; break;
00356        default:
00357          abort ();
00358          return;
00359        }
00360 
00361       current_cframe->ignoring = current_cframe->dead_tree || ! t;
00362     }
00363 
00364   if (LISTING_SKIP_COND ()
00365       && (current_cframe->previous_cframe == NULL
00366          || ! current_cframe->previous_cframe->ignoring))
00367     {
00368       if (! current_cframe->ignoring)
00369        listing_list (1);
00370       else
00371        listing_list (2);
00372     }
00373 
00374   demand_empty_rest_of_line ();
00375 }
00376 
00377 void
00378 s_endif (int arg ATTRIBUTE_UNUSED)
00379 {
00380   struct conditional_frame *hold;
00381 
00382   if (current_cframe == NULL)
00383     {
00384       as_bad (_("\".endif\" without \".if\""));
00385     }
00386   else
00387     {
00388       if (LISTING_SKIP_COND ()
00389          && current_cframe->ignoring
00390          && (current_cframe->previous_cframe == NULL
00391              || ! current_cframe->previous_cframe->ignoring))
00392        listing_list (1);
00393 
00394       hold = current_cframe;
00395       current_cframe = current_cframe->previous_cframe;
00396       obstack_free (&cond_obstack, hold);
00397     }                       /* if one pop too many */
00398 
00399   if (flag_mri)
00400     {
00401       while (! is_end_of_line[(unsigned char) *input_line_pointer])
00402        ++input_line_pointer;
00403     }
00404 
00405   demand_empty_rest_of_line ();
00406 }
00407 
00408 void
00409 s_else (int arg ATTRIBUTE_UNUSED)
00410 {
00411   if (current_cframe == NULL)
00412     {
00413       as_bad (_("\".else\" without matching \".if\""));
00414     }
00415   else if (current_cframe->else_seen)
00416     {
00417       as_bad (_("duplicate \"else\""));
00418       as_bad_where (current_cframe->else_file_line.file,
00419                   current_cframe->else_file_line.line,
00420                   _("here is the previous \"else\""));
00421       as_bad_where (current_cframe->if_file_line.file,
00422                   current_cframe->if_file_line.line,
00423                   _("here is the previous \"if\""));
00424     }
00425   else
00426     {
00427       as_where (&current_cframe->else_file_line.file,
00428               &current_cframe->else_file_line.line);
00429 
00430       current_cframe->ignoring =
00431        current_cframe->dead_tree | !current_cframe->ignoring;
00432 
00433       if (LISTING_SKIP_COND ()
00434          && (current_cframe->previous_cframe == NULL
00435              || ! current_cframe->previous_cframe->ignoring))
00436        {
00437          if (! current_cframe->ignoring)
00438            listing_list (1);
00439          else
00440            listing_list (2);
00441        }
00442 
00443       current_cframe->else_seen = 1;
00444     }
00445 
00446   if (flag_mri)
00447     {
00448       while (! is_end_of_line[(unsigned char) *input_line_pointer])
00449        ++input_line_pointer;
00450     }
00451 
00452   demand_empty_rest_of_line ();
00453 }
00454 
00455 void
00456 s_ifeqs (int arg)
00457 {
00458   char *s1, *s2;
00459   int len1, len2;
00460   int res;
00461   struct conditional_frame cframe;
00462 
00463   s1 = demand_copy_C_string (&len1);
00464 
00465   SKIP_WHITESPACE ();
00466   if (*input_line_pointer != ',')
00467     {
00468       as_bad (_(".ifeqs syntax error"));
00469       ignore_rest_of_line ();
00470       return;
00471     }
00472 
00473   ++input_line_pointer;
00474 
00475   s2 = demand_copy_C_string (&len2);
00476 
00477   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
00478 
00479   initialize_cframe (&cframe);
00480   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
00481   current_cframe = ((struct conditional_frame *)
00482                   obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
00483 
00484   if (LISTING_SKIP_COND ()
00485       && cframe.ignoring
00486       && (cframe.previous_cframe == NULL
00487          || ! cframe.previous_cframe->ignoring))
00488     listing_list (2);
00489 
00490   demand_empty_rest_of_line ();
00491 }
00492 
00493 int
00494 ignore_input (void)
00495 {
00496   char *s;
00497 
00498   s = input_line_pointer;
00499 
00500   if (NO_PSEUDO_DOT || flag_m68k_mri)
00501     {
00502       if (s[-1] != '.')
00503        --s;
00504     }
00505   else
00506     {
00507       if (s[-1] != '.')
00508        return (current_cframe != NULL) && (current_cframe->ignoring);
00509     }
00510 
00511   /* We cannot ignore certain pseudo ops.  */
00512   if (((s[0] == 'i'
00513        || s[0] == 'I')
00514        && (!strncasecmp (s, "if", 2)
00515           || !strncasecmp (s, "ifdef", 5)
00516           || !strncasecmp (s, "ifndef", 6)))
00517       || ((s[0] == 'e'
00518           || s[0] == 'E')
00519          && (!strncasecmp (s, "else", 4)
00520              || !strncasecmp (s, "endif", 5)
00521              || !strncasecmp (s, "endc", 4))))
00522     return 0;
00523 
00524   return (current_cframe != NULL) && (current_cframe->ignoring);
00525 }
00526 
00527 static void
00528 initialize_cframe (struct conditional_frame *cframe)
00529 {
00530   memset (cframe, 0, sizeof (*cframe));
00531   as_where (&cframe->if_file_line.file,
00532            &cframe->if_file_line.line);
00533   cframe->previous_cframe = current_cframe;
00534   cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
00535   cframe->macro_nest = macro_nest;
00536 }
00537 
00538 /* Give an error if a conditional is unterminated inside a macro or
00539    the assembly as a whole.  If NEST is non negative, we are being
00540    called because of the end of a macro expansion.  If NEST is
00541    negative, we are being called at the of the input files.  */
00542 
00543 void
00544 cond_finish_check (int nest)
00545 {
00546   if (current_cframe != NULL && current_cframe->macro_nest >= nest)
00547     {
00548       if (nest >= 0)
00549        as_bad (_("end of macro inside conditional"));
00550       else
00551        as_bad (_("end of file inside conditional"));
00552       as_bad_where (current_cframe->if_file_line.file,
00553                   current_cframe->if_file_line.line,
00554                   _("here is the start of the unterminated conditional"));
00555       if (current_cframe->else_seen)
00556        as_bad_where (current_cframe->else_file_line.file,
00557                     current_cframe->else_file_line.line,
00558                     _("here is the \"else\" of the unterminated conditional"));
00559     }
00560 }
00561 
00562 /* This function is called when we exit out of a macro.  We assume
00563    that any conditionals which began within the macro are correctly
00564    nested, and just pop them off the stack.  */
00565 
00566 void
00567 cond_exit_macro (int nest)
00568 {
00569   while (current_cframe != NULL && current_cframe->macro_nest >= nest)
00570     {
00571       struct conditional_frame *hold;
00572 
00573       hold = current_cframe;
00574       current_cframe = current_cframe->previous_cframe;
00575       obstack_free (&cond_obstack, hold);
00576     }
00577 }