cond.c revision 38889
1260884Simp/* cond.c - conditional assembly pseudo-ops, and .include 2260884Simp Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 1998 3260884Simp Free Software Foundation, Inc. 4260884Simp 5260884Simp This file is part of GAS, the GNU Assembler. 6260884Simp 7260884Simp GAS is free software; you can redistribute it and/or modify 8260884Simp it under the terms of the GNU General Public License as published by 9260884Simp the Free Software Foundation; either version 2, or (at your option) 10260884Simp any later version. 11260884Simp 12260884Simp GAS is distributed in the hope that it will be useful, 13260884Simp but WITHOUT ANY WARRANTY; without even the implied warranty of 14260884Simp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15260884Simp GNU General Public License for more details. 16260884Simp 17260884Simp You should have received a copy of the GNU General Public License 18260884Simp along with GAS; see the file COPYING. If not, write to the Free 19260884Simp Software Foundation, 59 Temple Place - Suite 330, Boston, MA 20260884Simp 02111-1307, USA. */ 21260884Simp 22260884Simp#include "as.h" 23260884Simp#include "macro.h" 24260884Simp 25260884Simp#include "obstack.h" 26260884Simp 27260884Simp/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */ 28260884Simpstruct obstack cond_obstack; 29260884Simp 30260884Simpstruct file_line 31260884Simp{ 32260884Simp char *file; 33260884Simp unsigned int line; 34260884Simp}; 35260884Simp 36260884Simp/* We push one of these structures for each .if, and pop it at the 37260884Simp .endif. */ 38260884Simp 39260884Simpstruct conditional_frame 40260884Simp{ 41260884Simp /* The source file & line number of the "if". */ 42260884Simp struct file_line if_file_line; 43260884Simp /* The source file & line of the "else". */ 44260884Simp struct file_line else_file_line; 45260884Simp /* The previous conditional. */ 46260884Simp struct conditional_frame *previous_cframe; 47260884Simp /* Have we seen an else yet? */ 48260884Simp int else_seen; 49260884Simp /* Whether we are currently ignoring input. */ 50260884Simp int ignoring; 51260884Simp /* Whether a conditional at a higher level is ignoring input. */ 52260884Simp int dead_tree; 53260884Simp /* Macro nesting level at which this conditional was created. */ 54260884Simp int macro_nest; 55260884Simp}; 56260884Simp 57260884Simpstatic void initialize_cframe PARAMS ((struct conditional_frame *cframe)); 58260884Simpstatic char *get_mri_string PARAMS ((int, int *)); 59260884Simp 60260884Simpstatic struct conditional_frame *current_cframe = NULL; 61260884Simp 62260884Simpvoid 63260884Simps_ifdef (arg) 64260884Simp int arg; 65260884Simp{ 66260884Simp register char *name; /* points to name of symbol */ 67260884Simp register struct symbol *symbolP; /* Points to symbol */ 68260884Simp struct conditional_frame cframe; 69260884Simp 70260884Simp SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 71260884Simp name = input_line_pointer; 72260884Simp 73260884Simp if (!is_name_beginner (*name)) 74260884Simp { 75260884Simp as_bad ("invalid identifier for \".ifdef\""); 76260884Simp obstack_1grow (&cond_obstack, 0); 77260884Simp ignore_rest_of_line (); 78260884Simp } 79260884Simp else 80260884Simp { 81260884Simp char c; 82260884Simp 83260884Simp c = get_symbol_end (); 84260884Simp symbolP = symbol_find (name); 85260884Simp *input_line_pointer = c; 86260884Simp 87260884Simp initialize_cframe (&cframe); 88260884Simp cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg); 89260884Simp current_cframe = ((struct conditional_frame *) 90260884Simp obstack_copy (&cond_obstack, &cframe, 91260884Simp sizeof (cframe))); 92260884Simp 93260884Simp if (LISTING_SKIP_COND () 94260884Simp && cframe.ignoring 95260884Simp && (cframe.previous_cframe == NULL 96260884Simp || ! cframe.previous_cframe->ignoring)) 97260884Simp listing_list (2); 98260884Simp 99260884Simp demand_empty_rest_of_line (); 100260884Simp } /* if a valid identifyer name */ 101260884Simp} /* s_ifdef() */ 102260884Simp 103260884Simpvoid 104260884Simps_if (arg) 105260884Simp int arg; 106260884Simp{ 107260884Simp expressionS operand; 108260884Simp struct conditional_frame cframe; 109260884Simp int t; 110260884Simp char *stop = NULL; 111260884Simp char stopc; 112260884Simp 113260884Simp if (flag_mri) 114260884Simp stop = mri_comment_field (&stopc); 115260884Simp 116260884Simp 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_endif (arg) 251 int arg; 252{ 253 struct conditional_frame *hold; 254 255 if (current_cframe == NULL) 256 { 257 as_bad ("\".endif\" without \".if\""); 258 } 259 else 260 { 261 if (LISTING_SKIP_COND () 262 && current_cframe->ignoring 263 && (current_cframe->previous_cframe == NULL 264 || ! current_cframe->previous_cframe->ignoring)) 265 listing_list (1); 266 267 hold = current_cframe; 268 current_cframe = current_cframe->previous_cframe; 269 obstack_free (&cond_obstack, hold); 270 } /* if one pop too many */ 271 272 if (flag_mri) 273 { 274 while (! is_end_of_line[(unsigned char) *input_line_pointer]) 275 ++input_line_pointer; 276 } 277 278 demand_empty_rest_of_line (); 279} /* s_endif() */ 280 281void 282s_else (arg) 283 int arg; 284{ 285 if (current_cframe == NULL) 286 { 287 as_bad (".else without matching .if - ignored"); 288 289 } 290 else if (current_cframe->else_seen) 291 { 292 as_bad ("duplicate \"else\" - ignored"); 293 as_bad_where (current_cframe->else_file_line.file, 294 current_cframe->else_file_line.line, 295 "here is the previous \"else\""); 296 as_bad_where (current_cframe->if_file_line.file, 297 current_cframe->if_file_line.line, 298 "here is the previous \"if\""); 299 } 300 else 301 { 302 as_where (¤t_cframe->else_file_line.file, 303 ¤t_cframe->else_file_line.line); 304 305 if (!current_cframe->dead_tree) 306 { 307 current_cframe->ignoring = !current_cframe->ignoring; 308 if (LISTING_SKIP_COND ()) 309 { 310 if (! current_cframe->ignoring) 311 listing_list (1); 312 else 313 listing_list (2); 314 } 315 } /* if not a dead tree */ 316 317 current_cframe->else_seen = 1; 318 } /* if error else do it */ 319 320 if (flag_mri) 321 { 322 while (! is_end_of_line[(unsigned char) *input_line_pointer]) 323 ++input_line_pointer; 324 } 325 326 demand_empty_rest_of_line (); 327} /* s_else() */ 328 329void 330s_ifeqs (arg) 331 int arg; 332{ 333 char *s1, *s2; 334 int len1, len2; 335 int res; 336 struct conditional_frame cframe; 337 338 s1 = demand_copy_C_string (&len1); 339 340 SKIP_WHITESPACE (); 341 if (*input_line_pointer != ',') 342 { 343 as_bad (".ifeqs syntax error"); 344 ignore_rest_of_line (); 345 return; 346 } 347 348 ++input_line_pointer; 349 350 s2 = demand_copy_C_string (&len2); 351 352 res = len1 == len2 && strncmp (s1, s2, len1) == 0; 353 354 initialize_cframe (&cframe); 355 cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 356 current_cframe = ((struct conditional_frame *) 357 obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 358 359 if (LISTING_SKIP_COND () 360 && cframe.ignoring 361 && (cframe.previous_cframe == NULL 362 || ! cframe.previous_cframe->ignoring)) 363 listing_list (2); 364 365 demand_empty_rest_of_line (); 366} /* s_ifeqs() */ 367 368int 369ignore_input () 370{ 371 char *s; 372 373 s = input_line_pointer; 374 375 if (flag_m68k_mri 376#ifdef NO_PSEUDO_DOT 377 || 1 378#endif 379 ) 380 { 381 if (s[-1] != '.') 382 --s; 383 } 384 else 385 { 386 if (s[-1] != '.') 387 return (current_cframe != NULL) && (current_cframe->ignoring); 388 } 389 390 /* We cannot ignore certain pseudo ops. */ 391 if (((s[0] == 'i' 392 || s[0] == 'I') 393 && (!strncasecmp (s, "if", 2) 394 || !strncasecmp (s, "ifdef", 5) 395 || !strncasecmp (s, "ifndef", 6))) 396 || ((s[0] == 'e' 397 || s[0] == 'E') 398 && (!strncasecmp (s, "else", 4) 399 || !strncasecmp (s, "endif", 5) 400 || !strncasecmp (s, "endc", 4)))) 401 return 0; 402 403 return (current_cframe != NULL) && (current_cframe->ignoring); 404} /* ignore_input() */ 405 406static void 407initialize_cframe (cframe) 408 struct conditional_frame *cframe; 409{ 410 memset (cframe, 0, sizeof (*cframe)); 411 as_where (&cframe->if_file_line.file, 412 &cframe->if_file_line.line); 413 cframe->previous_cframe = current_cframe; 414 cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; 415 cframe->macro_nest = macro_nest; 416} 417 418/* Give an error if a conditional is unterminated inside a macro or 419 the assembly as a whole. If NEST is non negative, we are being 420 called because of the end of a macro expansion. If NEST is 421 negative, we are being called at the of the input files. */ 422 423void 424cond_finish_check (nest) 425 int nest; 426{ 427 if (current_cframe != NULL && current_cframe->macro_nest >= nest) 428 { 429 as_bad ("end of %s inside conditional", 430 nest >= 0 ? "macro" : "file"); 431 as_bad_where (current_cframe->if_file_line.file, 432 current_cframe->if_file_line.line, 433 "here is the start of the unterminated conditional"); 434 if (current_cframe->else_seen) 435 as_bad_where (current_cframe->else_file_line.file, 436 current_cframe->else_file_line.line, 437 "here is the \"else\" of the unterminated conditional"); 438 } 439} 440 441/* This function is called when we exit out of a macro. We assume 442 that any conditionals which began within the macro are correctly 443 nested, and just pop them off the stack. */ 444 445void 446cond_exit_macro (nest) 447 int nest; 448{ 449 while (current_cframe != NULL && current_cframe->macro_nest >= nest) 450 { 451 struct conditional_frame *hold; 452 453 hold = current_cframe; 454 current_cframe = current_cframe->previous_cframe; 455 obstack_free (&cond_obstack, hold); 456 } 457} 458 459/* end of cond.c */ 460