Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5222 serge 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 (¤t_cframe->else_file_line.file,
322
		¤t_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 (¤t_cframe->else_file_line.file,
428
		¤t_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
}