xref: /csrg-svn/contrib/gas-1.38/read.c (revision 49403)
1*49403Sbostic /*-
2*49403Sbostic  * This code is derived from software copyrighted by the Free Software
3*49403Sbostic  * Foundation.
4*49403Sbostic  *
5*49403Sbostic  * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
6*49403Sbostic  */
747445Sdonn 
8*49403Sbostic #ifndef lint
9*49403Sbostic static char sccsid[] = "@(#)read.c	6.4 (Berkeley) 05/08/91";
10*49403Sbostic #endif /* not lint */
1147445Sdonn 
1247406Sdonn /* read.c - read a source file -
1347406Sdonn    Copyright (C) 1986,1987 Free Software Foundation, Inc.
1447406Sdonn 
1547406Sdonn This file is part of GAS, the GNU Assembler.
1647406Sdonn 
1747406Sdonn GAS is free software; you can redistribute it and/or modify
1847406Sdonn it under the terms of the GNU General Public License as published by
1947406Sdonn the Free Software Foundation; either version 1, or (at your option)
2047406Sdonn any later version.
2147406Sdonn 
2247406Sdonn GAS is distributed in the hope that it will be useful,
2347406Sdonn but WITHOUT ANY WARRANTY; without even the implied warranty of
2447406Sdonn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2547406Sdonn GNU General Public License for more details.
2647406Sdonn 
2747406Sdonn You should have received a copy of the GNU General Public License
2847406Sdonn along with GAS; see the file COPYING.  If not, write to
2947406Sdonn the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
3047406Sdonn 
3147406Sdonn #define MASK_CHAR (0xFF)	/* If your chars aren't 8 bits, you will
3247406Sdonn 				   change this a bit.  But then, GNU isn't
3347406Sdonn 				   spozed to run on your machine anyway.
3447406Sdonn 				   (RMS is so shortsighted sometimes.)
3547406Sdonn 				 */
3647406Sdonn 
3747406Sdonn #define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
3847406Sdonn 				/* This is the largest known floating point */
3947406Sdonn 				/* format (for now). It will grow when we */
4047406Sdonn 				/* do 4361 style flonums. */
4147406Sdonn 
4247406Sdonn 
4347406Sdonn /* Routines that read assembler source text to build spagetti in memory. */
4447406Sdonn /* Another group of these functions is in the as-expr.c module */
4547406Sdonn 
4647406Sdonn #include <ctype.h>
4747406Sdonn #include <sys/types.h>
4847406Sdonn #include <sys/stat.h>
4947406Sdonn #include "as.h"
5047406Sdonn #include "read.h"
5147406Sdonn #include "md.h"
5247406Sdonn #include "hash.h"
5347406Sdonn #include "obstack.h"
5447406Sdonn #include "frags.h"
5547406Sdonn #include "flonum.h"
5647406Sdonn #include "struc-symbol.h"
5747406Sdonn #include "expr.h"
5847406Sdonn #include "symbols.h"
5947406Sdonn 
6047406Sdonn #ifdef SPARC
6147406Sdonn #include "sparc.h"
6247406Sdonn #define OTHER_ALIGN
6347406Sdonn #endif
6447406Sdonn #ifdef I860
6547406Sdonn #include "i860.h"
6647406Sdonn #endif
6747406Sdonn 
6847406Sdonn char *	input_line_pointer;	/* -> next char of source file to parse. */
6947406Sdonn 
7047406Sdonn 
7147406Sdonn #if BITS_PER_CHAR != 8
7247406Sdonn The following table is indexed by [ (char) ] and will break if
7347406Sdonn a char does not have exactly 256 states (hopefully 0:255!) !
7447406Sdonn #endif
7547406Sdonn 
7647406Sdonn const char				/* used by is_... macros. our ctype[] */
7747406Sdonn lex_type [256] = {
7847406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* @ABCDEFGHIJKLMNO */
7947406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* PQRSTUVWXYZ[\]^_ */
8047406Sdonn   0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,       /* _!"#$%&'()*+,-./ */
8147406Sdonn   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,       /* 0123456789:;<=>? */
8247406Sdonn   0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,       /* @ABCDEFGHIJKLMNO */
8347406Sdonn   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3,       /* PQRSTUVWXYZ[\]^_ */
8447406Sdonn   0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,       /* `abcdefghijklmno */
8547406Sdonn   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,       /* pqrstuvwxyz{|}~. */
8647406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8747406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8847406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8947406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9047406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9147406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9247406Sdonn   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
9347406Sdonn };
9447406Sdonn 
9547406Sdonn 
9647406Sdonn /*
9747406Sdonn  * In: a character.
9847406Sdonn  * Out: TRUE if this character ends a line.
9947406Sdonn  */
10047406Sdonn #define _ (0)
10147406Sdonn const char is_end_of_line [256] = {
10247406Sdonn  _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
10347406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
10447406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
10547406Sdonn  _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
10647406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
10747406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
10847406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
10947406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
11047406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
11147406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
11247406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
11347406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
11447406Sdonn  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _  /*                  */
11547406Sdonn };
11647406Sdonn #undef _
11747406Sdonn 
11847406Sdonn 				/* Functions private to this file. */
11947406Sdonn void			equals();
12047406Sdonn void			big_cons();
12147406Sdonn void			cons();
12247406Sdonn static char*		demand_copy_C_string();
12347406Sdonn static char*		demand_copy_string();
12447406Sdonn void			demand_empty_rest_of_line();
12547406Sdonn void			float_cons();
12647406Sdonn long int		get_absolute_expression();
12747406Sdonn static char		get_absolute_expression_and_terminator();
12847406Sdonn static segT		get_known_segmented_expression();
12947406Sdonn void			ignore_rest_of_line();
13047406Sdonn static int		is_it_end_of_statement();
13147406Sdonn static void		pobegin();
13247406Sdonn static void		pseudo_set();
13347406Sdonn static void		stab();
13447406Sdonn static void		stringer();
13547406Sdonn 
13647406Sdonn extern char line_comment_chars[];
13747406Sdonn 
13847406Sdonn static char *	buffer_limit;	/* -> 1 + last char in buffer. */
13947406Sdonn 
14047406Sdonn static char *	bignum_low;	/* Lowest char of bignum. */
14147406Sdonn static char *	bignum_limit;	/* 1st illegal address of bignum. */
14247406Sdonn static char *	bignum_high;	/* Highest char of bignum. */
14347406Sdonn 				/* May point to (bignum_start-1). */
14447406Sdonn 				/* Never >= bignum_limit. */
14547406Sdonn static char *old_buffer = 0;	/* JF a hack */
14647406Sdonn static char *old_input;
14747406Sdonn static char *old_limit;
14847406Sdonn 
14947406Sdonn #ifndef WORKING_DOT_WORD
15047406Sdonn struct broken_word *broken_words;
15147406Sdonn int new_broken_words = 0;
15247406Sdonn #endif
15347406Sdonn 
15447406Sdonn static void grow_bignum ();
15547406Sdonn static int next_char_of_string ();
15647406Sdonn 
15747406Sdonn void
read_begin()15847406Sdonn read_begin()
15947406Sdonn {
16047406Sdonn   pobegin();
16147406Sdonn   obstack_begin( &notes, 5000 );
16247406Sdonn #define BIGNUM_BEGIN_SIZE (16)
16347406Sdonn   bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
16447406Sdonn   bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
16547406Sdonn }
16647406Sdonn 
16747406Sdonn /* set up pseudo-op tables */
16847406Sdonn 
16947406Sdonn static struct hash_control *
17047406Sdonn po_hash = NULL;			/* use before set up: NULL-> address error */
17147406Sdonn 
17247406Sdonn 
17347406Sdonn void	s_abort(),	s_align(),	s_comm(),	s_data();
17447406Sdonn void	s_desc(),	s_even(),	s_file(),	s_fill();
17547406Sdonn void	s_globl(),	s_lcomm(),	s_line(),	s_lsym();
17647406Sdonn void	s_org(),	s_set(),	s_space(),	s_text();
17747406Sdonn #ifdef VMS
17847406Sdonn char const_flag = 0;
17947406Sdonn void s_const();
18047406Sdonn #endif
18147406Sdonn 
18247406Sdonn #ifdef DONTDEF
18347406Sdonn void	s_gdbline(),	s_gdblinetab();
18447406Sdonn void	s_gdbbeg(),	s_gdbblock(),	s_gdbend(),	s_gdbsym();
18547406Sdonn #endif
18647406Sdonn 
18747406Sdonn void	stringer();
18847406Sdonn void	cons();
18947406Sdonn void	float_cons();
19047406Sdonn void	big_cons();
19147406Sdonn void	stab();
19247406Sdonn 
19347406Sdonn static const pseudo_typeS
19447406Sdonn potable[] =
19547406Sdonn {
19647406Sdonn   { "abort",	s_abort,	0	},
19747406Sdonn   { "align",	s_align,	0	},
19847406Sdonn   { "ascii",	stringer,	0	},
19947406Sdonn   { "asciz",	stringer,	1	},
20047406Sdonn   { "byte",	cons,		1	},
20147406Sdonn   { "comm",	s_comm,		0	},
20247406Sdonn #ifdef VMS
20347406Sdonn   { "const",	s_const,	0	},
20447406Sdonn #endif
20547406Sdonn   { "data",	s_data,		0	},
20647406Sdonn   { "desc",	s_desc,		0	},
20747406Sdonn   { "double",	float_cons,	'd'	},
20847406Sdonn   { "file",	s_file,		0	},
20947406Sdonn   { "fill",	s_fill,		0	},
21047406Sdonn   { "float",	float_cons,	'f'	},
21147406Sdonn #ifdef DONTDEF
21247406Sdonn   { "gdbbeg",	s_gdbbeg,	0	},
21347406Sdonn   { "gdbblock",	s_gdbblock,	0	},
21447406Sdonn   { "gdbend",	s_gdbend,	0	},
21547406Sdonn   { "gdbsym",	s_gdbsym,	0	},
21647406Sdonn   { "gdbline",	s_gdbline,	0	},
21747406Sdonn   { "gdblinetab",s_gdblinetab,	0	},
21847406Sdonn #endif
21947406Sdonn   { "globl",	s_globl,	0	},
22047406Sdonn   { "int",	cons,		4	},
22147406Sdonn   { "lcomm",	s_lcomm,	0	},
22247406Sdonn   { "line",	s_line,		0	},
22347406Sdonn   { "long",	cons,		4	},
22447406Sdonn   { "lsym",	s_lsym,		0	},
22547406Sdonn   { "octa",	big_cons,	16	},
22647406Sdonn   { "org",	s_org,		0	},
22747406Sdonn   { "quad",	big_cons,	8	},
22847406Sdonn   { "set",	s_set,		0	},
22947406Sdonn   { "short",	cons,		2	},
23047406Sdonn   { "single",	float_cons,	'f'	},
23147406Sdonn   { "space",	s_space,	0	},
23247406Sdonn   { "stabd",	stab,		'd'	},
23347406Sdonn   { "stabn",	stab,		'n'	},
23447406Sdonn   { "stabs",	stab,		's'	},
23547406Sdonn   { "text",	s_text,		0	},
23647406Sdonn #ifndef SPARC
23747406Sdonn   { "word",	cons,		2	},
23847406Sdonn #endif
23947406Sdonn   { NULL}	/* end sentinel */
24047406Sdonn };
24147406Sdonn 
24247406Sdonn static void
pobegin()24347406Sdonn pobegin()
24447406Sdonn {
24547406Sdonn   char *	errtxt;		/* error text */
24647406Sdonn   const pseudo_typeS * pop;
24747406Sdonn 
24847406Sdonn   po_hash = hash_new();
24947406Sdonn   errtxt = "";			/* OK so far */
25047406Sdonn   for (pop=potable; pop->poc_name && !*errtxt; pop++)
25147406Sdonn     {
25247406Sdonn       errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
25347406Sdonn     }
25447406Sdonn 
25547406Sdonn   for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++)
25647406Sdonn       errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
25747406Sdonn 
25847406Sdonn   if (*errtxt)
25947406Sdonn     {
26047406Sdonn       as_fatal ("error constructing pseudo-op table");
26147406Sdonn     }
26247406Sdonn }				/* pobegin() */
26347406Sdonn 
26447406Sdonn /*			read_a_source_file()
26547406Sdonn  *
26647406Sdonn  * File has already been opened, and will be closed by our caller.
26747406Sdonn  *
26847406Sdonn  * We read the file, putting things into a web that
26947406Sdonn  * represents what we have been reading.
27047406Sdonn  */
27147406Sdonn void
read_a_source_file(buffer)27247406Sdonn read_a_source_file (buffer)
27347406Sdonn      char *	buffer;		/* 1st character of each buffer of lines is here. */
27447406Sdonn {
27547406Sdonn   register char		c;
27647406Sdonn   register char *	s;	/* string of symbol, '\0' appended */
27747406Sdonn   register int		temp;
27847406Sdonn   /* register struct frag * fragP; JF unused */	/* a frag we just made */
27947406Sdonn   pseudo_typeS	*pop;
28047406Sdonn #ifdef DONTDEF
28147406Sdonn   void gdb_block_beg();
28247406Sdonn   void gdb_block_position();
28347406Sdonn   void gdb_block_end();
28447406Sdonn   void gdb_symbols_fixup();
28547406Sdonn #endif
28647406Sdonn 
28747406Sdonn   subseg_new (SEG_TEXT, 0);
28847406Sdonn   while ( buffer_limit = input_scrub_next_buffer (&buffer) )
28947406Sdonn     {				/* We have another line to parse. */
29047406Sdonn       know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */
29147406Sdonn       input_line_pointer = buffer;
29247406Sdonn  contin:	/* JF this goto is my fault I admit it.  Someone brave please re-write
29347406Sdonn 		   the whole input section here?  Pleeze??? */
29447406Sdonn       while ( input_line_pointer < buffer_limit )
29547406Sdonn 	{			/* We have more of this buffer to parse. */
29647406Sdonn 	  /*
29747406Sdonn 	   * We now have input_line_pointer -> 1st char of next line.
29847406Sdonn 	   * If input_line_pointer [-1] == '\n' then we just
29947406Sdonn 	   * scanned another line: so bump line counters.
30047406Sdonn 	   */
30147406Sdonn 	  if (input_line_pointer [-1] == '\n')
30247406Sdonn 	    {
30347406Sdonn 	      bump_line_counters ();
30447406Sdonn 	    }
30547406Sdonn 	  /*
30647406Sdonn 	   * We are at the begining of a line, or similar place.
30747406Sdonn 	   * We expect a well-formed assembler statement.
30847406Sdonn 	   * A "symbol-name:" is a statement.
30947406Sdonn 	   *
31047406Sdonn 	   * Depending on what compiler is used, the order of these tests
31147406Sdonn 	   * may vary to catch most common case 1st.
31247406Sdonn 	   * Each test is independent of all other tests at the (top) level.
31347406Sdonn 	   * PLEASE make a compiler that doesn't use this assembler.
31447406Sdonn 	   * It is crufty to waste a compiler's time encoding things for this
31547406Sdonn 	   * assembler, which then wastes more time decoding it.
31647406Sdonn 	   * (And communicating via (linear) files is silly!
31747406Sdonn 	   * If you must pass stuff, please pass a tree!)
31847406Sdonn 	   */
31947406Sdonn 	  if ( (c= * input_line_pointer ++) == '\t' || c == ' ' || c=='\f')
32047406Sdonn 	    {
32147406Sdonn 	      c = * input_line_pointer ++;
32247406Sdonn 	    }
32347406Sdonn 	  know( c != ' ' );	/* No further leading whitespace. */
32447406Sdonn 	  /*
32547406Sdonn 	   * C is the 1st significant character.
32647406Sdonn 	   * Input_line_pointer points after that character.
32747406Sdonn 	   */
32847406Sdonn 	  if ( is_name_beginner(c) )
32947406Sdonn 	    {			/* want user-defined label or pseudo/opcode */
33047406Sdonn 	      s = -- input_line_pointer;
33147406Sdonn 	      c = get_symbol_end(); /* name's delimiter */
33247406Sdonn 	      /*
33347406Sdonn 	       * C is character after symbol.
33447406Sdonn 	       * That character's place in the input line is now '\0'.
33547406Sdonn 	       * S points to the beginning of the symbol.
33647406Sdonn 	       *   [In case of pseudo-op, s -> '.'.]
33747406Sdonn 	       * Input_line_pointer -> '\0' where c was.
33847406Sdonn 	       */
33947406Sdonn 	      if ( c == ':' )
34047406Sdonn 		{
34147447Sdonn 		  if (flagseen['g'])
34247447Sdonn 		    /* set line number for function definition */
34347447Sdonn 		    funcstab(s);
34447406Sdonn 		  colon(s);	/* user-defined label */
34547406Sdonn 		  * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */
34647406Sdonn 				/* Input_line_pointer -> after ':'. */
34747406Sdonn 		  SKIP_WHITESPACE();
34847406Sdonn 		}
34947406Sdonn 	      else if(c=='=' || input_line_pointer[1]=='=')		/* JF deal with FOO=BAR */
35047406Sdonn 	        {
35147406Sdonn 		  equals(s);
35247406Sdonn 		  demand_empty_rest_of_line();
35347406Sdonn 		}
35447406Sdonn 	      else
35547406Sdonn 		{		/* expect pseudo-op or machine instruction */
35647406Sdonn 		  if ( *s=='.' )
35747406Sdonn 		    {
35847406Sdonn 		      /*
35947406Sdonn 		       * PSEUDO - OP.
36047406Sdonn 		       *
36147406Sdonn 		       * WARNING: c has next char, which may be end-of-line.
36247406Sdonn 		       * We lookup the pseudo-op table with s+1 because we
36347406Sdonn 		       * already know that the pseudo-op begins with a '.'.
36447406Sdonn 		       */
36547406Sdonn 
36647406Sdonn 		      pop= (pseudo_typeS *) hash_find (po_hash, s+1);
36747406Sdonn 
36847406Sdonn 		      /* Print the error msg now, while we still can */
36947406Sdonn 		      if(!pop)
37047406Sdonn 			  as_bad("Unknown pseudo-op:  '%s'",s);
37147406Sdonn 
37247406Sdonn 				/* Put it back for error messages etc. */
37347406Sdonn 		      * input_line_pointer = c;
37447406Sdonn 				/* The following skip of whitespace is compulsory. */
37547406Sdonn 				/* A well shaped space is sometimes all that seperates keyword from operands. */
37647406Sdonn 		      if ( c == ' ' || c == '\t' )
37747406Sdonn 			{	/* Skip seperator after keyword. */
37847406Sdonn 			  input_line_pointer ++;
37947406Sdonn 			}
38047406Sdonn 		      /*
38147406Sdonn 		       * Input_line is restored.
38247406Sdonn 		       * Input_line_pointer -> 1st non-blank char
38347406Sdonn 		       * after pseudo-operation.
38447406Sdonn 		       */
38547406Sdonn 		        if(!pop) {
38647406Sdonn 			  ignore_rest_of_line();
38747406Sdonn 			  break;
38847406Sdonn 			}
38947406Sdonn 			else
39047406Sdonn 			  (*pop->poc_handler)(pop->poc_val);
39147406Sdonn 		    }
39247406Sdonn 		  else
39347406Sdonn 		    {		/* machine instruction */
39447445Sdonn 		      /* If source file debugging, emit a stab. */
39547445Sdonn 		      if (flagseen['g'])
39647445Sdonn 			linestab();
39747445Sdonn 
39847406Sdonn 		      /* WARNING: c has char, which may be end-of-line. */
39947406Sdonn 		      /* Also: input_line_pointer -> `\0` where c was. */
40047406Sdonn 		      * input_line_pointer = c;
40147406Sdonn 		      while ( ! is_end_of_line [* input_line_pointer] )
40247406Sdonn 			{
40347406Sdonn 			  input_line_pointer ++;
40447406Sdonn 			}
40547406Sdonn 		      c = * input_line_pointer;
40647406Sdonn 		      * input_line_pointer = '\0';
40747406Sdonn 		      md_assemble (s);	/* Assemble 1 instruction. */
40847406Sdonn 		      * input_line_pointer ++ = c;
40947406Sdonn 		      /* We resume loop AFTER the end-of-line from this instruction */
41047406Sdonn 		    }		/* if (*s=='.') */
41147406Sdonn 		}		/* if c==':' */
41247406Sdonn 	      continue;
41347406Sdonn 	    }			/* if (is_name_beginner(c) */
41447406Sdonn 
41547406Sdonn 
41647406Sdonn 	  if ( is_end_of_line [c] )
41747406Sdonn 	    {			/* empty statement */
41847406Sdonn 	      continue;
41947406Sdonn 	    }
42047406Sdonn 
42147406Sdonn 	  if ( isdigit(c) )
42247406Sdonn 	    {			/* local label  ("4:") */
42347406Sdonn 	      temp = c - '0';
42447406Sdonn #ifdef SUN_ASM_SYNTAX
42547406Sdonn 	      if( *input_line_pointer=='$')
42647406Sdonn 		input_line_pointer++;
42747406Sdonn #endif
42847406Sdonn 	      if ( * input_line_pointer ++ == ':' )
42947406Sdonn 		{
43047406Sdonn 		  local_colon (temp);
43147406Sdonn 		}
43247406Sdonn 	      else
43347406Sdonn 		{
43447406Sdonn 		  as_bad( "Spurious digit %d.", temp);
43547406Sdonn 		  input_line_pointer -- ;
43647406Sdonn 		  ignore_rest_of_line();
43747406Sdonn 		}
43847406Sdonn 	      continue;
43947406Sdonn 	    }
44047406Sdonn 	  if(c && index(line_comment_chars,c)) {	/* Its a comment.  Better say APP or NO_APP */
44147406Sdonn 		char *ends;
44247406Sdonn 		char *strstr();
44347406Sdonn 		char	*new_buf;
44447406Sdonn 		char	*new_tmp;
44547406Sdonn 		int	new_length;
44647406Sdonn 		char	*tmp_buf = 0;
44747406Sdonn 		extern char *scrub_string,*scrub_last_string;
44847406Sdonn 		int	scrub_from_string();
44947406Sdonn 		void	scrub_to_string();
45047406Sdonn 
45147406Sdonn 		bump_line_counters();
45247406Sdonn 		s=input_line_pointer;
45347406Sdonn 		if(strncmp(s,"APP\n",4))
45447406Sdonn 			continue;	/* We ignore it */
45547406Sdonn 		s+=4;
45647406Sdonn 
45747406Sdonn 		ends=strstr(s,"#NO_APP\n");
45847406Sdonn 
45947406Sdonn 		if(!ends) {
46047406Sdonn 			int	tmp_len;
46147406Sdonn 			int	num;
46247406Sdonn 
46347406Sdonn 			/* The end of the #APP wasn't in this buffer.  We
46447406Sdonn 			   keep reading in buffers until we find the #NO_APP
46547406Sdonn 			   that goes with this #APP  There is one.  The specs
46647406Sdonn  			   guarentee it. . .*/
46747406Sdonn 			tmp_len=buffer_limit-s;
46847406Sdonn 			tmp_buf=xmalloc(tmp_len);
46947406Sdonn 			bcopy(s,tmp_buf,tmp_len);
47047406Sdonn 			do {
47147406Sdonn 				new_tmp = input_scrub_next_buffer(&buffer);
47247406Sdonn 				if(!new_tmp)
47347406Sdonn 					break;
47447406Sdonn 				else
47547406Sdonn 					buffer_limit = new_tmp;
47647406Sdonn 				input_line_pointer = buffer;
47747406Sdonn 				ends = strstr(buffer,"#NO_APP\n");
47847406Sdonn 				if(ends)
47947406Sdonn 					num=ends-buffer;
48047406Sdonn 				else
48147406Sdonn 					num=buffer_limit-buffer;
48247406Sdonn 
48347406Sdonn 				tmp_buf=xrealloc(tmp_buf,tmp_len+num);
48447406Sdonn 				bcopy(buffer,tmp_buf+tmp_len,num);
48547406Sdonn 				tmp_len+=num;
48647406Sdonn 			} while(!ends);
48747406Sdonn 
48847406Sdonn 			input_line_pointer= ends ? ends+8 : NULL;
48947406Sdonn 
49047406Sdonn 			s=tmp_buf;
49147406Sdonn 			ends=s+tmp_len;
49247406Sdonn 
49347406Sdonn 		} else {
49447406Sdonn 			input_line_pointer=ends+8;
49547406Sdonn 		}
49647406Sdonn 		new_buf=xmalloc(100);
49747406Sdonn 		new_length=100;
49847406Sdonn 		new_tmp=new_buf;
49947406Sdonn 
50047406Sdonn 		scrub_string=s;
50147406Sdonn 		scrub_last_string = ends;
50247406Sdonn 		for(;;) {
50347406Sdonn 			int ch;
50447406Sdonn 
50547406Sdonn 			ch=do_scrub_next_char(scrub_from_string,scrub_to_string);
50647406Sdonn 			if(ch==EOF) break;
50747406Sdonn 			*new_tmp++=ch;
50847406Sdonn 			if(new_tmp==new_buf+new_length) {
50947406Sdonn 				new_buf=xrealloc(new_buf,new_length+100);
51047406Sdonn 				new_tmp=new_buf+new_length;
51147406Sdonn 				new_length+=100;
51247406Sdonn 			}
51347406Sdonn 		}
51447406Sdonn 
51547406Sdonn 		if(tmp_buf)
51647406Sdonn 			free(tmp_buf);
51747406Sdonn 		old_buffer=buffer;
51847406Sdonn 		old_input=input_line_pointer;
51947406Sdonn 		old_limit=buffer_limit;
52047406Sdonn 		buffer=new_buf;
52147406Sdonn 		input_line_pointer=new_buf;
52247406Sdonn 		buffer_limit=new_tmp;
52347406Sdonn 		continue;
52447406Sdonn 	  }
52547406Sdonn 
52647406Sdonn 	  as_bad("Junk character %d.",c);
52747406Sdonn 	  ignore_rest_of_line();
52847406Sdonn 	}			/* while (input_line_pointer<buffer_limit )*/
52947406Sdonn 	if(old_buffer) {
53047406Sdonn 		bump_line_counters();
53147406Sdonn 		if(old_input == 0)
53247406Sdonn 			return;
53347406Sdonn 		buffer=old_buffer;
53447406Sdonn 		input_line_pointer=old_input;
53547406Sdonn 		buffer_limit=old_limit;
53647406Sdonn 		old_buffer = 0;
53747406Sdonn 		goto contin;
53847406Sdonn 	}
53947406Sdonn     }				/* while (more bufrers to scan) */
54047406Sdonn }				/* read_a_source_file() */
54147406Sdonn 
54247406Sdonn void
s_abort()54347406Sdonn s_abort()
54447406Sdonn {
54547406Sdonn 	as_fatal(".abort detected.  Abandoning ship.");
54647406Sdonn }
54747406Sdonn 
54847406Sdonn #ifdef OTHER_ALIGN
54947406Sdonn static void
s_align()55047406Sdonn s_align()
55147406Sdonn {
55247406Sdonn     register unsigned int temp;
55347406Sdonn     register long int temp_fill;
55447406Sdonn     unsigned int i;
55547406Sdonn 
55647406Sdonn     temp = get_absolute_expression ();
55747406Sdonn #define MAX_ALIGNMENT (1 << 15)
55847406Sdonn     if ( temp > MAX_ALIGNMENT ) {
55947406Sdonn 	as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
56047406Sdonn     }
56147406Sdonn 
56247406Sdonn     /*
56347406Sdonn      * For the sparc, `.align (1<<n)' actually means `.align n'
56447406Sdonn      * so we have to convert it.
56547406Sdonn      */
56647406Sdonn     if (temp != 0) {
56747406Sdonn 	for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
56847406Sdonn 	    ;
56947406Sdonn     }
57047406Sdonn     if (temp != 1)
57147406Sdonn 	as_bad("Alignment not a power of 2");
57247406Sdonn 
57347406Sdonn     temp = i;
57447406Sdonn     if (*input_line_pointer == ',') {
57547406Sdonn 	input_line_pointer ++;
57647406Sdonn 	temp_fill = get_absolute_expression ();
57747406Sdonn     } else {
57847406Sdonn 	temp_fill = 0;
57947406Sdonn     }
58047406Sdonn     /* Only make a frag if we HAVE to. . . */
58147406Sdonn     if (temp && ! need_pass_2)
58247406Sdonn 	frag_align (temp, (int)temp_fill);
58347406Sdonn 
58447406Sdonn     demand_empty_rest_of_line();
58547406Sdonn }
58647406Sdonn #else
58747406Sdonn 
58847406Sdonn void
s_align()58947406Sdonn s_align()
59047406Sdonn {
59147406Sdonn 	register int temp;
59247406Sdonn 	register long int temp_fill;
59347406Sdonn 
59447406Sdonn 	temp = get_absolute_expression ();
59547406Sdonn #define MAX_ALIGNMENT (15)
59647406Sdonn 	if ( temp > MAX_ALIGNMENT )
59747406Sdonn 		as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
59847406Sdonn 	else if ( temp < 0 ) {
59947406Sdonn 		as_bad("Alignment negative. 0 assumed.");
60047406Sdonn 		temp = 0;
60147406Sdonn 	}
60247406Sdonn 	if ( *input_line_pointer == ',' ) {
60347406Sdonn 		input_line_pointer ++;
60447406Sdonn 		temp_fill = get_absolute_expression ();
60547406Sdonn 	} else
60647406Sdonn 		temp_fill = 0;
60747406Sdonn 	/* Only make a frag if we HAVE to. . . */
60847406Sdonn 	if ( temp && ! need_pass_2 )
60947406Sdonn 		frag_align (temp, (int)temp_fill);
61047406Sdonn 	demand_empty_rest_of_line();
61147406Sdonn }
61247406Sdonn #endif
61347406Sdonn 
61447406Sdonn void
s_comm()61547406Sdonn s_comm()
61647406Sdonn {
61747406Sdonn 	register char *name;
61847406Sdonn 	register char c;
61947406Sdonn 	register char *p;
62047406Sdonn 	register int temp;
62147406Sdonn 	register symbolS *	symbolP;
62247406Sdonn 
62347406Sdonn 	name = input_line_pointer;
62447406Sdonn 	c = get_symbol_end();
62547406Sdonn 	/* just after name is now '\0' */
62647406Sdonn 	p = input_line_pointer;
62747406Sdonn 	*p = c;
62847406Sdonn 	SKIP_WHITESPACE();
62947406Sdonn 	if ( * input_line_pointer != ',' ) {
63047406Sdonn 		as_bad("Expected comma after symbol-name");
63147406Sdonn 		ignore_rest_of_line();
63247406Sdonn 		return;
63347406Sdonn 	}
63447406Sdonn 	input_line_pointer ++; /* skip ',' */
63547406Sdonn 	if ( (temp = get_absolute_expression ()) < 0 ) {
63647406Sdonn 		as_warn(".COMMon length (%d.) <0! Ignored.", temp);
63747406Sdonn 		ignore_rest_of_line();
63847406Sdonn 		return;
63947406Sdonn 	}
64047406Sdonn 	*p = 0;
64147406Sdonn 	symbolP = symbol_find_or_make (name);
64247406Sdonn 	*p = c;
64347406Sdonn 	if (   (symbolP -> sy_type & N_TYPE) != N_UNDF ||
64447406Sdonn  symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) {
64547406Sdonn 		as_warn( "Ignoring attempt to re-define symbol");
64647406Sdonn 		ignore_rest_of_line();
64747406Sdonn 		return;
64847406Sdonn 	}
64947406Sdonn 	if (symbolP -> sy_value) {
65047406Sdonn 		if (symbolP -> sy_value != temp)
65147406Sdonn 			as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
65247406Sdonn  symbolP -> sy_name, symbolP -> sy_value, temp);
65347406Sdonn 	} else {
65447406Sdonn 		symbolP -> sy_value = temp;
65547406Sdonn 		symbolP -> sy_type |= N_EXT;
65647406Sdonn 	}
65747406Sdonn #ifdef VMS
65847406Sdonn 	if(!temp)
65947406Sdonn 		symbolP->sy_other = const_flag;
66047406Sdonn #endif
66147406Sdonn 	know( symbolP -> sy_frag == &zero_address_frag );
66247406Sdonn 	demand_empty_rest_of_line();
66347406Sdonn }
66447406Sdonn 
66547406Sdonn #ifdef VMS
66647406Sdonn void
s_const()66747406Sdonn s_const()
66847406Sdonn {
66947406Sdonn 	register int temp;
67047406Sdonn 
67147406Sdonn 	temp = get_absolute_expression ();
67247406Sdonn 	subseg_new (SEG_DATA, (subsegT)temp);
67347406Sdonn 	const_flag = 1;
67447406Sdonn 	demand_empty_rest_of_line();
67547406Sdonn }
67647406Sdonn #endif
67747406Sdonn 
67847406Sdonn void
s_data()67947406Sdonn s_data()
68047406Sdonn {
68147406Sdonn 	register int temp;
68247406Sdonn 
68347406Sdonn 	temp = get_absolute_expression ();
68447406Sdonn 	subseg_new (SEG_DATA, (subsegT)temp);
68547406Sdonn #ifdef VMS
68647406Sdonn 	const_flag = 0;
68747406Sdonn #endif
68847406Sdonn 	demand_empty_rest_of_line();
68947406Sdonn }
69047406Sdonn 
69147406Sdonn void
s_desc()69247406Sdonn s_desc()
69347406Sdonn {
69447406Sdonn 	register char *name;
69547406Sdonn 	register char c;
69647406Sdonn 	register char *p;
69747406Sdonn 	register symbolS *	symbolP;
69847406Sdonn 	register int temp;
69947406Sdonn 
70047406Sdonn 	/*
70147406Sdonn 	 * Frob invented at RMS' request. Set the n_desc of a symbol.
70247406Sdonn 	 */
70347406Sdonn 	name = input_line_pointer;
70447406Sdonn 	c = get_symbol_end();
70547406Sdonn 	p = input_line_pointer;
70647406Sdonn 	symbolP = symbol_table_lookup (name);
70747406Sdonn 	* p = c;
70847406Sdonn 	SKIP_WHITESPACE();
70947406Sdonn 	if ( * input_line_pointer != ',' ) {
71047406Sdonn 		*p = 0;
71147406Sdonn 		as_bad("Expected comma after name \"%s\"", name);
71247406Sdonn 		*p = c;
71347406Sdonn 		ignore_rest_of_line();
71447406Sdonn 	} else {
71547406Sdonn 		input_line_pointer ++;
71647406Sdonn 		temp = get_absolute_expression ();
71747406Sdonn 		*p = 0;
71847406Sdonn 		symbolP = symbol_find_or_make (name);
71947406Sdonn 		*p = c;
72047406Sdonn 		symbolP -> sy_desc = temp;
72147406Sdonn 	}
72247406Sdonn 	demand_empty_rest_of_line();
72347406Sdonn }
72447406Sdonn 
72547406Sdonn void
s_file()72647406Sdonn s_file()
72747406Sdonn {
72847406Sdonn 	register char *s;
72947406Sdonn 	int	length;
73047406Sdonn 
73147406Sdonn 	/* Some assemblers tolerate immediately following '"' */
73247406Sdonn 	if ( s = demand_copy_string( & length ) ) {
73347406Sdonn 		new_logical_line (s, -1);
73447406Sdonn 		demand_empty_rest_of_line();
73547406Sdonn 	}
73647406Sdonn }
73747406Sdonn 
73847406Sdonn void
s_fill()73947406Sdonn s_fill()
74047406Sdonn {
74147406Sdonn 	long int temp_repeat;
74247406Sdonn 	long int temp_size;
74347406Sdonn 	register long int temp_fill;
74447406Sdonn 	char	*p;
74547406Sdonn 
74647406Sdonn 	if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) {
74747406Sdonn 		input_line_pointer --; /* Backup over what was not a ','. */
74847406Sdonn 		as_warn("Expect comma after rep-size in .fill");
74947406Sdonn 		ignore_rest_of_line();
75047406Sdonn 		return;
75147406Sdonn 	}
75247406Sdonn 	if ( get_absolute_expression_and_terminator( & temp_size) != ',' ) {
75347406Sdonn 		  input_line_pointer --; /* Backup over what was not a ','. */
75447406Sdonn 		  as_warn("Expected comma after size in .fill");
75547406Sdonn 		  ignore_rest_of_line();
75647406Sdonn 		  return;
75747406Sdonn 	}
75847406Sdonn 	/*
75947406Sdonn 	 * This is to be compatible with BSD 4.2 AS, not for any rational reason.
76047406Sdonn 	 */
76147406Sdonn #define BSD_FILL_SIZE_CROCK_8 (8)
76247406Sdonn 	if ( temp_size > BSD_FILL_SIZE_CROCK_8 ) {
76347406Sdonn 		as_bad(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
76447406Sdonn 		temp_size = BSD_FILL_SIZE_CROCK_8 ;
76547406Sdonn 	} if ( temp_size < 0 ) {
76647406Sdonn 		as_warn("Size negative: .fill ignored.");
76747406Sdonn 		temp_size = 0;
76847406Sdonn 	} else if ( temp_repeat <= 0 ) {
76947406Sdonn 		as_warn("Repeat < 0, .fill ignored");
77047406Sdonn 		temp_size = 0;
77147406Sdonn 	}
77247406Sdonn 	temp_fill = get_absolute_expression ();
77347406Sdonn 	if ( temp_size && !need_pass_2 ) {
77447406Sdonn 		p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
77547406Sdonn 		bzero (p, (int)temp_size);
77647406Sdonn /*
77747406Sdonn  * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS.
77847406Sdonn  * The following bizzare behaviour is to be compatible with above.
77947406Sdonn  * I guess they tried to take up to 8 bytes from a 4-byte expression
78047406Sdonn  * and they forgot to sign extend. Un*x Sux.
78147406Sdonn  */
78247406Sdonn #define BSD_FILL_SIZE_CROCK_4 (4)
78347406Sdonn 		md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
78447406Sdonn /*
78547406Sdonn  * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
78647406Sdonn  * but emits no error message because it seems a legal thing to do.
78747406Sdonn  * It is a degenerate case of .fill but could be emitted by a compiler.
78847406Sdonn  */
78947406Sdonn 	}
79047406Sdonn 	demand_empty_rest_of_line();
79147406Sdonn }
79247406Sdonn 
79347406Sdonn #ifdef DONTDEF
79447406Sdonn void
s_gdbbeg()79547406Sdonn s_gdbbeg()
79647406Sdonn {
79747406Sdonn 	register int temp;
79847406Sdonn 
79947406Sdonn 	temp = get_absolute_expression ();
80047406Sdonn 	if (temp < 0)
80147406Sdonn 		as_warn( "Block number <0. Ignored." );
80247406Sdonn 	else if (flagseen ['G'])
80347406Sdonn 		gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
80447406Sdonn 	demand_empty_rest_of_line ();
80547406Sdonn }
80647406Sdonn 
80747406Sdonn void
s_gdbblock()80847406Sdonn s_gdbblock()
80947406Sdonn {
81047406Sdonn 	register int	position;
81147406Sdonn 	int	temp;
81247406Sdonn 
81347406Sdonn 	if (get_absolute_expression_and_terminator (&temp) != ',') {
81447406Sdonn 		as_warn( "expected comma before position in .gdbblock");
81547406Sdonn 		--input_line_pointer;
81647406Sdonn 		ignore_rest_of_line ();
81747406Sdonn 		return;
81847406Sdonn 	}
81947406Sdonn 	position = get_absolute_expression ();
82047406Sdonn 	if (flagseen ['G'])
82147406Sdonn 		gdb_block_position ((long int) temp, (long int) position);
82247406Sdonn 	demand_empty_rest_of_line ();
82347406Sdonn }
82447406Sdonn 
82547406Sdonn void
s_gdbend()82647406Sdonn s_gdbend()
82747406Sdonn {
82847406Sdonn 	register int temp;
82947406Sdonn 
83047406Sdonn 	temp = get_absolute_expression ();
83147406Sdonn 	if (temp < 0)
83247406Sdonn 		as_warn( "Block number <0. Ignored." );
83347406Sdonn 	else if (flagseen ['G'])
83447406Sdonn 		gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
83547406Sdonn 	demand_empty_rest_of_line ();
83647406Sdonn }
83747406Sdonn 
83847406Sdonn void
s_gdbsym()83947406Sdonn s_gdbsym()
84047406Sdonn {
84147406Sdonn 	register char *name,
84247406Sdonn 			*p;
84347406Sdonn 	register char c;
84447406Sdonn 	register symbolS *	symbolP;
84547406Sdonn 	register int temp;
84647406Sdonn 
84747406Sdonn 	name = input_line_pointer;
84847406Sdonn 	c = get_symbol_end();
84947406Sdonn 	p = input_line_pointer;
85047406Sdonn 	symbolP = symbol_find_or_make (name);
85147406Sdonn 	*p = c;
85247406Sdonn 	SKIP_WHITESPACE();
85347406Sdonn 	if ( * input_line_pointer != ',' ) {
85447406Sdonn 		as_warn("Expected comma after name");
85547406Sdonn 		ignore_rest_of_line();
85647406Sdonn 		return;
85747406Sdonn 	}
85847406Sdonn 	input_line_pointer ++;
85947406Sdonn 	if ( (temp = get_absolute_expression ()) < 0 ) {
86047406Sdonn 		as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
86147406Sdonn 		ignore_rest_of_line();
86247406Sdonn 		return;
86347406Sdonn 	}
86447406Sdonn 	if (flagseen ['G'])
86547406Sdonn 		gdb_symbols_fixup (symbolP, (long int)temp);
86647406Sdonn 	demand_empty_rest_of_line ();
86747406Sdonn }
86847406Sdonn 
86947406Sdonn void
s_gdbline()87047406Sdonn s_gdbline()
87147406Sdonn {
87247406Sdonn 	int	file_number,
87347406Sdonn 		lineno;
87447406Sdonn 
87547406Sdonn 	if(get_absolute_expression_and_terminator(&file_number) != ',') {
87647406Sdonn 		as_warn("expected comman after filenum in .gdbline");
87747406Sdonn 		ignore_rest_of_line();
87847406Sdonn 		return;
87947406Sdonn 	}
88047406Sdonn 	lineno=get_absolute_expression();
88147406Sdonn 	if(flagseen['G'])
88247406Sdonn 		gdb_line(file_number,lineno);
88347406Sdonn 	demand_empty_rest_of_line();
88447406Sdonn }
88547406Sdonn 
88647406Sdonn 
88747406Sdonn void
s_gdblinetab()88847406Sdonn s_gdblinetab()
88947406Sdonn {
89047406Sdonn 	int	file_number,
89147406Sdonn 		offset;
89247406Sdonn 
89347406Sdonn 	if(get_absolute_expression_and_terminator(&file_number) != ',') {
89447406Sdonn 		as_warn("expected comman after filenum in .gdblinetab");
89547406Sdonn 		ignore_rest_of_line();
89647406Sdonn 		return;
89747406Sdonn 	}
89847406Sdonn 	offset=get_absolute_expression();
89947406Sdonn 	if(flagseen['G'])
90047406Sdonn 		gdb_line_tab(file_number,offset);
90147406Sdonn 	demand_empty_rest_of_line();
90247406Sdonn }
90347406Sdonn #endif
90447406Sdonn 
90547406Sdonn void
s_globl()90647406Sdonn s_globl()
90747406Sdonn {
90847406Sdonn 	register char *name;
90947406Sdonn 	register int c;
91047406Sdonn 	register symbolS *	symbolP;
91147406Sdonn 
91247406Sdonn 	do {
91347406Sdonn 		name = input_line_pointer;
91447406Sdonn 		c = get_symbol_end();
91547406Sdonn 		symbolP = symbol_find_or_make (name);
91647406Sdonn 		* input_line_pointer = c;
91747406Sdonn 		SKIP_WHITESPACE();
91847406Sdonn 		symbolP -> sy_type |= N_EXT;
91947406Sdonn 		if(c==',') {
92047406Sdonn 			input_line_pointer++;
92147406Sdonn 			SKIP_WHITESPACE();
92247406Sdonn 			if(*input_line_pointer=='\n')
92347406Sdonn 				c='\n';
92447406Sdonn 		}
92547406Sdonn 	} while(c==',');
92647406Sdonn 	demand_empty_rest_of_line();
92747406Sdonn }
92847406Sdonn 
92947406Sdonn void
s_lcomm()93047406Sdonn s_lcomm()
93147406Sdonn {
93247406Sdonn 	register char *name;
93347406Sdonn 	register char c;
93447406Sdonn 	register char *p;
93547406Sdonn 	register int temp;
93647406Sdonn 	register symbolS *	symbolP;
93747406Sdonn 
93847406Sdonn 	name = input_line_pointer;
93947406Sdonn 	c = get_symbol_end();
94047406Sdonn 	p = input_line_pointer;
94147406Sdonn 	*p = c;
94247406Sdonn 	SKIP_WHITESPACE();
94347406Sdonn 	if ( * input_line_pointer != ',' ) {
94447406Sdonn 		as_warn("Expected comma after name");
94547406Sdonn 		ignore_rest_of_line();
94647406Sdonn 		return;
94747406Sdonn 	}
94847406Sdonn 	input_line_pointer ++;
94947406Sdonn 	if ( (temp = get_absolute_expression ()) < 0 ) {
95047406Sdonn 		as_warn("BSS length (%d.) <0! Ignored.", temp);
95147406Sdonn 		ignore_rest_of_line();
95247406Sdonn 		return;
95347406Sdonn 	}
95447406Sdonn 	*p = 0;
95547406Sdonn 	symbolP = symbol_find_or_make (name);
95647406Sdonn 	*p = c;
95747406Sdonn 	if (   symbolP -> sy_other == 0
95847406Sdonn 	    && symbolP -> sy_desc  == 0
95947406Sdonn 	    && (   (   symbolP -> sy_type  == N_BSS
96047406Sdonn 	    && symbolP -> sy_value == local_bss_counter)
96147406Sdonn 	    || (   (symbolP -> sy_type & N_TYPE) == N_UNDF
96247406Sdonn 	    && symbolP -> sy_value == 0))) {
96347406Sdonn 		symbolP -> sy_value = local_bss_counter;
96447406Sdonn 		symbolP -> sy_type  = N_BSS;
96547406Sdonn 		symbolP -> sy_frag  = & bss_address_frag;
96647406Sdonn 		local_bss_counter += temp;
96747406Sdonn 	} else
96847406Sdonn 		as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
96947406Sdonn  symbolP -> sy_value, local_bss_counter );
97047406Sdonn 	demand_empty_rest_of_line();
97147406Sdonn }
97247406Sdonn 
97347406Sdonn void
s_line()97447406Sdonn s_line()
97547406Sdonn {
97647406Sdonn 	/* Assume delimiter is part of expression. */
97747406Sdonn 	/* BSD4.2 as fails with delightful bug, so we */
97847406Sdonn 	/* are not being incompatible here. */
97947406Sdonn 	new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
98047406Sdonn 	demand_empty_rest_of_line();
98147406Sdonn }
98247406Sdonn 
98347406Sdonn void
s_long()98447406Sdonn s_long()
98547406Sdonn {
98647406Sdonn 	cons(4);
98747406Sdonn }
98847406Sdonn 
98947406Sdonn void
s_int()99047406Sdonn s_int()
99147406Sdonn {
99247406Sdonn 	cons(4);
99347406Sdonn }
99447406Sdonn 
99547406Sdonn void
s_lsym()99647406Sdonn s_lsym()
99747406Sdonn {
99847406Sdonn 	register char *name;
99947406Sdonn 	register char c;
100047406Sdonn 	register char *p;
100147406Sdonn 	register segT segment;
100247406Sdonn 	expressionS exp;
100347406Sdonn 	register symbolS *symbolP;
100447406Sdonn 
100547406Sdonn 	/* we permit ANY expression: BSD4.2 demands constants */
100647406Sdonn 	name = input_line_pointer;
100747406Sdonn 	c = get_symbol_end();
100847406Sdonn 	p = input_line_pointer;
100947406Sdonn 	*p = c;
101047406Sdonn 	SKIP_WHITESPACE();
101147406Sdonn 	if ( * input_line_pointer != ',' ) {
101247406Sdonn 		*p = 0;
101347406Sdonn 		as_warn("Expected comma after name \"%s\"", name);
101447406Sdonn 		*p = c;
101547406Sdonn 		ignore_rest_of_line();
101647406Sdonn 		return;
101747406Sdonn 	}
101847406Sdonn 	input_line_pointer ++;
101947406Sdonn 	segment = expression (& exp);
102047406Sdonn 	if (   segment != SEG_ABSOLUTE && segment != SEG_DATA &&
102147406Sdonn  segment != SEG_TEXT && segment != SEG_BSS) {
102247406Sdonn 		as_bad("Bad expression: %s", seg_name [(int)segment]);
102347406Sdonn 		ignore_rest_of_line();
102447406Sdonn 		return;
102547406Sdonn 	}
102647406Sdonn  know(   segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS );
102747406Sdonn 	*p = 0;
102847406Sdonn 	symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
102947406Sdonn  0, 0, (valueT)(exp . X_add_number), & zero_address_frag);
103047406Sdonn 	*p = c;
103147406Sdonn 	demand_empty_rest_of_line();
103247406Sdonn }
103347406Sdonn 
103447406Sdonn void
s_org()103547406Sdonn s_org()
103647406Sdonn {
103747406Sdonn 	register segT segment;
103847406Sdonn 	expressionS exp;
103947406Sdonn 	register long int temp_fill;
104047406Sdonn 	register char *p;
104147406Sdonn /*
104247406Sdonn  * Don't believe the documentation of BSD 4.2 AS.
104347406Sdonn  * There is no such thing as a sub-segment-relative origin.
104447406Sdonn  * Any absolute origin is given a warning, then assumed to be segment-relative.
104547406Sdonn  * Any segmented origin expression ("foo+42") had better be in the right
104647406Sdonn  * segment or the .org is ignored.
104747406Sdonn  *
104847406Sdonn  * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
104947406Sdonn  * never know sub-segment sizes when we are reading code.
105047406Sdonn  * BSD will crash trying to emit -ve numbers of filler bytes in certain
105147406Sdonn  * .orgs. We don't crash, but see as-write for that code.
105247406Sdonn  */
105347406Sdonn /*
105447406Sdonn  * Don't make frag if need_pass_2==TRUE.
105547406Sdonn  */
105647406Sdonn 	segment = get_known_segmented_expression(& exp);
105747406Sdonn 	if ( *input_line_pointer == ',' ) {
105847406Sdonn 		input_line_pointer ++;
105947406Sdonn 		temp_fill = get_absolute_expression ();
106047406Sdonn 	} else
106147406Sdonn 		temp_fill = 0;
106247406Sdonn 	if ( ! need_pass_2 ) {
106347406Sdonn 		if (segment != now_seg && segment != SEG_ABSOLUTE)
106447406Sdonn 			as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
106547406Sdonn  seg_name [(int) segment], seg_name [(int) now_seg]);
106647406Sdonn 		p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol,
106747406Sdonn  exp . X_add_number, (char *)0);
106847406Sdonn 		* p = temp_fill;
106947406Sdonn 	} /* if (ok to make frag) */
107047406Sdonn 	demand_empty_rest_of_line();
107147406Sdonn }
107247406Sdonn 
107347406Sdonn void
s_set()107447406Sdonn s_set()
107547406Sdonn {
107647406Sdonn 	register char *name;
107747406Sdonn 	register char delim;
107847406Sdonn 	register char *end_name;
107947406Sdonn 	register symbolS *symbolP;
108047406Sdonn 
108147406Sdonn 	/*
108247406Sdonn 	 * Especial apologies for the random logic:
108347406Sdonn 	 * this just grew, and could be parsed much more simply!
108447406Sdonn 	 * Dean in haste.
108547406Sdonn 	 */
108647406Sdonn 	name = input_line_pointer;
108747406Sdonn 	delim = get_symbol_end();
108847406Sdonn 	end_name = input_line_pointer;
108947406Sdonn 	*end_name = delim;
109047406Sdonn 	SKIP_WHITESPACE();
109147406Sdonn 	if ( * input_line_pointer != ',' ) {
109247406Sdonn 		*end_name = 0;
109347406Sdonn 		as_warn("Expected comma after name \"%s\"", name);
109447406Sdonn 		*end_name = delim;
109547406Sdonn 		ignore_rest_of_line();
109647406Sdonn 		return;
109747406Sdonn 	}
109847406Sdonn 	input_line_pointer ++;
109947406Sdonn 	*end_name = 0;
110047406Sdonn 	if(name[0]=='.' && name[1]=='\0') {
110147406Sdonn 	  /* Turn '. = mumble' into a .org mumble */
110247406Sdonn 	  register segT segment;
110347406Sdonn 	  expressionS exp;
110447406Sdonn 	  register char *ptr;
110547406Sdonn 
110647406Sdonn 	  segment = get_known_segmented_expression(& exp);
110747406Sdonn 	  if ( ! need_pass_2 ) {
110847406Sdonn 	    if (segment != now_seg && segment != SEG_ABSOLUTE)
110947406Sdonn 	      as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
111047406Sdonn 		      seg_name [(int) segment], seg_name [(int) now_seg]);
111147406Sdonn 	    ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
111247406Sdonn 			  exp.X_add_number, (char *)0);
111347406Sdonn 	    *ptr= 0;
111447406Sdonn 	  } /* if (ok to make frag) */
111547406Sdonn 	  *end_name = delim;
111647406Sdonn 	  return;
111747406Sdonn 	}
111847406Sdonn 	symbolP = symbol_find_or_make (name);
111947406Sdonn 	*end_name = delim;
112047406Sdonn 	pseudo_set (symbolP);
112147406Sdonn 	demand_empty_rest_of_line ();
112247406Sdonn }
112347406Sdonn 
112447406Sdonn void
s_space()112547406Sdonn s_space()
112647406Sdonn {
112747406Sdonn 	long int temp_repeat;
112847406Sdonn 	register long int temp_fill;
112947406Sdonn 	register char *p;
113047406Sdonn 
113147406Sdonn 	/* Just like .fill, but temp_size = 1 */
113247406Sdonn 	if ( get_absolute_expression_and_terminator( & temp_repeat) == ',' ) {
113347406Sdonn 		temp_fill = get_absolute_expression ();
113447406Sdonn 	} else {
113547406Sdonn 		input_line_pointer --; /* Backup over what was not a ','. */
113647406Sdonn 		temp_fill = 0;
113747406Sdonn 	}
113847406Sdonn 	if ( temp_repeat <= 0 ) {
113947406Sdonn 		as_warn("Repeat < 0, .space ignored");
114047406Sdonn 		ignore_rest_of_line();
114147406Sdonn 		return;
114247406Sdonn 	}
114347406Sdonn 	if ( ! need_pass_2 ) {
114447406Sdonn 		p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
114547406Sdonn  temp_repeat, (char *)0);
114647406Sdonn 		* p = temp_fill;
114747406Sdonn 	}
114847406Sdonn 	demand_empty_rest_of_line();
114947406Sdonn }
115047406Sdonn 
115147406Sdonn void
s_text()115247406Sdonn s_text()
115347406Sdonn {
115447406Sdonn 	register int temp;
115547406Sdonn 
115647406Sdonn 	temp = get_absolute_expression ();
115747406Sdonn 	subseg_new (SEG_TEXT, (subsegT)temp);
115847406Sdonn 	demand_empty_rest_of_line();
115947406Sdonn }
116047406Sdonn 
116147406Sdonn 
116247406Sdonn /*( JF was static, but can't be if machine dependent pseudo-ops are to use it */
116347406Sdonn 
116447406Sdonn void
demand_empty_rest_of_line()116547406Sdonn demand_empty_rest_of_line()
116647406Sdonn {
116747406Sdonn   SKIP_WHITESPACE();
116847406Sdonn   if ( is_end_of_line [* input_line_pointer] )
116947406Sdonn     {
117047406Sdonn       input_line_pointer ++;
117147406Sdonn     }
117247406Sdonn   else
117347406Sdonn     {
117447406Sdonn       ignore_rest_of_line();
117547406Sdonn     }
117647406Sdonn 				/* Return having already swallowed end-of-line. */
117747406Sdonn }				/* Return pointing just after end-of-line. */
117847406Sdonn 
117947406Sdonn 
118047406Sdonn void
ignore_rest_of_line()118147406Sdonn ignore_rest_of_line()		/* For suspect lines: gives warning. */
118247406Sdonn {
118347406Sdonn   if ( ! is_end_of_line [* input_line_pointer])
118447406Sdonn     {
118547406Sdonn       as_warn("Rest of line ignored. 1st junk character valued %d (%c)."
118647406Sdonn 	      , * input_line_pointer, *input_line_pointer);
118747406Sdonn       while (   input_line_pointer < buffer_limit
118847406Sdonn 	     && ! is_end_of_line [* input_line_pointer] )
118947406Sdonn 	{
119047406Sdonn 	  input_line_pointer ++;
119147406Sdonn 	}
119247406Sdonn     }
119347406Sdonn   input_line_pointer ++;	/* Return pointing just after end-of-line. */
119447406Sdonn   know( is_end_of_line [input_line_pointer [-1]] );
119547406Sdonn }
119647406Sdonn 
119747406Sdonn /*
119847406Sdonn  *			stab()
119947406Sdonn  *
120047406Sdonn  * Handle .stabX directives, which used to be open-coded.
120147406Sdonn  * So much creeping featurism overloaded the semantics that we decided
120247406Sdonn  * to put all .stabX thinking in one place. Here.
120347406Sdonn  *
120447406Sdonn  * We try to make any .stabX directive legal. Other people's AS will often
120547406Sdonn  * do assembly-time consistency checks: eg assigning meaning to n_type bits
120647406Sdonn  * and "protecting" you from setting them to certain values. (They also zero
120747406Sdonn  * certain bits before emitting symbols. Tut tut.)
120847406Sdonn  *
120947406Sdonn  * If an expression is not absolute we either gripe or use the relocation
121047406Sdonn  * information. Other people's assemblers silently forget information they
121147406Sdonn  * don't need and invent information they need that you didn't supply.
121247406Sdonn  *
121347406Sdonn  * .stabX directives always make a symbol table entry. It may be junk if
121447406Sdonn  * the rest of your .stabX directive is malformed.
121547406Sdonn  */
121647406Sdonn static void
stab(what)121747406Sdonn stab (what)
121847406Sdonn int what;
121947406Sdonn {
122047406Sdonn   register symbolS *	symbolP;
122147406Sdonn   register char *	string;
122247406Sdonn 	   int		saved_type;
122347406Sdonn   	   int		length;
122447406Sdonn   	   int		goof;	/* TRUE if we have aborted. */
122547406Sdonn 	   long int	longint;
122647406Sdonn 
122747406Sdonn /*
122847406Sdonn  * Enter with input_line_pointer pointing past .stabX and any following
122947406Sdonn  * whitespace.
123047406Sdonn  */
123147406Sdonn 	goof = FALSE; /* JF who forgot this?? */
123247406Sdonn 	if (what == 's') {
123347406Sdonn 		string = demand_copy_C_string (& length);
123447406Sdonn 		SKIP_WHITESPACE();
123547406Sdonn 		if (* input_line_pointer == ',')
123647406Sdonn 			input_line_pointer ++;
123747406Sdonn 		else {
123847406Sdonn 			as_warn( "I need a comma after symbol's name" );
123947406Sdonn 			goof = TRUE;
124047406Sdonn 		}
124147406Sdonn 	} else
124247406Sdonn 		string = "";
124347406Sdonn 
124447406Sdonn /*
124547406Sdonn  * Input_line_pointer->after ','.  String -> symbol name.
124647406Sdonn  */
124747406Sdonn 	if (! goof) {
124847406Sdonn 		symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0);
124947406Sdonn 		switch (what) {
125047406Sdonn 		case 'd':
125147406Sdonn 			symbolP->sy_name = NULL; /* .stabd feature. */
125247406Sdonn 			symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal;
125347406Sdonn 			symbolP->sy_frag = frag_now;
125447406Sdonn 			break;
125547406Sdonn 
125647406Sdonn 		case 'n':
125747406Sdonn 			symbolP->sy_frag = &zero_address_frag;
125847406Sdonn 			break;
125947406Sdonn 
126047406Sdonn 		case 's':
126147406Sdonn 			symbolP->sy_frag = & zero_address_frag;
126247406Sdonn 			break;
126347406Sdonn 
126447406Sdonn 		default:
126547406Sdonn 			BAD_CASE( what );
126647406Sdonn 			break;
126747406Sdonn 		}
126847406Sdonn 		if (get_absolute_expression_and_terminator (& longint) == ',')
126947406Sdonn 			symbolP->sy_type = saved_type = longint;
127047406Sdonn 		else {
127147406Sdonn 			as_warn( "I want a comma after the n_type expression" );
127247406Sdonn 			goof = TRUE;
127347406Sdonn 			input_line_pointer --; /* Backup over a non-',' char. */
127447406Sdonn 		}
127547406Sdonn 	}
127647406Sdonn 	if (! goof) {
127747406Sdonn 		if (get_absolute_expression_and_terminator (& longint) == ',')
127847406Sdonn 			symbolP->sy_other = longint;
127947406Sdonn 		else {
128047406Sdonn 			as_warn( "I want a comma after the n_other expression" );
128147406Sdonn 			goof = TRUE;
128247406Sdonn 			input_line_pointer --; /* Backup over a non-',' char. */
128347406Sdonn 		}
128447406Sdonn 	}
128547406Sdonn 	if (! goof) {
128647406Sdonn 		symbolP->sy_desc = get_absolute_expression ();
128747406Sdonn 		if (what == 's' || what == 'n') {
128847406Sdonn 			if (* input_line_pointer != ',') {
128947406Sdonn 				as_warn( "I want a comma after the n_desc expression" );
129047406Sdonn 				goof = TRUE;
129147406Sdonn 			} else {
129247406Sdonn 				input_line_pointer ++;
129347406Sdonn 			}
129447406Sdonn 		}
129547406Sdonn 	}
129647406Sdonn 	if ((! goof) && (what=='s' || what=='n')) {
129747406Sdonn 		pseudo_set (symbolP);
129847406Sdonn 		symbolP->sy_type = saved_type;
129947406Sdonn 	}
130047406Sdonn 	if (goof)
130147406Sdonn 		ignore_rest_of_line ();
130247406Sdonn 	else
130347406Sdonn 		demand_empty_rest_of_line ();
130447406Sdonn }
130547406Sdonn 
130647406Sdonn /*
130747406Sdonn  *			pseudo_set()
130847406Sdonn  *
130947406Sdonn  * In:	Pointer to a symbol.
131047406Sdonn  *	Input_line_pointer -> expression.
131147406Sdonn  *
131247406Sdonn  * Out:	Input_line_pointer -> just after any whitespace after expression.
131347406Sdonn  *	Tried to set symbol to value of expression.
131447406Sdonn  *	Will change sy_type, sy_value, sy_frag;
131547406Sdonn  *	May set need_pass_2 == TRUE.
131647406Sdonn  */
131747406Sdonn static void
pseudo_set(symbolP)131847406Sdonn pseudo_set (symbolP)
131947406Sdonn      symbolS *	symbolP;
132047406Sdonn {
132147406Sdonn   expressionS	exp;
132247406Sdonn   register segT	segment;
132347406Sdonn   int ext;
132447406Sdonn 
132547406Sdonn   know( symbolP );		/* NULL pointer is logic error. */
132647406Sdonn   ext=(symbolP->sy_type&N_EXT);
132747406Sdonn   if ((segment = expression( & exp )) == SEG_NONE)
132847406Sdonn     {
132947406Sdonn       as_warn( "Missing expression: absolute 0 assumed" );
133047406Sdonn       exp . X_seg		= SEG_ABSOLUTE;
133147406Sdonn       exp . X_add_number	= 0;
133247406Sdonn     }
133347406Sdonn   switch (segment)
133447406Sdonn     {
133547406Sdonn     case SEG_BIG:
133647406Sdonn       as_warn( "%s number illegal. Absolute 0 assumed.",
133747406Sdonn 	      exp . X_add_number > 0 ? "Bignum" : "Floating-Point" );
133847406Sdonn       symbolP -> sy_type = N_ABS | ext;
133947406Sdonn       symbolP -> sy_value = 0;
134047406Sdonn       symbolP -> sy_frag = & zero_address_frag;
134147406Sdonn       break;
134247406Sdonn 
134347406Sdonn     case SEG_NONE:
134447406Sdonn       as_warn("No expression:  Using absolute 0");
134547406Sdonn       symbolP -> sy_type = N_ABS | ext;
134647406Sdonn       symbolP -> sy_value = 0;
134747406Sdonn       symbolP -> sy_frag = & zero_address_frag;
134847406Sdonn       break;
134947406Sdonn 
135047406Sdonn     case SEG_DIFFERENCE:
135147406Sdonn       if (exp.X_add_symbol && exp.X_subtract_symbol
135247406Sdonn           &&    (exp.X_add_symbol->sy_type & N_TYPE)
135347406Sdonn 	     == (exp.X_subtract_symbol->sy_type & N_TYPE)) {
135447406Sdonn 	if(exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) {
135547406Sdonn 	  as_bad("Unknown expression: symbols %s and %s are in different frags.",exp.X_add_symbol->sy_name, exp.X_subtract_symbol->sy_name);
135647406Sdonn 	  need_pass_2++;
135747406Sdonn 	}
135847406Sdonn 	exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value;
135947406Sdonn       } else
136047406Sdonn 	as_warn( "Complex expression. Absolute segment assumed." );
136147406Sdonn     case SEG_ABSOLUTE:
136247406Sdonn       symbolP -> sy_type = N_ABS | ext;
136347406Sdonn       symbolP -> sy_value = exp . X_add_number;
136447406Sdonn       symbolP -> sy_frag = & zero_address_frag;
136547406Sdonn       break;
136647406Sdonn 
136747406Sdonn     case SEG_DATA:
136847406Sdonn     case SEG_TEXT:
136947406Sdonn     case SEG_BSS:
137047406Sdonn       symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext;
137147406Sdonn       symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value;
137247406Sdonn       symbolP -> sy_frag = exp . X_add_symbol -> sy_frag;
137347406Sdonn       break;
137447406Sdonn 
137547406Sdonn     case SEG_PASS1:		/* Not an error. Just try another pass. */
137647406Sdonn       symbolP->sy_forward=exp.X_add_symbol;
137747406Sdonn       as_warn("Unknown expression");
137847406Sdonn       know( need_pass_2 == TRUE );
137947406Sdonn       break;
138047406Sdonn 
138147406Sdonn     case SEG_UNKNOWN:
138247406Sdonn       symbolP->sy_forward=exp.X_add_symbol;
138347406Sdonn       /* as_warn("unknown symbol"); */
138447406Sdonn       /* need_pass_2 = TRUE; */
138547406Sdonn       break;
138647406Sdonn 
138747406Sdonn     default:
138847406Sdonn       BAD_CASE( segment );
138947406Sdonn       break;
139047406Sdonn     }
139147406Sdonn }
139247406Sdonn 
139347406Sdonn /*
139447445Sdonn  * stabs(file), stabf(func) and stabd(line) -- for the purpose of
139547445Sdonn  * source file debugging of assembly files, generate file,
139647445Sdonn  * function and line number stabs, respectively.
139747447Sdonn  * These functions have corresponding functions named
139847447Sdonn  * filestab(), funcstab() and linestab() in input-scrub.c,
139947447Sdonn  * where logical files and logical line numbers are handled.
140047445Sdonn  */
140147445Sdonn 
140247445Sdonn #include <stab.h>
140347445Sdonn 
stabs(file)140447445Sdonn stabs(file)
140547445Sdonn      char *file;
140647445Sdonn {
140747445Sdonn   /* .stabs "file",100,0,0,. */
140847445Sdonn   (void) symbol_new(file,
140947445Sdonn 		    N_SO,
141047445Sdonn 		    0,
141147445Sdonn 		    0,
141247445Sdonn 		    obstack_next_free(& frags) - frag_now->fr_literal,
141347445Sdonn 		    frag_now);
141447445Sdonn }
141547445Sdonn 
stabf(func)141647445Sdonn stabf(func)
141747445Sdonn      char *func;
141847445Sdonn {
141947445Sdonn   symbolS *symbolP;
142047445Sdonn   static int void_undefined = 1;
142147445Sdonn 
142247445Sdonn   /* crudely filter uninteresting labels: require an initial '_' */
142347447Sdonn   if (*func++ != '_')
142447445Sdonn     return;
142547445Sdonn 
142647445Sdonn   /* assembly functions are assumed to have void type */
142747445Sdonn   if (void_undefined)
142847445Sdonn     {
142947445Sdonn       /* .stabs "void:t15=15",128,0,0,0 */
143047445Sdonn       (void) symbol_new("void:t1=1",
143147445Sdonn 			N_LSYM,
143247445Sdonn 			0,
143347445Sdonn 			0,
143447445Sdonn 			0,
143547445Sdonn 			&zero_address_frag);
143647445Sdonn       void_undefined = 0;
143747445Sdonn     }
143847445Sdonn 
143947445Sdonn   /* .stabs "func:F1",36,0,0,. */
144047445Sdonn   symbolP = symbol_new((char *) 0,
144147445Sdonn 		       N_FUN,
144247445Sdonn 		       0,
144347445Sdonn 		       0,
144447445Sdonn 		       obstack_next_free(& frags) - frag_now->fr_literal,
144547445Sdonn 		       frag_now);
144647445Sdonn   obstack_grow(&notes, func, strlen(func));
144747445Sdonn   obstack_1grow(&notes, ':');
144847445Sdonn   obstack_1grow(&notes, 'F');
144947445Sdonn   obstack_1grow(&notes, '1');
145047445Sdonn   obstack_1grow(&notes, '\0');
145147445Sdonn   symbolP->sy_name = obstack_finish(&notes);
145247445Sdonn }
145347445Sdonn 
stabd(line)145447445Sdonn stabd(line)
145547445Sdonn      unsigned line;
145647445Sdonn {
145747445Sdonn   /* .stabd 68,0,line */
145847445Sdonn   (void) symbol_new((char *)0,
145947445Sdonn 		    N_SLINE,
146047445Sdonn 		    0,
146147445Sdonn 		    line,
146247445Sdonn 		    obstack_next_free(& frags) - frag_now->fr_literal,
146347445Sdonn 		    frag_now);
146447445Sdonn }
146547445Sdonn 
146647445Sdonn /*
146747406Sdonn  *			cons()
146847406Sdonn  *
146947406Sdonn  * CONStruct more frag of .bytes, or .words etc.
147047406Sdonn  * Should need_pass_2 be TRUE then emit no frag(s).
147147406Sdonn  * This understands EXPRESSIONS, as opposed to big_cons().
147247406Sdonn  *
147347406Sdonn  * Bug (?)
147447406Sdonn  *
147547406Sdonn  * This has a split personality. We use expression() to read the
147647406Sdonn  * value. We can detect if the value won't fit in a byte or word.
147747406Sdonn  * But we can't detect if expression() discarded significant digits
147847406Sdonn  * in the case of a long. Not worth the crocks required to fix it.
147947406Sdonn  */
148047406Sdonn void
cons(nbytes)148147406Sdonn cons(nbytes)			/* worker to do .byte etc statements */
148247406Sdonn 				/* clobbers input_line_pointer, checks */
148347406Sdonn 				/* end-of-line. */
148447406Sdonn      register int	nbytes;	/* 1=.byte, 2=.word, 4=.long */
148547406Sdonn {
148647406Sdonn   register char		c;
148747406Sdonn   register long int	mask;	/* High-order bits we will left-truncate, */
148847406Sdonn 				/* but includes sign bit also. */
148947406Sdonn   register long int     get;	/* what we get */
149047406Sdonn   register long int	use;	/* get after truncation. */
149147406Sdonn   register long int	unmask;	/* what bits we will store */
149247406Sdonn   register char *	p;
149347406Sdonn   register segT		segment;
149447406Sdonn            expressionS	exp;
149547406Sdonn #ifdef NS32K
149647406Sdonn   void fix_new_ns32k();
149747406Sdonn #else
149847406Sdonn   void	fix_new();
149947406Sdonn #endif
150047406Sdonn 
150147406Sdonn   /*
150247406Sdonn    * Input_line_pointer -> 1st char after pseudo-op-code and could legally
150347406Sdonn    * be a end-of-line. (Or, less legally an eof - which we cope with.)
150447406Sdonn    */
150547406Sdonn   /* JF << of >= number of bits in the object is undefined.  In particular
150647406Sdonn      SPARC (Sun 4) has problems */
150747406Sdonn   if(nbytes>=sizeof(long int))
150847406Sdonn     mask = 0;
150947406Sdonn   else
151047406Sdonn     mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
151147406Sdonn   unmask = ~ mask;		/* Do store these bits. */
151247406Sdonn #ifdef NEVER
151347406Sdonn   "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
151447406Sdonn   mask = ~ (unmask >> 1);	/* Includes sign bit now. */
151547406Sdonn #endif
151647406Sdonn   /*
151747406Sdonn    * The following awkward logic is to parse ZERO or more expressions,
151847406Sdonn    * comma seperated. Recall an expression includes its leading &
151947406Sdonn    * trailing blanks. We fake a leading ',' if there is (supposed to
152047406Sdonn    * be) a 1st expression, and keep demanding 1 expression for each ','.
152147406Sdonn    */
152247406Sdonn   if (is_it_end_of_statement())
152347406Sdonn     {
152447406Sdonn       c = 0;			/* Skip loop. */
152547406Sdonn       input_line_pointer ++;	/* Matches end-of-loop 'correction'. */
152647406Sdonn     }
152747406Sdonn   else
152847406Sdonn       c = ',';			/* Do loop. */
152947406Sdonn   while ( c == ','  )
153047406Sdonn     {
153147406Sdonn       segment = expression( &exp ); /* At least scan over the expression. */
153247406Sdonn       if ( ! need_pass_2 )
153347406Sdonn 	{			/* Still worthwhile making frags. */
153447406Sdonn 
153547406Sdonn 	  /* Don't call this if we are going to junk this pass anyway! */
153647406Sdonn 	  know( segment != SEG_PASS1 );
153747406Sdonn 
153847406Sdonn 	  if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL )
153947406Sdonn 	    {
154047406Sdonn 	      as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
154147406Sdonn 		      exp . X_subtract_symbol -> sy_name,
154247406Sdonn 		      seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]);
154347406Sdonn 	      segment = SEG_ABSOLUTE;
154447406Sdonn 	      /* Leave exp . X_add_number alone. */
154547406Sdonn 	    }
154647406Sdonn 	  p = frag_more (nbytes);
154747406Sdonn 	  switch (segment)
154847406Sdonn 	    {
154947406Sdonn 	    case SEG_BIG:
155047406Sdonn 	      as_warn( "%s number illegal. Absolute 0 assumed.",
155147406Sdonn 		      exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
155247406Sdonn 	      md_number_to_chars (p, (long)0, nbytes);
155347406Sdonn 	      break;
155447406Sdonn 
155547406Sdonn 	    case SEG_NONE:
155647406Sdonn 	      as_warn( "0 assumed for missing expression" );
155747406Sdonn 	      exp . X_add_number = 0;
155847406Sdonn 	      know( exp . X_add_symbol == NULL );
155947406Sdonn 	      /* fall into SEG_ABSOLUTE */
156047406Sdonn 	    case SEG_ABSOLUTE:
156147406Sdonn 	      get = exp . X_add_number;
156247406Sdonn 	      use = get & unmask;
156347406Sdonn 	      if ( (get & mask) && (get & mask) != mask )
156447406Sdonn 		{		/* Leading bits contain both 0s & 1s. */
156547406Sdonn 		  as_warn("Value x%x truncated to x%x.", get, use);
156647406Sdonn 		}
156747406Sdonn 	      md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
156847406Sdonn 	      break;
156947406Sdonn 
157047406Sdonn 	    case SEG_DIFFERENCE:
157147406Sdonn #ifndef WORKING_DOT_WORD
157247406Sdonn 	      if(nbytes==2) {
157347406Sdonn 		struct broken_word *x;
157447406Sdonn 
157547406Sdonn 		x=(struct broken_word *)xmalloc(sizeof(struct broken_word));
157647406Sdonn 		x->next_broken_word=broken_words;
157747406Sdonn 		broken_words=x;
157847406Sdonn 		x->frag=frag_now;
157947406Sdonn 		x->word_goes_here=p;
158047406Sdonn 		x->dispfrag=0;
158147406Sdonn 		x->add=exp.X_add_symbol;
158247406Sdonn 		x->sub=exp.X_subtract_symbol;
158347406Sdonn 		x->addnum=exp.X_add_number;
158447406Sdonn 		x->added=0;
158547406Sdonn 		new_broken_words++;
158647406Sdonn 		break;
158747406Sdonn 	      }
158847406Sdonn 	      /* Else Fall through into. . . */
158947406Sdonn #endif
159047406Sdonn 	    case SEG_BSS:
159147406Sdonn 	    case SEG_UNKNOWN:
159247406Sdonn 	    case SEG_TEXT:
159347406Sdonn 	    case SEG_DATA:
159447406Sdonn #if defined(SPARC) || defined(I860)
159547406Sdonn 	      fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
159647406Sdonn 		       exp . X_add_symbol, exp . X_subtract_symbol,
159747406Sdonn 		       exp . X_add_number, 0, RELOC_32);
159847406Sdonn #endif
159947406Sdonn #ifdef NS32K
160047406Sdonn 	      fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes,
160147406Sdonn 		       exp . X_add_symbol, exp . X_subtract_symbol,
160247406Sdonn 		       exp . X_add_number, 0, 0, 2, 0, 0);
160347406Sdonn #endif
160447406Sdonn #if !defined(SPARC) && !defined(NS32K) && !defined(I860)
160547406Sdonn 	      fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
160647406Sdonn 		       exp . X_add_symbol, exp . X_subtract_symbol,
160747406Sdonn 		       exp . X_add_number, 0);
160847406Sdonn #endif
160947406Sdonn 	      break;
161047406Sdonn 
161147406Sdonn 	    default:
161247406Sdonn 	      BAD_CASE( segment );
161347406Sdonn 	      break;
161447406Sdonn 	    }			/* switch(segment) */
161547406Sdonn 	}			/* if(!need_pass_2) */
161647406Sdonn       c = * input_line_pointer ++;
161747406Sdonn     }				/* while(c==',') */
161847406Sdonn   input_line_pointer --;	/* Put terminator back into stream. */
161947406Sdonn   demand_empty_rest_of_line();
162047406Sdonn }				/* cons() */
162147406Sdonn 
162247406Sdonn /*
162347406Sdonn  *			big_cons()
162447406Sdonn  *
162547406Sdonn  * CONStruct more frag(s) of .quads, or .octa etc.
162647406Sdonn  * Makes 0 or more new frags.
162747406Sdonn  * If need_pass_2 == TRUE, generate no frag.
162847406Sdonn  * This understands only bignums, not expressions. Cons() understands
162947406Sdonn  * expressions.
163047406Sdonn  *
163147406Sdonn  * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
163247406Sdonn  *
163347406Sdonn  * This creates objects with struct obstack_control objs, destroying
163447406Sdonn  * any context objs held about a partially completed object. Beware!
163547406Sdonn  *
163647406Sdonn  *
163747406Sdonn  * I think it sucks to have 2 different types of integers, with 2
163847406Sdonn  * routines to read them, store them etc.
163947406Sdonn  * It would be nicer to permit bignums in expressions and only
164047406Sdonn  * complain if the result overflowed. However, due to "efficiency"...
164147406Sdonn  */
164247406Sdonn void
big_cons(nbytes)164347406Sdonn big_cons(nbytes)		/* worker to do .quad etc statements */
164447406Sdonn 				/* clobbers input_line_pointer, checks */
164547406Sdonn 				/* end-of-line. */
164647406Sdonn      register int	nbytes;	/* 8=.quad 16=.octa ... */
164747406Sdonn {
164847406Sdonn   register char		c;	/* input_line_pointer -> c. */
164947406Sdonn   register int		radix;
165047406Sdonn   register long int	length;	/* Number of chars in an object. */
165147406Sdonn   register int		digit;	/* Value of 1 digit. */
165247406Sdonn   register int		carry;	/* For multi-precision arithmetic. */
165347406Sdonn   register int		work;	/* For multi-precision arithmetic. */
165447406Sdonn   register char *	p;	/* For multi-precision arithmetic. */
165547406Sdonn 
165647406Sdonn   extern char hex_value[];	/* In hex_value.c. */
165747406Sdonn 
165847406Sdonn   /*
165947406Sdonn    * The following awkward logic is to parse ZERO or more strings,
166047406Sdonn    * comma seperated. Recall an expression includes its leading &
166147406Sdonn    * trailing blanks. We fake a leading ',' if there is (supposed to
166247406Sdonn    * be) a 1st expression, and keep demanding 1 expression for each ','.
166347406Sdonn    */
166447406Sdonn   if (is_it_end_of_statement())
166547406Sdonn     {
166647406Sdonn       c = 0;			/* Skip loop. */
166747406Sdonn     }
166847406Sdonn   else
166947406Sdonn     {
167047406Sdonn       c = ',';			/* Do loop. */
167147406Sdonn       -- input_line_pointer;
167247406Sdonn     }
167347406Sdonn   while (c == ',')
167447406Sdonn     {
167547406Sdonn       ++ input_line_pointer;
167647406Sdonn       SKIP_WHITESPACE();
167747406Sdonn       c = * input_line_pointer;
167847406Sdonn       /* C contains 1st non-blank character of what we hope is a number. */
167947406Sdonn       if (c == '0')
168047406Sdonn 	{
168147406Sdonn 	  c = * ++ input_line_pointer;
168247406Sdonn 	  if (c == 'x' || c=='X')
168347406Sdonn 	    {
168447406Sdonn 	      c = * ++ input_line_pointer;
168547406Sdonn 	      radix = 16;
168647406Sdonn 	    }
168747406Sdonn 	  else
168847406Sdonn 	    {
168947406Sdonn 	      radix = 8;
169047406Sdonn 	    }
169147406Sdonn 	}
169247406Sdonn       else
169347406Sdonn 	{
169447406Sdonn 	  radix = 10;
169547406Sdonn 	}
169647406Sdonn       /*
169747406Sdonn        * This feature (?) is here to stop people worrying about
169847406Sdonn        * mysterious zero constants: which is what they get when
169947406Sdonn        * they completely omit digits.
170047406Sdonn        */
170147406Sdonn       if (hex_value[c] >= radix)
170247406Sdonn 	{
170347406Sdonn 	  as_warn( "Missing digits. 0 assumed." );
170447406Sdonn 	}
170547406Sdonn       bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
170647406Sdonn       for(   ;   (digit = hex_value [c]) < radix;   c = * ++ input_line_pointer)
170747406Sdonn 	{
170847406Sdonn 	  /* Multiply existing number by radix, then add digit. */
170947406Sdonn 	  carry = digit;
171047406Sdonn 	  for (p=bignum_low;   p <= bignum_high;   p++)
171147406Sdonn 	    {
171247406Sdonn 	      work = (*p & MASK_CHAR) * radix + carry;
171347406Sdonn 	      *p = work & MASK_CHAR;
171447406Sdonn 	      carry = work >> BITS_PER_CHAR;
171547406Sdonn 	    }
171647406Sdonn 	  if (carry)
171747406Sdonn 	    {
171847406Sdonn 	      grow_bignum();
171947406Sdonn 	      * bignum_high = carry & MASK_CHAR;
172047406Sdonn 	      know( (carry & ~ MASK_CHAR) == 0);
172147406Sdonn 	    }
172247406Sdonn 	}
172347406Sdonn       length = bignum_high - bignum_low + 1;
172447406Sdonn       if (length > nbytes)
172547406Sdonn 	{
172647406Sdonn 	  as_warn( "Most significant bits truncated in integer constant." );
172747406Sdonn 	}
172847406Sdonn       else
172947406Sdonn 	{
173047406Sdonn 	  register long int	leading_zeroes;
173147406Sdonn 
173247406Sdonn 	  for(leading_zeroes = nbytes - length;
173347406Sdonn 	      leading_zeroes;
173447406Sdonn 	      leading_zeroes --)
173547406Sdonn 	    {
173647406Sdonn 	      grow_bignum();
173747406Sdonn 	      * bignum_high = 0;
173847406Sdonn 	    }
173947406Sdonn 	}
174047406Sdonn       if (! need_pass_2)
174147406Sdonn 	{
174247406Sdonn 	  p = frag_more (nbytes);
174347406Sdonn 	  bcopy (bignum_low, p, (int)nbytes);
174447406Sdonn 	}
174547406Sdonn       /* C contains character after number. */
174647406Sdonn       SKIP_WHITESPACE();
174747406Sdonn       c = * input_line_pointer;
174847406Sdonn       /* C contains 1st non-blank character after number. */
174947406Sdonn     }
175047406Sdonn   demand_empty_rest_of_line();
175147406Sdonn }				/* big_cons() */
175247406Sdonn 
175347406Sdonn static void
grow_bignum()175447406Sdonn grow_bignum()			/* Extend bignum by 1 char. */
175547406Sdonn {
175647406Sdonn   register long int	length;
175747406Sdonn 
175847406Sdonn   bignum_high ++;
175947406Sdonn   if (bignum_high >= bignum_limit)
176047406Sdonn     {
176147406Sdonn       length = bignum_limit - bignum_low;
176247406Sdonn       bignum_low = xrealloc (bignum_low, length + length);
176347406Sdonn       bignum_high = bignum_low + length;
176447406Sdonn       bignum_limit = bignum_low + length + length;
176547406Sdonn     }
176647406Sdonn }				/* grow_bignum(); */
176747406Sdonn 
176847406Sdonn /*
176947406Sdonn  *			float_cons()
177047406Sdonn  *
177147406Sdonn  * CONStruct some more frag chars of .floats .ffloats etc.
177247406Sdonn  * Makes 0 or more new frags.
177347406Sdonn  * If need_pass_2 == TRUE, no frags are emitted.
177447406Sdonn  * This understands only floating literals, not expressions. Sorry.
177547406Sdonn  *
177647406Sdonn  * A floating constant is defined by atof_generic(), except it is preceded
177747406Sdonn  * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
177847406Sdonn  * reading, I decided to be incompatible. This always tries to give you
177947406Sdonn  * rounded bits to the precision of the pseudo-op. Former AS did premature
178047406Sdonn  * truncatation, restored noisy bits instead of trailing 0s AND gave you
178147406Sdonn  * a choice of 2 flavours of noise according to which of 2 floating-point
178247406Sdonn  * scanners you directed AS to use.
178347406Sdonn  *
178447406Sdonn  * In:	input_line_pointer -> whitespace before, or '0' of flonum.
178547406Sdonn  *
178647406Sdonn  */
178747406Sdonn 
178847406Sdonn void	/* JF was static, but can't be if VAX.C is goning to use it */
float_cons(float_type)178947406Sdonn float_cons(float_type)		/* Worker to do .float etc statements. */
179047406Sdonn 				/* Clobbers input_line-pointer, checks end-of-line. */
179147406Sdonn      register float_type;	/* 'f':.ffloat ... 'F':.float ... */
179247406Sdonn {
179347406Sdonn   register char *	p;
179447406Sdonn   register char		c;
179547406Sdonn   int	length;	/* Number of chars in an object. */
179647406Sdonn   register char *	err;	/* Error from scanning floating literal. */
179747406Sdonn   char		temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
179847406Sdonn 
179947406Sdonn   /*
180047406Sdonn    * The following awkward logic is to parse ZERO or more strings,
180147406Sdonn    * comma seperated. Recall an expression includes its leading &
180247406Sdonn    * trailing blanks. We fake a leading ',' if there is (supposed to
180347406Sdonn    * be) a 1st expression, and keep demanding 1 expression for each ','.
180447406Sdonn    */
180547406Sdonn   if (is_it_end_of_statement())
180647406Sdonn     {
180747406Sdonn       c = 0;			/* Skip loop. */
180847406Sdonn       ++ input_line_pointer;	/* -> past termintor. */
180947406Sdonn     }
181047406Sdonn   else
181147406Sdonn     {
181247406Sdonn       c = ',';			/* Do loop. */
181347406Sdonn     }
181447406Sdonn   while (c == ',')
181547406Sdonn     {
181647406Sdonn       /* input_line_pointer -> 1st char of a flonum (we hope!). */
181747406Sdonn       SKIP_WHITESPACE();
181847406Sdonn       /* Skip any 0{letter} that may be present. Don't even check if the
181947406Sdonn        * letter is legal. Someone may invent a "z" format and this routine
182047406Sdonn        * has no use for such information. Lusers beware: you get
182147406Sdonn        * diagnostics if your input is ill-conditioned.
182247406Sdonn        */
182347406Sdonn 
182447406Sdonn       if(input_line_pointer[0]=='0' && isalpha(input_line_pointer[1]))
182547406Sdonn 	  input_line_pointer+=2;
182647406Sdonn 
182747406Sdonn       err = md_atof (float_type, temp, &length);
182847406Sdonn       know( length <=  MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
182947406Sdonn       know( length > 0 );
183047406Sdonn       if (* err)
183147406Sdonn 	{
183247406Sdonn 	  as_warn( "Bad floating literal: %s", err);
183347406Sdonn 	  ignore_rest_of_line();
183447406Sdonn 	  /* Input_line_pointer -> just after end-of-line. */
183547406Sdonn 	  c = 0;		/* Break out of loop. */
183647406Sdonn 	}
183747406Sdonn       else
183847406Sdonn 	{
183947406Sdonn 	  if ( ! need_pass_2)
184047406Sdonn 	    {
184147406Sdonn 	      p = frag_more (length);
184247406Sdonn 	      bcopy (temp, p, length);
184347406Sdonn 	    }
184447406Sdonn 	  SKIP_WHITESPACE();
184547406Sdonn 	  c = * input_line_pointer ++;
184647406Sdonn 	  /* C contains 1st non-white character after number. */
184747406Sdonn 	  /* input_line_pointer -> just after terminator (c). */
184847406Sdonn 	}
184947406Sdonn     }
185047406Sdonn   -- input_line_pointer;		/* -> terminator (is not ','). */
185147406Sdonn   demand_empty_rest_of_line();
185247406Sdonn }				/* float_cons() */
185347406Sdonn 
185447406Sdonn /*
185547406Sdonn  *			stringer()
185647406Sdonn  *
185747406Sdonn  * We read 0 or more ',' seperated, double-quoted strings.
185847406Sdonn  *
185947406Sdonn  * Caller should have checked need_pass_2 is FALSE because we don't check it.
186047406Sdonn  */
186147406Sdonn static void
stringer(append_zero)186247406Sdonn stringer(append_zero)		/* Worker to do .ascii etc statements. */
186347406Sdonn 				/* Checks end-of-line. */
186447406Sdonn      register int append_zero;	/* 0: don't append '\0', else 1 */
186547406Sdonn {
186647406Sdonn   /* register char *	p; JF unused */
186747406Sdonn   /* register int		length; JF unused */	/* Length of string we read, excluding */
186847406Sdonn 				/* trailing '\0' implied by closing quote. */
186947406Sdonn   /* register char *	where; JF unused */
187047406Sdonn   /* register fragS *	fragP; JF unused */
187147406Sdonn   register int c;
187247406Sdonn 
187347406Sdonn   /*
187447406Sdonn    * The following awkward logic is to parse ZERO or more strings,
187547406Sdonn    * comma seperated. Recall a string expression includes spaces
187647406Sdonn    * before the opening '\"' and spaces after the closing '\"'.
187747406Sdonn    * We fake a leading ',' if there is (supposed to be)
187847406Sdonn    * a 1st, expression. We keep demanding expressions for each
187947406Sdonn    * ','.
188047406Sdonn    */
188147406Sdonn   if (is_it_end_of_statement())
188247406Sdonn     {
188347406Sdonn       c = 0;			/* Skip loop. */
188447406Sdonn       ++ input_line_pointer;	/* Compensate for end of loop. */
188547406Sdonn     }
188647406Sdonn   else
188747406Sdonn     {
188847406Sdonn       c = ',';			/* Do loop. */
188947406Sdonn     }
189047406Sdonn   for (   ;   c == ',';   c = *input_line_pointer ++)
189147406Sdonn     {
189247406Sdonn       SKIP_WHITESPACE();
189347406Sdonn       if (* input_line_pointer == '\"')
189447406Sdonn 	{
189547406Sdonn 	  ++ input_line_pointer; /* -> 1st char of string. */
189647406Sdonn 	  while ( (c = next_char_of_string()) >= 0)
189747406Sdonn 	    {
189847406Sdonn 	      FRAG_APPEND_1_CHAR( c );
189947406Sdonn 	    }
190047406Sdonn 	  if (append_zero)
190147406Sdonn 	    {
190247406Sdonn 	      FRAG_APPEND_1_CHAR( 0 );
190347406Sdonn 	    }
190447406Sdonn 	  know( input_line_pointer [-1] == '\"' );
190547406Sdonn 	}
190647406Sdonn       else
190747406Sdonn 	{
190847406Sdonn 	  as_warn( "Expected \"-ed string" );
190947406Sdonn 	}
191047406Sdonn       SKIP_WHITESPACE();
191147406Sdonn     }
191247406Sdonn   -- input_line_pointer;
191347406Sdonn   demand_empty_rest_of_line();
191447406Sdonn }				/* stringer() */
191547406Sdonn 
191647406Sdonn static int
next_char_of_string()191747406Sdonn next_char_of_string ()
191847406Sdonn {
191947406Sdonn   register int c;
192047406Sdonn 
192147406Sdonn   c = * input_line_pointer ++;
192247406Sdonn   switch (c)
192347406Sdonn     {
192447406Sdonn     case '\"':
192547406Sdonn       c = -1;
192647406Sdonn       break;
192747406Sdonn 
192847406Sdonn     case '\\':
192947406Sdonn       switch (c = * input_line_pointer ++)
193047406Sdonn 	{
193147406Sdonn 	case 'b':
193247406Sdonn 	  c = '\b';
193347406Sdonn 	  break;
193447406Sdonn 
193547406Sdonn 	case 'f':
193647406Sdonn 	  c = '\f';
193747406Sdonn 	  break;
193847406Sdonn 
193947406Sdonn 	case 'n':
194047406Sdonn 	  c = '\n';
194147406Sdonn 	  break;
194247406Sdonn 
194347406Sdonn 	case 'r':
194447406Sdonn 	  c = '\r';
194547406Sdonn 	  break;
194647406Sdonn 
194747406Sdonn 	case 't':
194847406Sdonn 	  c = '\t';
194947406Sdonn 	  break;
195047406Sdonn 
195147406Sdonn 	case '\\':
195247406Sdonn 	case '"':
195347406Sdonn 	  break;		/* As itself. */
195447406Sdonn 
195547406Sdonn 	case '0':
195647406Sdonn 	case '1':
195747406Sdonn 	case '2':
195847406Sdonn 	case '3':
195947406Sdonn 	case '4':
196047406Sdonn 	case '5':
196147406Sdonn 	case '6':
196247406Sdonn 	case '7':
196347406Sdonn 	case '8':
196447406Sdonn 	case '9':
196547406Sdonn 	  {
196647406Sdonn 	    long int number;
196747406Sdonn 
196847406Sdonn 	    for (number = 0;   isdigit(c);   c = * input_line_pointer ++)
196947406Sdonn 	      {
197047406Sdonn 		number = number * 8 + c - '0';
197147406Sdonn 	      }
197247406Sdonn 	    c = number;
197347406Sdonn 	  }
197447406Sdonn 	  -- input_line_pointer;
197547406Sdonn 	  break;
197647406Sdonn 
197747406Sdonn 	case '\n':
197847406Sdonn /*	  as_fatal( "Unterminated string - use app!" ); */
197947406Sdonn /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
198047406Sdonn 	  c = '\n';
198147406Sdonn 	  break;
198247406Sdonn 
198347406Sdonn 	default:
198447406Sdonn 	  as_warn( "Bad escaped character in string, '?' assumed" );
198547406Sdonn 	  c = '?';
198647406Sdonn 	  break;
198747406Sdonn 	}
198847406Sdonn       break;
198947406Sdonn 
199047406Sdonn     default:
199147406Sdonn       break;
199247406Sdonn     }
199347406Sdonn   return (c);
199447406Sdonn }
199547406Sdonn 
199647406Sdonn static segT
get_segmented_expression(expP)199747406Sdonn get_segmented_expression ( expP )
199847406Sdonn      register expressionS *	expP;
199947406Sdonn {
200047406Sdonn   register segT		retval;
200147406Sdonn 
200247406Sdonn   if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG )
200347406Sdonn     {
200447406Sdonn       as_warn("Expected address expression: absolute 0 assumed");
200547406Sdonn       retval = expP -> X_seg = SEG_ABSOLUTE;
200647406Sdonn       expP -> X_add_number   = 0;
200747406Sdonn       expP -> X_add_symbol   = expP -> X_subtract_symbol = 0;
200847406Sdonn     }
200947406Sdonn   return (retval);		/* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
201047406Sdonn }
201147406Sdonn 
201247406Sdonn static segT
get_known_segmented_expression(expP)201347406Sdonn get_known_segmented_expression ( expP )
201447406Sdonn      register expressionS *	expP;
201547406Sdonn {
201647406Sdonn   register segT		retval;
201747406Sdonn   register char *	name1;
201847406Sdonn   register char *	name2;
201947406Sdonn 
202047406Sdonn   if (   (retval = get_segmented_expression (expP)) == SEG_UNKNOWN
202147406Sdonn       )
202247406Sdonn     {
202347406Sdonn       name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : "";
202447406Sdonn       name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : "";
202547406Sdonn       if ( name1 && name2 )
202647406Sdonn 	{
202747406Sdonn 	  as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
202847406Sdonn 		  name1, name2);
202947406Sdonn 	}
203047406Sdonn       else
203147406Sdonn 	{
203247406Sdonn 	  as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
203347406Sdonn 		  name1 ? name1 : name2);
203447406Sdonn 	}
203547406Sdonn       retval = expP -> X_seg = SEG_ABSOLUTE;
203647406Sdonn       expP -> X_add_number   = 0;
203747406Sdonn       expP -> X_add_symbol   = expP -> X_subtract_symbol = NULL;
203847406Sdonn     }
203947406Sdonn  know(   retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE );
204047406Sdonn   return (retval);
204147406Sdonn }				/* get_known_segmented_expression() */
204247406Sdonn 
204347406Sdonn 
204447406Sdonn 
204547406Sdonn /* static */ long int /* JF was static, but can't be if the MD pseudos are to use it */
get_absolute_expression()204647406Sdonn get_absolute_expression ()
204747406Sdonn {
204847406Sdonn   expressionS	exp;
204947406Sdonn   register segT s;
205047406Sdonn 
205147406Sdonn   if ( (s = expression(& exp)) != SEG_ABSOLUTE )
205247406Sdonn     {
205347406Sdonn       if ( s != SEG_NONE )
205447406Sdonn 	{
205547406Sdonn 	  as_warn( "Bad Absolute Expression, absolute 0 assumed.");
205647406Sdonn 	}
205747406Sdonn       exp . X_add_number = 0;
205847406Sdonn     }
205947406Sdonn   return (exp . X_add_number);
206047406Sdonn }
206147406Sdonn 
206247406Sdonn static char			/* return terminator */
get_absolute_expression_and_terminator(val_pointer)206347406Sdonn get_absolute_expression_and_terminator( val_pointer)
206447406Sdonn      long int *		val_pointer; /* return value of expression */
206547406Sdonn {
206647406Sdonn   * val_pointer = get_absolute_expression ();
206747406Sdonn   return ( * input_line_pointer ++ );
206847406Sdonn }
206947406Sdonn 
207047406Sdonn /*
207147406Sdonn  *			demand_copy_C_string()
207247406Sdonn  *
207347406Sdonn  * Like demand_copy_string, but return NULL if the string contains any '\0's.
207447406Sdonn  * Give a warning if that happens.
207547406Sdonn  */
207647406Sdonn static char *
demand_copy_C_string(len_pointer)207747406Sdonn demand_copy_C_string (len_pointer)
207847406Sdonn      int *	len_pointer;
207947406Sdonn {
208047406Sdonn   register char *	s;
208147406Sdonn 
208247406Sdonn   if (s = demand_copy_string (len_pointer))
208347406Sdonn     {
208447406Sdonn       register int	len;
208547406Sdonn 
208647406Sdonn       for (len = * len_pointer;
208747406Sdonn 	   len > 0;
208847406Sdonn 	   len--)
208947406Sdonn 	{
209047406Sdonn 	  if (* s == 0)
209147406Sdonn 	    {
209247406Sdonn 	      s = 0;
209347406Sdonn 	      len = 1;
209447406Sdonn 	      * len_pointer = 0;
209547406Sdonn 	      as_warn( "This string may not contain \'\\0\'" );
209647406Sdonn 	    }
209747406Sdonn 	}
209847406Sdonn     }
209947406Sdonn   return (s);
210047406Sdonn }
210147406Sdonn 
210247406Sdonn /*
210347406Sdonn  *			demand_copy_string()
210447406Sdonn  *
210547406Sdonn  * Demand string, but return a safe (=private) copy of the string.
210647406Sdonn  * Return NULL if we can't read a string here.
210747406Sdonn  */
210847406Sdonn static char *
demand_copy_string(lenP)210947406Sdonn demand_copy_string (lenP)
211047406Sdonn      int *	lenP;
211147406Sdonn {
211247406Sdonn   register int		c;
211347406Sdonn   register int		len;
211447406Sdonn 	   char *	retval;
211547406Sdonn 
211647406Sdonn   len = 0;
211747406Sdonn   SKIP_WHITESPACE();
211847406Sdonn   if (* input_line_pointer == '\"')
211947406Sdonn     {
212047406Sdonn       input_line_pointer ++;	/* Skip opening quote. */
212147406Sdonn       while ( (c = next_char_of_string()) >= 0 ) {
212247406Sdonn 	  obstack_1grow ( &notes, c );
212347406Sdonn 	  len ++;
212447406Sdonn 	}
212547406Sdonn       /* JF this next line is so demand_copy_C_string will return a null
212647406Sdonn          termanated string. */
212747406Sdonn       obstack_1grow(&notes,'\0');
212847406Sdonn       retval=obstack_finish( &notes);
212947406Sdonn   } else {
213047406Sdonn       as_warn( "Missing string" );
213147406Sdonn       retval = NULL;
213247406Sdonn       ignore_rest_of_line ();
213347406Sdonn     }
213447406Sdonn   * lenP = len;
213547406Sdonn   return (retval);
213647406Sdonn }
213747406Sdonn 
213847406Sdonn /*
213947406Sdonn  *		is_it_end_of_statement()
214047406Sdonn  *
214147406Sdonn  * In:	Input_line_pointer -> next character.
214247406Sdonn  *
214347406Sdonn  * Do:	Skip input_line_pointer over all whitespace.
214447406Sdonn  *
214547406Sdonn  * Out:	TRUE if input_line_pointer -> end-of-line.
214647406Sdonn  */
214747406Sdonn static int
is_it_end_of_statement()214847406Sdonn is_it_end_of_statement()
214947406Sdonn {
215047406Sdonn   SKIP_WHITESPACE();
215147406Sdonn   return (is_end_of_line [* input_line_pointer]);
215247406Sdonn }
215347406Sdonn 
215447406Sdonn void
equals(sym_name)215547406Sdonn equals(sym_name)
215647406Sdonn char *sym_name;
215747406Sdonn {
215847406Sdonn   register struct symbol * symbolP; /* symbol we are working with */
215947406Sdonn 
216047406Sdonn   input_line_pointer++;
216147406Sdonn   if(*input_line_pointer=='=')
216247406Sdonn     input_line_pointer++;
216347406Sdonn 
216447406Sdonn   while(*input_line_pointer==' ' || *input_line_pointer=='\t')
216547406Sdonn     input_line_pointer++;
216647406Sdonn 
216747406Sdonn   if(sym_name[0]=='.' && sym_name[1]=='\0') {
216847406Sdonn     /* Turn '. = mumble' into a .org mumble */
216947406Sdonn     register segT segment;
217047406Sdonn     expressionS exp;
217147406Sdonn     register char *p;
217247406Sdonn 
217347406Sdonn     segment = get_known_segmented_expression(& exp);
217447406Sdonn     if ( ! need_pass_2 ) {
217547406Sdonn       if (segment != now_seg && segment != SEG_ABSOLUTE)
217647406Sdonn         as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
217747406Sdonn                 seg_name [(int) segment], seg_name [(int) now_seg]);
217847406Sdonn       p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
217947406Sdonn                     exp.X_add_number, (char *)0);
218047406Sdonn       * p = 0;
218147406Sdonn     } /* if (ok to make frag) */
218247406Sdonn   } else {
218347406Sdonn     symbolP=symbol_find_or_make(sym_name);
218447406Sdonn     pseudo_set(symbolP);
218547406Sdonn   }
218647406Sdonn }
218747406Sdonn 
218847406Sdonn /* end: read.c */
2189