Merge branch 'vendor/GCC44'
[dragonfly.git] / contrib / binutils-2.22 / gas / cond.c
1 /* cond.c - conditional assembly pseudo-ops, and .include
2    Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
3    2003, 2005, 2006, 2007 Free Software Foundation, Inc.
4
5    This file is part of GAS, the GNU Assembler.
6
7    GAS is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11
12    GAS is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GAS; see the file COPYING.  If not, write to the Free
19    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20    02110-1301, USA.  */
21
22 #include "as.h"
23 #include "sb.h"
24 #include "macro.h"
25
26 #include "obstack.h"
27
28 /* This is allocated to grow and shrink as .ifdef/.endif pairs are
29    scanned.  */
30 struct obstack cond_obstack;
31
32 struct file_line {
33   char *file;
34   unsigned int line;
35 };
36
37 /* We push one of these structures for each .if, and pop it at the
38    .endif.  */
39
40 struct conditional_frame {
41   /* The source file & line number of the "if".  */
42   struct file_line if_file_line;
43   /* The source file & line of the "else".  */
44   struct file_line else_file_line;
45   /* The previous conditional.  */
46   struct conditional_frame *previous_cframe;
47   /* Have we seen an else yet?  */
48   int else_seen;
49   /* Whether we are currently ignoring input.  */
50   int ignoring;
51   /* Whether a conditional at a higher level is ignoring input.
52      Set also when a branch of an "if .. elseif .." tree has matched
53      to prevent further matches.  */
54   int dead_tree;
55   /* Macro nesting level at which this conditional was created.  */
56   int macro_nest;
57 };
58
59 static void initialize_cframe (struct conditional_frame *cframe);
60 static char *get_mri_string (int, int *);
61
62 static struct conditional_frame *current_cframe = NULL;
63
64 /* Performs the .ifdef (test_defined == 1) and
65    the .ifndef (test_defined == 0) pseudo op.  */
66
67 void
68 s_ifdef (int test_defined)
69 {
70   /* Points to name of symbol.  */
71   char *name;
72   /* Points to symbol.  */
73   symbolS *symbolP;
74   struct conditional_frame cframe;
75   char c;
76
77   /* Leading whitespace is part of operand.  */
78   SKIP_WHITESPACE ();
79   name = input_line_pointer;
80
81   if (!is_name_beginner (*name))
82     {
83       as_bad (_("invalid identifier for \".ifdef\""));
84       obstack_1grow (&cond_obstack, 0);
85       ignore_rest_of_line ();
86       return;
87     }
88
89   c = get_symbol_end ();
90   symbolP = symbol_find (name);
91   *input_line_pointer = c;
92
93   initialize_cframe (&cframe);
94   
95   if (cframe.dead_tree)
96     cframe.ignoring = 1;
97   else
98     {
99       int is_defined;
100
101       /* Use the same definition of 'defined' as .equiv so that a symbol
102          which has been referenced but not yet given a value/address is
103          considered to be undefined.  */
104       is_defined =
105         symbolP != NULL
106         && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
107         && S_GET_SEGMENT (symbolP) != reg_section;
108
109       cframe.ignoring = ! (test_defined ^ is_defined);
110     }
111
112   current_cframe = ((struct conditional_frame *)
113                     obstack_copy (&cond_obstack, &cframe,
114                                   sizeof (cframe)));
115
116   if (LISTING_SKIP_COND ()
117       && cframe.ignoring
118       && (cframe.previous_cframe == NULL
119           || ! cframe.previous_cframe->ignoring))
120     listing_list (2);
121
122   demand_empty_rest_of_line ();
123 }
124
125 void
126 s_if (int arg)
127 {
128   expressionS operand;
129   struct conditional_frame cframe;
130   int t;
131   char *stop = NULL;
132   char stopc;
133
134   if (flag_mri)
135     stop = mri_comment_field (&stopc);
136
137   /* Leading whitespace is part of operand.  */
138   SKIP_WHITESPACE ();
139
140   if (current_cframe != NULL && current_cframe->ignoring)
141     {
142       operand.X_add_number = 0;
143       while (! is_end_of_line[(unsigned char) *input_line_pointer])
144         ++input_line_pointer;
145     }
146   else
147     {
148       expression_and_evaluate (&operand);
149       if (operand.X_op != O_constant)
150         as_bad (_("non-constant expression in \".if\" statement"));
151     }
152
153   switch ((operatorT) arg)
154     {
155     case O_eq: t = operand.X_add_number == 0; break;
156     case O_ne: t = operand.X_add_number != 0; break;
157     case O_lt: t = operand.X_add_number < 0; break;
158     case O_le: t = operand.X_add_number <= 0; break;
159     case O_ge: t = operand.X_add_number >= 0; break;
160     case O_gt: t = operand.X_add_number > 0; break;
161     default:
162       abort ();
163       return;
164     }
165
166   /* If the above error is signaled, this will dispatch
167      using an undefined result.  No big deal.  */
168   initialize_cframe (&cframe);
169   cframe.ignoring = cframe.dead_tree || ! t;
170   current_cframe = ((struct conditional_frame *)
171                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
172
173   if (LISTING_SKIP_COND ()
174       && cframe.ignoring
175       && (cframe.previous_cframe == NULL
176           || ! cframe.previous_cframe->ignoring))
177     listing_list (2);
178
179   if (flag_mri)
180     mri_comment_end (stop, stopc);
181
182   demand_empty_rest_of_line ();
183 }
184
185 /* Performs the .ifb (test_blank == 1) and
186    the .ifnb (test_blank == 0) pseudo op.  */
187
188 void
189 s_ifb (int test_blank)
190 {
191   struct conditional_frame cframe;
192
193   initialize_cframe (&cframe);
194   
195   if (cframe.dead_tree)
196     cframe.ignoring = 1;
197   else
198     {
199       int is_eol;
200
201       SKIP_WHITESPACE ();
202       is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
203       cframe.ignoring = (test_blank == !is_eol);
204     }
205
206   current_cframe = ((struct conditional_frame *)
207                     obstack_copy (&cond_obstack, &cframe,
208                                   sizeof (cframe)));
209
210   if (LISTING_SKIP_COND ()
211       && cframe.ignoring
212       && (cframe.previous_cframe == NULL
213           || ! cframe.previous_cframe->ignoring))
214     listing_list (2);
215
216   ignore_rest_of_line ();
217 }
218
219 /* Get a string for the MRI IFC or IFNC pseudo-ops.  */
220
221 static char *
222 get_mri_string (int terminator, int *len)
223 {
224   char *ret;
225   char *s;
226
227   SKIP_WHITESPACE ();
228   s = ret = input_line_pointer;
229   if (*input_line_pointer == '\'')
230     {
231       ++s;
232       ++input_line_pointer;
233       while (! is_end_of_line[(unsigned char) *input_line_pointer])
234         {
235           *s++ = *input_line_pointer++;
236           if (s[-1] == '\'')
237             {
238               if (*input_line_pointer != '\'')
239                 break;
240               ++input_line_pointer;
241             }
242         }
243       SKIP_WHITESPACE ();
244     }
245   else
246     {
247       while (*input_line_pointer != terminator
248              && ! is_end_of_line[(unsigned char) *input_line_pointer])
249         ++input_line_pointer;
250       s = input_line_pointer;
251       while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
252         --s;
253     }
254
255   *len = s - ret;
256   return ret;
257 }
258
259 /* The MRI IFC and IFNC pseudo-ops.  */
260
261 void
262 s_ifc (int arg)
263 {
264   char *stop = NULL;
265   char stopc;
266   char *s1, *s2;
267   int len1, len2;
268   int res;
269   struct conditional_frame cframe;
270
271   if (flag_mri)
272     stop = mri_comment_field (&stopc);
273
274   s1 = get_mri_string (',', &len1);
275
276   if (*input_line_pointer != ',')
277     as_bad (_("bad format for ifc or ifnc"));
278   else
279     ++input_line_pointer;
280
281   s2 = get_mri_string (';', &len2);
282
283   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
284
285   initialize_cframe (&cframe);
286   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
287   current_cframe = ((struct conditional_frame *)
288                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
289
290   if (LISTING_SKIP_COND ()
291       && cframe.ignoring
292       && (cframe.previous_cframe == NULL
293           || ! cframe.previous_cframe->ignoring))
294     listing_list (2);
295
296   if (flag_mri)
297     mri_comment_end (stop, stopc);
298
299   demand_empty_rest_of_line ();
300 }
301
302 void
303 s_elseif (int arg)
304 {
305   if (current_cframe == NULL)
306     {
307       as_bad (_("\".elseif\" without matching \".if\""));
308     }
309   else if (current_cframe->else_seen)
310     {
311       as_bad (_("\".elseif\" after \".else\""));
312       as_bad_where (current_cframe->else_file_line.file,
313                     current_cframe->else_file_line.line,
314                     _("here is the previous \".else\""));
315       as_bad_where (current_cframe->if_file_line.file,
316                     current_cframe->if_file_line.line,
317                     _("here is the previous \".if\""));
318     }
319   else
320     {
321       as_where (&current_cframe->else_file_line.file,
322                 &current_cframe->else_file_line.line);
323
324       current_cframe->dead_tree |= !current_cframe->ignoring;
325       current_cframe->ignoring = current_cframe->dead_tree;
326     }
327
328   if (current_cframe == NULL || current_cframe->ignoring)
329     {
330       while (! is_end_of_line[(unsigned char) *input_line_pointer])
331         ++input_line_pointer;
332
333       if (current_cframe == NULL)
334         return;
335     }
336   else
337     {
338       expressionS operand;
339       int t;
340
341       /* Leading whitespace is part of operand.  */
342       SKIP_WHITESPACE ();
343
344       expression_and_evaluate (&operand);
345       if (operand.X_op != O_constant)
346         as_bad (_("non-constant expression in \".elseif\" statement"));
347
348       switch ((operatorT) arg)
349         {
350         case O_eq: t = operand.X_add_number == 0; break;
351         case O_ne: t = operand.X_add_number != 0; break;
352         case O_lt: t = operand.X_add_number < 0; break;
353         case O_le: t = operand.X_add_number <= 0; break;
354         case O_ge: t = operand.X_add_number >= 0; break;
355         case O_gt: t = operand.X_add_number > 0; break;
356         default:
357           abort ();
358           return;
359         }
360
361       current_cframe->ignoring = current_cframe->dead_tree || ! t;
362     }
363
364   if (LISTING_SKIP_COND ()
365       && (current_cframe->previous_cframe == NULL
366           || ! current_cframe->previous_cframe->ignoring))
367     {
368       if (! current_cframe->ignoring)
369         listing_list (1);
370       else
371         listing_list (2);
372     }
373
374   demand_empty_rest_of_line ();
375 }
376
377 void
378 s_endif (int arg ATTRIBUTE_UNUSED)
379 {
380   struct conditional_frame *hold;
381
382   if (current_cframe == NULL)
383     {
384       as_bad (_("\".endif\" without \".if\""));
385     }
386   else
387     {
388       if (LISTING_SKIP_COND ()
389           && current_cframe->ignoring
390           && (current_cframe->previous_cframe == NULL
391               || ! current_cframe->previous_cframe->ignoring))
392         listing_list (1);
393
394       hold = current_cframe;
395       current_cframe = current_cframe->previous_cframe;
396       obstack_free (&cond_obstack, hold);
397     }                           /* if one pop too many */
398
399   if (flag_mri)
400     {
401       while (! is_end_of_line[(unsigned char) *input_line_pointer])
402         ++input_line_pointer;
403     }
404
405   demand_empty_rest_of_line ();
406 }
407
408 void
409 s_else (int arg ATTRIBUTE_UNUSED)
410 {
411   if (current_cframe == NULL)
412     {
413       as_bad (_("\".else\" without matching \".if\""));
414     }
415   else if (current_cframe->else_seen)
416     {
417       as_bad (_("duplicate \".else\""));
418       as_bad_where (current_cframe->else_file_line.file,
419                     current_cframe->else_file_line.line,
420                     _("here is the previous \".else\""));
421       as_bad_where (current_cframe->if_file_line.file,
422                     current_cframe->if_file_line.line,
423                     _("here is the previous \".if\""));
424     }
425   else
426     {
427       as_where (&current_cframe->else_file_line.file,
428                 &current_cframe->else_file_line.line);
429
430       current_cframe->ignoring =
431         current_cframe->dead_tree | !current_cframe->ignoring;
432
433       if (LISTING_SKIP_COND ()
434           && (current_cframe->previous_cframe == NULL
435               || ! current_cframe->previous_cframe->ignoring))
436         {
437           if (! current_cframe->ignoring)
438             listing_list (1);
439           else
440             listing_list (2);
441         }
442
443       current_cframe->else_seen = 1;
444     }
445
446   if (flag_mri)
447     {
448       while (! is_end_of_line[(unsigned char) *input_line_pointer])
449         ++input_line_pointer;
450     }
451
452   demand_empty_rest_of_line ();
453 }
454
455 void
456 s_ifeqs (int arg)
457 {
458   char *s1, *s2;
459   int len1, len2;
460   int res;
461   struct conditional_frame cframe;
462
463   s1 = demand_copy_C_string (&len1);
464
465   SKIP_WHITESPACE ();
466   if (*input_line_pointer != ',')
467     {
468       as_bad (_(".ifeqs syntax error"));
469       ignore_rest_of_line ();
470       return;
471     }
472
473   ++input_line_pointer;
474
475   s2 = demand_copy_C_string (&len2);
476
477   res = len1 == len2 && strncmp (s1, s2, len1) == 0;
478
479   initialize_cframe (&cframe);
480   cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
481   current_cframe = ((struct conditional_frame *)
482                     obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
483
484   if (LISTING_SKIP_COND ()
485       && cframe.ignoring
486       && (cframe.previous_cframe == NULL
487           || ! cframe.previous_cframe->ignoring))
488     listing_list (2);
489
490   demand_empty_rest_of_line ();
491 }
492
493 int
494 ignore_input (void)
495 {
496   char *s;
497
498   s = input_line_pointer;
499
500   if (NO_PSEUDO_DOT || flag_m68k_mri)
501     {
502       if (s[-1] != '.')
503         --s;
504     }
505   else
506     {
507       if (s[-1] != '.')
508         return (current_cframe != NULL) && (current_cframe->ignoring);
509     }
510
511   /* We cannot ignore certain pseudo ops.  */
512   if (((s[0] == 'i'
513         || s[0] == 'I')
514        && (!strncasecmp (s, "if", 2)
515            || !strncasecmp (s, "ifdef", 5)
516            || !strncasecmp (s, "ifndef", 6)))
517       || ((s[0] == 'e'
518            || s[0] == 'E')
519           && (!strncasecmp (s, "else", 4)
520               || !strncasecmp (s, "endif", 5)
521               || !strncasecmp (s, "endc", 4))))
522     return 0;
523
524   return (current_cframe != NULL) && (current_cframe->ignoring);
525 }
526
527 static void
528 initialize_cframe (struct conditional_frame *cframe)
529 {
530   memset (cframe, 0, sizeof (*cframe));
531   as_where (&cframe->if_file_line.file,
532             &cframe->if_file_line.line);
533   cframe->previous_cframe = current_cframe;
534   cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
535   cframe->macro_nest = macro_nest;
536 }
537
538 /* Give an error if a conditional is unterminated inside a macro or
539    the assembly as a whole.  If NEST is non negative, we are being
540    called because of the end of a macro expansion.  If NEST is
541    negative, we are being called at the of the input files.  */
542
543 void
544 cond_finish_check (int nest)
545 {
546   if (current_cframe != NULL && current_cframe->macro_nest >= nest)
547     {
548       if (nest >= 0)
549         as_bad (_("end of macro inside conditional"));
550       else
551         as_bad (_("end of file inside conditional"));
552       as_bad_where (current_cframe->if_file_line.file,
553                     current_cframe->if_file_line.line,
554                     _("here is the start of the unterminated conditional"));
555       if (current_cframe->else_seen)
556         as_bad_where (current_cframe->else_file_line.file,
557                       current_cframe->else_file_line.line,
558                       _("here is the \"else\" of the unterminated conditional"));
559     }
560 }
561
562 /* This function is called when we exit out of a macro.  We assume
563    that any conditionals which began within the macro are correctly
564    nested, and just pop them off the stack.  */
565
566 void
567 cond_exit_macro (int nest)
568 {
569   while (current_cframe != NULL && current_cframe->macro_nest >= nest)
570     {
571       struct conditional_frame *hold;
572
573       hold = current_cframe;
574       current_cframe = current_cframe->previous_cframe;
575       obstack_free (&cond_obstack, hold);
576     }
577 }