aboutsummaryrefslogtreecommitdiff
path: root/gas/cond.c
blob: 38aec6fe4e3995b785f0080870fbb1bfd271e565 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* cond.c - conditional assembly pseudo-ops, and .include
   Copyright (C) 1990, 1991 Free Software Foundation, Inc.

This file is part of GAS, the GNU Assembler.

GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* static const char rcsid[] = "$Id$"; */

#include "as.h"

#include "obstack.h"

void s_ifdef(arg)
int arg;
{
/*	register char c; */
	register char *name;	/* points to name of symbol */
	register struct symbol *	symbolP; /* Points to symbol */
	
	SKIP_WHITESPACE();		/* Leading whitespace is part of operand. */
	name = input_line_pointer;
	if (!is_name_beginner(*name)) {
		as_bad("invalid identifier for .ifdef");
		obstack_1grow (&cond_obstack, 0);
	} else {
		get_symbol_end();
		++input_line_pointer;
		symbolP = symbol_find(name);
		
		/* ??? Should we try to optimize such that if we hit a .endif
		   before a .else, we don't need to push state?  */
		obstack_1grow(&cond_obstack, (symbolP != 0) ^ arg);
	}
} /* s_ifdef() */

/* This is allocated to grow and shrink as .ifdef/.endif pairs
   are scanned.  When the top element is nonzero, it means
   we should accept input.  Otherwise, we should ignore input.  */
struct obstack cond_obstack;

void s_if(arg)
int arg;
{
	expressionS operand;
	
	SKIP_WHITESPACE();		/* Leading whitespace is part of operand. */
	expr(0, &operand);
	
	if (operand.X_add_symbol != NULL
	    || operand.X_subtract_symbol != NULL)
	    as_bad("non-constant expression in .if statement");
	
	/* If the above error is signaled, this will dispatch
	   using an undefined result.  No big deal.  */
	obstack_1grow(&cond_obstack, (operand.X_add_number != 0) ^ arg);
} /* s_if() */

void s_endif(arg)
int arg;
{
	char *base = obstack_base(&cond_obstack);
	char *ptr = obstack_next_free(&cond_obstack);
	
	if (ptr-1 == base) {
		as_bad("unbalanced .endif");
	} else {
		obstack_free(&cond_obstack, ptr-1);
		cond_obstack.object_base = base;
	}
} /* s_endif() */

void s_else(arg)
int arg;
{
	char *ptr = obstack_next_free(&cond_obstack);
	if (ptr-1 == obstack_base(&cond_obstack)) {
		as_bad(".else without matching .if");
	} else {
		ptr[-1] = !ptr[-1];
	}
} /* s_else() */

void s_ifeqs(arg)
int arg;
{
	as_bad("ifeqs not implemented.");
} /* s_ifeqs() */

void s_end(arg)
int arg;
{
	;
} /* s_end() */

int ignore_input() {
  char *ptr = obstack_next_free (&cond_obstack);

  /* We cannot ignore certain pseudo ops.  */
  if (input_line_pointer[-1] == '.')
    {
      if (input_line_pointer[0] == 'i'
	  && (!strncmp (input_line_pointer, "if", 2)
	      || !strncmp (input_line_pointer, "ifdef", 5)
	      || !strncmp (input_line_pointer, "ifndef", 6)))
	return 0;
      if (input_line_pointer[0] == 'e'
	  && (!strncmp (input_line_pointer, "else", 4)
	      || !strncmp (input_line_pointer, "endif", 5)))
	return 0;
    }

  return (ptr[-1] == 0);
} /* ignore_input() */

/* end of cond.c */