cond.c revision 38889
133965Sjdp/* cond.c - conditional assembly pseudo-ops, and .include
238889Sjdp   Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 1998
338889Sjdp   Free Software Foundation, Inc.
433965Sjdp
533965Sjdp   This file is part of GAS, the GNU Assembler.
633965Sjdp
733965Sjdp   GAS is free software; you can redistribute it and/or modify
833965Sjdp   it under the terms of the GNU General Public License as published by
933965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1033965Sjdp   any later version.
1133965Sjdp
1233965Sjdp   GAS is distributed in the hope that it will be useful,
1333965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1433965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1533965Sjdp   GNU General Public License for more details.
1633965Sjdp
1733965Sjdp   You should have received a copy of the GNU General Public License
1833965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
1933965Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2033965Sjdp   02111-1307, USA.  */
2133965Sjdp
2233965Sjdp#include "as.h"
2333965Sjdp#include "macro.h"
2433965Sjdp
2533965Sjdp#include "obstack.h"
2633965Sjdp
2733965Sjdp/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */
2833965Sjdpstruct obstack cond_obstack;
2933965Sjdp
3033965Sjdpstruct file_line
3133965Sjdp{
3233965Sjdp  char *file;
3333965Sjdp  unsigned int line;
3433965Sjdp};
3533965Sjdp
3633965Sjdp/* We push one of these structures for each .if, and pop it at the
3733965Sjdp   .endif.  */
3833965Sjdp
3933965Sjdpstruct conditional_frame
4033965Sjdp{
4133965Sjdp  /* The source file & line number of the "if".  */
4233965Sjdp  struct file_line if_file_line;
4333965Sjdp  /* The source file & line of the "else".  */
4433965Sjdp  struct file_line else_file_line;
4533965Sjdp  /* The previous conditional.  */
4633965Sjdp  struct conditional_frame *previous_cframe;
4733965Sjdp  /* Have we seen an else yet?  */
4833965Sjdp  int else_seen;
4933965Sjdp  /* Whether we are currently ignoring input.  */
5033965Sjdp  int ignoring;
5133965Sjdp  /* Whether a conditional at a higher level is ignoring input.  */
5233965Sjdp  int dead_tree;
5333965Sjdp  /* Macro nesting level at which this conditional was created.  */
5433965Sjdp  int macro_nest;
5533965Sjdp};
5633965Sjdp
5733965Sjdpstatic void initialize_cframe PARAMS ((struct conditional_frame *cframe));
5833965Sjdpstatic char *get_mri_string PARAMS ((int, int *));
5933965Sjdp
6033965Sjdpstatic struct conditional_frame *current_cframe = NULL;
6133965Sjdp
6233965Sjdpvoid
6333965Sjdps_ifdef (arg)
6433965Sjdp     int arg;
6533965Sjdp{
6633965Sjdp  register char *name;		/* points to name of symbol */
6733965Sjdp  register struct symbol *symbolP;	/* Points to symbol */
6833965Sjdp  struct conditional_frame cframe;
6933965Sjdp
7033965Sjdp  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
7133965Sjdp  name = input_line_pointer;
7233965Sjdp
7333965Sjdp  if (!is_name_beginner (*name))
7433965Sjdp    {
7533965Sjdp      as_bad ("invalid identifier for \".ifdef\"");
7633965Sjdp      obstack_1grow (&cond_obstack, 0);
7733965Sjdp      ignore_rest_of_line ();
7833965Sjdp    }
7933965Sjdp  else
8033965Sjdp    {
8133965Sjdp      char c;
8233965Sjdp
8333965Sjdp      c = get_symbol_end ();
8433965Sjdp      symbolP = symbol_find (name);
8533965Sjdp      *input_line_pointer = c;
8633965Sjdp
8733965Sjdp      initialize_cframe (&cframe);
8833965Sjdp      cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg);
8933965Sjdp      current_cframe = ((struct conditional_frame *)
9033965Sjdp			obstack_copy (&cond_obstack, &cframe,
9133965Sjdp				      sizeof (cframe)));
9233965Sjdp
9333965Sjdp      if (LISTING_SKIP_COND ()
9433965Sjdp	  && cframe.ignoring
9533965Sjdp	  && (cframe.previous_cframe == NULL
9633965Sjdp	      || ! cframe.previous_cframe->ignoring))
9733965Sjdp	listing_list (2);
9833965Sjdp
9933965Sjdp      demand_empty_rest_of_line ();
10033965Sjdp    }				/* if a valid identifyer name */
10133965Sjdp}				/* s_ifdef() */
10233965Sjdp
10333965Sjdpvoid
10433965Sjdps_if (arg)
10533965Sjdp     int arg;
10633965Sjdp{
10733965Sjdp  expressionS operand;
10833965Sjdp  struct conditional_frame cframe;
10933965Sjdp  int t;
11033965Sjdp  char *stop = NULL;
11133965Sjdp  char stopc;
11233965Sjdp
11333965Sjdp  if (flag_mri)
11433965Sjdp    stop = mri_comment_field (&stopc);
11533965Sjdp
11633965Sjdp  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
11733965Sjdp
11833965Sjdp  if (current_cframe != NULL && current_cframe->ignoring)
11933965Sjdp    {
12033965Sjdp      operand.X_add_number = 0;
12133965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
12233965Sjdp	++input_line_pointer;
12333965Sjdp    }
12433965Sjdp  else
12533965Sjdp    {
12633965Sjdp      expression (&operand);
12733965Sjdp      if (operand.X_op != O_constant)
12833965Sjdp	as_bad ("non-constant expression in \".if\" statement");
12933965Sjdp    }
13033965Sjdp
13133965Sjdp  switch ((operatorT) arg)
13233965Sjdp    {
13333965Sjdp    case O_eq: t = operand.X_add_number == 0; break;
13433965Sjdp    case O_ne: t = operand.X_add_number != 0; break;
13533965Sjdp    case O_lt: t = operand.X_add_number < 0; break;
13633965Sjdp    case O_le: t = operand.X_add_number <= 0; break;
13733965Sjdp    case O_ge: t = operand.X_add_number >= 0; break;
13833965Sjdp    case O_gt: t = operand.X_add_number > 0; break;
13933965Sjdp    default:
14033965Sjdp      abort ();
14138889Sjdp      return;
14233965Sjdp    }
14333965Sjdp
14433965Sjdp  /* If the above error is signaled, this will dispatch
14533965Sjdp     using an undefined result.  No big deal.  */
14633965Sjdp  initialize_cframe (&cframe);
14733965Sjdp  cframe.ignoring = cframe.dead_tree || ! t;
14833965Sjdp  current_cframe = ((struct conditional_frame *)
14933965Sjdp		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
15033965Sjdp
15133965Sjdp  if (LISTING_SKIP_COND ()
15233965Sjdp      && cframe.ignoring
15333965Sjdp      && (cframe.previous_cframe == NULL
15433965Sjdp	  || ! cframe.previous_cframe->ignoring))
15533965Sjdp    listing_list (2);
15633965Sjdp
15733965Sjdp  if (flag_mri)
15833965Sjdp    mri_comment_end (stop, stopc);
15933965Sjdp
16033965Sjdp  demand_empty_rest_of_line ();
16133965Sjdp}				/* s_if() */
16233965Sjdp
16333965Sjdp/* Get a string for the MRI IFC or IFNC pseudo-ops.  */
16433965Sjdp
16533965Sjdpstatic char *
16633965Sjdpget_mri_string (terminator, len)
16733965Sjdp     int terminator;
16833965Sjdp     int *len;
16933965Sjdp{
17033965Sjdp  char *ret;
17133965Sjdp  char *s;
17233965Sjdp
17333965Sjdp  SKIP_WHITESPACE ();
17433965Sjdp  s = ret = input_line_pointer;
17533965Sjdp  if (*input_line_pointer == '\'')
17633965Sjdp    {
17733965Sjdp      ++s;
17833965Sjdp      ++input_line_pointer;
17933965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
18033965Sjdp	{
18133965Sjdp	  *s++ = *input_line_pointer++;
18233965Sjdp	  if (s[-1] == '\'')
18333965Sjdp	    {
18433965Sjdp	      if (*input_line_pointer != '\'')
18533965Sjdp		break;
18633965Sjdp	      ++input_line_pointer;
18733965Sjdp	    }
18833965Sjdp	}
18933965Sjdp      SKIP_WHITESPACE ();
19033965Sjdp    }
19133965Sjdp  else
19233965Sjdp    {
19333965Sjdp      while (*input_line_pointer != terminator
19433965Sjdp	     && ! is_end_of_line[(unsigned char) *input_line_pointer])
19533965Sjdp	++input_line_pointer;
19633965Sjdp      s = input_line_pointer;
19733965Sjdp      while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
19833965Sjdp	--s;
19933965Sjdp    }
20033965Sjdp
20133965Sjdp  *len = s - ret;
20233965Sjdp  return ret;
20333965Sjdp}
20433965Sjdp
20533965Sjdp/* The MRI IFC and IFNC pseudo-ops.  */
20633965Sjdp
20733965Sjdpvoid
20833965Sjdps_ifc (arg)
20933965Sjdp     int arg;
21033965Sjdp{
21133965Sjdp  char *stop = NULL;
21233965Sjdp  char stopc;
21333965Sjdp  char *s1, *s2;
21433965Sjdp  int len1, len2;
21533965Sjdp  int res;
21633965Sjdp  struct conditional_frame cframe;
21733965Sjdp
21833965Sjdp  if (flag_mri)
21933965Sjdp    stop = mri_comment_field (&stopc);
22033965Sjdp
22133965Sjdp  s1 = get_mri_string (',', &len1);
22233965Sjdp
22333965Sjdp  if (*input_line_pointer != ',')
22433965Sjdp    as_bad ("bad format for ifc or ifnc");
22533965Sjdp  else
22633965Sjdp    ++input_line_pointer;
22733965Sjdp
22833965Sjdp  s2 = get_mri_string (';', &len2);
22933965Sjdp
23033965Sjdp  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
23133965Sjdp
23233965Sjdp  initialize_cframe (&cframe);
23333965Sjdp  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
23433965Sjdp  current_cframe = ((struct conditional_frame *)
23533965Sjdp		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
23633965Sjdp
23733965Sjdp  if (LISTING_SKIP_COND ()
23833965Sjdp      && cframe.ignoring
23933965Sjdp      && (cframe.previous_cframe == NULL
24033965Sjdp	  || ! cframe.previous_cframe->ignoring))
24133965Sjdp    listing_list (2);
24233965Sjdp
24333965Sjdp  if (flag_mri)
24433965Sjdp    mri_comment_end (stop, stopc);
24538889Sjdp
24638889Sjdp  demand_empty_rest_of_line ();
24733965Sjdp}
24833965Sjdp
24933965Sjdpvoid
25033965Sjdps_endif (arg)
25133965Sjdp     int arg;
25233965Sjdp{
25333965Sjdp  struct conditional_frame *hold;
25433965Sjdp
25533965Sjdp  if (current_cframe == NULL)
25633965Sjdp    {
25733965Sjdp      as_bad ("\".endif\" without \".if\"");
25833965Sjdp    }
25933965Sjdp  else
26033965Sjdp    {
26133965Sjdp      if (LISTING_SKIP_COND ()
26233965Sjdp	  && current_cframe->ignoring
26333965Sjdp	  && (current_cframe->previous_cframe == NULL
26433965Sjdp	      || ! current_cframe->previous_cframe->ignoring))
26533965Sjdp	listing_list (1);
26633965Sjdp
26733965Sjdp      hold = current_cframe;
26833965Sjdp      current_cframe = current_cframe->previous_cframe;
26933965Sjdp      obstack_free (&cond_obstack, hold);
27033965Sjdp    }				/* if one pop too many */
27133965Sjdp
27233965Sjdp  if (flag_mri)
27333965Sjdp    {
27433965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
27533965Sjdp	++input_line_pointer;
27633965Sjdp    }
27733965Sjdp
27833965Sjdp  demand_empty_rest_of_line ();
27933965Sjdp}				/* s_endif() */
28033965Sjdp
28133965Sjdpvoid
28233965Sjdps_else (arg)
28333965Sjdp     int arg;
28433965Sjdp{
28533965Sjdp  if (current_cframe == NULL)
28633965Sjdp    {
28733965Sjdp      as_bad (".else without matching .if - ignored");
28833965Sjdp
28933965Sjdp    }
29033965Sjdp  else if (current_cframe->else_seen)
29133965Sjdp    {
29233965Sjdp      as_bad ("duplicate \"else\" - ignored");
29333965Sjdp      as_bad_where (current_cframe->else_file_line.file,
29433965Sjdp		    current_cframe->else_file_line.line,
29533965Sjdp		    "here is the previous \"else\"");
29633965Sjdp      as_bad_where (current_cframe->if_file_line.file,
29733965Sjdp		    current_cframe->if_file_line.line,
29833965Sjdp		    "here is the previous \"if\"");
29933965Sjdp    }
30033965Sjdp  else
30133965Sjdp    {
30233965Sjdp      as_where (&current_cframe->else_file_line.file,
30333965Sjdp		&current_cframe->else_file_line.line);
30433965Sjdp
30533965Sjdp      if (!current_cframe->dead_tree)
30633965Sjdp	{
30733965Sjdp	  current_cframe->ignoring = !current_cframe->ignoring;
30838889Sjdp	  if (LISTING_SKIP_COND ())
30938889Sjdp	    {
31038889Sjdp	      if (! current_cframe->ignoring)
31138889Sjdp		listing_list (1);
31238889Sjdp	      else
31338889Sjdp		listing_list (2);
31438889Sjdp	    }
31533965Sjdp	}			/* if not a dead tree */
31633965Sjdp
31733965Sjdp      current_cframe->else_seen = 1;
31833965Sjdp    }				/* if error else do it */
31933965Sjdp
32033965Sjdp  if (flag_mri)
32133965Sjdp    {
32233965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
32333965Sjdp	++input_line_pointer;
32433965Sjdp    }
32533965Sjdp
32633965Sjdp  demand_empty_rest_of_line ();
32733965Sjdp}				/* s_else() */
32833965Sjdp
32933965Sjdpvoid
33033965Sjdps_ifeqs (arg)
33133965Sjdp     int arg;
33233965Sjdp{
33333965Sjdp  char *s1, *s2;
33433965Sjdp  int len1, len2;
33533965Sjdp  int res;
33633965Sjdp  struct conditional_frame cframe;
33733965Sjdp
33833965Sjdp  s1 = demand_copy_C_string (&len1);
33933965Sjdp
34033965Sjdp  SKIP_WHITESPACE ();
34133965Sjdp  if (*input_line_pointer != ',')
34233965Sjdp    {
34333965Sjdp      as_bad (".ifeqs syntax error");
34433965Sjdp      ignore_rest_of_line ();
34533965Sjdp      return;
34633965Sjdp    }
34733965Sjdp
34833965Sjdp  ++input_line_pointer;
34933965Sjdp
35033965Sjdp  s2 = demand_copy_C_string (&len2);
35133965Sjdp
35233965Sjdp  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
35333965Sjdp
35433965Sjdp  initialize_cframe (&cframe);
35533965Sjdp  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
35633965Sjdp  current_cframe = ((struct conditional_frame *)
35733965Sjdp		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
35833965Sjdp
35933965Sjdp  if (LISTING_SKIP_COND ()
36033965Sjdp      && cframe.ignoring
36133965Sjdp      && (cframe.previous_cframe == NULL
36233965Sjdp	  || ! cframe.previous_cframe->ignoring))
36333965Sjdp    listing_list (2);
36433965Sjdp
36533965Sjdp  demand_empty_rest_of_line ();
36633965Sjdp}				/* s_ifeqs() */
36733965Sjdp
36833965Sjdpint
36933965Sjdpignore_input ()
37033965Sjdp{
37133965Sjdp  char *s;
37233965Sjdp
37333965Sjdp  s = input_line_pointer;
37433965Sjdp
37533965Sjdp  if (flag_m68k_mri
37633965Sjdp#ifdef NO_PSEUDO_DOT
37733965Sjdp      || 1
37833965Sjdp#endif
37933965Sjdp      )
38033965Sjdp    {
38133965Sjdp      if (s[-1] != '.')
38233965Sjdp	--s;
38333965Sjdp    }
38433965Sjdp  else
38533965Sjdp    {
38633965Sjdp      if (s[-1] != '.')
38733965Sjdp	return (current_cframe != NULL) && (current_cframe->ignoring);
38833965Sjdp    }
38933965Sjdp
39033965Sjdp  /* We cannot ignore certain pseudo ops.  */
39133965Sjdp  if (((s[0] == 'i'
39233965Sjdp	|| s[0] == 'I')
39333965Sjdp       && (!strncasecmp (s, "if", 2)
39433965Sjdp	   || !strncasecmp (s, "ifdef", 5)
39533965Sjdp	   || !strncasecmp (s, "ifndef", 6)))
39633965Sjdp      || ((s[0] == 'e'
39733965Sjdp	   || s[0] == 'E')
39833965Sjdp	  && (!strncasecmp (s, "else", 4)
39933965Sjdp	      || !strncasecmp (s, "endif", 5)
40033965Sjdp	      || !strncasecmp (s, "endc", 4))))
40133965Sjdp    return 0;
40233965Sjdp
40333965Sjdp  return (current_cframe != NULL) && (current_cframe->ignoring);
40433965Sjdp}				/* ignore_input() */
40533965Sjdp
40633965Sjdpstatic void
40733965Sjdpinitialize_cframe (cframe)
40833965Sjdp     struct conditional_frame *cframe;
40933965Sjdp{
41033965Sjdp  memset (cframe, 0, sizeof (*cframe));
41133965Sjdp  as_where (&cframe->if_file_line.file,
41233965Sjdp	    &cframe->if_file_line.line);
41333965Sjdp  cframe->previous_cframe = current_cframe;
41433965Sjdp  cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
41533965Sjdp  cframe->macro_nest = macro_nest;
41633965Sjdp}
41733965Sjdp
41833965Sjdp/* Give an error if a conditional is unterminated inside a macro or
41933965Sjdp   the assembly as a whole.  If NEST is non negative, we are being
42033965Sjdp   called because of the end of a macro expansion.  If NEST is
42133965Sjdp   negative, we are being called at the of the input files.  */
42233965Sjdp
42333965Sjdpvoid
42433965Sjdpcond_finish_check (nest)
42533965Sjdp     int nest;
42633965Sjdp{
42733965Sjdp  if (current_cframe != NULL && current_cframe->macro_nest >= nest)
42833965Sjdp    {
42933965Sjdp      as_bad ("end of %s inside conditional",
43033965Sjdp	      nest >= 0 ? "macro" : "file");
43133965Sjdp      as_bad_where (current_cframe->if_file_line.file,
43233965Sjdp		    current_cframe->if_file_line.line,
43333965Sjdp		    "here is the start of the unterminated conditional");
43433965Sjdp      if (current_cframe->else_seen)
43533965Sjdp	as_bad_where (current_cframe->else_file_line.file,
43633965Sjdp		      current_cframe->else_file_line.line,
43733965Sjdp		      "here is the \"else\" of the unterminated conditional");
43833965Sjdp    }
43933965Sjdp}
44033965Sjdp
44133965Sjdp/* This function is called when we exit out of a macro.  We assume
44233965Sjdp   that any conditionals which began within the macro are correctly
44333965Sjdp   nested, and just pop them off the stack.  */
44433965Sjdp
44533965Sjdpvoid
44633965Sjdpcond_exit_macro (nest)
44733965Sjdp     int nest;
44833965Sjdp{
44933965Sjdp  while (current_cframe != NULL && current_cframe->macro_nest >= nest)
45033965Sjdp    {
45133965Sjdp      struct conditional_frame *hold;
45233965Sjdp
45333965Sjdp      hold = current_cframe;
45433965Sjdp      current_cframe = current_cframe->previous_cframe;
45533965Sjdp      obstack_free (&cond_obstack, hold);
45633965Sjdp    }
45733965Sjdp}
45833965Sjdp
45933965Sjdp/* end of cond.c */
460