(linenum→info "unix/slp.c:2238")

binutils/2.18/gas/cond.c

    1: /* cond.c - conditional assembly pseudo-ops, and .include
    2:    Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
    3:    2003, 2006, 2007 Free Software Foundation, Inc.
    4: 
    5:    This file is part of GAS, the GNU Assembler.
    6: 
    7:    GAS is free software; you can redistribute it and/or modify
    8:    it under the terms of the GNU General Public License as published by
    9:    the Free Software Foundation; either version 3, or (at your option)
   10:    any later version.
   11: 
   12:    GAS is distributed in the hope that it will be useful,
   13:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:    GNU General Public License for more details.
   16: 
   17:    You should have received a copy of the GNU General Public License
   18:    along with GAS; see the file COPYING.  If not, write to the Free
   19:    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
   20:    02110-1301, USA.  */
   21: 
   22: #include "as.h"
   23: #include "sb.h"
   24: #include "macro.h"
   25: 
   26: #include "obstack.h"
   27: 
   28: /* This is allocated to grow and shrink as .ifdef/.endif pairs are
   29:    scanned.  */
   30: struct obstack cond_obstack;
   31: 
   32: struct file_line {
   33:   char *file;
   34:   unsigned int line;
   35: };
   36: 
   37: /* We push one of these structures for each .if, and pop it at the
   38:    .endif.  */
   39: 
   40: struct conditional_frame {
   41:   /* The source file & line number of the "if".  */
   42:   struct file_line if_file_line;
   43:   /* The source file & line of the "else".  */
   44:   struct file_line else_file_line;
   45:   /* The previous conditional.  */
   46:   struct conditional_frame *previous_cframe;
   47:   /* Have we seen an else yet?  */
   48:   int else_seen;
   49:   /* Whether we are currently ignoring input.  */
   50:   int ignoring;
   51:   /* Whether a conditional at a higher level is ignoring input.
   52:      Set also when a branch of an "if .. elseif .." tree has matched
   53:      to prevent further matches.  */
   54:   int dead_tree;
   55:   /* Macro nesting level at which this conditional was created.  */
   56:   int macro_nest;
   57: };
   58: 
   59: static void initialize_cframe (struct conditional_frame *cframe);
   60: static char *get_mri_string (int, int *);
   61: 
   62: static struct conditional_frame *current_cframe = NULL;
   63: 
   64: /* Performs the .ifdef (test_defined == 1) and
   65:    the .ifndef (test_defined == 0) pseudo op.  */
   66: 
   67: void
   68: s_ifdef (int test_defined)
   69: {
   70:   /* Points to name of symbol.  */
   71:   char *name;
   72:   /* Points to symbol.  */
   73:   symbolS *symbolP;
   74:   struct conditional_frame cframe;
   75:   char c;
   76: 
   77:   /* Leading whitespace is part of operand.  */
   78:   SKIP_WHITESPACE ();
   79:   name = input_line_pointer;
   80: 
   81:   if (!is_name_beginner (*name))
   82:     {
   83:       as_bad (_("invalid identifier for \".ifdef\""));
   84:       obstack_1grow (&cond_obstack, 0);
   85:       ignore_rest_of_line ();
   86:       return;
   87:     }
   88: 
   89:   c = get_symbol_end ();
   90:   symbolP = symbol_find (name);
   91:   *input_line_pointer = c;
   92: 
   93:   initialize_cframe (&cframe);
   94:   
   95:   if (cframe.dead_tree)
   96:     cframe.ignoring = 1;
   97:   else
   98:     {
   99:       int is_defined;
  100: 
  101:       /* Use the same definition of 'defined' as .equiv so that a symbol
  102:          which has been referenced but not yet given a value/address is
  103:          considered to be undefined.  */
  104:       is_defined =
  105:         symbolP != NULL
  106:         && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
  107:         && S_GET_SEGMENT (symbolP) != reg_section;
  108: 
  109:       cframe.ignoring = ! (test_defined ^ is_defined);
  110:     }
  111: 
  112:   current_cframe = ((struct conditional_frame *)
  113:                     obstack_copy (&cond_obstack, &cframe,
  114:                                   sizeof (cframe)));
  115: 
  116:   if (LISTING_SKIP_COND ()
  117:       && cframe.ignoring
  118:       && (cframe.previous_cframe == NULL
  119:           || ! cframe.previous_cframe->ignoring))
  120:     listing_list (2);
  121: 
  122:   demand_empty_rest_of_line ();
  123: }
  124: 
  125: void
  126: s_if (int arg)
  127: {
  128:   expressionS operand;
  129:   struct conditional_frame cframe;
  130:   int t;
  131:   char *stop = NULL;
  132:   char stopc;
  133: 
  134:   if (flag_mri)
  135:     stop = mri_comment_field (&stopc);
  136: 
  137:   /* Leading whitespace is part of operand.  */
  138:   SKIP_WHITESPACE ();
  139: 
  140:   if (current_cframe != NULL && current_cframe->ignoring)
  141:     {
  142:       operand.X_add_number = 0;
  143:       while (! is_end_of_line[(unsigned char) *input_line_pointer])
  144:         ++input_line_pointer;
  145:     }
  146:   else
  147:     {
  148:       expression_and_evaluate (&operand);
  149:       if (operand.X_op != O_constant)
  150:         as_bad (_("non-constant expression in \".if\" statement"));
  151:     }
  152: 
  153:   switch ((operatorT) arg)
  154:     {
  155:     case O_eq: t = operand.X_add_number == 0; break;
  156:     case O_ne: t = operand.X_add_number != 0; break;
  157:     case O_lt: t = operand.X_add_number < 0; break;
  158:     case O_le: t = operand.X_add_number <= 0; break;
  159:     case O_ge: t = operand.X_add_number >= 0; break;
  160:     case O_gt: t = operand.X_add_number > 0; break;
  161:     default:
  162:       abort ();
  163:       return;
  164:     }
  165: 
  166:   /* If the above error is signaled, this will dispatch
  167:      using an undefined result.  No big deal.  */
  168:   initialize_cframe (&cframe);
  169:   cframe.ignoring = cframe.dead_tree || ! t;
  170:   current_cframe = ((struct conditional_frame *)
  171:                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
  172: 
  173:   if (LISTING_SKIP_COND ()
  174:       && cframe.ignoring
  175:       && (cframe.previous_cframe == NULL
  176:           || ! cframe.previous_cframe->ignoring))
  177:     listing_list (2);
  178: 
  179:   if (flag_mri)
  180:     mri_comment_end (stop, stopc);
  181: 
  182:   demand_empty_rest_of_line ();
  183: }
  184: 
  185: /* Performs the .ifb (test_blank == 1) and
  186:    the .ifnb (test_blank == 0) pseudo op.  */
  187: 
  188: void
  189: s_ifb (int test_blank)
  190: {
  191:   struct conditional_frame cframe;
  192: 
  193:   initialize_cframe (&cframe);
  194:   
  195:   if (cframe.dead_tree)
  196:     cframe.ignoring = 1;
  197:   else
  198:     {
  199:       int is_eol;
  200: 
  201:       SKIP_WHITESPACE ();
  202:       is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
  203:       cframe.ignoring = (test_blank == !is_eol);
  204:     }
  205: 
  206:   current_cframe = ((struct conditional_frame *)
  207:                     obstack_copy (&cond_obstack, &cframe,
  208:                                   sizeof (cframe)));
  209: 
  210:   if (LISTING_SKIP_COND ()
  211:       && cframe.ignoring
  212:       && (cframe.previous_cframe == NULL
  213:           || ! cframe.previous_cframe->ignoring))
  214:     listing_list (2);
  215: 
  216:   ignore_rest_of_line ();
  217: }
  218: 
  219: /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
  220: 
  221: static char *
  222: get_mri_string (int terminator, int *len)
  223: {
  224:   char *ret;
  225:   char *s;
  226: 
  227:   SKIP_WHITESPACE ();
  228:   s = ret = input_line_pointer;
  229:   if (*input_line_pointer == '\'')
  230:     {
  231:       ++s;
  232:       ++input_line_pointer;
  233:       while (! is_end_of_line[(unsigned char) *input_line_pointer])
  234:         {
  235:           *s++ = *input_line_pointer++;
  236:           if (s[-1] == '\'')
  237:             {
  238:               if (*input_line_pointer != '\'')
  239:                 break;
  240:               ++input_line_pointer;
  241:             }
  242:         }
  243:       SKIP_WHITESPACE ();
  244:     }
  245:   else
  246:     {
  247:       while (*input_line_pointer != terminator
  248:              && ! is_end_of_line[(unsigned char) *input_line_pointer])
  249:         ++input_line_pointer;
  250:       s = input_line_pointer;
  251:       while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
  252:         --s;
  253:     }
  254: 
  255:   *len = s - ret;
  256:   return ret;
  257: }
  258: 
  259: /* The MRI IFC and IFNC pseudo-ops.  */
  260: 
  261: void
  262: s_ifc (int arg)
  263: {
  264:   char *stop = NULL;
  265:   char stopc;
  266:   char *s1, *s2;
  267:   int len1, len2;
  268:   int res;
  269:   struct conditional_frame cframe;
  270: 
  271:   if (flag_mri)
  272:     stop = mri_comment_field (&stopc);
  273: 
  274:   s1 = get_mri_string (',', &len1);
  275: 
  276:   if (*input_line_pointer != ',')
  277:     as_bad (_("bad format for ifc or ifnc"));
  278:   else
  279:     ++input_line_pointer;
  280: 
  281:   s2 = get_mri_string (';', &len2);
  282: 
  283:   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
  284: 
  285:   initialize_cframe (&cframe);
  286:   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
  287:   current_cframe = ((struct conditional_frame *)
  288:                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
  289: 
  290:   if (LISTING_SKIP_COND ()
  291:       && cframe.ignoring
  292:       && (cframe.previous_cframe == NULL
  293:           || ! cframe.previous_cframe->ignoring))
  294:     listing_list (2);
  295: 
  296:   if (flag_mri)
  297:     mri_comment_end (stop, stopc);
  298: 
  299:   demand_empty_rest_of_line ();
  300: }
  301: 
  302: void
  303: s_elseif (int arg)
  304: {
  305:   if (current_cframe == NULL)
  306:     {
  307:       as_bad (_("\".elseif\" without matching \".if\""));
  308:     }
  309:   else if (current_cframe->else_seen)
  310:     {
  311:       as_bad (_("\".elseif\" after \".else\""));
  312:       as_bad_where (current_cframe->else_file_line.file,
  313:                     current_cframe->else_file_line.line,
  314:                     _("here is the previous \"else\""));
  315:       as_bad_where (current_cframe->if_file_line.file,
  316:                     current_cframe->if_file_line.line,
  317:                     _("here is the previous \"if\""));
  318:     }
  319:   else
  320:     {
  321:       as_where (&current_cframe->else_file_line.file,
  322:                 &current_cframe->else_file_line.line);
  323: 
  324:       current_cframe->dead_tree |= !current_cframe->ignoring;
  325:       current_cframe->ignoring = current_cframe->dead_tree;
  326:     }
  327: 
  328:   if (current_cframe == NULL || current_cframe->ignoring)
  329:     {
  330:       while (! is_end_of_line[(unsigned char) *input_line_pointer])
  331:         ++input_line_pointer;
  332: 
  333:       if (current_cframe == NULL)
  334:         return;
  335:     }
  336:   else
  337:     {
  338:       expressionS operand;
  339:       int t;
  340: 
  341:       /* Leading whitespace is part of operand.  */
  342:       SKIP_WHITESPACE ();
  343: 
  344:       expression_and_evaluate (&operand);
  345:       if (operand.X_op != O_constant)
  346:         as_bad (_("non-constant expression in \".elseif\" statement"));
  347: 
  348:       switch ((operatorT) arg)
  349:         {
  350:         case O_eq: t = operand.X_add_number == 0; break;
  351:         case O_ne: t = operand.X_add_number != 0; break;
  352:         case O_lt: t = operand.X_add_number < 0; break;
  353:         case O_le: t = operand.X_add_number <= 0; break;
  354:         case O_ge: t = operand.X_add_number >= 0; break;
  355:         case O_gt: t = operand.X_add_number > 0; break;
  356:         default:
  357:           abort ();
  358:           return;
  359:         }
  360: 
  361:       current_cframe->ignoring = current_cframe->dead_tree || ! t;
  362:     }
  363: 
  364:   if (LISTING_SKIP_COND ()
  365:       && (current_cframe->previous_cframe == NULL
  366:           || ! current_cframe->previous_cframe->ignoring))
  367:     {
  368:       if (! current_cframe->ignoring)
  369:         listing_list (1);
  370:       else
  371:         listing_list (2);
  372:     }
  373: 
  374:   demand_empty_rest_of_line ();
  375: }
  376: 
  377: void
  378: s_endif (int arg ATTRIBUTE_UNUSED)
  379: {
  380:   struct conditional_frame *hold;
  381: 
  382:   if (current_cframe == NULL)
  383:     {
  384:       as_bad (_("\".endif\" without \".if\""));
  385:     }
  386:   else
  387:     {
  388:       if (LISTING_SKIP_COND ()
  389:           && current_cframe->ignoring
  390:           && (current_cframe->previous_cframe == NULL
  391:               || ! current_cframe->previous_cframe->ignoring))
  392:         listing_list (1);
  393: 
  394:       hold = current_cframe;
  395:       current_cframe = current_cframe->previous_cframe;
  396:       obstack_free (&cond_obstack, hold);
  397:     }                           /* if one pop too many */
  398: 
  399:   if (flag_mri)
  400:     {
  401:       while (! is_end_of_line[(unsigned char) *input_line_pointer])
  402:         ++input_line_pointer;
  403:     }
  404: 
  405:   demand_empty_rest_of_line ();
  406: }
  407: 
  408: void
  409: s_else (int arg ATTRIBUTE_UNUSED)
  410: {
  411:   if (current_cframe == NULL)
  412:     {
  413:       as_bad (_("\".else\" without matching \".if\""));
  414:     }
  415:   else if (current_cframe->else_seen)
  416:     {
  417:       as_bad (_("duplicate \"else\""));
  418:       as_bad_where (current_cframe->else_file_line.file,
  419:                     current_cframe->else_file_line.line,
  420:                     _("here is the previous \"else\""));
  421:       as_bad_where (current_cframe->if_file_line.file,
  422:                     current_cframe->if_file_line.line,
  423:                     _("here is the previous \"if\""));
  424:     }
  425:   else
  426:     {
  427:       as_where (&current_cframe->else_file_line.file,
  428:                 &current_cframe->else_file_line.line);
  429: 
  430:       current_cframe->ignoring =
  431:         current_cframe->dead_tree | !current_cframe->ignoring;
  432: 
  433:       if (LISTING_SKIP_COND ()
  434:           && (current_cframe->previous_cframe == NULL
  435:               || ! current_cframe->previous_cframe->ignoring))
  436:         {
  437:           if (! current_cframe->ignoring)
  438:             listing_list (1);
  439:           else
  440:             listing_list (2);
  441:         }
  442: 
  443:       current_cframe->else_seen = 1;
  444:     }
  445: 
  446:   if (flag_mri)
  447:     {
  448:       while (! is_end_of_line[(unsigned char) *input_line_pointer])
  449:         ++input_line_pointer;
  450:     }
  451: 
  452:   demand_empty_rest_of_line ();
  453: }
  454: 
  455: void
  456: s_ifeqs (int arg)
  457: {
  458:   char *s1, *s2;
  459:   int len1, len2;
  460:   int res;
  461:   struct conditional_frame cframe;
  462: 
  463:   s1 = demand_copy_C_string (&len1);
  464: 
  465:   SKIP_WHITESPACE ();
  466:   if (*input_line_pointer != ',')
  467:     {
  468:       as_bad (_(".ifeqs syntax error"));
  469:       ignore_rest_of_line ();
  470:       return;
  471:     }
  472: 
  473:   ++input_line_pointer;
  474: 
  475:   s2 = demand_copy_C_string (&len2);
  476: 
  477:   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
  478: 
  479:   initialize_cframe (&cframe);
  480:   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
  481:   current_cframe = ((struct conditional_frame *)
  482:                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
  483: 
  484:   if (LISTING_SKIP_COND ()
  485:       && cframe.ignoring
  486:       && (cframe.previous_cframe == NULL
  487:           || ! cframe.previous_cframe->ignoring))
  488:     listing_list (2);
  489: 
  490:   demand_empty_rest_of_line ();
  491: }
  492: 
  493: int
  494: ignore_input (void)
  495: {
  496:   char *s;
  497: 
  498:   s = input_line_pointer;
  499: 
  500:   if (NO_PSEUDO_DOT || flag_m68k_mri)
  501:     {
  502:       if (s[-1] != '.')
  503:         --s;
  504:     }
  505:   else
  506:     {
  507:       if (s[-1] != '.')
  508:         return (current_cframe != NULL) && (current_cframe->ignoring);
  509:     }
  510: 
  511:   /* We cannot ignore certain pseudo ops.  */
  512:   if (((s[0] == 'i'
  513:         || s[0] == 'I')
  514:        && (!strncasecmp (s, "if", 2)
  515:            || !strncasecmp (s, "ifdef", 5)
  516:            || !strncasecmp (s, "ifndef", 6)))
  517:       || ((s[0] == 'e'
  518:            || s[0] == 'E')
  519:           && (!strncasecmp (s, "else", 4)
  520:               || !strncasecmp (s, "endif", 5)
  521:               || !strncasecmp (s, "endc", 4))))
  522:     return 0;
  523: 
  524:   return (current_cframe != NULL) && (current_cframe->ignoring);
  525: }
  526: 
  527: static void
  528: initialize_cframe (struct conditional_frame *cframe)
  529: {
  530:   memset (cframe, 0, sizeof (*cframe));
  531:   as_where (&cframe->if_file_line.file,
  532:             &cframe->if_file_line.line);
  533:   cframe->previous_cframe = current_cframe;
  534:   cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
  535:   cframe->macro_nest = macro_nest;
  536: }
  537: 
  538: /* Give an error if a conditional is unterminated inside a macro or
  539:    the assembly as a whole.  If NEST is non negative, we are being
  540:    called because of the end of a macro expansion.  If NEST is
  541:    negative, we are being called at the of the input files.  */
  542: 
  543: void
  544: cond_finish_check (int nest)
  545: {
  546:   if (current_cframe != NULL && current_cframe->macro_nest >= nest)
  547:     {
  548:       if (nest >= 0)
  549:         as_bad (_("end of macro inside conditional"));
  550:       else
  551:         as_bad (_("end of file inside conditional"));
  552:       as_bad_where (current_cframe->if_file_line.file,
  553:                     current_cframe->if_file_line.line,
  554:                     _("here is the start of the unterminated conditional"));
  555:       if (current_cframe->else_seen)
  556:         as_bad_where (current_cframe->else_file_line.file,
  557:                       current_cframe->else_file_line.line,
  558:                       _("here is the \"else\" of the unterminated conditional"));
  559:     }
  560: }
  561: 
  562: /* This function is called when we exit out of a macro.  We assume
  563:    that any conditionals which began within the macro are correctly
  564:    nested, and just pop them off the stack.  */
  565: 
  566: void
  567: cond_exit_macro (int nest)
  568: {
  569:   while (current_cframe != NULL && current_cframe->macro_nest >= nest)
  570:     {
  571:       struct conditional_frame *hold;
  572: 
  573:       hold = current_cframe;
  574:       current_cframe = current_cframe->previous_cframe;
  575:       obstack_free (&cond_obstack, hold);
  576:     }
  577: }
1
Syntax (Markdown)