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