Subversion Repositories Kolibri OS

Rev

Rev 5222 | Details | Compare with Previous | Last modification | View Log | RSS feed

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