Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /* cond.c - conditional assembly pseudo-ops, and .include
  2.    Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
  3.    2003, 2005, 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. }
  578.