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