Subversion Repositories Kolibri OS

Rev

Rev 5222 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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