PR 10471
[deliverable/binutils-gdb.git] / gas / cond.c
CommitLineData
252b5132 1/* cond.c - conditional assembly pseudo-ops, and .include
2da5c037 2 Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
ec2655a6 3 2003, 2006, 2007 Free Software Foundation, Inc.
252b5132
RH
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
ec2655a6 9 the Free Software Foundation; either version 3, or (at your option)
252b5132
RH
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
4b4da160
NC
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
252b5132
RH
21
22#include "as.h"
ebd1c875 23#include "sb.h"
252b5132
RH
24#include "macro.h"
25
26#include "obstack.h"
27
76b0a8c0
KH
28/* This is allocated to grow and shrink as .ifdef/.endif pairs are
29 scanned. */
252b5132
RH
30struct obstack cond_obstack;
31
30a2b4ef 32struct file_line {
252b5132
RH
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
30a2b4ef 40struct conditional_frame {
252b5132
RH
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;
cdbc6895
AM
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. */
252b5132
RH
54 int dead_tree;
55 /* Macro nesting level at which this conditional was created. */
56 int macro_nest;
57};
58
73ee5e4c
KH
59static void initialize_cframe (struct conditional_frame *cframe);
60static char *get_mri_string (int, int *);
252b5132
RH
61
62static struct conditional_frame *current_cframe = NULL;
63
8dfa0188
NC
64/* Performs the .ifdef (test_defined == 1) and
65 the .ifndef (test_defined == 0) pseudo op. */
66
76b0a8c0 67void
73ee5e4c 68s_ifdef (int test_defined)
252b5132 69{
76b0a8c0 70 /* Points to name of symbol. */
8dfa0188 71 char *name;
76b0a8c0 72 /* Points to symbol. */
8dfa0188 73 symbolS *symbolP;
252b5132 74 struct conditional_frame cframe;
8dfa0188 75 char c;
252b5132 76
76b0a8c0
KH
77 /* Leading whitespace is part of operand. */
78 SKIP_WHITESPACE ();
252b5132
RH
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 ();
8dfa0188 86 return;
252b5132 87 }
8dfa0188
NC
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;
252b5132
RH
97 else
98 {
8dfa0188
NC
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
92757bc9 106 && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
8dfa0188
NC
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 ();
76b0a8c0 123}
252b5132 124
76b0a8c0 125void
73ee5e4c 126s_if (int arg)
252b5132
RH
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
76b0a8c0
KH
137 /* Leading whitespace is part of operand. */
138 SKIP_WHITESPACE ();
252b5132
RH
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 {
9497f5ac 148 expression_and_evaluate (&operand);
252b5132
RH
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 ();
76b0a8c0 183}
252b5132 184
26aca5f6
JB
185/* Performs the .ifb (test_blank == 1) and
186 the .ifnb (test_blank == 0) pseudo op. */
187
188void
189s_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
252b5132
RH
219/* Get a string for the MRI IFC or IFNC pseudo-ops. */
220
221static char *
73ee5e4c 222get_mri_string (int terminator, int *len)
252b5132
RH
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
261void
73ee5e4c 262s_ifc (int arg)
252b5132
RH
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
76b0a8c0 302void
73ee5e4c 303s_elseif (int arg)
3fd9f047 304{
3fd9f047
TW
305 if (current_cframe == NULL)
306 {
0e389e77 307 as_bad (_("\".elseif\" without matching \".if\""));
3fd9f047
TW
308 }
309 else if (current_cframe->else_seen)
310 {
0e389e77 311 as_bad (_("\".elseif\" after \".else\""));
3fd9f047
TW
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
61b96bb4
AM
324 current_cframe->dead_tree |= !current_cframe->ignoring;
325 current_cframe->ignoring = current_cframe->dead_tree;
326 }
3fd9f047 327
cdbc6895 328 if (current_cframe == NULL || current_cframe->ignoring)
3fd9f047 329 {
3fd9f047
TW
330 while (! is_end_of_line[(unsigned char) *input_line_pointer])
331 ++input_line_pointer;
61b96bb4
AM
332
333 if (current_cframe == NULL)
334 return;
3fd9f047 335 }
61b96bb4
AM
336 else
337 {
338 expressionS operand;
339 int t;
cdbc6895 340
61b96bb4
AM
341 /* Leading whitespace is part of operand. */
342 SKIP_WHITESPACE ();
cdbc6895 343
9497f5ac 344 expression_and_evaluate (&operand);
61b96bb4
AM
345 if (operand.X_op != O_constant)
346 as_bad (_("non-constant expression in \".elseif\" statement"));
76b0a8c0 347
61b96bb4
AM
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 }
3fd9f047 360
61b96bb4
AM
361 current_cframe->ignoring = current_cframe->dead_tree || ! t;
362 }
3fd9f047
TW
363
364 if (LISTING_SKIP_COND ()
3fd9f047
TW
365 && (current_cframe->previous_cframe == NULL
366 || ! current_cframe->previous_cframe->ignoring))
61b96bb4
AM
367 {
368 if (! current_cframe->ignoring)
369 listing_list (1);
370 else
371 listing_list (2);
372 }
3fd9f047
TW
373
374 demand_empty_rest_of_line ();
375}
376
76b0a8c0 377void
73ee5e4c 378s_endif (int arg ATTRIBUTE_UNUSED)
252b5132
RH
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 ();
76b0a8c0 406}
252b5132 407
76b0a8c0 408void
73ee5e4c 409s_else (int arg ATTRIBUTE_UNUSED)
252b5132
RH
410{
411 if (current_cframe == NULL)
412 {
0e389e77 413 as_bad (_("\".else\" without matching \".if\""));
252b5132
RH
414 }
415 else if (current_cframe->else_seen)
416 {
0e389e77 417 as_bad (_("duplicate \"else\""));
252b5132
RH
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
61b96bb4
AM
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))
252b5132 436 {
61b96bb4
AM
437 if (! current_cframe->ignoring)
438 listing_list (1);
439 else
440 listing_list (2);
441 }
252b5132
RH
442
443 current_cframe->else_seen = 1;
61b96bb4 444 }
252b5132
RH
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 ();
76b0a8c0 453}
252b5132 454
76b0a8c0 455void
73ee5e4c 456s_ifeqs (int arg)
252b5132
RH
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 ();
76b0a8c0 491}
252b5132 492
76b0a8c0 493int
73ee5e4c 494ignore_input (void)
252b5132
RH
495{
496 char *s;
497
498 s = input_line_pointer;
499
abd63a32 500 if (NO_PSEUDO_DOT || flag_m68k_mri)
252b5132
RH
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);
76b0a8c0 525}
252b5132 526
76b0a8c0 527static void
73ee5e4c 528initialize_cframe (struct conditional_frame *cframe)
252b5132
RH
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
543void
73ee5e4c 544cond_finish_check (int nest)
252b5132
RH
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
566void
73ee5e4c 567cond_exit_macro (int nest)
252b5132
RH
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}
This page took 0.475722 seconds and 4 git commands to generate.