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