cond.c revision 60484
133965Sjdp/* cond.c - conditional assembly pseudo-ops, and .include
260484Sobrien   Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 98, 99, 2000
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 */
6760484Sobrien  register symbolS *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    {
7560484Sobrien      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)
12860484Sobrien	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 != ',')
22460484Sobrien    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
25060484Sobriens_elseif (arg)
25133965Sjdp     int arg;
25233965Sjdp{
25360484Sobrien  expressionS operand;
25460484Sobrien  int t;
25560484Sobrien
25660484Sobrien  if (current_cframe == NULL)
25760484Sobrien    {
25860484Sobrien      as_bad (_("\".elseif\" without matching \".if\" - ignored"));
25960484Sobrien
26060484Sobrien    }
26160484Sobrien  else if (current_cframe->else_seen)
26260484Sobrien    {
26360484Sobrien      as_bad (_("\".elseif\" after \".else\" - ignored"));
26460484Sobrien      as_bad_where (current_cframe->else_file_line.file,
26560484Sobrien		    current_cframe->else_file_line.line,
26660484Sobrien		    _("here is the previous \"else\""));
26760484Sobrien      as_bad_where (current_cframe->if_file_line.file,
26860484Sobrien		    current_cframe->if_file_line.line,
26960484Sobrien		    _("here is the previous \"if\""));
27060484Sobrien    }
27160484Sobrien  else
27260484Sobrien    {
27360484Sobrien      as_where (&current_cframe->else_file_line.file,
27460484Sobrien		&current_cframe->else_file_line.line);
27560484Sobrien
27660484Sobrien      if (!current_cframe->dead_tree)
27760484Sobrien	{
27860484Sobrien	  current_cframe->ignoring = !current_cframe->ignoring;
27960484Sobrien	  if (LISTING_SKIP_COND ())
28060484Sobrien	    {
28160484Sobrien	      if (! current_cframe->ignoring)
28260484Sobrien		listing_list (1);
28360484Sobrien	      else
28460484Sobrien		listing_list (2);
28560484Sobrien	    }
28660484Sobrien	}			/* if not a dead tree */
28760484Sobrien    }				/* if error else do it */
28860484Sobrien
28960484Sobrien
29060484Sobrien  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
29160484Sobrien
29260484Sobrien  if (current_cframe != NULL && current_cframe->ignoring)
29360484Sobrien    {
29460484Sobrien      operand.X_add_number = 0;
29560484Sobrien      while (! is_end_of_line[(unsigned char) *input_line_pointer])
29660484Sobrien	++input_line_pointer;
29760484Sobrien    }
29860484Sobrien  else
29960484Sobrien    {
30060484Sobrien      expression (&operand);
30160484Sobrien      if (operand.X_op != O_constant)
30260484Sobrien	as_bad (_("non-constant expression in \".elseif\" statement"));
30360484Sobrien    }
30460484Sobrien
30560484Sobrien  switch ((operatorT) arg)
30660484Sobrien    {
30760484Sobrien    case O_eq: t = operand.X_add_number == 0; break;
30860484Sobrien    case O_ne: t = operand.X_add_number != 0; break;
30960484Sobrien    case O_lt: t = operand.X_add_number < 0; break;
31060484Sobrien    case O_le: t = operand.X_add_number <= 0; break;
31160484Sobrien    case O_ge: t = operand.X_add_number >= 0; break;
31260484Sobrien    case O_gt: t = operand.X_add_number > 0; break;
31360484Sobrien    default:
31460484Sobrien      abort ();
31560484Sobrien      return;
31660484Sobrien    }
31760484Sobrien
31860484Sobrien  current_cframe->ignoring = current_cframe->dead_tree || ! t;
31960484Sobrien
32060484Sobrien  if (LISTING_SKIP_COND ()
32160484Sobrien      && current_cframe->ignoring
32260484Sobrien      && (current_cframe->previous_cframe == NULL
32360484Sobrien	  || ! current_cframe->previous_cframe->ignoring))
32460484Sobrien    listing_list (2);
32560484Sobrien
32660484Sobrien  demand_empty_rest_of_line ();
32760484Sobrien}
32860484Sobrien
32960484Sobrienvoid
33060484Sobriens_endif (arg)
33160484Sobrien     int arg ATTRIBUTE_UNUSED;
33260484Sobrien{
33333965Sjdp  struct conditional_frame *hold;
33433965Sjdp
33533965Sjdp  if (current_cframe == NULL)
33633965Sjdp    {
33760484Sobrien      as_bad (_("\".endif\" without \".if\""));
33833965Sjdp    }
33933965Sjdp  else
34033965Sjdp    {
34133965Sjdp      if (LISTING_SKIP_COND ()
34233965Sjdp	  && current_cframe->ignoring
34333965Sjdp	  && (current_cframe->previous_cframe == NULL
34433965Sjdp	      || ! current_cframe->previous_cframe->ignoring))
34533965Sjdp	listing_list (1);
34633965Sjdp
34733965Sjdp      hold = current_cframe;
34833965Sjdp      current_cframe = current_cframe->previous_cframe;
34933965Sjdp      obstack_free (&cond_obstack, hold);
35033965Sjdp    }				/* if one pop too many */
35133965Sjdp
35233965Sjdp  if (flag_mri)
35333965Sjdp    {
35433965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
35533965Sjdp	++input_line_pointer;
35633965Sjdp    }
35733965Sjdp
35833965Sjdp  demand_empty_rest_of_line ();
35933965Sjdp}				/* s_endif() */
36033965Sjdp
36133965Sjdpvoid
36233965Sjdps_else (arg)
36360484Sobrien     int arg ATTRIBUTE_UNUSED;
36433965Sjdp{
36533965Sjdp  if (current_cframe == NULL)
36633965Sjdp    {
36760484Sobrien      as_bad (_(".else without matching .if - ignored"));
36833965Sjdp
36933965Sjdp    }
37033965Sjdp  else if (current_cframe->else_seen)
37133965Sjdp    {
37260484Sobrien      as_bad (_("duplicate \"else\" - ignored"));
37333965Sjdp      as_bad_where (current_cframe->else_file_line.file,
37433965Sjdp		    current_cframe->else_file_line.line,
37560484Sobrien		    _("here is the previous \"else\""));
37633965Sjdp      as_bad_where (current_cframe->if_file_line.file,
37733965Sjdp		    current_cframe->if_file_line.line,
37860484Sobrien		    _("here is the previous \"if\""));
37933965Sjdp    }
38033965Sjdp  else
38133965Sjdp    {
38233965Sjdp      as_where (&current_cframe->else_file_line.file,
38333965Sjdp		&current_cframe->else_file_line.line);
38433965Sjdp
38533965Sjdp      if (!current_cframe->dead_tree)
38633965Sjdp	{
38733965Sjdp	  current_cframe->ignoring = !current_cframe->ignoring;
38838889Sjdp	  if (LISTING_SKIP_COND ())
38938889Sjdp	    {
39038889Sjdp	      if (! current_cframe->ignoring)
39138889Sjdp		listing_list (1);
39238889Sjdp	      else
39338889Sjdp		listing_list (2);
39438889Sjdp	    }
39533965Sjdp	}			/* if not a dead tree */
39633965Sjdp
39733965Sjdp      current_cframe->else_seen = 1;
39833965Sjdp    }				/* if error else do it */
39933965Sjdp
40033965Sjdp  if (flag_mri)
40133965Sjdp    {
40233965Sjdp      while (! is_end_of_line[(unsigned char) *input_line_pointer])
40333965Sjdp	++input_line_pointer;
40433965Sjdp    }
40533965Sjdp
40633965Sjdp  demand_empty_rest_of_line ();
40733965Sjdp}				/* s_else() */
40833965Sjdp
40933965Sjdpvoid
41033965Sjdps_ifeqs (arg)
41133965Sjdp     int arg;
41233965Sjdp{
41333965Sjdp  char *s1, *s2;
41433965Sjdp  int len1, len2;
41533965Sjdp  int res;
41633965Sjdp  struct conditional_frame cframe;
41733965Sjdp
41833965Sjdp  s1 = demand_copy_C_string (&len1);
41933965Sjdp
42033965Sjdp  SKIP_WHITESPACE ();
42133965Sjdp  if (*input_line_pointer != ',')
42233965Sjdp    {
42360484Sobrien      as_bad (_(".ifeqs syntax error"));
42433965Sjdp      ignore_rest_of_line ();
42533965Sjdp      return;
42633965Sjdp    }
42733965Sjdp
42833965Sjdp  ++input_line_pointer;
42933965Sjdp
43033965Sjdp  s2 = demand_copy_C_string (&len2);
43133965Sjdp
43233965Sjdp  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
43333965Sjdp
43433965Sjdp  initialize_cframe (&cframe);
43533965Sjdp  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
43633965Sjdp  current_cframe = ((struct conditional_frame *)
43733965Sjdp		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
43833965Sjdp
43933965Sjdp  if (LISTING_SKIP_COND ()
44033965Sjdp      && cframe.ignoring
44133965Sjdp      && (cframe.previous_cframe == NULL
44233965Sjdp	  || ! cframe.previous_cframe->ignoring))
44333965Sjdp    listing_list (2);
44433965Sjdp
44533965Sjdp  demand_empty_rest_of_line ();
44633965Sjdp}				/* s_ifeqs() */
44733965Sjdp
44833965Sjdpint
44933965Sjdpignore_input ()
45033965Sjdp{
45133965Sjdp  char *s;
45233965Sjdp
45333965Sjdp  s = input_line_pointer;
45433965Sjdp
45560484Sobrien  if (NO_PSEUDO_DOT || flag_m68k_mri)
45633965Sjdp    {
45733965Sjdp      if (s[-1] != '.')
45833965Sjdp	--s;
45933965Sjdp    }
46033965Sjdp  else
46133965Sjdp    {
46233965Sjdp      if (s[-1] != '.')
46333965Sjdp	return (current_cframe != NULL) && (current_cframe->ignoring);
46433965Sjdp    }
46533965Sjdp
46633965Sjdp  /* We cannot ignore certain pseudo ops.  */
46733965Sjdp  if (((s[0] == 'i'
46833965Sjdp	|| s[0] == 'I')
46933965Sjdp       && (!strncasecmp (s, "if", 2)
47033965Sjdp	   || !strncasecmp (s, "ifdef", 5)
47133965Sjdp	   || !strncasecmp (s, "ifndef", 6)))
47233965Sjdp      || ((s[0] == 'e'
47333965Sjdp	   || s[0] == 'E')
47433965Sjdp	  && (!strncasecmp (s, "else", 4)
47533965Sjdp	      || !strncasecmp (s, "endif", 5)
47633965Sjdp	      || !strncasecmp (s, "endc", 4))))
47733965Sjdp    return 0;
47833965Sjdp
47933965Sjdp  return (current_cframe != NULL) && (current_cframe->ignoring);
48033965Sjdp}				/* ignore_input() */
48133965Sjdp
48233965Sjdpstatic void
48333965Sjdpinitialize_cframe (cframe)
48433965Sjdp     struct conditional_frame *cframe;
48533965Sjdp{
48633965Sjdp  memset (cframe, 0, sizeof (*cframe));
48733965Sjdp  as_where (&cframe->if_file_line.file,
48833965Sjdp	    &cframe->if_file_line.line);
48933965Sjdp  cframe->previous_cframe = current_cframe;
49033965Sjdp  cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
49133965Sjdp  cframe->macro_nest = macro_nest;
49233965Sjdp}
49333965Sjdp
49433965Sjdp/* Give an error if a conditional is unterminated inside a macro or
49533965Sjdp   the assembly as a whole.  If NEST is non negative, we are being
49633965Sjdp   called because of the end of a macro expansion.  If NEST is
49733965Sjdp   negative, we are being called at the of the input files.  */
49833965Sjdp
49933965Sjdpvoid
50033965Sjdpcond_finish_check (nest)
50133965Sjdp     int nest;
50233965Sjdp{
50333965Sjdp  if (current_cframe != NULL && current_cframe->macro_nest >= nest)
50433965Sjdp    {
50560484Sobrien      if (nest >= 0)
50660484Sobrien	as_bad (_("end of macro inside conditional"));
50760484Sobrien      else
50860484Sobrien	as_bad (_("end of file inside conditional"));
50933965Sjdp      as_bad_where (current_cframe->if_file_line.file,
51033965Sjdp		    current_cframe->if_file_line.line,
51160484Sobrien		    _("here is the start of the unterminated conditional"));
51233965Sjdp      if (current_cframe->else_seen)
51333965Sjdp	as_bad_where (current_cframe->else_file_line.file,
51433965Sjdp		      current_cframe->else_file_line.line,
51560484Sobrien		      _("here is the \"else\" of the unterminated conditional"));
51633965Sjdp    }
51733965Sjdp}
51833965Sjdp
51933965Sjdp/* This function is called when we exit out of a macro.  We assume
52033965Sjdp   that any conditionals which began within the macro are correctly
52133965Sjdp   nested, and just pop them off the stack.  */
52233965Sjdp
52333965Sjdpvoid
52433965Sjdpcond_exit_macro (nest)
52533965Sjdp     int nest;
52633965Sjdp{
52733965Sjdp  while (current_cframe != NULL && current_cframe->macro_nest >= nest)
52833965Sjdp    {
52933965Sjdp      struct conditional_frame *hold;
53033965Sjdp
53133965Sjdp      hold = current_cframe;
53233965Sjdp      current_cframe = current_cframe->previous_cframe;
53333965Sjdp      obstack_free (&cond_obstack, hold);
53433965Sjdp    }
53533965Sjdp}
53633965Sjdp
53733965Sjdp/* end of cond.c */
538