cond.c revision 33965
111820Sjulian/* cond.c - conditional assembly pseudo-ops, and .include
211820Sjulian   Copyright (C) 1990, 91, 92, 93, 95, 96, 1997 Free Software Foundation, Inc.
311820Sjulian
411820Sjulian   This file is part of GAS, the GNU Assembler.
511820Sjulian
611820Sjulian   GAS is free software; you can redistribute it and/or modify
711820Sjulian   it under the terms of the GNU General Public License as published by
811820Sjulian   the Free Software Foundation; either version 2, or (at your option)
911820Sjulian   any later version.
1011820Sjulian
1111820Sjulian   GAS is distributed in the hope that it will be useful,
1211820Sjulian   but WITHOUT ANY WARRANTY; without even the implied warranty of
1311820Sjulian   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1411820Sjulian   GNU General Public License for more details.
1511820Sjulian
1611820Sjulian   You should have received a copy of the GNU General Public License
1711820Sjulian   along with GAS; see the file COPYING.  If not, write to the Free
1811820Sjulian   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1911820Sjulian   02111-1307, USA.  */
2011820Sjulian
2111820Sjulian#include "as.h"
2211820Sjulian#include "macro.h"
2311820Sjulian
2411820Sjulian#include "obstack.h"
2511820Sjulian
2611820Sjulian/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */
2711820Sjulianstruct obstack cond_obstack;
2811820Sjulian
2911820Sjulianstruct file_line
3011820Sjulian{
3111820Sjulian  char *file;
3211820Sjulian  unsigned int line;
3311820Sjulian};
3411820Sjulian
3511820Sjulian/* We push one of these structures for each .if, and pop it at the
3611820Sjulian   .endif.  */
3711820Sjulian
3827244Sjhaystruct conditional_frame
3911820Sjulian{
4011820Sjulian  /* The source file & line number of the "if".  */
4111820Sjulian  struct file_line if_file_line;
4211820Sjulian  /* The source file & line of the "else".  */
4311820Sjulian  struct file_line else_file_line;
4411820Sjulian  /* The previous conditional.  */
4511820Sjulian  struct conditional_frame *previous_cframe;
4611820Sjulian  /* Have we seen an else yet?  */
4711820Sjulian  int else_seen;
4811820Sjulian  /* Whether we are currently ignoring input.  */
4911820Sjulian  int ignoring;
5011820Sjulian  /* Whether a conditional at a higher level is ignoring input.  */
5111820Sjulian  int dead_tree;
5211820Sjulian  /* Macro nesting level at which this conditional was created.  */
5311820Sjulian  int macro_nest;
5411820Sjulian};
5511820Sjulian
5611820Sjulianstatic void initialize_cframe PARAMS ((struct conditional_frame *cframe));
5711820Sjulianstatic char *get_mri_string PARAMS ((int, int *));
5811820Sjulian
5911820Sjulianstatic struct conditional_frame *current_cframe = NULL;
6011820Sjulian
6111820Sjulianvoid
6211820Sjulians_ifdef (arg)
6311820Sjulian     int arg;
6411820Sjulian{
6511820Sjulian  register char *name;		/* points to name of symbol */
6627244Sjhay  register struct symbol *symbolP;	/* Points to symbol */
6711820Sjulian  struct conditional_frame cframe;
6811820Sjulian
6911820Sjulian  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
7011820Sjulian  name = input_line_pointer;
7111820Sjulian
7211820Sjulian  if (!is_name_beginner (*name))
7311820Sjulian    {
7411820Sjulian      as_bad ("invalid identifier for \".ifdef\"");
7511820Sjulian      obstack_1grow (&cond_obstack, 0);
7627244Sjhay      ignore_rest_of_line ();
7711820Sjulian    }
7811820Sjulian  else
7911820Sjulian    {
8011820Sjulian      char c;
8111820Sjulian
8211820Sjulian      c = get_symbol_end ();
8311820Sjulian      symbolP = symbol_find (name);
8411820Sjulian      *input_line_pointer = c;
8511820Sjulian
8611820Sjulian      initialize_cframe (&cframe);
8711820Sjulian      cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg);
8811820Sjulian      current_cframe = ((struct conditional_frame *)
8911820Sjulian			obstack_copy (&cond_obstack, &cframe,
9011820Sjulian				      sizeof (cframe)));
9111820Sjulian
9211820Sjulian      if (LISTING_SKIP_COND ()
9311820Sjulian	  && cframe.ignoring
9411820Sjulian	  && (cframe.previous_cframe == NULL
9511820Sjulian	      || ! cframe.previous_cframe->ignoring))
9611820Sjulian	listing_list (2);
9711820Sjulian
9811820Sjulian      demand_empty_rest_of_line ();
9911820Sjulian    }				/* if a valid identifyer name */
10011820Sjulian}				/* s_ifdef() */
10111820Sjulian
10211820Sjulianvoid
10311820Sjulians_if (arg)
10411820Sjulian     int arg;
10511820Sjulian{
10611820Sjulian  expressionS operand;
10711820Sjulian  struct conditional_frame cframe;
10811820Sjulian  int t;
10911820Sjulian  char *stop = NULL;
11011820Sjulian  char stopc;
11111820Sjulian
11211820Sjulian  if (flag_mri)
11327244Sjhay    stop = mri_comment_field (&stopc);
11411820Sjulian
11527244Sjhay  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
11627244Sjhay
11711820Sjulian  if (current_cframe != NULL && current_cframe->ignoring)
11811820Sjulian    {
11911820Sjulian      operand.X_add_number = 0;
12011820Sjulian      while (! is_end_of_line[(unsigned char) *input_line_pointer])
12111820Sjulian	++input_line_pointer;
12211820Sjulian    }
12311820Sjulian  else
12411820Sjulian    {
12511820Sjulian      expression (&operand);
12611820Sjulian      if (operand.X_op != O_constant)
12711820Sjulian	as_bad ("non-constant expression in \".if\" statement");
12827244Sjhay    }
12927244Sjhay
13011820Sjulian  switch ((operatorT) arg)
13111820Sjulian    {
13211820Sjulian    case O_eq: t = operand.X_add_number == 0; break;
13311820Sjulian    case O_ne: t = operand.X_add_number != 0; break;
13411820Sjulian    case O_lt: t = operand.X_add_number < 0; break;
13511820Sjulian    case O_le: t = operand.X_add_number <= 0; break;
13611820Sjulian    case O_ge: t = operand.X_add_number >= 0; break;
13727244Sjhay    case O_gt: t = operand.X_add_number > 0; break;
13811820Sjulian    default:
13911820Sjulian      abort ();
14011820Sjulian    }
14111820Sjulian
14227244Sjhay  /* If the above error is signaled, this will dispatch
14311820Sjulian     using an undefined result.  No big deal.  */
14411820Sjulian  initialize_cframe (&cframe);
14511820Sjulian  cframe.ignoring = cframe.dead_tree || ! t;
14611820Sjulian  current_cframe = ((struct conditional_frame *)
14711820Sjulian		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
14811820Sjulian
14911820Sjulian  if (LISTING_SKIP_COND ()
15011820Sjulian      && cframe.ignoring
15111820Sjulian      && (cframe.previous_cframe == NULL
15211820Sjulian	  || ! cframe.previous_cframe->ignoring))
15311820Sjulian    listing_list (2);
15411820Sjulian
15511820Sjulian  if (flag_mri)
15611820Sjulian    mri_comment_end (stop, stopc);
15711820Sjulian
15811820Sjulian  demand_empty_rest_of_line ();
15911820Sjulian}				/* s_if() */
16011820Sjulian
16111820Sjulian/* Get a string for the MRI IFC or IFNC pseudo-ops.  */
16211820Sjulian
16311820Sjulianstatic char *
16411820Sjulianget_mri_string (terminator, len)
16511820Sjulian     int terminator;
16611820Sjulian     int *len;
16711820Sjulian{
16811820Sjulian  char *ret;
16911820Sjulian  char *s;
17011820Sjulian
17111820Sjulian  SKIP_WHITESPACE ();
17227244Sjhay  s = ret = input_line_pointer;
17327244Sjhay  if (*input_line_pointer == '\'')
17427244Sjhay    {
17527244Sjhay      ++s;
17611820Sjulian      ++input_line_pointer;
17711820Sjulian      while (! is_end_of_line[(unsigned char) *input_line_pointer])
17811820Sjulian	{
17911820Sjulian	  *s++ = *input_line_pointer++;
18011820Sjulian	  if (s[-1] == '\'')
18111820Sjulian	    {
18211820Sjulian	      if (*input_line_pointer != '\'')
18311820Sjulian		break;
18411820Sjulian	      ++input_line_pointer;
18527244Sjhay	    }
18627244Sjhay	}
18727244Sjhay      SKIP_WHITESPACE ();
18827244Sjhay    }
18927244Sjhay  else
19027244Sjhay    {
19127244Sjhay      while (*input_line_pointer != terminator
19227244Sjhay	     && ! is_end_of_line[(unsigned char) *input_line_pointer])
19327244Sjhay	++input_line_pointer;
19427244Sjhay      s = input_line_pointer;
19527244Sjhay      while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
19627244Sjhay	--s;
19727244Sjhay    }
19827244Sjhay
19927244Sjhay  *len = s - ret;
20011820Sjulian  return ret;
20111820Sjulian}
20211820Sjulian
20327244Sjhay/* The MRI IFC and IFNC pseudo-ops.  */
20411820Sjulian
20511820Sjulianvoid
20611820Sjulians_ifc (arg)
20711820Sjulian     int arg;
20811820Sjulian{
20911820Sjulian  char *stop = NULL;
21011820Sjulian  char stopc;
21111820Sjulian  char *s1, *s2;
21211820Sjulian  int len1, len2;
21311820Sjulian  int res;
21411820Sjulian  struct conditional_frame cframe;
21511820Sjulian
21611820Sjulian  if (flag_mri)
21711820Sjulian    stop = mri_comment_field (&stopc);
21811820Sjulian
21911820Sjulian  s1 = get_mri_string (',', &len1);
22027244Sjhay
22111820Sjulian  if (*input_line_pointer != ',')
22211820Sjulian    as_bad ("bad format for ifc or ifnc");
22311820Sjulian  else
22411820Sjulian    ++input_line_pointer;
22527244Sjhay
22611820Sjulian  s2 = get_mri_string (';', &len2);
22711820Sjulian
22811820Sjulian  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
22911820Sjulian
23011820Sjulian  initialize_cframe (&cframe);
23111820Sjulian  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
23211820Sjulian  current_cframe = ((struct conditional_frame *)
23311820Sjulian		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
23411820Sjulian
23511820Sjulian  if (LISTING_SKIP_COND ()
23627244Sjhay      && cframe.ignoring
23711820Sjulian      && (cframe.previous_cframe == NULL
23811820Sjulian	  || ! cframe.previous_cframe->ignoring))
23911820Sjulian    listing_list (2);
240
241  if (flag_mri)
242    mri_comment_end (stop, stopc);
243}
244
245void
246s_endif (arg)
247     int arg;
248{
249  struct conditional_frame *hold;
250
251  if (current_cframe == NULL)
252    {
253      as_bad ("\".endif\" without \".if\"");
254    }
255  else
256    {
257      if (LISTING_SKIP_COND ()
258	  && current_cframe->ignoring
259	  && (current_cframe->previous_cframe == NULL
260	      || ! current_cframe->previous_cframe->ignoring))
261	listing_list (1);
262
263      hold = current_cframe;
264      current_cframe = current_cframe->previous_cframe;
265      obstack_free (&cond_obstack, hold);
266    }				/* if one pop too many */
267
268  if (flag_mri)
269    {
270      while (! is_end_of_line[(unsigned char) *input_line_pointer])
271	++input_line_pointer;
272    }
273
274  demand_empty_rest_of_line ();
275}				/* s_endif() */
276
277void
278s_else (arg)
279     int arg;
280{
281  if (current_cframe == NULL)
282    {
283      as_bad (".else without matching .if - ignored");
284
285    }
286  else if (current_cframe->else_seen)
287    {
288      as_bad ("duplicate \"else\" - ignored");
289      as_bad_where (current_cframe->else_file_line.file,
290		    current_cframe->else_file_line.line,
291		    "here is the previous \"else\"");
292      as_bad_where (current_cframe->if_file_line.file,
293		    current_cframe->if_file_line.line,
294		    "here is the previous \"if\"");
295    }
296  else
297    {
298      as_where (&current_cframe->else_file_line.file,
299		&current_cframe->else_file_line.line);
300
301      if (!current_cframe->dead_tree)
302	{
303	  current_cframe->ignoring = !current_cframe->ignoring;
304	  if (LISTING_SKIP_COND ()
305	      && ! current_cframe->ignoring)
306	    listing_list (1);
307	}			/* if not a dead tree */
308
309      current_cframe->else_seen = 1;
310    }				/* if error else do it */
311
312  if (flag_mri)
313    {
314      while (! is_end_of_line[(unsigned char) *input_line_pointer])
315	++input_line_pointer;
316    }
317
318  demand_empty_rest_of_line ();
319}				/* s_else() */
320
321void
322s_ifeqs (arg)
323     int arg;
324{
325  char *s1, *s2;
326  int len1, len2;
327  int res;
328  struct conditional_frame cframe;
329
330  s1 = demand_copy_C_string (&len1);
331
332  SKIP_WHITESPACE ();
333  if (*input_line_pointer != ',')
334    {
335      as_bad (".ifeqs syntax error");
336      ignore_rest_of_line ();
337      return;
338    }
339
340  ++input_line_pointer;
341
342  s2 = demand_copy_C_string (&len2);
343
344  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
345
346  initialize_cframe (&cframe);
347  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
348  current_cframe = ((struct conditional_frame *)
349		    obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
350
351  if (LISTING_SKIP_COND ()
352      && cframe.ignoring
353      && (cframe.previous_cframe == NULL
354	  || ! cframe.previous_cframe->ignoring))
355    listing_list (2);
356
357  demand_empty_rest_of_line ();
358}				/* s_ifeqs() */
359
360int
361ignore_input ()
362{
363  char *s;
364
365  s = input_line_pointer;
366
367  if (flag_m68k_mri
368#ifdef NO_PSEUDO_DOT
369      || 1
370#endif
371      )
372    {
373      if (s[-1] != '.')
374	--s;
375    }
376  else
377    {
378      if (s[-1] != '.')
379	return (current_cframe != NULL) && (current_cframe->ignoring);
380    }
381
382  /* We cannot ignore certain pseudo ops.  */
383  if (((s[0] == 'i'
384	|| s[0] == 'I')
385       && (!strncasecmp (s, "if", 2)
386	   || !strncasecmp (s, "ifdef", 5)
387	   || !strncasecmp (s, "ifndef", 6)))
388      || ((s[0] == 'e'
389	   || s[0] == 'E')
390	  && (!strncasecmp (s, "else", 4)
391	      || !strncasecmp (s, "endif", 5)
392	      || !strncasecmp (s, "endc", 4))))
393    return 0;
394
395  return (current_cframe != NULL) && (current_cframe->ignoring);
396}				/* ignore_input() */
397
398static void
399initialize_cframe (cframe)
400     struct conditional_frame *cframe;
401{
402  memset (cframe, 0, sizeof (*cframe));
403  as_where (&cframe->if_file_line.file,
404	    &cframe->if_file_line.line);
405  cframe->previous_cframe = current_cframe;
406  cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
407  cframe->macro_nest = macro_nest;
408}
409
410/* Give an error if a conditional is unterminated inside a macro or
411   the assembly as a whole.  If NEST is non negative, we are being
412   called because of the end of a macro expansion.  If NEST is
413   negative, we are being called at the of the input files.  */
414
415void
416cond_finish_check (nest)
417     int nest;
418{
419  if (current_cframe != NULL && current_cframe->macro_nest >= nest)
420    {
421      as_bad ("end of %s inside conditional",
422	      nest >= 0 ? "macro" : "file");
423      as_bad_where (current_cframe->if_file_line.file,
424		    current_cframe->if_file_line.line,
425		    "here is the start of the unterminated conditional");
426      if (current_cframe->else_seen)
427	as_bad_where (current_cframe->else_file_line.file,
428		      current_cframe->else_file_line.line,
429		      "here is the \"else\" of the unterminated conditional");
430    }
431}
432
433/* This function is called when we exit out of a macro.  We assume
434   that any conditionals which began within the macro are correctly
435   nested, and just pop them off the stack.  */
436
437void
438cond_exit_macro (nest)
439     int nest;
440{
441  while (current_cframe != NULL && current_cframe->macro_nest >= nest)
442    {
443      struct conditional_frame *hold;
444
445      hold = current_cframe;
446      current_cframe = current_cframe->previous_cframe;
447      obstack_free (&cond_obstack, hold);
448    }
449}
450
451/* end of cond.c */
452