* as.h (strdup): Don't declare.
[platform/upstream/binutils.git] / gas / cond.c
1 /* cond.c - conditional assembly pseudo-ops, and .include
2    Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3
4    This file is part of GAS, the GNU Assembler.
5
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to
18    the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "as.h"
21
22 #include "obstack.h"
23
24 /* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */
25 struct obstack cond_obstack;
26
27 struct file_line
28 {
29   char *file;
30   unsigned int line;
31 };                              /* file_line */
32
33 /* This is what we push and pop. */
34 struct conditional_frame
35   {
36     struct file_line if_file_line;      /* the source file & line number of the "if" */
37     struct file_line else_file_line;    /* the source file & line of the "else" */
38     struct conditional_frame *previous_cframe;
39     int else_seen;              /* have we seen an else yet? */
40     int ignoring;               /* if we are currently ignoring input. */
41     int dead_tree;              /* if a conditional at a higher level is ignoring input. */
42   };                            /* conditional_frame */
43
44 static void initialize_cframe PARAMS ((struct conditional_frame *cframe));
45 static char *get_mri_string PARAMS ((int, int *));
46
47 static struct conditional_frame *current_cframe = NULL;
48
49 void 
50 s_ifdef (arg)
51      int arg;
52 {
53   register char *name;          /* points to name of symbol */
54   register struct symbol *symbolP;      /* Points to symbol */
55   struct conditional_frame cframe;
56
57   SKIP_WHITESPACE ();           /* Leading whitespace is part of operand. */
58   name = input_line_pointer;
59
60   if (!is_name_beginner (*name))
61     {
62       as_bad ("invalid identifier for \".ifdef\"");
63       obstack_1grow (&cond_obstack, 0);
64       ignore_rest_of_line ();
65     }
66   else
67     {
68       char c;
69
70       c = get_symbol_end ();
71       symbolP = symbol_find (name);
72       *input_line_pointer = c;
73
74       initialize_cframe (&cframe);
75       cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg);
76       current_cframe = ((struct conditional_frame *)
77                         obstack_copy (&cond_obstack, &cframe,
78                                       sizeof (cframe)));
79       demand_empty_rest_of_line ();
80     }                           /* if a valid identifyer name */
81 }                               /* s_ifdef() */
82
83 void 
84 s_if (arg)
85      int arg;
86 {
87   expressionS operand;
88   struct conditional_frame cframe;
89   int t;
90
91   SKIP_WHITESPACE ();           /* Leading whitespace is part of operand. */
92
93   if (current_cframe != NULL && current_cframe->ignoring)
94     {
95       operand.X_add_number = 0;
96       while (! is_end_of_line[(unsigned char) *input_line_pointer])
97         ++input_line_pointer;
98     }
99   else
100     {
101       expression (&operand);
102       if (operand.X_op != O_constant)
103         as_bad ("non-constant expression in \".if\" statement");
104     }
105
106   switch ((operatorT) arg)
107     {
108     case O_eq: t = operand.X_add_number == 0; break;
109     case O_ne: t = operand.X_add_number != 0; break;
110     case O_lt: t = operand.X_add_number < 0; break;
111     case O_le: t = operand.X_add_number <= 0; break;
112     case O_ge: t = operand.X_add_number >= 0; break;
113     case O_gt: t = operand.X_add_number > 0; break;
114     default:
115       abort ();
116     }
117
118   /* If the above error is signaled, this will dispatch
119      using an undefined result.  No big deal.  */
120   initialize_cframe (&cframe);
121   cframe.ignoring = cframe.dead_tree || ! t;
122   current_cframe = ((struct conditional_frame *)
123                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
124
125   demand_empty_rest_of_line ();
126 }                               /* s_if() */
127
128 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
129
130 static char *
131 get_mri_string (terminator, len)
132      int terminator;
133      int *len;
134 {
135   char *ret;
136   char *s;
137
138   SKIP_WHITESPACE ();
139   s = ret = input_line_pointer;
140   if (*input_line_pointer == '\'')
141     {
142       ++s;
143       ++input_line_pointer;
144       while (! is_end_of_line[(unsigned char) *input_line_pointer])
145         {
146           *s++ = *input_line_pointer++;
147           if (s[-1] == '\'')
148             {
149               if (*input_line_pointer != '\'')
150                 break;
151               ++input_line_pointer;
152             }
153         }
154       SKIP_WHITESPACE ();
155     }
156   else
157     {
158       while (*input_line_pointer != terminator
159              && ! is_end_of_line[(unsigned char) *input_line_pointer])
160         ++input_line_pointer;
161       s = input_line_pointer;
162       while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
163         --s;
164     }
165
166   *len = s - ret;
167   return ret;
168 }
169
170 /* The MRI IFC and IFNC pseudo-ops.  */
171
172 void
173 s_ifc (arg)
174      int arg;
175 {
176   char *s1, *s2;
177   int len1, len2;
178   int res;
179   struct conditional_frame cframe;
180
181   s1 = get_mri_string (',', &len1);
182
183   if (*input_line_pointer != ',')
184     as_bad ("bad format for ifc or ifnc");
185   else
186     ++input_line_pointer;
187
188   s2 = get_mri_string (';', &len2);
189
190   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
191
192   initialize_cframe (&cframe);
193   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
194   current_cframe = ((struct conditional_frame *)
195                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
196 }
197
198 void 
199 s_endif (arg)
200      int arg;
201 {
202   struct conditional_frame *hold;
203
204   if (current_cframe == NULL)
205     {
206       as_bad ("\".endif\" without \".if\"");
207     }
208   else
209     {
210       hold = current_cframe;
211       current_cframe = current_cframe->previous_cframe;
212       obstack_free (&cond_obstack, hold);
213     }                           /* if one pop too many */
214
215   return;
216 }                               /* s_endif() */
217
218 void 
219 s_else (arg)
220      int arg;
221 {
222   if (current_cframe == NULL)
223     {
224       as_bad (".else without matching .if - ignored");
225
226     }
227   else if (current_cframe->else_seen)
228     {
229       as_bad ("duplicate \"else\" - ignored");
230       as_bad_where (current_cframe->else_file_line.file,
231                     current_cframe->else_file_line.line,
232                     "here is the previous \"else\"");
233       as_bad_where (current_cframe->if_file_line.file,
234                     current_cframe->if_file_line.line,
235                     "here is the previous \"if\"");
236     }
237   else
238     {
239       as_where (&current_cframe->else_file_line.file,
240                 &current_cframe->else_file_line.line);
241
242       if (!current_cframe->dead_tree)
243         {
244           current_cframe->ignoring = !current_cframe->ignoring;
245         }                       /* if not a dead tree */
246
247       current_cframe->else_seen = 1;
248     }                           /* if error else do it */
249
250   return;
251 }                               /* s_else() */
252
253 void 
254 s_ifeqs (arg)
255      int arg;
256 {
257   as_bad ("ifeqs not implemented.");
258
259   return;
260 }                               /* s_ifeqs() */
261
262 int 
263 ignore_input ()
264 {
265   char *s;
266
267   s = input_line_pointer;
268
269   if (flag_mri
270 #ifdef NO_PSEUDO_DOT
271       || 1
272 #endif
273       )
274     {
275       if (s[-1] != '.')
276         --s;
277     }
278   else
279     {
280       if (s[-1] != '.')
281         return (current_cframe != NULL) && (current_cframe->ignoring);
282     }
283
284   /* We cannot ignore certain pseudo ops.  */
285   if (((s[0] == 'i'
286         || s[0] == 'I')
287        && (!strncasecmp (s, "if", 2)
288            || !strncasecmp (s, "ifdef", 5)
289            || !strncasecmp (s, "ifndef", 6)))
290       || ((s[0] == 'e'
291            || s[0] == 'E')
292           && (!strncasecmp (s, "else", 4)
293               || !strncasecmp (s, "endif", 5)
294               || !strncasecmp (s, "endc", 4))))
295     return 0;
296
297   return (current_cframe != NULL) && (current_cframe->ignoring);
298 }                               /* ignore_input() */
299
300 static void 
301 initialize_cframe (cframe)
302      struct conditional_frame *cframe;
303 {
304   memset (cframe, 0, sizeof (*cframe));
305   as_where (&cframe->if_file_line.file,
306             &cframe->if_file_line.line);
307   cframe->previous_cframe = current_cframe;
308   cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
309
310   return;
311 }                               /* initialize_cframe() */
312
313 /*
314  * Local Variables:
315  * fill-column: 131
316  * comment-column: 0
317  * End:
318  */
319
320 /* end of cond.c */