cond.c revision 38889
133965Sjdp/* cond.c - conditional assembly pseudo-ops, and .include 238889Sjdp Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 1998 338889Sjdp Free Software Foundation, Inc. 433965Sjdp 533965Sjdp This file is part of GAS, the GNU Assembler. 633965Sjdp 733965Sjdp GAS is free software; you can redistribute it and/or modify 833965Sjdp it under the terms of the GNU General Public License as published by 933965Sjdp the Free Software Foundation; either version 2, or (at your option) 1033965Sjdp any later version. 1133965Sjdp 1233965Sjdp GAS is distributed in the hope that it will be useful, 1333965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1433965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1533965Sjdp GNU General Public License for more details. 1633965Sjdp 1733965Sjdp You should have received a copy of the GNU General Public License 1833965Sjdp along with GAS; see the file COPYING. If not, write to the Free 1933965Sjdp Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2033965Sjdp 02111-1307, USA. */ 2133965Sjdp 2233965Sjdp#include "as.h" 2333965Sjdp#include "macro.h" 2433965Sjdp 2533965Sjdp#include "obstack.h" 2633965Sjdp 2733965Sjdp/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */ 2833965Sjdpstruct obstack cond_obstack; 2933965Sjdp 3033965Sjdpstruct file_line 3133965Sjdp{ 3233965Sjdp char *file; 3333965Sjdp unsigned int line; 3433965Sjdp}; 3533965Sjdp 3633965Sjdp/* We push one of these structures for each .if, and pop it at the 3733965Sjdp .endif. */ 3833965Sjdp 3933965Sjdpstruct conditional_frame 4033965Sjdp{ 4133965Sjdp /* The source file & line number of the "if". */ 4233965Sjdp struct file_line if_file_line; 4333965Sjdp /* The source file & line of the "else". */ 4433965Sjdp struct file_line else_file_line; 4533965Sjdp /* The previous conditional. */ 4633965Sjdp struct conditional_frame *previous_cframe; 4733965Sjdp /* Have we seen an else yet? */ 4833965Sjdp int else_seen; 4933965Sjdp /* Whether we are currently ignoring input. */ 5033965Sjdp int ignoring; 5133965Sjdp /* Whether a conditional at a higher level is ignoring input. */ 5233965Sjdp int dead_tree; 5333965Sjdp /* Macro nesting level at which this conditional was created. */ 5433965Sjdp int macro_nest; 5533965Sjdp}; 5633965Sjdp 5733965Sjdpstatic void initialize_cframe PARAMS ((struct conditional_frame *cframe)); 5833965Sjdpstatic char *get_mri_string PARAMS ((int, int *)); 5933965Sjdp 6033965Sjdpstatic struct conditional_frame *current_cframe = NULL; 6133965Sjdp 6233965Sjdpvoid 6333965Sjdps_ifdef (arg) 6433965Sjdp int arg; 6533965Sjdp{ 6633965Sjdp register char *name; /* points to name of symbol */ 6733965Sjdp register struct symbol *symbolP; /* Points to symbol */ 6833965Sjdp struct conditional_frame cframe; 6933965Sjdp 7033965Sjdp SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 7133965Sjdp name = input_line_pointer; 7233965Sjdp 7333965Sjdp if (!is_name_beginner (*name)) 7433965Sjdp { 7533965Sjdp as_bad ("invalid identifier for \".ifdef\""); 7633965Sjdp obstack_1grow (&cond_obstack, 0); 7733965Sjdp ignore_rest_of_line (); 7833965Sjdp } 7933965Sjdp else 8033965Sjdp { 8133965Sjdp char c; 8233965Sjdp 8333965Sjdp c = get_symbol_end (); 8433965Sjdp symbolP = symbol_find (name); 8533965Sjdp *input_line_pointer = c; 8633965Sjdp 8733965Sjdp initialize_cframe (&cframe); 8833965Sjdp cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg); 8933965Sjdp current_cframe = ((struct conditional_frame *) 9033965Sjdp obstack_copy (&cond_obstack, &cframe, 9133965Sjdp sizeof (cframe))); 9233965Sjdp 9333965Sjdp if (LISTING_SKIP_COND () 9433965Sjdp && cframe.ignoring 9533965Sjdp && (cframe.previous_cframe == NULL 9633965Sjdp || ! cframe.previous_cframe->ignoring)) 9733965Sjdp listing_list (2); 9833965Sjdp 9933965Sjdp demand_empty_rest_of_line (); 10033965Sjdp } /* if a valid identifyer name */ 10133965Sjdp} /* s_ifdef() */ 10233965Sjdp 10333965Sjdpvoid 10433965Sjdps_if (arg) 10533965Sjdp int arg; 10633965Sjdp{ 10733965Sjdp expressionS operand; 10833965Sjdp struct conditional_frame cframe; 10933965Sjdp int t; 11033965Sjdp char *stop = NULL; 11133965Sjdp char stopc; 11233965Sjdp 11333965Sjdp if (flag_mri) 11433965Sjdp stop = mri_comment_field (&stopc); 11533965Sjdp 11633965Sjdp SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 11733965Sjdp 11833965Sjdp if (current_cframe != NULL && current_cframe->ignoring) 11933965Sjdp { 12033965Sjdp operand.X_add_number = 0; 12133965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 12233965Sjdp ++input_line_pointer; 12333965Sjdp } 12433965Sjdp else 12533965Sjdp { 12633965Sjdp expression (&operand); 12733965Sjdp if (operand.X_op != O_constant) 12833965Sjdp as_bad ("non-constant expression in \".if\" statement"); 12933965Sjdp } 13033965Sjdp 13133965Sjdp switch ((operatorT) arg) 13233965Sjdp { 13333965Sjdp case O_eq: t = operand.X_add_number == 0; break; 13433965Sjdp case O_ne: t = operand.X_add_number != 0; break; 13533965Sjdp case O_lt: t = operand.X_add_number < 0; break; 13633965Sjdp case O_le: t = operand.X_add_number <= 0; break; 13733965Sjdp case O_ge: t = operand.X_add_number >= 0; break; 13833965Sjdp case O_gt: t = operand.X_add_number > 0; break; 13933965Sjdp default: 14033965Sjdp abort (); 14138889Sjdp return; 14233965Sjdp } 14333965Sjdp 14433965Sjdp /* If the above error is signaled, this will dispatch 14533965Sjdp using an undefined result. No big deal. */ 14633965Sjdp initialize_cframe (&cframe); 14733965Sjdp cframe.ignoring = cframe.dead_tree || ! t; 14833965Sjdp current_cframe = ((struct conditional_frame *) 14933965Sjdp obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 15033965Sjdp 15133965Sjdp if (LISTING_SKIP_COND () 15233965Sjdp && cframe.ignoring 15333965Sjdp && (cframe.previous_cframe == NULL 15433965Sjdp || ! cframe.previous_cframe->ignoring)) 15533965Sjdp listing_list (2); 15633965Sjdp 15733965Sjdp if (flag_mri) 15833965Sjdp mri_comment_end (stop, stopc); 15933965Sjdp 16033965Sjdp demand_empty_rest_of_line (); 16133965Sjdp} /* s_if() */ 16233965Sjdp 16333965Sjdp/* Get a string for the MRI IFC or IFNC pseudo-ops. */ 16433965Sjdp 16533965Sjdpstatic char * 16633965Sjdpget_mri_string (terminator, len) 16733965Sjdp int terminator; 16833965Sjdp int *len; 16933965Sjdp{ 17033965Sjdp char *ret; 17133965Sjdp char *s; 17233965Sjdp 17333965Sjdp SKIP_WHITESPACE (); 17433965Sjdp s = ret = input_line_pointer; 17533965Sjdp if (*input_line_pointer == '\'') 17633965Sjdp { 17733965Sjdp ++s; 17833965Sjdp ++input_line_pointer; 17933965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 18033965Sjdp { 18133965Sjdp *s++ = *input_line_pointer++; 18233965Sjdp if (s[-1] == '\'') 18333965Sjdp { 18433965Sjdp if (*input_line_pointer != '\'') 18533965Sjdp break; 18633965Sjdp ++input_line_pointer; 18733965Sjdp } 18833965Sjdp } 18933965Sjdp SKIP_WHITESPACE (); 19033965Sjdp } 19133965Sjdp else 19233965Sjdp { 19333965Sjdp while (*input_line_pointer != terminator 19433965Sjdp && ! is_end_of_line[(unsigned char) *input_line_pointer]) 19533965Sjdp ++input_line_pointer; 19633965Sjdp s = input_line_pointer; 19733965Sjdp while (s > ret && (s[-1] == ' ' || s[-1] == '\t')) 19833965Sjdp --s; 19933965Sjdp } 20033965Sjdp 20133965Sjdp *len = s - ret; 20233965Sjdp return ret; 20333965Sjdp} 20433965Sjdp 20533965Sjdp/* The MRI IFC and IFNC pseudo-ops. */ 20633965Sjdp 20733965Sjdpvoid 20833965Sjdps_ifc (arg) 20933965Sjdp int arg; 21033965Sjdp{ 21133965Sjdp char *stop = NULL; 21233965Sjdp char stopc; 21333965Sjdp char *s1, *s2; 21433965Sjdp int len1, len2; 21533965Sjdp int res; 21633965Sjdp struct conditional_frame cframe; 21733965Sjdp 21833965Sjdp if (flag_mri) 21933965Sjdp stop = mri_comment_field (&stopc); 22033965Sjdp 22133965Sjdp s1 = get_mri_string (',', &len1); 22233965Sjdp 22333965Sjdp if (*input_line_pointer != ',') 22433965Sjdp as_bad ("bad format for ifc or ifnc"); 22533965Sjdp else 22633965Sjdp ++input_line_pointer; 22733965Sjdp 22833965Sjdp s2 = get_mri_string (';', &len2); 22933965Sjdp 23033965Sjdp res = len1 == len2 && strncmp (s1, s2, len1) == 0; 23133965Sjdp 23233965Sjdp initialize_cframe (&cframe); 23333965Sjdp cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 23433965Sjdp current_cframe = ((struct conditional_frame *) 23533965Sjdp obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 23633965Sjdp 23733965Sjdp if (LISTING_SKIP_COND () 23833965Sjdp && cframe.ignoring 23933965Sjdp && (cframe.previous_cframe == NULL 24033965Sjdp || ! cframe.previous_cframe->ignoring)) 24133965Sjdp listing_list (2); 24233965Sjdp 24333965Sjdp if (flag_mri) 24433965Sjdp mri_comment_end (stop, stopc); 24538889Sjdp 24638889Sjdp demand_empty_rest_of_line (); 24733965Sjdp} 24833965Sjdp 24933965Sjdpvoid 25033965Sjdps_endif (arg) 25133965Sjdp int arg; 25233965Sjdp{ 25333965Sjdp struct conditional_frame *hold; 25433965Sjdp 25533965Sjdp if (current_cframe == NULL) 25633965Sjdp { 25733965Sjdp as_bad ("\".endif\" without \".if\""); 25833965Sjdp } 25933965Sjdp else 26033965Sjdp { 26133965Sjdp if (LISTING_SKIP_COND () 26233965Sjdp && current_cframe->ignoring 26333965Sjdp && (current_cframe->previous_cframe == NULL 26433965Sjdp || ! current_cframe->previous_cframe->ignoring)) 26533965Sjdp listing_list (1); 26633965Sjdp 26733965Sjdp hold = current_cframe; 26833965Sjdp current_cframe = current_cframe->previous_cframe; 26933965Sjdp obstack_free (&cond_obstack, hold); 27033965Sjdp } /* if one pop too many */ 27133965Sjdp 27233965Sjdp if (flag_mri) 27333965Sjdp { 27433965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 27533965Sjdp ++input_line_pointer; 27633965Sjdp } 27733965Sjdp 27833965Sjdp demand_empty_rest_of_line (); 27933965Sjdp} /* s_endif() */ 28033965Sjdp 28133965Sjdpvoid 28233965Sjdps_else (arg) 28333965Sjdp int arg; 28433965Sjdp{ 28533965Sjdp if (current_cframe == NULL) 28633965Sjdp { 28733965Sjdp as_bad (".else without matching .if - ignored"); 28833965Sjdp 28933965Sjdp } 29033965Sjdp else if (current_cframe->else_seen) 29133965Sjdp { 29233965Sjdp as_bad ("duplicate \"else\" - ignored"); 29333965Sjdp as_bad_where (current_cframe->else_file_line.file, 29433965Sjdp current_cframe->else_file_line.line, 29533965Sjdp "here is the previous \"else\""); 29633965Sjdp as_bad_where (current_cframe->if_file_line.file, 29733965Sjdp current_cframe->if_file_line.line, 29833965Sjdp "here is the previous \"if\""); 29933965Sjdp } 30033965Sjdp else 30133965Sjdp { 30233965Sjdp as_where (¤t_cframe->else_file_line.file, 30333965Sjdp ¤t_cframe->else_file_line.line); 30433965Sjdp 30533965Sjdp if (!current_cframe->dead_tree) 30633965Sjdp { 30733965Sjdp current_cframe->ignoring = !current_cframe->ignoring; 30838889Sjdp if (LISTING_SKIP_COND ()) 30938889Sjdp { 31038889Sjdp if (! current_cframe->ignoring) 31138889Sjdp listing_list (1); 31238889Sjdp else 31338889Sjdp listing_list (2); 31438889Sjdp } 31533965Sjdp } /* if not a dead tree */ 31633965Sjdp 31733965Sjdp current_cframe->else_seen = 1; 31833965Sjdp } /* if error else do it */ 31933965Sjdp 32033965Sjdp if (flag_mri) 32133965Sjdp { 32233965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 32333965Sjdp ++input_line_pointer; 32433965Sjdp } 32533965Sjdp 32633965Sjdp demand_empty_rest_of_line (); 32733965Sjdp} /* s_else() */ 32833965Sjdp 32933965Sjdpvoid 33033965Sjdps_ifeqs (arg) 33133965Sjdp int arg; 33233965Sjdp{ 33333965Sjdp char *s1, *s2; 33433965Sjdp int len1, len2; 33533965Sjdp int res; 33633965Sjdp struct conditional_frame cframe; 33733965Sjdp 33833965Sjdp s1 = demand_copy_C_string (&len1); 33933965Sjdp 34033965Sjdp SKIP_WHITESPACE (); 34133965Sjdp if (*input_line_pointer != ',') 34233965Sjdp { 34333965Sjdp as_bad (".ifeqs syntax error"); 34433965Sjdp ignore_rest_of_line (); 34533965Sjdp return; 34633965Sjdp } 34733965Sjdp 34833965Sjdp ++input_line_pointer; 34933965Sjdp 35033965Sjdp s2 = demand_copy_C_string (&len2); 35133965Sjdp 35233965Sjdp res = len1 == len2 && strncmp (s1, s2, len1) == 0; 35333965Sjdp 35433965Sjdp initialize_cframe (&cframe); 35533965Sjdp cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 35633965Sjdp current_cframe = ((struct conditional_frame *) 35733965Sjdp obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 35833965Sjdp 35933965Sjdp if (LISTING_SKIP_COND () 36033965Sjdp && cframe.ignoring 36133965Sjdp && (cframe.previous_cframe == NULL 36233965Sjdp || ! cframe.previous_cframe->ignoring)) 36333965Sjdp listing_list (2); 36433965Sjdp 36533965Sjdp demand_empty_rest_of_line (); 36633965Sjdp} /* s_ifeqs() */ 36733965Sjdp 36833965Sjdpint 36933965Sjdpignore_input () 37033965Sjdp{ 37133965Sjdp char *s; 37233965Sjdp 37333965Sjdp s = input_line_pointer; 37433965Sjdp 37533965Sjdp if (flag_m68k_mri 37633965Sjdp#ifdef NO_PSEUDO_DOT 37733965Sjdp || 1 37833965Sjdp#endif 37933965Sjdp ) 38033965Sjdp { 38133965Sjdp if (s[-1] != '.') 38233965Sjdp --s; 38333965Sjdp } 38433965Sjdp else 38533965Sjdp { 38633965Sjdp if (s[-1] != '.') 38733965Sjdp return (current_cframe != NULL) && (current_cframe->ignoring); 38833965Sjdp } 38933965Sjdp 39033965Sjdp /* We cannot ignore certain pseudo ops. */ 39133965Sjdp if (((s[0] == 'i' 39233965Sjdp || s[0] == 'I') 39333965Sjdp && (!strncasecmp (s, "if", 2) 39433965Sjdp || !strncasecmp (s, "ifdef", 5) 39533965Sjdp || !strncasecmp (s, "ifndef", 6))) 39633965Sjdp || ((s[0] == 'e' 39733965Sjdp || s[0] == 'E') 39833965Sjdp && (!strncasecmp (s, "else", 4) 39933965Sjdp || !strncasecmp (s, "endif", 5) 40033965Sjdp || !strncasecmp (s, "endc", 4)))) 40133965Sjdp return 0; 40233965Sjdp 40333965Sjdp return (current_cframe != NULL) && (current_cframe->ignoring); 40433965Sjdp} /* ignore_input() */ 40533965Sjdp 40633965Sjdpstatic void 40733965Sjdpinitialize_cframe (cframe) 40833965Sjdp struct conditional_frame *cframe; 40933965Sjdp{ 41033965Sjdp memset (cframe, 0, sizeof (*cframe)); 41133965Sjdp as_where (&cframe->if_file_line.file, 41233965Sjdp &cframe->if_file_line.line); 41333965Sjdp cframe->previous_cframe = current_cframe; 41433965Sjdp cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; 41533965Sjdp cframe->macro_nest = macro_nest; 41633965Sjdp} 41733965Sjdp 41833965Sjdp/* Give an error if a conditional is unterminated inside a macro or 41933965Sjdp the assembly as a whole. If NEST is non negative, we are being 42033965Sjdp called because of the end of a macro expansion. If NEST is 42133965Sjdp negative, we are being called at the of the input files. */ 42233965Sjdp 42333965Sjdpvoid 42433965Sjdpcond_finish_check (nest) 42533965Sjdp int nest; 42633965Sjdp{ 42733965Sjdp if (current_cframe != NULL && current_cframe->macro_nest >= nest) 42833965Sjdp { 42933965Sjdp as_bad ("end of %s inside conditional", 43033965Sjdp nest >= 0 ? "macro" : "file"); 43133965Sjdp as_bad_where (current_cframe->if_file_line.file, 43233965Sjdp current_cframe->if_file_line.line, 43333965Sjdp "here is the start of the unterminated conditional"); 43433965Sjdp if (current_cframe->else_seen) 43533965Sjdp as_bad_where (current_cframe->else_file_line.file, 43633965Sjdp current_cframe->else_file_line.line, 43733965Sjdp "here is the \"else\" of the unterminated conditional"); 43833965Sjdp } 43933965Sjdp} 44033965Sjdp 44133965Sjdp/* This function is called when we exit out of a macro. We assume 44233965Sjdp that any conditionals which began within the macro are correctly 44333965Sjdp nested, and just pop them off the stack. */ 44433965Sjdp 44533965Sjdpvoid 44633965Sjdpcond_exit_macro (nest) 44733965Sjdp int nest; 44833965Sjdp{ 44933965Sjdp while (current_cframe != NULL && current_cframe->macro_nest >= nest) 45033965Sjdp { 45133965Sjdp struct conditional_frame *hold; 45233965Sjdp 45333965Sjdp hold = current_cframe; 45433965Sjdp current_cframe = current_cframe->previous_cframe; 45533965Sjdp obstack_free (&cond_obstack, hold); 45633965Sjdp } 45733965Sjdp} 45833965Sjdp 45933965Sjdp/* end of cond.c */ 460