cond.c revision 33965
111820Sjulian/* cond.c - conditional assembly pseudo-ops, and .include 211820Sjulian Copyright (C) 1990, 91, 92, 93, 95, 96, 1997 Free Software Foundation, Inc. 311820Sjulian 411820Sjulian This file is part of GAS, the GNU Assembler. 511820Sjulian 611820Sjulian GAS is free software; you can redistribute it and/or modify 711820Sjulian it under the terms of the GNU General Public License as published by 811820Sjulian the Free Software Foundation; either version 2, or (at your option) 911820Sjulian any later version. 1011820Sjulian 1111820Sjulian GAS is distributed in the hope that it will be useful, 1211820Sjulian but WITHOUT ANY WARRANTY; without even the implied warranty of 1311820Sjulian MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1411820Sjulian GNU General Public License for more details. 1511820Sjulian 1611820Sjulian You should have received a copy of the GNU General Public License 1711820Sjulian along with GAS; see the file COPYING. If not, write to the Free 1811820Sjulian Software Foundation, 59 Temple Place - Suite 330, Boston, MA 1911820Sjulian 02111-1307, USA. */ 2011820Sjulian 2111820Sjulian#include "as.h" 2211820Sjulian#include "macro.h" 2311820Sjulian 2411820Sjulian#include "obstack.h" 2511820Sjulian 2611820Sjulian/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */ 2711820Sjulianstruct obstack cond_obstack; 2811820Sjulian 2911820Sjulianstruct file_line 3011820Sjulian{ 3111820Sjulian char *file; 3211820Sjulian unsigned int line; 3311820Sjulian}; 3411820Sjulian 3511820Sjulian/* We push one of these structures for each .if, and pop it at the 3611820Sjulian .endif. */ 3711820Sjulian 3827244Sjhaystruct conditional_frame 3911820Sjulian{ 4011820Sjulian /* The source file & line number of the "if". */ 4111820Sjulian struct file_line if_file_line; 4211820Sjulian /* The source file & line of the "else". */ 4311820Sjulian struct file_line else_file_line; 4411820Sjulian /* The previous conditional. */ 4511820Sjulian struct conditional_frame *previous_cframe; 4611820Sjulian /* Have we seen an else yet? */ 4711820Sjulian int else_seen; 4811820Sjulian /* Whether we are currently ignoring input. */ 4911820Sjulian int ignoring; 5011820Sjulian /* Whether a conditional at a higher level is ignoring input. */ 5111820Sjulian int dead_tree; 5211820Sjulian /* Macro nesting level at which this conditional was created. */ 5311820Sjulian int macro_nest; 5411820Sjulian}; 5511820Sjulian 5611820Sjulianstatic void initialize_cframe PARAMS ((struct conditional_frame *cframe)); 5711820Sjulianstatic char *get_mri_string PARAMS ((int, int *)); 5811820Sjulian 5911820Sjulianstatic struct conditional_frame *current_cframe = NULL; 6011820Sjulian 6111820Sjulianvoid 6211820Sjulians_ifdef (arg) 6311820Sjulian int arg; 6411820Sjulian{ 6511820Sjulian register char *name; /* points to name of symbol */ 6627244Sjhay register struct symbol *symbolP; /* Points to symbol */ 6711820Sjulian struct conditional_frame cframe; 6811820Sjulian 6911820Sjulian SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 7011820Sjulian name = input_line_pointer; 7111820Sjulian 7211820Sjulian if (!is_name_beginner (*name)) 7311820Sjulian { 7411820Sjulian as_bad ("invalid identifier for \".ifdef\""); 7511820Sjulian obstack_1grow (&cond_obstack, 0); 7627244Sjhay ignore_rest_of_line (); 7711820Sjulian } 7811820Sjulian else 7911820Sjulian { 8011820Sjulian char c; 8111820Sjulian 8211820Sjulian c = get_symbol_end (); 8311820Sjulian symbolP = symbol_find (name); 8411820Sjulian *input_line_pointer = c; 8511820Sjulian 8611820Sjulian initialize_cframe (&cframe); 8711820Sjulian cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg); 8811820Sjulian current_cframe = ((struct conditional_frame *) 8911820Sjulian obstack_copy (&cond_obstack, &cframe, 9011820Sjulian sizeof (cframe))); 9111820Sjulian 9211820Sjulian if (LISTING_SKIP_COND () 9311820Sjulian && cframe.ignoring 9411820Sjulian && (cframe.previous_cframe == NULL 9511820Sjulian || ! cframe.previous_cframe->ignoring)) 9611820Sjulian listing_list (2); 9711820Sjulian 9811820Sjulian demand_empty_rest_of_line (); 9911820Sjulian } /* if a valid identifyer name */ 10011820Sjulian} /* s_ifdef() */ 10111820Sjulian 10211820Sjulianvoid 10311820Sjulians_if (arg) 10411820Sjulian int arg; 10511820Sjulian{ 10611820Sjulian expressionS operand; 10711820Sjulian struct conditional_frame cframe; 10811820Sjulian int t; 10911820Sjulian char *stop = NULL; 11011820Sjulian char stopc; 11111820Sjulian 11211820Sjulian if (flag_mri) 11327244Sjhay stop = mri_comment_field (&stopc); 11411820Sjulian 11527244Sjhay SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 11627244Sjhay 11711820Sjulian if (current_cframe != NULL && current_cframe->ignoring) 11811820Sjulian { 11911820Sjulian operand.X_add_number = 0; 12011820Sjulian while (! is_end_of_line[(unsigned char) *input_line_pointer]) 12111820Sjulian ++input_line_pointer; 12211820Sjulian } 12311820Sjulian else 12411820Sjulian { 12511820Sjulian expression (&operand); 12611820Sjulian if (operand.X_op != O_constant) 12711820Sjulian as_bad ("non-constant expression in \".if\" statement"); 12827244Sjhay } 12927244Sjhay 13011820Sjulian switch ((operatorT) arg) 13111820Sjulian { 13211820Sjulian case O_eq: t = operand.X_add_number == 0; break; 13311820Sjulian case O_ne: t = operand.X_add_number != 0; break; 13411820Sjulian case O_lt: t = operand.X_add_number < 0; break; 13511820Sjulian case O_le: t = operand.X_add_number <= 0; break; 13611820Sjulian case O_ge: t = operand.X_add_number >= 0; break; 13727244Sjhay case O_gt: t = operand.X_add_number > 0; break; 13811820Sjulian default: 13911820Sjulian abort (); 14011820Sjulian } 14111820Sjulian 14227244Sjhay /* If the above error is signaled, this will dispatch 14311820Sjulian using an undefined result. No big deal. */ 14411820Sjulian initialize_cframe (&cframe); 14511820Sjulian cframe.ignoring = cframe.dead_tree || ! t; 14611820Sjulian current_cframe = ((struct conditional_frame *) 14711820Sjulian obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 14811820Sjulian 14911820Sjulian if (LISTING_SKIP_COND () 15011820Sjulian && cframe.ignoring 15111820Sjulian && (cframe.previous_cframe == NULL 15211820Sjulian || ! cframe.previous_cframe->ignoring)) 15311820Sjulian listing_list (2); 15411820Sjulian 15511820Sjulian if (flag_mri) 15611820Sjulian mri_comment_end (stop, stopc); 15711820Sjulian 15811820Sjulian demand_empty_rest_of_line (); 15911820Sjulian} /* s_if() */ 16011820Sjulian 16111820Sjulian/* Get a string for the MRI IFC or IFNC pseudo-ops. */ 16211820Sjulian 16311820Sjulianstatic char * 16411820Sjulianget_mri_string (terminator, len) 16511820Sjulian int terminator; 16611820Sjulian int *len; 16711820Sjulian{ 16811820Sjulian char *ret; 16911820Sjulian char *s; 17011820Sjulian 17111820Sjulian SKIP_WHITESPACE (); 17227244Sjhay s = ret = input_line_pointer; 17327244Sjhay if (*input_line_pointer == '\'') 17427244Sjhay { 17527244Sjhay ++s; 17611820Sjulian ++input_line_pointer; 17711820Sjulian while (! is_end_of_line[(unsigned char) *input_line_pointer]) 17811820Sjulian { 17911820Sjulian *s++ = *input_line_pointer++; 18011820Sjulian if (s[-1] == '\'') 18111820Sjulian { 18211820Sjulian if (*input_line_pointer != '\'') 18311820Sjulian break; 18411820Sjulian ++input_line_pointer; 18527244Sjhay } 18627244Sjhay } 18727244Sjhay SKIP_WHITESPACE (); 18827244Sjhay } 18927244Sjhay else 19027244Sjhay { 19127244Sjhay while (*input_line_pointer != terminator 19227244Sjhay && ! is_end_of_line[(unsigned char) *input_line_pointer]) 19327244Sjhay ++input_line_pointer; 19427244Sjhay s = input_line_pointer; 19527244Sjhay while (s > ret && (s[-1] == ' ' || s[-1] == '\t')) 19627244Sjhay --s; 19727244Sjhay } 19827244Sjhay 19927244Sjhay *len = s - ret; 20011820Sjulian return ret; 20111820Sjulian} 20211820Sjulian 20327244Sjhay/* The MRI IFC and IFNC pseudo-ops. */ 20411820Sjulian 20511820Sjulianvoid 20611820Sjulians_ifc (arg) 20711820Sjulian int arg; 20811820Sjulian{ 20911820Sjulian char *stop = NULL; 21011820Sjulian char stopc; 21111820Sjulian char *s1, *s2; 21211820Sjulian int len1, len2; 21311820Sjulian int res; 21411820Sjulian struct conditional_frame cframe; 21511820Sjulian 21611820Sjulian if (flag_mri) 21711820Sjulian stop = mri_comment_field (&stopc); 21811820Sjulian 21911820Sjulian s1 = get_mri_string (',', &len1); 22027244Sjhay 22111820Sjulian if (*input_line_pointer != ',') 22211820Sjulian as_bad ("bad format for ifc or ifnc"); 22311820Sjulian else 22411820Sjulian ++input_line_pointer; 22527244Sjhay 22611820Sjulian s2 = get_mri_string (';', &len2); 22711820Sjulian 22811820Sjulian res = len1 == len2 && strncmp (s1, s2, len1) == 0; 22911820Sjulian 23011820Sjulian initialize_cframe (&cframe); 23111820Sjulian cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 23211820Sjulian current_cframe = ((struct conditional_frame *) 23311820Sjulian obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 23411820Sjulian 23511820Sjulian if (LISTING_SKIP_COND () 23627244Sjhay && cframe.ignoring 23711820Sjulian && (cframe.previous_cframe == NULL 23811820Sjulian || ! cframe.previous_cframe->ignoring)) 23911820Sjulian listing_list (2); 240 241 if (flag_mri) 242 mri_comment_end (stop, stopc); 243} 244 245void 246s_endif (arg) 247 int arg; 248{ 249 struct conditional_frame *hold; 250 251 if (current_cframe == NULL) 252 { 253 as_bad ("\".endif\" without \".if\""); 254 } 255 else 256 { 257 if (LISTING_SKIP_COND () 258 && current_cframe->ignoring 259 && (current_cframe->previous_cframe == NULL 260 || ! current_cframe->previous_cframe->ignoring)) 261 listing_list (1); 262 263 hold = current_cframe; 264 current_cframe = current_cframe->previous_cframe; 265 obstack_free (&cond_obstack, hold); 266 } /* if one pop too many */ 267 268 if (flag_mri) 269 { 270 while (! is_end_of_line[(unsigned char) *input_line_pointer]) 271 ++input_line_pointer; 272 } 273 274 demand_empty_rest_of_line (); 275} /* s_endif() */ 276 277void 278s_else (arg) 279 int arg; 280{ 281 if (current_cframe == NULL) 282 { 283 as_bad (".else without matching .if - ignored"); 284 285 } 286 else if (current_cframe->else_seen) 287 { 288 as_bad ("duplicate \"else\" - ignored"); 289 as_bad_where (current_cframe->else_file_line.file, 290 current_cframe->else_file_line.line, 291 "here is the previous \"else\""); 292 as_bad_where (current_cframe->if_file_line.file, 293 current_cframe->if_file_line.line, 294 "here is the previous \"if\""); 295 } 296 else 297 { 298 as_where (¤t_cframe->else_file_line.file, 299 ¤t_cframe->else_file_line.line); 300 301 if (!current_cframe->dead_tree) 302 { 303 current_cframe->ignoring = !current_cframe->ignoring; 304 if (LISTING_SKIP_COND () 305 && ! current_cframe->ignoring) 306 listing_list (1); 307 } /* if not a dead tree */ 308 309 current_cframe->else_seen = 1; 310 } /* if error else do it */ 311 312 if (flag_mri) 313 { 314 while (! is_end_of_line[(unsigned char) *input_line_pointer]) 315 ++input_line_pointer; 316 } 317 318 demand_empty_rest_of_line (); 319} /* s_else() */ 320 321void 322s_ifeqs (arg) 323 int arg; 324{ 325 char *s1, *s2; 326 int len1, len2; 327 int res; 328 struct conditional_frame cframe; 329 330 s1 = demand_copy_C_string (&len1); 331 332 SKIP_WHITESPACE (); 333 if (*input_line_pointer != ',') 334 { 335 as_bad (".ifeqs syntax error"); 336 ignore_rest_of_line (); 337 return; 338 } 339 340 ++input_line_pointer; 341 342 s2 = demand_copy_C_string (&len2); 343 344 res = len1 == len2 && strncmp (s1, s2, len1) == 0; 345 346 initialize_cframe (&cframe); 347 cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 348 current_cframe = ((struct conditional_frame *) 349 obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 350 351 if (LISTING_SKIP_COND () 352 && cframe.ignoring 353 && (cframe.previous_cframe == NULL 354 || ! cframe.previous_cframe->ignoring)) 355 listing_list (2); 356 357 demand_empty_rest_of_line (); 358} /* s_ifeqs() */ 359 360int 361ignore_input () 362{ 363 char *s; 364 365 s = input_line_pointer; 366 367 if (flag_m68k_mri 368#ifdef NO_PSEUDO_DOT 369 || 1 370#endif 371 ) 372 { 373 if (s[-1] != '.') 374 --s; 375 } 376 else 377 { 378 if (s[-1] != '.') 379 return (current_cframe != NULL) && (current_cframe->ignoring); 380 } 381 382 /* We cannot ignore certain pseudo ops. */ 383 if (((s[0] == 'i' 384 || s[0] == 'I') 385 && (!strncasecmp (s, "if", 2) 386 || !strncasecmp (s, "ifdef", 5) 387 || !strncasecmp (s, "ifndef", 6))) 388 || ((s[0] == 'e' 389 || s[0] == 'E') 390 && (!strncasecmp (s, "else", 4) 391 || !strncasecmp (s, "endif", 5) 392 || !strncasecmp (s, "endc", 4)))) 393 return 0; 394 395 return (current_cframe != NULL) && (current_cframe->ignoring); 396} /* ignore_input() */ 397 398static void 399initialize_cframe (cframe) 400 struct conditional_frame *cframe; 401{ 402 memset (cframe, 0, sizeof (*cframe)); 403 as_where (&cframe->if_file_line.file, 404 &cframe->if_file_line.line); 405 cframe->previous_cframe = current_cframe; 406 cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; 407 cframe->macro_nest = macro_nest; 408} 409 410/* Give an error if a conditional is unterminated inside a macro or 411 the assembly as a whole. If NEST is non negative, we are being 412 called because of the end of a macro expansion. If NEST is 413 negative, we are being called at the of the input files. */ 414 415void 416cond_finish_check (nest) 417 int nest; 418{ 419 if (current_cframe != NULL && current_cframe->macro_nest >= nest) 420 { 421 as_bad ("end of %s inside conditional", 422 nest >= 0 ? "macro" : "file"); 423 as_bad_where (current_cframe->if_file_line.file, 424 current_cframe->if_file_line.line, 425 "here is the start of the unterminated conditional"); 426 if (current_cframe->else_seen) 427 as_bad_where (current_cframe->else_file_line.file, 428 current_cframe->else_file_line.line, 429 "here is the \"else\" of the unterminated conditional"); 430 } 431} 432 433/* This function is called when we exit out of a macro. We assume 434 that any conditionals which began within the macro are correctly 435 nested, and just pop them off the stack. */ 436 437void 438cond_exit_macro (nest) 439 int nest; 440{ 441 while (current_cframe != NULL && current_cframe->macro_nest >= nest) 442 { 443 struct conditional_frame *hold; 444 445 hold = current_cframe; 446 current_cframe = current_cframe->previous_cframe; 447 obstack_free (&cond_obstack, hold); 448 } 449} 450 451/* end of cond.c */ 452