source: trunk/src/binutils/gas/cond.c@ 610

Last change on this file since 610 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 13.5 KB
Line 
1/* cond.c - conditional assembly pseudo-ops, and .include
2 Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001
3 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 2, 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, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22#include "as.h"
23#include "macro.h"
24
25#include "obstack.h"
26
27/* This is allocated to grow and shrink as .ifdef/.endif pairs are
28 scanned. */
29struct obstack cond_obstack;
30
31struct file_line {
32 char *file;
33 unsigned int line;
34};
35
36/* We push one of these structures for each .if, and pop it at the
37 .endif. */
38
39struct conditional_frame {
40 /* The source file & line number of the "if". */
41 struct file_line if_file_line;
42 /* The source file & line of the "else". */
43 struct file_line else_file_line;
44 /* The previous conditional. */
45 struct conditional_frame *previous_cframe;
46 /* Have we seen an else yet? */
47 int else_seen;
48 /* Whether we are currently ignoring input. */
49 int ignoring;
50 /* Whether a conditional at a higher level is ignoring input.
51 Set also when a branch of an "if .. elseif .." tree has matched
52 to prevent further matches. */
53 int dead_tree;
54 /* Macro nesting level at which this conditional was created. */
55 int macro_nest;
56};
57
58static void initialize_cframe PARAMS ((struct conditional_frame *cframe));
59static char *get_mri_string PARAMS ((int, int *));
60
61static struct conditional_frame *current_cframe = NULL;
62
63/* Performs the .ifdef (test_defined == 1) and
64 the .ifndef (test_defined == 0) pseudo op. */
65
66void
67s_ifdef (test_defined)
68 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)
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
125void
126s_if (arg)
127 int arg;
128{
129 expressionS operand;
130 struct conditional_frame cframe;
131 int t;
132 char *stop = NULL;
133 char stopc;
134
135 if (flag_mri)
136 stop = mri_comment_field (&stopc);
137
138 /* Leading whitespace is part of operand. */
139 SKIP_WHITESPACE ();
140
141 if (current_cframe != NULL && current_cframe->ignoring)
142 {
143 operand.X_add_number = 0;
144 while (! is_end_of_line[(unsigned char) *input_line_pointer])
145 ++input_line_pointer;
146 }
147 else
148 {
149 expression (&operand);
150 if (operand.X_op != O_constant)
151 as_bad (_("non-constant expression in \".if\" statement"));
152 }
153
154 switch ((operatorT) arg)
155 {
156 case O_eq: t = operand.X_add_number == 0; break;
157 case O_ne: t = operand.X_add_number != 0; break;
158 case O_lt: t = operand.X_add_number < 0; break;
159 case O_le: t = operand.X_add_number <= 0; break;
160 case O_ge: t = operand.X_add_number >= 0; break;
161 case O_gt: t = operand.X_add_number > 0; break;
162 default:
163 abort ();
164 return;
165 }
166
167 /* If the above error is signaled, this will dispatch
168 using an undefined result. No big deal. */
169 initialize_cframe (&cframe);
170 cframe.ignoring = cframe.dead_tree || ! t;
171 current_cframe = ((struct conditional_frame *)
172 obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
173
174 if (LISTING_SKIP_COND ()
175 && cframe.ignoring
176 && (cframe.previous_cframe == NULL
177 || ! cframe.previous_cframe->ignoring))
178 listing_list (2);
179
180 if (flag_mri)
181 mri_comment_end (stop, stopc);
182
183 demand_empty_rest_of_line ();
184}
185
186/* Get a string for the MRI IFC or IFNC pseudo-ops. */
187
188static char *
189get_mri_string (terminator, len)
190 int terminator;
191 int *len;
192{
193 char *ret;
194 char *s;
195
196 SKIP_WHITESPACE ();
197 s = ret = input_line_pointer;
198 if (*input_line_pointer == '\'')
199 {
200 ++s;
201 ++input_line_pointer;
202 while (! is_end_of_line[(unsigned char) *input_line_pointer])
203 {
204 *s++ = *input_line_pointer++;
205 if (s[-1] == '\'')
206 {
207 if (*input_line_pointer != '\'')
208 break;
209 ++input_line_pointer;
210 }
211 }
212 SKIP_WHITESPACE ();
213 }
214 else
215 {
216 while (*input_line_pointer != terminator
217 && ! is_end_of_line[(unsigned char) *input_line_pointer])
218 ++input_line_pointer;
219 s = input_line_pointer;
220 while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
221 --s;
222 }
223
224 *len = s - ret;
225 return ret;
226}
227
228/* The MRI IFC and IFNC pseudo-ops. */
229
230void
231s_ifc (arg)
232 int arg;
233{
234 char *stop = NULL;
235 char stopc;
236 char *s1, *s2;
237 int len1, len2;
238 int res;
239 struct conditional_frame cframe;
240
241 if (flag_mri)
242 stop = mri_comment_field (&stopc);
243
244 s1 = get_mri_string (',', &len1);
245
246 if (*input_line_pointer != ',')
247 as_bad (_("bad format for ifc or ifnc"));
248 else
249 ++input_line_pointer;
250
251 s2 = get_mri_string (';', &len2);
252
253 res = len1 == len2 && strncmp (s1, s2, len1) == 0;
254
255 initialize_cframe (&cframe);
256 cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
257 current_cframe = ((struct conditional_frame *)
258 obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
259
260 if (LISTING_SKIP_COND ()
261 && cframe.ignoring
262 && (cframe.previous_cframe == NULL
263 || ! cframe.previous_cframe->ignoring))
264 listing_list (2);
265
266 if (flag_mri)
267 mri_comment_end (stop, stopc);
268
269 demand_empty_rest_of_line ();
270}
271
272void
273s_elseif (arg)
274 int arg;
275{
276 if (current_cframe == NULL)
277 {
278 as_bad (_("\".elseif\" without matching \".if\""));
279 }
280 else if (current_cframe->else_seen)
281 {
282 as_bad (_("\".elseif\" after \".else\""));
283 as_bad_where (current_cframe->else_file_line.file,
284 current_cframe->else_file_line.line,
285 _("here is the previous \"else\""));
286 as_bad_where (current_cframe->if_file_line.file,
287 current_cframe->if_file_line.line,
288 _("here is the previous \"if\""));
289 }
290 else
291 {
292 as_where (&current_cframe->else_file_line.file,
293 &current_cframe->else_file_line.line);
294
295 current_cframe->dead_tree |= !current_cframe->ignoring;
296 current_cframe->ignoring = current_cframe->dead_tree;
297 }
298
299 if (current_cframe == NULL || current_cframe->ignoring)
300 {
301 while (! is_end_of_line[(unsigned char) *input_line_pointer])
302 ++input_line_pointer;
303
304 if (current_cframe == NULL)
305 return;
306 }
307 else
308 {
309 expressionS operand;
310 int t;
311
312 /* Leading whitespace is part of operand. */
313 SKIP_WHITESPACE ();
314
315 expression (&operand);
316 if (operand.X_op != O_constant)
317 as_bad (_("non-constant expression in \".elseif\" statement"));
318
319 switch ((operatorT) arg)
320 {
321 case O_eq: t = operand.X_add_number == 0; break;
322 case O_ne: t = operand.X_add_number != 0; break;
323 case O_lt: t = operand.X_add_number < 0; break;
324 case O_le: t = operand.X_add_number <= 0; break;
325 case O_ge: t = operand.X_add_number >= 0; break;
326 case O_gt: t = operand.X_add_number > 0; break;
327 default:
328 abort ();
329 return;
330 }
331
332 current_cframe->ignoring = current_cframe->dead_tree || ! t;
333 }
334
335 if (LISTING_SKIP_COND ()
336 && (current_cframe->previous_cframe == NULL
337 || ! current_cframe->previous_cframe->ignoring))
338 {
339 if (! current_cframe->ignoring)
340 listing_list (1);
341 else
342 listing_list (2);
343 }
344
345 demand_empty_rest_of_line ();
346}
347
348void
349s_endif (arg)
350 int arg ATTRIBUTE_UNUSED;
351{
352 struct conditional_frame *hold;
353
354 if (current_cframe == NULL)
355 {
356 as_bad (_("\".endif\" without \".if\""));
357 }
358 else
359 {
360 if (LISTING_SKIP_COND ()
361 && current_cframe->ignoring
362 && (current_cframe->previous_cframe == NULL
363 || ! current_cframe->previous_cframe->ignoring))
364 listing_list (1);
365
366 hold = current_cframe;
367 current_cframe = current_cframe->previous_cframe;
368 obstack_free (&cond_obstack, hold);
369 } /* if one pop too many */
370
371 if (flag_mri)
372 {
373 while (! is_end_of_line[(unsigned char) *input_line_pointer])
374 ++input_line_pointer;
375 }
376
377 demand_empty_rest_of_line ();
378}
379
380void
381s_else (arg)
382 int arg ATTRIBUTE_UNUSED;
383{
384 if (current_cframe == NULL)
385 {
386 as_bad (_("\".else\" without matching \".if\""));
387 }
388 else if (current_cframe->else_seen)
389 {
390 as_bad (_("duplicate \"else\""));
391 as_bad_where (current_cframe->else_file_line.file,
392 current_cframe->else_file_line.line,
393 _("here is the previous \"else\""));
394 as_bad_where (current_cframe->if_file_line.file,
395 current_cframe->if_file_line.line,
396 _("here is the previous \"if\""));
397 }
398 else
399 {
400 as_where (&current_cframe->else_file_line.file,
401 &current_cframe->else_file_line.line);
402
403 current_cframe->ignoring =
404 current_cframe->dead_tree | !current_cframe->ignoring;
405
406 if (LISTING_SKIP_COND ()
407 && (current_cframe->previous_cframe == NULL
408 || ! current_cframe->previous_cframe->ignoring))
409 {
410 if (! current_cframe->ignoring)
411 listing_list (1);
412 else
413 listing_list (2);
414 }
415
416 current_cframe->else_seen = 1;
417 }
418
419 if (flag_mri)
420 {
421 while (! is_end_of_line[(unsigned char) *input_line_pointer])
422 ++input_line_pointer;
423 }
424
425 demand_empty_rest_of_line ();
426}
427
428void
429s_ifeqs (arg)
430 int arg;
431{
432 char *s1, *s2;
433 int len1, len2;
434 int res;
435 struct conditional_frame cframe;
436
437 s1 = demand_copy_C_string (&len1);
438
439 SKIP_WHITESPACE ();
440 if (*input_line_pointer != ',')
441 {
442 as_bad (_(".ifeqs syntax error"));
443 ignore_rest_of_line ();
444 return;
445 }
446
447 ++input_line_pointer;
448
449 s2 = demand_copy_C_string (&len2);
450
451 res = len1 == len2 && strncmp (s1, s2, len1) == 0;
452
453 initialize_cframe (&cframe);
454 cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
455 current_cframe = ((struct conditional_frame *)
456 obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
457
458 if (LISTING_SKIP_COND ()
459 && cframe.ignoring
460 && (cframe.previous_cframe == NULL
461 || ! cframe.previous_cframe->ignoring))
462 listing_list (2);
463
464 demand_empty_rest_of_line ();
465}
466
467int
468ignore_input ()
469{
470 char *s;
471
472 s = input_line_pointer;
473
474 if (NO_PSEUDO_DOT || flag_m68k_mri)
475 {
476 if (s[-1] != '.')
477 --s;
478 }
479 else
480 {
481 if (s[-1] != '.')
482 return (current_cframe != NULL) && (current_cframe->ignoring);
483 }
484
485 /* We cannot ignore certain pseudo ops. */
486 if (((s[0] == 'i'
487 || s[0] == 'I')
488 && (!strncasecmp (s, "if", 2)
489 || !strncasecmp (s, "ifdef", 5)
490 || !strncasecmp (s, "ifndef", 6)))
491 || ((s[0] == 'e'
492 || s[0] == 'E')
493 && (!strncasecmp (s, "else", 4)
494 || !strncasecmp (s, "endif", 5)
495 || !strncasecmp (s, "endc", 4))))
496 return 0;
497
498 return (current_cframe != NULL) && (current_cframe->ignoring);
499}
500
501static void
502initialize_cframe (cframe)
503 struct conditional_frame *cframe;
504{
505 memset (cframe, 0, sizeof (*cframe));
506 as_where (&cframe->if_file_line.file,
507 &cframe->if_file_line.line);
508 cframe->previous_cframe = current_cframe;
509 cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
510 cframe->macro_nest = macro_nest;
511}
512
513/* Give an error if a conditional is unterminated inside a macro or
514 the assembly as a whole. If NEST is non negative, we are being
515 called because of the end of a macro expansion. If NEST is
516 negative, we are being called at the of the input files. */
517
518void
519cond_finish_check (nest)
520 int nest;
521{
522 if (current_cframe != NULL && current_cframe->macro_nest >= nest)
523 {
524 if (nest >= 0)
525 as_bad (_("end of macro inside conditional"));
526 else
527 as_bad (_("end of file inside conditional"));
528 as_bad_where (current_cframe->if_file_line.file,
529 current_cframe->if_file_line.line,
530 _("here is the start of the unterminated conditional"));
531 if (current_cframe->else_seen)
532 as_bad_where (current_cframe->else_file_line.file,
533 current_cframe->else_file_line.line,
534 _("here is the \"else\" of the unterminated conditional"));
535 }
536}
537
538/* This function is called when we exit out of a macro. We assume
539 that any conditionals which began within the macro are correctly
540 nested, and just pop them off the stack. */
541
542void
543cond_exit_macro (nest)
544 int nest;
545{
546 while (current_cframe != NULL && current_cframe->macro_nest >= nest)
547 {
548 struct conditional_frame *hold;
549
550 hold = current_cframe;
551 current_cframe = current_cframe->previous_cframe;
552 obstack_free (&cond_obstack, hold);
553 }
554}
Note: See TracBrowser for help on using the repository browser.