cond.c revision 60484
133965Sjdp/* cond.c - conditional assembly pseudo-ops, and .include 260484Sobrien Copyright (C) 1990, 91, 92, 93, 95, 96, 97, 98, 99, 2000 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 */ 6760484Sobrien register symbolS *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 { 7560484Sobrien 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) 12860484Sobrien 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 != ',') 22460484Sobrien 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 25060484Sobriens_elseif (arg) 25133965Sjdp int arg; 25233965Sjdp{ 25360484Sobrien expressionS operand; 25460484Sobrien int t; 25560484Sobrien 25660484Sobrien if (current_cframe == NULL) 25760484Sobrien { 25860484Sobrien as_bad (_("\".elseif\" without matching \".if\" - ignored")); 25960484Sobrien 26060484Sobrien } 26160484Sobrien else if (current_cframe->else_seen) 26260484Sobrien { 26360484Sobrien as_bad (_("\".elseif\" after \".else\" - ignored")); 26460484Sobrien as_bad_where (current_cframe->else_file_line.file, 26560484Sobrien current_cframe->else_file_line.line, 26660484Sobrien _("here is the previous \"else\"")); 26760484Sobrien as_bad_where (current_cframe->if_file_line.file, 26860484Sobrien current_cframe->if_file_line.line, 26960484Sobrien _("here is the previous \"if\"")); 27060484Sobrien } 27160484Sobrien else 27260484Sobrien { 27360484Sobrien as_where (¤t_cframe->else_file_line.file, 27460484Sobrien ¤t_cframe->else_file_line.line); 27560484Sobrien 27660484Sobrien if (!current_cframe->dead_tree) 27760484Sobrien { 27860484Sobrien current_cframe->ignoring = !current_cframe->ignoring; 27960484Sobrien if (LISTING_SKIP_COND ()) 28060484Sobrien { 28160484Sobrien if (! current_cframe->ignoring) 28260484Sobrien listing_list (1); 28360484Sobrien else 28460484Sobrien listing_list (2); 28560484Sobrien } 28660484Sobrien } /* if not a dead tree */ 28760484Sobrien } /* if error else do it */ 28860484Sobrien 28960484Sobrien 29060484Sobrien SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ 29160484Sobrien 29260484Sobrien if (current_cframe != NULL && current_cframe->ignoring) 29360484Sobrien { 29460484Sobrien operand.X_add_number = 0; 29560484Sobrien while (! is_end_of_line[(unsigned char) *input_line_pointer]) 29660484Sobrien ++input_line_pointer; 29760484Sobrien } 29860484Sobrien else 29960484Sobrien { 30060484Sobrien expression (&operand); 30160484Sobrien if (operand.X_op != O_constant) 30260484Sobrien as_bad (_("non-constant expression in \".elseif\" statement")); 30360484Sobrien } 30460484Sobrien 30560484Sobrien switch ((operatorT) arg) 30660484Sobrien { 30760484Sobrien case O_eq: t = operand.X_add_number == 0; break; 30860484Sobrien case O_ne: t = operand.X_add_number != 0; break; 30960484Sobrien case O_lt: t = operand.X_add_number < 0; break; 31060484Sobrien case O_le: t = operand.X_add_number <= 0; break; 31160484Sobrien case O_ge: t = operand.X_add_number >= 0; break; 31260484Sobrien case O_gt: t = operand.X_add_number > 0; break; 31360484Sobrien default: 31460484Sobrien abort (); 31560484Sobrien return; 31660484Sobrien } 31760484Sobrien 31860484Sobrien current_cframe->ignoring = current_cframe->dead_tree || ! t; 31960484Sobrien 32060484Sobrien if (LISTING_SKIP_COND () 32160484Sobrien && current_cframe->ignoring 32260484Sobrien && (current_cframe->previous_cframe == NULL 32360484Sobrien || ! current_cframe->previous_cframe->ignoring)) 32460484Sobrien listing_list (2); 32560484Sobrien 32660484Sobrien demand_empty_rest_of_line (); 32760484Sobrien} 32860484Sobrien 32960484Sobrienvoid 33060484Sobriens_endif (arg) 33160484Sobrien int arg ATTRIBUTE_UNUSED; 33260484Sobrien{ 33333965Sjdp struct conditional_frame *hold; 33433965Sjdp 33533965Sjdp if (current_cframe == NULL) 33633965Sjdp { 33760484Sobrien as_bad (_("\".endif\" without \".if\"")); 33833965Sjdp } 33933965Sjdp else 34033965Sjdp { 34133965Sjdp if (LISTING_SKIP_COND () 34233965Sjdp && current_cframe->ignoring 34333965Sjdp && (current_cframe->previous_cframe == NULL 34433965Sjdp || ! current_cframe->previous_cframe->ignoring)) 34533965Sjdp listing_list (1); 34633965Sjdp 34733965Sjdp hold = current_cframe; 34833965Sjdp current_cframe = current_cframe->previous_cframe; 34933965Sjdp obstack_free (&cond_obstack, hold); 35033965Sjdp } /* if one pop too many */ 35133965Sjdp 35233965Sjdp if (flag_mri) 35333965Sjdp { 35433965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 35533965Sjdp ++input_line_pointer; 35633965Sjdp } 35733965Sjdp 35833965Sjdp demand_empty_rest_of_line (); 35933965Sjdp} /* s_endif() */ 36033965Sjdp 36133965Sjdpvoid 36233965Sjdps_else (arg) 36360484Sobrien int arg ATTRIBUTE_UNUSED; 36433965Sjdp{ 36533965Sjdp if (current_cframe == NULL) 36633965Sjdp { 36760484Sobrien as_bad (_(".else without matching .if - ignored")); 36833965Sjdp 36933965Sjdp } 37033965Sjdp else if (current_cframe->else_seen) 37133965Sjdp { 37260484Sobrien as_bad (_("duplicate \"else\" - ignored")); 37333965Sjdp as_bad_where (current_cframe->else_file_line.file, 37433965Sjdp current_cframe->else_file_line.line, 37560484Sobrien _("here is the previous \"else\"")); 37633965Sjdp as_bad_where (current_cframe->if_file_line.file, 37733965Sjdp current_cframe->if_file_line.line, 37860484Sobrien _("here is the previous \"if\"")); 37933965Sjdp } 38033965Sjdp else 38133965Sjdp { 38233965Sjdp as_where (¤t_cframe->else_file_line.file, 38333965Sjdp ¤t_cframe->else_file_line.line); 38433965Sjdp 38533965Sjdp if (!current_cframe->dead_tree) 38633965Sjdp { 38733965Sjdp current_cframe->ignoring = !current_cframe->ignoring; 38838889Sjdp if (LISTING_SKIP_COND ()) 38938889Sjdp { 39038889Sjdp if (! current_cframe->ignoring) 39138889Sjdp listing_list (1); 39238889Sjdp else 39338889Sjdp listing_list (2); 39438889Sjdp } 39533965Sjdp } /* if not a dead tree */ 39633965Sjdp 39733965Sjdp current_cframe->else_seen = 1; 39833965Sjdp } /* if error else do it */ 39933965Sjdp 40033965Sjdp if (flag_mri) 40133965Sjdp { 40233965Sjdp while (! is_end_of_line[(unsigned char) *input_line_pointer]) 40333965Sjdp ++input_line_pointer; 40433965Sjdp } 40533965Sjdp 40633965Sjdp demand_empty_rest_of_line (); 40733965Sjdp} /* s_else() */ 40833965Sjdp 40933965Sjdpvoid 41033965Sjdps_ifeqs (arg) 41133965Sjdp int arg; 41233965Sjdp{ 41333965Sjdp char *s1, *s2; 41433965Sjdp int len1, len2; 41533965Sjdp int res; 41633965Sjdp struct conditional_frame cframe; 41733965Sjdp 41833965Sjdp s1 = demand_copy_C_string (&len1); 41933965Sjdp 42033965Sjdp SKIP_WHITESPACE (); 42133965Sjdp if (*input_line_pointer != ',') 42233965Sjdp { 42360484Sobrien as_bad (_(".ifeqs syntax error")); 42433965Sjdp ignore_rest_of_line (); 42533965Sjdp return; 42633965Sjdp } 42733965Sjdp 42833965Sjdp ++input_line_pointer; 42933965Sjdp 43033965Sjdp s2 = demand_copy_C_string (&len2); 43133965Sjdp 43233965Sjdp res = len1 == len2 && strncmp (s1, s2, len1) == 0; 43333965Sjdp 43433965Sjdp initialize_cframe (&cframe); 43533965Sjdp cframe.ignoring = cframe.dead_tree || ! (res ^ arg); 43633965Sjdp current_cframe = ((struct conditional_frame *) 43733965Sjdp obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); 43833965Sjdp 43933965Sjdp if (LISTING_SKIP_COND () 44033965Sjdp && cframe.ignoring 44133965Sjdp && (cframe.previous_cframe == NULL 44233965Sjdp || ! cframe.previous_cframe->ignoring)) 44333965Sjdp listing_list (2); 44433965Sjdp 44533965Sjdp demand_empty_rest_of_line (); 44633965Sjdp} /* s_ifeqs() */ 44733965Sjdp 44833965Sjdpint 44933965Sjdpignore_input () 45033965Sjdp{ 45133965Sjdp char *s; 45233965Sjdp 45333965Sjdp s = input_line_pointer; 45433965Sjdp 45560484Sobrien if (NO_PSEUDO_DOT || flag_m68k_mri) 45633965Sjdp { 45733965Sjdp if (s[-1] != '.') 45833965Sjdp --s; 45933965Sjdp } 46033965Sjdp else 46133965Sjdp { 46233965Sjdp if (s[-1] != '.') 46333965Sjdp return (current_cframe != NULL) && (current_cframe->ignoring); 46433965Sjdp } 46533965Sjdp 46633965Sjdp /* We cannot ignore certain pseudo ops. */ 46733965Sjdp if (((s[0] == 'i' 46833965Sjdp || s[0] == 'I') 46933965Sjdp && (!strncasecmp (s, "if", 2) 47033965Sjdp || !strncasecmp (s, "ifdef", 5) 47133965Sjdp || !strncasecmp (s, "ifndef", 6))) 47233965Sjdp || ((s[0] == 'e' 47333965Sjdp || s[0] == 'E') 47433965Sjdp && (!strncasecmp (s, "else", 4) 47533965Sjdp || !strncasecmp (s, "endif", 5) 47633965Sjdp || !strncasecmp (s, "endc", 4)))) 47733965Sjdp return 0; 47833965Sjdp 47933965Sjdp return (current_cframe != NULL) && (current_cframe->ignoring); 48033965Sjdp} /* ignore_input() */ 48133965Sjdp 48233965Sjdpstatic void 48333965Sjdpinitialize_cframe (cframe) 48433965Sjdp struct conditional_frame *cframe; 48533965Sjdp{ 48633965Sjdp memset (cframe, 0, sizeof (*cframe)); 48733965Sjdp as_where (&cframe->if_file_line.file, 48833965Sjdp &cframe->if_file_line.line); 48933965Sjdp cframe->previous_cframe = current_cframe; 49033965Sjdp cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; 49133965Sjdp cframe->macro_nest = macro_nest; 49233965Sjdp} 49333965Sjdp 49433965Sjdp/* Give an error if a conditional is unterminated inside a macro or 49533965Sjdp the assembly as a whole. If NEST is non negative, we are being 49633965Sjdp called because of the end of a macro expansion. If NEST is 49733965Sjdp negative, we are being called at the of the input files. */ 49833965Sjdp 49933965Sjdpvoid 50033965Sjdpcond_finish_check (nest) 50133965Sjdp int nest; 50233965Sjdp{ 50333965Sjdp if (current_cframe != NULL && current_cframe->macro_nest >= nest) 50433965Sjdp { 50560484Sobrien if (nest >= 0) 50660484Sobrien as_bad (_("end of macro inside conditional")); 50760484Sobrien else 50860484Sobrien as_bad (_("end of file inside conditional")); 50933965Sjdp as_bad_where (current_cframe->if_file_line.file, 51033965Sjdp current_cframe->if_file_line.line, 51160484Sobrien _("here is the start of the unterminated conditional")); 51233965Sjdp if (current_cframe->else_seen) 51333965Sjdp as_bad_where (current_cframe->else_file_line.file, 51433965Sjdp current_cframe->else_file_line.line, 51560484Sobrien _("here is the \"else\" of the unterminated conditional")); 51633965Sjdp } 51733965Sjdp} 51833965Sjdp 51933965Sjdp/* This function is called when we exit out of a macro. We assume 52033965Sjdp that any conditionals which began within the macro are correctly 52133965Sjdp nested, and just pop them off the stack. */ 52233965Sjdp 52333965Sjdpvoid 52433965Sjdpcond_exit_macro (nest) 52533965Sjdp int nest; 52633965Sjdp{ 52733965Sjdp while (current_cframe != NULL && current_cframe->macro_nest >= nest) 52833965Sjdp { 52933965Sjdp struct conditional_frame *hold; 53033965Sjdp 53133965Sjdp hold = current_cframe; 53233965Sjdp current_cframe = current_cframe->previous_cframe; 53333965Sjdp obstack_free (&cond_obstack, hold); 53433965Sjdp } 53533965Sjdp} 53633965Sjdp 53733965Sjdp/* end of cond.c */ 538