/* read.c - read a source file -
- Copyright (C) 1986, 1987, 1990, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GAS; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with GAS; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#if 0
#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
#include <ctype.h>
#include "as.h"
-#ifdef BFD_ASSEMBLER
#include "subsegs.h"
-#endif
-
+#include "sb.h"
+#include "macro.h"
#include "obstack.h"
#include "listing.h"
-
+#include "ecoff.h"
#ifndef TC_START_LABEL
#define TC_START_LABEL(x,y) (x==':')
char *input_line_pointer; /*->next char of source file to parse. */
+int generate_asm_lineno = 0; /* flag to generate line stab for .s file */
+
#if BITS_PER_CHAR != 8
/* The following table is indexed by[(char)] and will break if
a char does not have exactly 256 states (hopefully 0:255!)! */
#define LEX_AT 0
#endif
+#ifndef LEX_BR
+/* The RS/6000 assembler uses {,},[,] as parts of symbol names. */
+#define LEX_BR 0
+#endif
+
+#ifndef LEX_PCT
+/* The Delta 68k assembler permits % inside label names. */
+#define LEX_PCT 0
+#endif
+
+#ifndef LEX_QM
+/* The PowerPC Windows NT assemblers permits ? inside label names. */
+#define LEX_QM 0
+#endif
+
+#ifndef LEX_DOLLAR
+/* The a29k assembler does not permits labels to start with $. */
+#define LEX_DOLLAR 3
+#endif
+
+#ifndef LEX_TILDE
+/* The Delta 68k assembler permits ~ at start of label names. */
+#define LEX_TILDE 0
+#endif
+
/* used by is_... macros. our ctype[] */
-const char lex_type[256] =
+char lex_type[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
- 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
+ 0, 0, 0, 0, LEX_DOLLAR, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, LEX_QM, /* 0123456789:;<=>? */
LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
static char *buffer; /* 1st char of each buffer of lines is here. */
static char *buffer_limit; /*->1 + last char in buffer. */
-static char *bignum_low; /* Lowest char of bignum. */
-static char *bignum_limit; /* 1st illegal address of bignum. */
-static char *bignum_high; /* Highest char of bignum. */
-/* May point to (bignum_start-1). */
-/* Never >= bignum_limit. */
-
-int target_big_endian;
+/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the
+ tc-<CPU>.h file. See the "Porting GAS" section of the internals manual. */
+int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
static char *old_buffer; /* JF a hack */
static char *old_input;
int new_broken_words;
#endif
-static char *demand_copy_string PARAMS ((int *lenP));
-int is_it_end_of_statement PARAMS ((void));
-unsigned int next_char_of_string PARAMS ((void));
+/* The current offset into the absolute section. We don't try to
+ build frags in the absolute section, since no data can be stored
+ there. We just keep track of the current offset. */
+addressT abs_section_offset;
+
+/* If this line had an MRI style label, it is stored in this variable.
+ This is used by some of the MRI pseudo-ops. */
+symbolS *line_label;
+
+/* This global variable is used to support MRI common sections. We
+ translate such sections into a common symbol. This variable is
+ non-NULL when we are in an MRI common section. */
+symbolS *mri_common_symbol;
+
+/* In MRI mode, after a dc.b pseudo-op with an odd number of bytes, we
+ need to align to an even byte boundary unless the next pseudo-op is
+ dc.b, ds.b, or dcb.b. This variable is set to 1 if an alignment
+ may be needed. */
+static int mri_pending_align;
+
+static void cons_worker PARAMS ((int, int));
+static int scrub_from_string PARAMS ((char **));
+static void do_align PARAMS ((int, char *, int, int));
+static void s_align PARAMS ((int, int));
+static int hex_float PARAMS ((int, char *));
+static void do_org PARAMS ((segT, expressionS *, int));
+char *demand_copy_string PARAMS ((int *lenP));
+static segT get_segmented_expression PARAMS ((expressionS *expP));
static segT get_known_segmented_expression PARAMS ((expressionS * expP));
-static void grow_bignum PARAMS ((void));
static void pobegin PARAMS ((void));
-
-extern int listing;
+static int get_line_sb PARAMS ((sb *));
\f
void
pobegin ();
obj_read_begin_hook ();
- obstack_begin (¬es, 5000);
- obstack_begin (&cond_obstack, 960);
-
-#define BIGNUM_BEGIN_SIZE (16)
- bignum_low = xmalloc ((long) BIGNUM_BEGIN_SIZE);
- bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
+ /* Something close -- but not too close -- to a multiple of 1024.
+ The debugging malloc I'm using has 24 bytes of overhead. */
+ obstack_begin (¬es, chunksize);
+ obstack_begin (&cond_obstack, chunksize);
/* Use machine dependent syntax */
for (p = line_separator_chars; *p; p++)
- is_end_of_line[*p] = 1;
+ is_end_of_line[(unsigned char) *p] = 1;
/* Use more. FIXME-SOMEDAY. */
+
+ if (flag_mri)
+ lex_type['?'] = 3;
}
\f
/* set up pseudo-op tables */
-struct hash_control *po_hash;
+static struct hash_control *po_hash;
static const pseudo_typeS potable[] =
{
{"align", s_align_ptwo, 0},
{"ascii", stringer, 0},
{"asciz", stringer, 1},
+ {"balign", s_align_bytes, 0},
+ {"balignw", s_align_bytes, -2},
+ {"balignl", s_align_bytes, -4},
/* block */
{"byte", cons, 1},
{"comm", s_comm, 0},
+ {"common", s_mri_common, 0},
+ {"common.s", s_mri_common, 1},
{"data", s_data, 0},
+ {"dc", cons, 2},
+ {"dc.b", cons, 1},
+ {"dc.d", float_cons, 'd'},
+ {"dc.l", cons, 4},
+ {"dc.s", float_cons, 'f'},
+ {"dc.w", cons, 2},
+ {"dc.x", float_cons, 'x'},
+ {"dcb", s_space, 2},
+ {"dcb.b", s_space, 1},
+ {"dcb.d", s_float_space, 'd'},
+ {"dcb.l", s_space, 4},
+ {"dcb.s", s_float_space, 'f'},
+ {"dcb.w", s_space, 2},
+ {"dcb.x", s_float_space, 'x'},
+ {"ds", s_space, 2},
+ {"ds.b", s_space, 1},
+ {"ds.d", s_space, 8},
+ {"ds.l", s_space, 4},
+ {"ds.p", s_space, 12},
+ {"ds.s", s_space, 4},
+ {"ds.w", s_space, 2},
+ {"ds.x", s_space, 12},
+ {"debug", s_ignore, 0},
+#ifdef S_SET_DESC
+ {"desc", s_desc, 0},
+#endif
/* dim */
{"double", float_cons, 'd'},
/* dsect */
{"eject", listing_eject, 0}, /* Formfeed listing */
{"else", s_else, 0},
+ {"elsec", s_else, 0},
{"end", s_end, 0},
+ {"endc", s_endif, 0},
{"endif", s_endif, 0},
/* endef */
{"equ", s_set, 0},
-/* err */
+ {"err", s_err, 0},
+ {"exitm", s_mexit, 0},
/* extend */
{"extern", s_ignore, 0}, /* We treat all undef as ext */
{"appfile", s_app_file, 1},
{"appline", s_app_line, 0},
+ {"fail", s_fail, 0},
{"file", s_app_file, 0},
{"fill", s_fill, 0},
{"float", float_cons, 'f'},
+ {"format", s_ignore, 0},
{"global", s_globl, 0},
{"globl", s_globl, 0},
{"hword", cons, 2},
- {"if", s_if, 0},
+ {"if", s_if, (int) O_ne},
+ {"ifc", s_ifc, 0},
{"ifdef", s_ifdef, 0},
+ {"ifeq", s_if, (int) O_eq},
{"ifeqs", s_ifeqs, 0},
+ {"ifge", s_if, (int) O_ge},
+ {"ifgt", s_if, (int) O_gt},
+ {"ifle", s_if, (int) O_le},
+ {"iflt", s_if, (int) O_lt},
+ {"ifnc", s_ifc, 1},
{"ifndef", s_ifdef, 1},
+ {"ifne", s_if, (int) O_ne},
{"ifnes", s_ifeqs, 1},
{"ifnotdef", s_ifdef, 1},
{"include", s_include, 0},
{"int", cons, 4},
+ {"irp", s_irp, 0},
+ {"irep", s_irp, 0},
+ {"irpc", s_irp, 1},
+ {"irepc", s_irp, 1},
{"lcomm", s_lcomm, 0},
{"lflags", listing_flags, 0}, /* Listing flags */
+ {"linkonce", s_linkonce, 0},
{"list", listing_list, 1}, /* Turn listing on */
+ {"llen", listing_psize, 1},
{"long", cons, 4},
{"lsym", s_lsym, 0},
+ {"macro", s_macro, 0},
+ {"mexit", s_mexit, 0},
+ {"mri", s_mri, 0},
+ {".mri", s_mri, 0}, /* Special case so .mri works in MRI mode. */
+ {"name", s_ignore, 0},
+ {"noformat", s_ignore, 0},
{"nolist", listing_list, 0}, /* Turn listing off */
- {"octa", big_cons, 16},
+ {"nopage", listing_nopage, 0},
+ {"octa", cons, 16},
+ {"offset", s_struct, 0},
{"org", s_org, 0},
+ {"p2align", s_align_ptwo, 0},
+ {"p2alignw", s_align_ptwo, -2},
+ {"p2alignl", s_align_ptwo, -4},
+ {"page", listing_eject, 0},
+ {"plen", listing_psize, 0},
+ {"print", s_print, 0},
{"psize", listing_psize, 0}, /* set paper size */
-/* print */
- {"quad", big_cons, 8},
+ {"purgem", s_purgem, 0},
+ {"quad", cons, 8},
+ {"rep", s_rept, 0},
+ {"rept", s_rept, 0},
+ {"rva", s_rva, 4},
{"sbttl", listing_title, 1}, /* Subtitle of listing */
/* scl */
/* sect */
{"single", float_cons, 'f'},
/* size */
{"space", s_space, 0},
+ {"skip", s_space, 0},
+ {"spc", s_ignore, 0},
+ {"stabd", s_stab, 'd'},
+ {"stabn", s_stab, 'n'},
+ {"stabs", s_stab, 's'},
+ {"string", stringer, 1},
+ {"struct", s_struct, 0},
/* tag */
{"text", s_text, 0},
+
+ /* This is for gcc to use. It's only just been added (2/94), so gcc
+ won't be able to use it for a while -- probably a year or more.
+ But once this has been released, check with gcc maintainers
+ before deleting it or even changing the spelling. */
+ {"this_GCC_requires_the_GNU_assembler", s_ignore, 0},
+ /* If we're folding case -- done for some targets, not necessarily
+ all -- the above string in an input file will be converted to
+ this one. Match it either way... */
+ {"this_gcc_requires_the_gnu_assembler", s_ignore, 0},
+
{"title", listing_title, 0}, /* Listing title */
+ {"ttl", listing_title, 0},
/* type */
/* use */
/* val */
+ {"xcom", s_comm, 0},
+ {"xdef", s_globl, 0},
+ {"xref", s_ignore, 0},
+ {"xstabs", s_xstab, 's'},
{"word", cons, 2},
+ {"zero", s_space, 0},
{NULL} /* end sentinel */
};
-static void
-pobegin ()
+static int pop_override_ok = 0;
+static const char *pop_table_name;
+
+void
+pop_insert (table)
+ const pseudo_typeS *table;
{
- char *errtxt; /* error text */
+ const char *errtxt;
const pseudo_typeS *pop;
+ for (pop = table; pop->poc_name; pop++)
+ {
+ errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
+ if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists")))
+ as_fatal ("error constructing %s pseudo-op table: %s", pop_table_name,
+ errtxt);
+ }
+}
+
+#ifndef md_pop_insert
+#define md_pop_insert() pop_insert(md_pseudo_table)
+#endif
+#ifndef obj_pop_insert
+#define obj_pop_insert() pop_insert(obj_pseudo_table)
+#endif
+
+static void
+pobegin ()
+{
po_hash = hash_new ();
/* Do the target-specific pseudo ops. */
- for (pop = md_pseudo_table; pop->poc_name; pop++)
- {
- errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
- if (errtxt && *errtxt)
- {
- as_fatal ("error constructing md pseudo-op table");
- } /* on error */
- } /* for each op */
+ pop_table_name = "md";
+ md_pop_insert ();
/* Now object specific. Skip any that were in the target table. */
- for (pop = obj_pseudo_table; pop->poc_name; pop++)
- {
- errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
- if (errtxt && *errtxt)
- {
- if (!strcmp (errtxt, "exists"))
- {
-#ifdef DIE_ON_OVERRIDES
- as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name);
-#endif /* DIE_ON_OVERRIDES */
- continue; /* OK if target table overrides. */
- }
- else
- {
- as_fatal ("error constructing obj pseudo-op table");
- } /* if overridden */
- } /* on error */
- } /* for each op */
+ pop_table_name = "obj";
+ pop_override_ok = 1;
+ obj_pop_insert ();
/* Now portable ones. Skip any that we've seen already. */
- for (pop = potable; pop->poc_name; pop++)
- {
- errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
- if (errtxt && *errtxt)
- {
- if (!strcmp (errtxt, "exists"))
- {
-#ifdef DIE_ON_OVERRIDES
- as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name);
-#endif /* DIE_ON_OVERRIDES */
- continue; /* OK if target table overrides. */
- }
- else
- {
- as_fatal ("error constructing obj pseudo-op table");
- } /* if overridden */
- } /* on error */
- } /* for each op */
-
- return;
-} /* pobegin() */
+ pop_table_name = "standard";
+ pop_insert (potable);
+}
\f
-#define HANDLE_CONDITIONAL_ASSEMBLY() \
- if (ignore_input ()) \
- { \
- while (! is_end_of_line[*input_line_pointer++]) \
- if (input_line_pointer == buffer_limit) \
- break; \
- continue; \
+#define HANDLE_CONDITIONAL_ASSEMBLY() \
+ if (ignore_input ()) \
+ { \
+ while (! is_end_of_line[(unsigned char) *input_line_pointer++]) \
+ if (input_line_pointer == buffer_limit) \
+ break; \
+ continue; \
}
+/* This function is used when scrubbing the characters between #APP
+ and #NO_APP. */
+
+static char *scrub_string;
+static char *scrub_string_end;
+
+static int
+scrub_from_string (from)
+ char **from;
+{
+ int size;
+
+ *from = scrub_string;
+ size = scrub_string_end - scrub_string;
+ scrub_string = scrub_string_end;
+ return size;
+}
+
/* read_a_source_file()
*
* We read the file, putting things into a web that
* If input_line_pointer [-1] == '\n' then we just
* scanned another line: so bump line counters.
*/
- if (input_line_pointer[-1] == '\n')
+ if (is_end_of_line[(unsigned char) input_line_pointer[-1]])
{
- bump_line_counters ();
+#ifdef md_start_line_hook
+ md_start_line_hook ();
+#endif
-#ifdef MRI
- /* Text at the start of a line must be a label, we run down and stick a colon in */
- if (is_name_beginner (*input_line_pointer))
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+
+ line_label = NULL;
+
+ if (flag_m68k_mri
+#ifdef LABELS_WITHOUT_COLONS
+ || 1
+#endif
+ )
{
- char *line_start = input_line_pointer;
- char c = get_symbol_end ();
- colon (line_start);
- *input_line_pointer = c;
- if (c == ':')
- input_line_pointer++;
+ /* Text at the start of a line must be a label, we
+ run down and stick a colon in. */
+ if (is_name_beginner (*input_line_pointer))
+ {
+ char *line_start = input_line_pointer;
+ char c;
+ int mri_line_macro;
+
+ LISTING_NEWLINE ();
+ HANDLE_CONDITIONAL_ASSEMBLY ();
+
+ c = get_symbol_end ();
+
+ /* In MRI mode, the EQU and MACRO pseudoops must
+ be handled specially. */
+ mri_line_macro = 0;
+ if (flag_m68k_mri)
+ {
+ char *rest = input_line_pointer + 1;
+
+ if (*rest == ':')
+ ++rest;
+ if (*rest == ' ' || *rest == '\t')
+ ++rest;
+ if ((strncasecmp (rest, "EQU", 3) == 0
+ || strncasecmp (rest, "SET", 3) == 0)
+ && (rest[3] == ' ' || rest[3] == '\t'))
+ {
+ input_line_pointer = rest + 3;
+ equals (line_start,
+ strncasecmp (rest, "SET", 3) == 0);
+ continue;
+ }
+ if (strncasecmp (rest, "MACRO", 5) == 0
+ && (rest[5] == ' '
+ || rest[5] == '\t'
+ || is_end_of_line[(unsigned char) rest[5]]))
+ mri_line_macro = 1;
+ }
+
+ /* In MRI mode, we need to handle the MACRO
+ pseudo-op specially: we don't want to put the
+ symbol in the symbol table. */
+ if (! mri_line_macro)
+ line_label = colon (line_start);
+ else
+ line_label = symbol_create (line_start,
+ absolute_section,
+ (valueT) 0,
+ &zero_address_frag);
+ *input_line_pointer = c;
+ if (c == ':')
+ input_line_pointer++;
+ }
}
-#endif
}
-
/*
* We are at the begining of a line, or similar place.
* We expect a well-formed assembler statement.
* Input_line_pointer points after that character.
*/
if (is_name_beginner (c))
- { /* want user-defined label or pseudo/opcode */
+ {
+ /* want user-defined label or pseudo/opcode */
HANDLE_CONDITIONAL_ASSEMBLY ();
s = --input_line_pointer;
*/
if (TC_START_LABEL(c, input_line_pointer))
{
- colon (s); /* user-defined label */
+ if (flag_m68k_mri)
+ {
+ char *rest = input_line_pointer + 1;
+
+ /* In MRI mode, \tsym: set 0 is permitted. */
+
+ if (*rest == ':')
+ ++rest;
+ if (*rest == ' ' || *rest == '\t')
+ ++rest;
+ if ((strncasecmp (rest, "EQU", 3) == 0
+ || strncasecmp (rest, "SET", 3) == 0)
+ && (rest[3] == ' ' || rest[3] == '\t'))
+ {
+ input_line_pointer = rest + 3;
+ equals (s, 1);
+ continue;
+ }
+ }
+
+ line_label = colon (s); /* user-defined label */
*input_line_pointer++ = ':'; /* Put ':' back for error messages' sake. */
/* Input_line_pointer->after ':'. */
SKIP_WHITESPACE ();
}
- else if (c == '=' || input_line_pointer[1] == '=')
+ else if (c == '='
+ || ((c == ' ' || c == '\t')
+ && input_line_pointer[1] == '='
+#ifdef TC_EQUAL_IN_INSN
+ && ! TC_EQUAL_IN_INSN (c, input_line_pointer)
+#endif
+ ))
{
- equals (s);
+ equals (s, 1);
demand_empty_rest_of_line ();
}
else
{ /* expect pseudo-op or machine instruction */
-#ifdef MRI
- if (!done_pseudo (s))
+ pop = NULL;
+
+#define IGNORE_OPCODE_CASE
+#ifdef IGNORE_OPCODE_CASE
+ {
+ char *s2 = s;
+ while (*s2)
+ {
+ if (isupper (*s2))
+ *s2 = tolower (*s2);
+ s2++;
+ }
+ }
+#endif
-#else
- if (*s == '.')
+ if (flag_m68k_mri
+#ifdef NO_PSEUDO_DOT
+ || 1
+#endif
+ )
+ {
+ /* The MRI assembler and the m88k use pseudo-ops
+ without a period. */
+ pop = (pseudo_typeS *) hash_find (po_hash, s);
+ if (pop != NULL && pop->poc_handler == NULL)
+ pop = NULL;
+ }
+
+ if (pop != NULL
+ || (! flag_m68k_mri && *s == '.'))
{
/*
* PSEUDO - OP.
* already know that the pseudo-op begins with a '.'.
*/
- pop = (pseudo_typeS *) hash_find (po_hash, s + 1);
+ if (pop == NULL)
+ pop = (pseudo_typeS *) hash_find (po_hash, s + 1);
+
+ /* In MRI mode, we may need to insert an
+ automatic alignment directive. What a hack
+ this is. */
+ if (mri_pending_align
+ && (pop == NULL
+ || ! ((pop->poc_handler == cons
+ && pop->poc_val == 1)
+ || (pop->poc_handler == s_space
+ && pop->poc_val == 1)
+#ifdef tc_conditional_pseudoop
+ || tc_conditional_pseudoop (pop)
+#endif
+ || pop->poc_handler == s_if
+ || pop->poc_handler == s_ifdef
+ || pop->poc_handler == s_ifc
+ || pop->poc_handler == s_ifeqs
+ || pop->poc_handler == s_else
+ || pop->poc_handler == s_endif
+ || pop->poc_handler == s_globl
+ || pop->poc_handler == s_ignore)))
+ {
+ do_align (1, (char *) NULL, 0, 0);
+ mri_pending_align = 0;
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
+ }
/* Print the error msg now, while we still can */
- if (!pop)
+ if (pop == NULL)
{
as_bad ("Unknown pseudo-op: `%s'", s);
*input_line_pointer = c;
s_ignore (0);
- break;
+ continue;
}
/* Put it back for error messages etc. */
A well shaped space is sometimes all that separates
keyword from operands. */
if (c == ' ' || c == '\t')
- {
- input_line_pointer++;
- } /* Skip seperator after keyword. */
+ input_line_pointer++;
/*
* Input_line is restored.
* Input_line_pointer->1st non-blank char
* after pseudo-operation.
*/
- if (!pop)
- {
- ignore_rest_of_line ();
- break;
- }
- else
- {
- (*pop->poc_handler) (pop->poc_val);
- } /* if we have one */
+ (*pop->poc_handler) (pop->poc_val);
+
+ /* If that was .end, just get out now. */
+ if (pop->poc_handler == s_end)
+ goto quit;
}
else
-#endif
- { /* machine instruction */
+ {
+ int inquote = 0;
+
/* WARNING: c has char, which may be end-of-line. */
/* Also: input_line_pointer->`\0` where c was. */
*input_line_pointer = c;
- while (!is_end_of_line[*input_line_pointer])
+ while (!is_end_of_line[(unsigned char) *input_line_pointer]
+ || inquote
+#ifdef TC_EOL_IN_INSN
+ || TC_EOL_IN_INSN (input_line_pointer)
+#endif
+ )
{
+ if (flag_m68k_mri && *input_line_pointer == '\'')
+ inquote = ! inquote;
input_line_pointer++;
}
c = *input_line_pointer;
*input_line_pointer = '\0';
+#ifdef OBJ_GENERATE_ASM_LINENO
+ if (generate_asm_lineno == 0)
+ {
+ if (ecoff_no_current_file ())
+ generate_asm_lineno = 1;
+ }
+ if (generate_asm_lineno == 1)
+ {
+ unsigned int lineno;
+ char *s;
+
+ as_where (&s, &lineno);
+ OBJ_GENERATE_ASM_LINENO (s, lineno);
+ }
+#endif
+
+ if (macro_defined)
+ {
+ sb out;
+ const char *err;
+
+ if (check_macro (s, &out, '\0', &err))
+ {
+ if (err != NULL)
+ as_bad (err);
+ *input_line_pointer++ = c;
+ input_scrub_include_sb (&out,
+ input_line_pointer);
+ sb_kill (&out);
+ buffer_limit =
+ input_scrub_next_buffer (&input_line_pointer);
+ continue;
+ }
+ }
+
+ if (mri_pending_align)
+ {
+ do_align (1, (char *) NULL, 0, 0);
+ mri_pending_align = 0;
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
+ }
+
md_assemble (s); /* Assemble 1 instruction. */
*input_line_pointer++ = c;
- /* We resume loop AFTER the end-of-line from this instruction */
+ /* We resume loop AFTER the end-of-line from
+ this instruction. */
} /* if (*s=='.') */
-
} /* if c==':' */
continue;
} /* if (is_name_beginner(c) */
- if (is_end_of_line[c])
- {
- continue;
- } /* empty statement */
-
+ /* Empty statement? */
+ if (is_end_of_line[(unsigned char) c])
+ continue;
-#if defined(LOCAL_LABELS_DOLLAR) || defined(LOCAL_LABELS_FB)
- if (isdigit (c))
- { /* local label ("4:") */
+ if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB)
+ && isdigit (c))
+ {
+ /* local label ("4:") */
char *backup = input_line_pointer;
HANDLE_CONDITIONAL_ASSEMBLY ();
++input_line_pointer;
} /* read the whole number */
-#ifdef LOCAL_LABELS_DOLLAR
- if (*input_line_pointer == '$'
+ if (LOCAL_LABELS_DOLLAR
+ && *input_line_pointer == '$'
&& *(input_line_pointer + 1) == ':')
{
input_line_pointer += 2;
colon (dollar_label_name (temp, 0));
continue;
}
-#endif /* LOCAL_LABELS_DOLLAR */
-#ifdef LOCAL_LABELS_FB
- if (*input_line_pointer++ == ':')
+ if (LOCAL_LABELS_FB
+ && *input_line_pointer++ == ':')
{
fb_label_instance_inc (temp);
colon (fb_label_name (temp, 0));
continue;
}
-#endif /* LOCAL_LABELS_FB */
input_line_pointer = backup;
} /* local label ("4:") */
-#endif /* LOCAL_LABELS_DOLLAR or LOCAL_LABELS_FB */
if (c && strchr (line_comment_chars, c))
{ /* Its a comment. Better say APP or NO_APP */
char *ends;
char *new_buf;
char *new_tmp;
- int new_length;
+ unsigned int new_length;
char *tmp_buf = 0;
- extern char *scrub_string, *scrub_last_string;
bump_line_counters ();
s = input_line_pointer;
if (!ends)
{
- int tmp_len;
- int num;
+ unsigned int tmp_len;
+ unsigned int num;
/* The end of the #APP wasn't in this buffer. We
keep reading in buffers until we find the #NO_APP
guarentee it. . . */
tmp_len = buffer_limit - s;
tmp_buf = xmalloc (tmp_len + 1);
- bcopy (s, tmp_buf, tmp_len);
+ memcpy (tmp_buf, s, tmp_len);
do
{
new_tmp = input_scrub_next_buffer (&buffer);
num = buffer_limit - buffer;
tmp_buf = xrealloc (tmp_buf, tmp_len + num);
- bcopy (buffer, tmp_buf + tmp_len, num);
+ memcpy (tmp_buf + tmp_len, buffer, num);
tmp_len += num;
}
while (!ends);
{
input_line_pointer = ends + 8;
}
- new_buf = xmalloc (100);
- new_length = 100;
- new_tmp = new_buf;
scrub_string = s;
- scrub_last_string = ends;
+ scrub_string_end = ends;
+
+ new_length = ends - s;
+ new_buf = (char *) xmalloc (new_length);
+ new_tmp = new_buf;
for (;;)
{
- int ch;
+ int space;
+ int size;
- ch = do_scrub_next_char (scrub_from_string, scrub_to_string);
- if (ch == EOF)
- break;
- *new_tmp++ = ch;
- if (new_tmp == new_buf + new_length)
+ space = (new_buf + new_length) - new_tmp;
+ size = do_scrub_chars (scrub_from_string, new_tmp, space);
+
+ if (size < space)
{
- new_buf = xrealloc (new_buf, new_length + 100);
- new_tmp = new_buf + new_length;
- new_length += 100;
+ new_tmp += size;
+ break;
}
+
+ new_buf = xrealloc (new_buf, new_length + 100);
+ new_tmp = new_buf + new_length;
+ new_length += 100;
}
if (tmp_buf)
HANDLE_CONDITIONAL_ASSEMBLY ();
+#ifdef tc_unrecognized_line
+ if (tc_unrecognized_line (c))
+ continue;
+#endif
+
/* as_warn("Junk character %d.",c); Now done by ignore_rest */
input_line_pointer--; /* Report unknown char as ignored. */
ignore_rest_of_line ();
} /* while (input_line_pointer<buffer_limit) */
+
+#ifdef md_after_pass_hook
+ md_after_pass_hook ();
+#endif
+
if (old_buffer)
{
+ free (buffer);
bump_line_counters ();
if (old_input != 0)
{
}
}
} /* while (more buffers to scan) */
+
+ quit:
+
+#ifdef md_cleanup
+ md_cleanup();
+#endif
input_scrub_close (); /* Close the input file */
+}
+
+/* For most MRI pseudo-ops, the line actually ends at the first
+ nonquoted space. This function looks for that point, stuffs a null
+ in, and sets *STOPCP to the character that used to be there, and
+ returns the location.
+
+ Until I hear otherwise, I am going to assume that this is only true
+ for the m68k MRI assembler. */
+
+char *
+mri_comment_field (stopcp)
+ char *stopcp;
+{
+#ifdef TC_M68K
+
+ char *s;
+ int inquote = 0;
+
+ know (flag_m68k_mri);
-} /* read_a_source_file() */
+ for (s = input_line_pointer;
+ ((! is_end_of_line[(unsigned char) *s] && *s != ' ' && *s != '\t')
+ || inquote);
+ s++)
+ {
+ if (*s == '\'')
+ inquote = ! inquote;
+ }
+ *stopcp = *s;
+ *s = '\0';
+ return s;
+
+#else
+
+ char *s;
+
+ for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++)
+ ;
+ *stopcp = *s;
+ *s = '\0';
+ return s;
+
+#endif
+
+}
+
+/* Skip to the end of an MRI comment field. */
+
+void
+mri_comment_end (stop, stopc)
+ char *stop;
+ int stopc;
+{
+ know (flag_mri);
+
+ input_line_pointer = stop;
+ *stop = stopc;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+}
void
-s_abort ()
+s_abort (ignore)
+ int ignore;
{
as_fatal (".abort detected. Abandoning ship.");
-} /* s_abort() */
+}
-/* For machines where ".align 4" means align to a 4 byte boundary. */
-void
-s_align_bytes (arg)
- int arg;
+/* Guts of .align directive. N is the power of two to which to align.
+ FILL may be NULL, or it may point to the bytes of the fill pattern.
+ LEN is the length of whatever FILL points to, if anything. MAX is
+ the maximum number of characters to skip when doing the alignment,
+ or 0 if there is no maximum. */
+
+static void
+do_align (n, fill, len, max)
+ int n;
+ char *fill;
+ int len;
+ int max;
{
- register unsigned int temp;
- register long temp_fill;
- unsigned int i = 0;
- unsigned long max_alignment = 1 << 15;
+ char default_fill;
- if (is_end_of_line[*input_line_pointer])
- temp = arg; /* Default value from pseudo-op table */
- else
- temp = get_absolute_expression ();
+#ifdef md_do_align
+ md_do_align (n, fill, len, max, just_record_alignment);
+#endif
- if (temp > max_alignment)
+ if (fill == NULL)
{
- as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+ /* FIXME: Fix this right for BFD! */
+ if (now_seg != data_section && now_seg != bss_section)
+ default_fill = NOP_OPCODE;
+ else
+ default_fill = 0;
+ fill = &default_fill;
+ len = 1;
}
- /*
- * For the sparc, `.align (1<<n)' actually means `.align n'
- * so we have to convert it.
- */
- if (temp != 0)
+ /* Only make a frag if we HAVE to. . . */
+ if (n != 0 && !need_pass_2)
{
- for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
- ;
+ if (len <= 1)
+ frag_align (n, *fill, max);
+ else
+ frag_align_pattern (n, fill, len, max);
}
- if (temp != 1)
- as_bad ("Alignment not a power of 2");
- temp = i;
- if (*input_line_pointer == ',')
+#ifdef md_do_align
+ just_record_alignment:
+#endif
+
+ record_alignment (now_seg, n);
+}
+
+/* Handle the .align pseudo-op. A positive ARG is a default alignment
+ (in bytes). A negative ARG is the negative of the length of the
+ fill pattern. BYTES_P is non-zero if the alignment value should be
+ interpreted as the byte boundary, rather than the power of 2. */
+
+static void
+s_align (arg, bytes_p)
+ int arg;
+ int bytes_p;
+{
+ register unsigned int align;
+ char *stop = NULL;
+ char stopc;
+ offsetT fill = 0;
+ int max;
+ int fill_p;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
+ if (arg < 0)
+ align = 0;
+ else
+ align = arg; /* Default value from pseudo-op table */
}
- else if (now_seg != data_section && now_seg != bss_section)
- temp_fill = NOP_OPCODE;
else
- temp_fill = 0;
- /* Only make a frag if we HAVE to. . . */
- if (temp && !need_pass_2)
- frag_align (temp, (int) temp_fill);
+ {
+ align = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+ }
- record_alignment (now_seg, temp);
+ if (bytes_p)
+ {
+ /* Convert to a power of 2. */
+ if (align != 0)
+ {
+ unsigned int i;
- demand_empty_rest_of_line ();
-} /* s_align_bytes() */
+ for (i = 0; (align & 1) == 0; align >>= 1, ++i)
+ ;
+ if (align != 1)
+ as_bad ("Alignment not a power of 2");
+ align = i;
+ }
+ }
-/* For machines where ".align 4" means align to 2**4 boundary. */
-void
-s_align_ptwo ()
-{
- register int temp;
- register long temp_fill;
- long max_alignment = 15;
+ if (align > 15)
+ {
+ align = 15;
+ as_bad ("Alignment too large: %u assumed", align);
+ }
- temp = get_absolute_expression ();
- if (temp > max_alignment)
- as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
- else if (temp < 0)
+ if (*input_line_pointer != ',')
{
- as_bad ("Alignment negative. 0 assumed.");
- temp = 0;
+ fill_p = 0;
+ max = 0;
}
- if (*input_line_pointer == ',')
+ else
{
- input_line_pointer++;
- temp_fill = get_absolute_expression ();
+ ++input_line_pointer;
+ if (*input_line_pointer == ',')
+ fill_p = 0;
+ else
+ {
+ fill = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+ fill_p = 1;
+ }
+
+ if (*input_line_pointer != ',')
+ max = 0;
+ else
+ {
+ ++input_line_pointer;
+ max = get_absolute_expression ();
+ }
+ }
+
+ if (! fill_p)
+ {
+ if (arg < 0)
+ as_warn ("expected fill pattern missing");
+ do_align (align, (char *) NULL, 0, max);
}
- /* @@ Fix this right for BFD! */
- else if (now_seg != data_section && now_seg != bss_section)
- temp_fill = NOP_OPCODE;
else
- temp_fill = 0;
- /* Only make a frag if we HAVE to. . . */
- if (temp && !need_pass_2)
- frag_align (temp, (int) temp_fill);
+ {
+ int fill_len;
+
+ if (arg >= 0)
+ fill_len = 1;
+ else
+ fill_len = - arg;
+ if (fill_len <= 1)
+ {
+ char fill_char;
+
+ fill_char = fill;
+ do_align (align, &fill_char, fill_len, max);
+ }
+ else
+ {
+ char ab[16];
+
+ if (fill_len > sizeof ab)
+ abort ();
+ md_number_to_chars (ab, fill, fill_len);
+ do_align (align, ab, fill_len, max);
+ }
+ }
- record_alignment (now_seg, temp);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
-} /* s_align_ptwo() */
+}
+
+/* Handle the .align pseudo-op on machines where ".align 4" means
+ align to a 4 byte boundary. */
+
+void
+s_align_bytes (arg)
+ int arg;
+{
+ s_align (arg, 1);
+}
+
+/* Handle the .align pseud-op on machines where ".align 4" means align
+ to a 2**4 boundary. */
+
+void
+s_align_ptwo (arg)
+ int arg;
+{
+ s_align (arg, 0);
+}
void
-s_comm ()
+s_comm (ignore)
+ int ignore;
{
register char *name;
register char c;
register char *p;
- valueT temp;
+ offsetT temp;
register symbolS *symbolP;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
name = input_line_pointer;
c = get_symbol_end ();
if (*input_line_pointer != ',')
{
as_bad ("Expected comma after symbol-name: rest of line ignored.");
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
input_line_pointer++; /* skip ',' */
if ((temp = get_absolute_expression ()) < 0)
{
- as_warn (".COMMon length (%d.) <0! Ignored.", temp);
+ as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
*p = c;
if (S_IS_DEFINED (symbolP))
{
- as_bad ("Ignoring attempt to re-define symbol");
+ as_bad ("Ignoring attempt to re-define symbol `%s'.",
+ S_GET_NAME (symbolP));
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
if (S_GET_VALUE (symbolP))
{
- if (S_GET_VALUE (symbolP) != temp)
- as_bad ("Length of .comm \"%s\" is already %d. Not changed to %d.",
+ if (S_GET_VALUE (symbolP) != (valueT) temp)
+ as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.",
S_GET_NAME (symbolP),
- S_GET_VALUE (symbolP),
- temp);
+ (long) S_GET_VALUE (symbolP),
+ (long) temp);
}
else
{
- S_SET_VALUE (symbolP, temp);
+ S_SET_VALUE (symbolP, (valueT) temp);
S_SET_EXTERNAL (symbolP);
}
#ifdef OBJ_VMS
- if ( (!temp) || !flagseen['1'])
- S_GET_OTHER(symbolP) = const_flag;
+ {
+ extern int flag_one;
+ if ( (!temp) || !flag_one)
+ S_GET_OTHER(symbolP) = const_flag;
+ }
#endif /* not OBJ_VMS */
know (symbolP->sy_frag == &zero_address_frag);
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
demand_empty_rest_of_line ();
} /* s_comm() */
+/* The MRI COMMON pseudo-op. We handle this by creating a common
+ symbol with the appropriate name. We make s_space do the right
+ thing by increasing the size. */
+
void
-s_data ()
+s_mri_common (small)
+ int small;
{
- register int temp;
+ char *name;
+ char c;
+ char *alc = NULL;
+ symbolS *sym;
+ offsetT align;
+ char *stop = NULL;
+ char stopc;
+
+ if (! flag_mri)
+ {
+ s_comm (0);
+ return;
+ }
- temp = get_absolute_expression ();
-#ifdef BFD_ASSEMBLER
- subseg_set (data_section, (subsegT) temp);
-#else
- subseg_new (data_section, (subsegT) temp);
+ stop = mri_comment_field (&stopc);
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ if (! isdigit ((unsigned char) *name))
+ c = get_symbol_end ();
+ else
+ {
+ do
+ {
+ ++input_line_pointer;
+ }
+ while (isdigit ((unsigned char) *input_line_pointer));
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (line_label != NULL)
+ {
+ alc = (char *) xmalloc (strlen (S_GET_NAME (line_label))
+ + (input_line_pointer - name)
+ + 1);
+ sprintf (alc, "%s%s", name, S_GET_NAME (line_label));
+ name = alc;
+ }
+ }
+
+ sym = symbol_find_or_make (name);
+ *input_line_pointer = c;
+ if (alc != NULL)
+ free (alc);
+
+ if (*input_line_pointer != ',')
+ align = 0;
+ else
+ {
+ ++input_line_pointer;
+ align = get_absolute_expression ();
+ }
+
+ if (S_IS_DEFINED (sym))
+ {
+#if defined (S_IS_COMMON) || defined (BFD_ASSEMBLER)
+ if (! S_IS_COMMON (sym))
+#endif
+ {
+ as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym));
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+
+ S_SET_EXTERNAL (sym);
+ mri_common_symbol = sym;
+
+#ifdef S_SET_ALIGN
+ if (align != 0)
+ S_SET_ALIGN (sym, align);
#endif
+ if (line_label != NULL)
+ {
+ line_label->sy_value.X_op = O_symbol;
+ line_label->sy_value.X_add_symbol = sym;
+ line_label->sy_value.X_add_number = S_GET_VALUE (sym);
+ line_label->sy_frag = &zero_address_frag;
+ S_SET_SEGMENT (line_label, expr_section);
+ }
+
+ /* FIXME: We just ignore the small argument, which distinguishes
+ COMMON and COMMON.S. I don't know what we can do about it. */
+
+ /* Ignore the type and hptype. */
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+void
+s_data (ignore)
+ int ignore;
+{
+ segT section;
+ register int temp;
+
+ temp = get_absolute_expression ();
+ if (flag_readonly_data_in_text)
+ {
+ section = text_section;
+ temp += 1000;
+ }
+ else
+ section = data_section;
+
+ subseg_set (section, (subsegT) temp);
+
#ifdef OBJ_VMS
const_flag = 0;
#endif
}
/* Handle the .appfile pseudo-op. This is automatically generated by
- do_scrub_next_char when a preprocessor # line comment is seen with
- a file name. This default definition may be overridden by the
- object or CPU specific pseudo-ops. This function is also the
- default definition for .file; the APPFILE argument is 1 for
- .appfile, 0 for .file. */
+ do_scrub_chars when a preprocessor # line comment is seen with a
+ file name. This default definition may be overridden by the object
+ or CPU specific pseudo-ops. This function is also the default
+ definition for .file; the APPFILE argument is 1 for .appfile, 0 for
+ .file. */
void
s_app_file (appfile)
the buffer. Passing -2 to new_logical_line tells it to
account for it. */
new_logical_line (s, appfile ? -2 : -1);
+
+ /* In MRI mode, the preprocessor may have inserted an extraneous
+ backquote. */
+ if (flag_m68k_mri
+ && *input_line_pointer == '\''
+ && is_end_of_line[(unsigned char) input_line_pointer[1]])
+ ++input_line_pointer;
+
demand_empty_rest_of_line ();
#ifdef LISTING
if (listing)
listing_source_file (s);
#endif
}
-#ifdef OBJ_COFF
- c_dot_file_symbol (s);
-#endif /* OBJ_COFF */
-#ifdef OBJ_ELF
- elf_file_symbol (s);
+#ifdef obj_app_file
+ obj_app_file (s);
#endif
}
/* Handle the .appline pseudo-op. This is automatically generated by
- do_scrub_next_char when a preprocessor # line comment is seen.
- This default definition may be overridden by the object or CPU
- specific pseudo-ops. */
+ do_scrub_chars when a preprocessor # line comment is seen. This
+ default definition may be overridden by the object or CPU specific
+ pseudo-ops. */
void
-s_app_line ()
+s_app_line (ignore)
+ int ignore;
{
int l;
/* The given number is that of the next line. */
l = get_absolute_expression () - 1;
- new_logical_line ((char *) NULL, l);
+ if (l < 0)
+ /* Some of the back ends can't deal with non-positive line numbers.
+ Besides, it's silly. */
+ as_warn ("Line numbers must be positive; line number %d rejected.", l+1);
+ else
+ {
+ new_logical_line ((char *) NULL, l);
#ifdef LISTING
- if (listing)
- listing_source_line (l);
+ if (listing)
+ listing_source_line (l);
#endif
+ }
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .end pseudo-op. Actually, the real work is done in
+ read_a_source_file. */
+
+void
+s_end (ignore)
+ int ignore;
+{
+ if (flag_mri)
+ {
+ /* The MRI assembler permits the start symbol to follow .end,
+ but we don't support that. */
+ SKIP_WHITESPACE ();
+ if (! is_end_of_line[(unsigned char) *input_line_pointer]
+ && *input_line_pointer != '*'
+ && *input_line_pointer != '!')
+ as_warn ("start address not supported");
+ }
+}
+
+/* Handle the .err pseudo-op. */
+
+void
+s_err (ignore)
+ int ignore;
+{
+ as_bad (".err encountered");
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI fail pseudo-op. */
+
+void
+s_fail (ignore)
+ int ignore;
+{
+ offsetT temp;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ temp = get_absolute_expression ();
+ if (temp >= 500)
+ as_warn (".fail %ld encountered", (long) temp);
+ else
+ as_bad (".fail %ld encountered", (long) temp);
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
demand_empty_rest_of_line ();
}
void
-s_fill ()
+s_fill (ignore)
+ int ignore;
{
long temp_repeat = 0;
long temp_size = 1;
register long temp_fill = 0;
char *p;
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
temp_repeat = get_absolute_expression ();
if (*input_line_pointer == ',')
}
else if (temp_repeat <= 0)
{
- as_warn ("Repeat < 0, .fill ignored");
+ if (temp_repeat < 0)
+ as_warn ("Repeat < 0, .fill ignored");
temp_size = 0;
}
if (temp_size && !need_pass_2)
{
p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0);
- memset (p, 0, (int) temp_size);
+ memset (p, 0, (unsigned int) temp_size);
/* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX
* flavoured AS. The following bizzare behaviour is to be
* compatible with above. I guess they tried to take up to 8
* bytes from a 4-byte expression and they forgot to sign
* extend. Un*x Sux. */
#define BSD_FILL_SIZE_CROCK_4 (4)
- md_number_to_chars (p, temp_fill,
+ md_number_to_chars (p, (valueT) temp_fill,
(temp_size > BSD_FILL_SIZE_CROCK_4
? BSD_FILL_SIZE_CROCK_4
: (int) temp_size));
}
void
-s_globl ()
+s_globl (ignore)
+ int ignore;
{
char *name;
int c;
symbolS *symbolP;
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
do
{
}
}
while (c == ',');
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI IRP and IRPC pseudo-ops. */
+
+void
+s_irp (irpc)
+ int irpc;
+{
+ char *file;
+ unsigned int line;
+ sb s;
+ const char *err;
+ sb out;
+
+ as_where (&file, &line);
+
+ sb_new (&s);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ sb_add_char (&s, *input_line_pointer++);
+
+ sb_new (&out);
+
+ err = expand_irp (irpc, 0, &s, &out, get_line_sb, '\0');
+ if (err != NULL)
+ as_bad_where (file, line, "%s", err);
+
+ sb_kill (&s);
+
+ input_scrub_include_sb (&out, input_line_pointer);
+ sb_kill (&out);
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
+
+/* Handle the .linkonce pseudo-op. This tells the assembler to mark
+ the section to only be linked once. However, this is not supported
+ by most object file formats. This takes an optional argument,
+ which is what to do about duplicates. */
+
+void
+s_linkonce (ignore)
+ int ignore;
+{
+ enum linkonce_type type;
+
+ SKIP_WHITESPACE ();
+
+ type = LINKONCE_DISCARD;
+
+ if (! is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ char *s;
+ char c;
+
+ s = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcasecmp (s, "discard") == 0)
+ type = LINKONCE_DISCARD;
+ else if (strcasecmp (s, "one_only") == 0)
+ type = LINKONCE_ONE_ONLY;
+ else if (strcasecmp (s, "same_size") == 0)
+ type = LINKONCE_SAME_SIZE;
+ else if (strcasecmp (s, "same_contents") == 0)
+ type = LINKONCE_SAME_CONTENTS;
+ else
+ as_warn ("unrecognized .linkonce type `%s'", s);
+
+ *input_line_pointer = c;
+ }
+
+#ifdef obj_handle_link_once
+ obj_handle_link_once (type);
+#else /* ! defined (obj_handle_link_once) */
+#ifdef BFD_ASSEMBLER
+ {
+ flagword flags;
+
+ if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0)
+ as_warn (".linkonce is not supported for this object file format");
+
+ flags = bfd_get_section_flags (stdoutput, now_seg);
+ flags |= SEC_LINK_ONCE;
+ switch (type)
+ {
+ default:
+ abort ();
+ case LINKONCE_DISCARD:
+ flags |= SEC_LINK_DUPLICATES_DISCARD;
+ break;
+ case LINKONCE_ONE_ONLY:
+ flags |= SEC_LINK_DUPLICATES_ONE_ONLY;
+ break;
+ case LINKONCE_SAME_SIZE:
+ flags |= SEC_LINK_DUPLICATES_SAME_SIZE;
+ break;
+ case LINKONCE_SAME_CONTENTS:
+ flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS;
+ break;
+ }
+ if (! bfd_set_section_flags (stdoutput, now_seg, flags))
+ as_bad ("bfd_set_section_flags: %s",
+ bfd_errmsg (bfd_get_error ()));
+ }
+#else /* ! defined (BFD_ASSEMBLER) */
+ as_warn (".linkonce is not supported for this object file format");
+#endif /* ! defined (BFD_ASSEMBLER) */
+#endif /* ! defined (obj_handle_link_once) */
+
demand_empty_rest_of_line ();
}
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
- if (*input_line_pointer != ',')
+
+ /* Accept an optional comma after the name. The comma used to be
+ required, but Irix 5 cc does not generate it. */
+ if (*input_line_pointer == ',')
{
- as_bad ("Expected comma after name");
- ignore_rest_of_line ();
- return;
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
}
- ++input_line_pointer;
-
if (*input_line_pointer == '\n')
{
as_bad ("Missing size expression");
return;
}
-#ifdef TC_MIPS
-#ifdef OBJ_ECOFF
- /* For MIPS ECOFF, small objects are put in .sbss. */
- if (temp <= bfd_get_gp_size (stdoutput))
- bss_seg = subseg_new (".sbss", 1);
+#if defined (TC_MIPS) || defined (TC_ALPHA)
+ if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+ || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ {
+ /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss. */
+ if (temp <= bfd_get_gp_size (stdoutput))
+ {
+ bss_seg = subseg_new (".sbss", 1);
+ seg_info (bss_seg)->bss = 1;
+#ifdef BFD_ASSEMBLER
+ if (! bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
+ as_warn ("error setting flags for \".sbss\": %s",
+ bfd_errmsg (bfd_get_error ()));
+#endif
+ }
+ }
#endif
+ if (!needs_align)
+ {
+ /* FIXME. This needs to be machine independent. */
+ if (temp >= 8)
+ align = 3;
+ else if (temp >= 4)
+ align = 2;
+ else if (temp >= 2)
+ align = 1;
+ else
+ align = 0;
+
+#ifdef OBJ_EVAX
+ /* FIXME: This needs to be done in a more general fashion. */
+ align = 3;
#endif
+ record_alignment(bss_seg, align);
+ }
+
if (needs_align)
{
align = 0;
}
record_alignment (bss_seg, align);
} /* if needs align */
+ else
+ {
+ /* Assume some objects may require alignment on some systems. */
+#if defined (TC_ALPHA) && ! defined (VMS)
+ if (temp > 1)
+ {
+ align = ffs (temp) - 1;
+ if (temp % (1 << align))
+ abort ();
+ }
+#endif
+ }
*p = 0;
symbolP = symbol_find_or_make (name);
(S_GET_SEGMENT (symbolP) == bss_seg
|| (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0)))
{
- char *p;
+ char *pfrag;
-#ifdef BFD_ASSEMBLER
subseg_set (bss_seg, 1);
-#else
- subseg_new (bss_seg, 1);
-#endif
if (align)
- frag_align (align, 0);
+ frag_align (align, 0, 0);
/* detach from old frag */
if (S_GET_SEGMENT (symbolP) == bss_seg)
symbolP->sy_frag->fr_symbol = NULL;
symbolP->sy_frag = frag_now;
- p = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
- temp, (char *)0);
- *p = 0;
+ pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
+ temp, (char *)0);
+ *pfrag = 0;
S_SET_SEGMENT (symbolP, bss_seg);
S_SET_STORAGE_CLASS (symbolP, C_STAT);
}
#endif /* OBJ_COFF */
+
+#ifdef S_SET_SIZE
+ S_SET_SIZE (symbolP, temp);
+#endif
}
else
- {
- as_bad ("Ignoring attempt to re-define symbol %s.", name);
- }
+ as_bad ("Ignoring attempt to re-define symbol `%s'.",
+ S_GET_NAME (symbolP));
-#ifdef BFD_ASSEMBLER
subseg_set (current_seg, current_subseg);
-#else
- subseg_new (current_seg, current_subseg);
-#endif
demand_empty_rest_of_line ();
} /* s_lcomm() */
-void
-s_long ()
-{
- cons (4);
-}
-
-void
-s_int ()
-{
- cons (4);
-}
-
void
-s_lsym ()
+s_lsym (ignore)
+ int ignore;
{
register char *name;
register char c;
register char *p;
- register segT segment;
expressionS exp;
register symbolS *symbolP;
return;
}
input_line_pointer++;
- segment = expression (&exp);
- if (segment != absolute_section
- && segment != reg_section
- && ! SEG_NORMAL (segment))
+ expression (&exp);
+ if (exp.X_op != O_constant
+ && exp.X_op != O_register)
{
- as_bad ("Bad expression: %s", segment_name (segment));
+ as_bad ("bad expression");
ignore_rest_of_line ();
return;
}
{
/* The name might be an undefined .global symbol; be sure to
keep the "external" bit. */
- S_SET_SEGMENT (symbolP, segment);
- S_SET_VALUE (symbolP, (valueT) (exp.X_add_number));
+ S_SET_SEGMENT (symbolP,
+ (exp.X_op == O_constant
+ ? absolute_section
+ : reg_section));
+ S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
}
else
{
demand_empty_rest_of_line ();
} /* s_lsym() */
+/* Read a line into an sb. */
+
+static int
+get_line_sb (line)
+ sb *line;
+{
+ char quote1, quote2, inquote;
+
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+
+ if (input_line_pointer >= buffer_limit)
+ {
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+ if (buffer_limit == 0)
+ return 0;
+ }
+
+ /* If app.c sets any other characters to LEX_IS_STRINGQUOTE, this
+ code needs to be changed. */
+ if (! flag_m68k_mri)
+ quote1 = '"';
+ else
+ quote1 = '\0';
+
+ quote2 = '\0';
+ if (flag_m68k_mri)
+ quote2 = '\'';
+#ifdef LEX_IS_STRINGQUOTE
+ quote2 = '\'';
+#endif
+
+ inquote = '\0';
+ while (! is_end_of_line[(unsigned char) *input_line_pointer]
+ || (inquote != '\0' && *input_line_pointer != '\n'))
+ {
+ if (inquote == *input_line_pointer)
+ inquote = '\0';
+ else if (inquote == '\0')
+ {
+ if (*input_line_pointer == quote1)
+ inquote = quote1;
+ else if (*input_line_pointer == quote2)
+ inquote = quote2;
+ }
+ sb_add_char (line, *input_line_pointer++);
+ }
+ while (input_line_pointer < buffer_limit && *input_line_pointer == '\n')
+ {
+ if (input_line_pointer[-1] == '\n')
+ bump_line_counters ();
+ ++input_line_pointer;
+ }
+ return 1;
+}
+
+/* Define a macro. This is an interface to macro.c, which is shared
+ between gas and gasp. */
+
+void
+s_macro (ignore)
+ int ignore;
+{
+ char *file;
+ unsigned int line;
+ sb s;
+ sb label;
+ const char *err;
+ const char *name;
+
+ as_where (&file, &line);
+
+ sb_new (&s);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ sb_add_char (&s, *input_line_pointer++);
+
+ sb_new (&label);
+ if (line_label != NULL)
+ sb_add_string (&label, S_GET_NAME (line_label));
+
+ err = define_macro (0, &s, &label, get_line_sb, &name);
+ if (err != NULL)
+ as_bad_where (file, line, "%s", err);
+ else
+ {
+ if (line_label != NULL)
+ {
+ S_SET_SEGMENT (line_label, undefined_section);
+ S_SET_VALUE (line_label, 0);
+ line_label->sy_frag = &zero_address_frag;
+ }
+
+ if (((flag_m68k_mri
+#ifdef NO_PSEUDO_DOT
+ || 1
+#endif
+ )
+ && hash_find (po_hash, name) != NULL)
+ || (! flag_m68k_mri
+ && *name == '.'
+ && hash_find (po_hash, name + 1) != NULL))
+ as_warn ("attempt to redefine pseudo-op `%s' ignored",
+ name);
+ }
+
+ sb_kill (&s);
+}
+
+/* Handle the .mexit pseudo-op, which immediately exits a macro
+ expansion. */
+
+void
+s_mexit (ignore)
+ int ignore;
+{
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
+
+/* Switch in and out of MRI mode. */
+
+void
+s_mri (ignore)
+ int ignore;
+{
+ int on, old_flag;
+
+ on = get_absolute_expression ();
+ old_flag = flag_mri;
+ if (on != 0)
+ {
+ flag_mri = 1;
+#ifdef TC_M68K
+ flag_m68k_mri = 1;
+#endif
+ }
+ else
+ {
+ flag_mri = 0;
+ flag_m68k_mri = 0;
+ }
+
+#ifdef MRI_MODE_CHANGE
+ if (on != old_flag)
+ MRI_MODE_CHANGE (on);
+#endif
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle changing the location counter. */
+
+static void
+do_org (segment, exp, fill)
+ segT segment;
+ expressionS *exp;
+ int fill;
+{
+ if (segment != now_seg && segment != absolute_section)
+ as_bad ("invalid segment \"%s\"; segment \"%s\" assumed",
+ segment_name (segment), segment_name (now_seg));
+
+ if (now_seg == absolute_section)
+ {
+ if (fill != 0)
+ as_warn ("ignoring fill value in absolute section");
+ if (exp->X_op != O_constant)
+ {
+ as_bad ("only constant offsets supported in absolute section");
+ exp->X_add_number = 0;
+ }
+ abs_section_offset = exp->X_add_number;
+ }
+ else
+ {
+ char *p;
+
+ p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp->X_add_symbol,
+ exp->X_add_number, (char *) NULL);
+ *p = fill;
+ }
+}
+
void
-s_org ()
+s_org (ignore)
+ int ignore;
{
register segT segment;
expressionS exp;
register long temp_fill;
- register char *p;
+
+ /* The m68k MRI assembler has a different meaning for .org. It
+ means to create an absolute section at a given address. We can't
+ support that--use a linker script instead. */
+ if (flag_m68k_mri)
+ {
+ as_bad ("MRI style ORG pseudo-op not supported");
+ ignore_rest_of_line ();
+ return;
+ }
+
/* Don't believe the documentation of BSD 4.2 AS. There is no such
thing as a sub-segment-relative origin. Any absolute origin is
given a warning, then assumed to be segment-relative. Any
}
else
temp_fill = 0;
+
if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment), segment_name (now_seg));
- p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *p = temp_fill;
- } /* if (ok to make frag) */
+ do_org (segment, &exp, temp_fill);
+
demand_empty_rest_of_line ();
} /* s_org() */
-void
-s_set ()
+/* Handle parsing for the MRI SECT/SECTION pseudo-op. This should be
+ called by the obj-format routine which handles section changing
+ when in MRI mode. It will create a new section, and return it. It
+ will set *TYPE to the section type: one of 'C' (code), 'D' (data),
+ 'M' (mixed), or 'R' (romable). If BFD_ASSEMBLER is defined, the
+ flags will be set in the section. */
+
+void
+s_mri_sect (type)
+ char *type;
+{
+#ifdef TC_M68K
+
+ char *name;
+ char c;
+ segT seg;
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ if (! isdigit ((unsigned char) *name))
+ c = get_symbol_end ();
+ else
+ {
+ do
+ {
+ ++input_line_pointer;
+ }
+ while (isdigit ((unsigned char) *input_line_pointer));
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+ }
+
+ name = xstrdup (name);
+
+ *input_line_pointer = c;
+
+ seg = subseg_new (name, 0);
+
+ if (*input_line_pointer == ',')
+ {
+ int align;
+
+ ++input_line_pointer;
+ align = get_absolute_expression ();
+ record_alignment (seg, align);
+ }
+
+ *type = 'C';
+ if (*input_line_pointer == ',')
+ {
+ c = *++input_line_pointer;
+ c = toupper ((unsigned char) c);
+ if (c == 'C' || c == 'D' || c == 'M' || c == 'R')
+ *type = c;
+ else
+ as_bad ("unrecognized section type");
+ ++input_line_pointer;
+
+#ifdef BFD_ASSEMBLER
+ {
+ flagword flags;
+
+ flags = SEC_NO_FLAGS;
+ if (*type == 'C')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE;
+ else if (*type == 'D' || *type == 'M')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_DATA;
+ else if (*type == 'R')
+ flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM;
+ if (flags != SEC_NO_FLAGS)
+ {
+ if (! bfd_set_section_flags (stdoutput, seg, flags))
+ as_warn ("error setting flags for \"%s\": %s",
+ bfd_section_name (stdoutput, seg),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ }
+#endif
+ }
+
+ /* Ignore the HP type. */
+ if (*input_line_pointer == ',')
+ input_line_pointer += 2;
+
+ demand_empty_rest_of_line ();
+
+#else /* ! TC_M68K */
+#ifdef TC_I960
+
+ char *name;
+ char c;
+ segT seg;
+
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+
+ name = xstrdup (name);
+
+ *input_line_pointer = c;
+
+ seg = subseg_new (name, 0);
+
+ if (*input_line_pointer != ',')
+ *type = 'C';
+ else
+ {
+ char *sectype;
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ sectype = input_line_pointer;
+ c = get_symbol_end ();
+ if (*sectype == '\0')
+ *type = 'C';
+ else if (strcasecmp (sectype, "text") == 0)
+ *type = 'C';
+ else if (strcasecmp (sectype, "data") == 0)
+ *type = 'D';
+ else if (strcasecmp (sectype, "romdata") == 0)
+ *type = 'R';
+ else
+ as_warn ("unrecognized section type `%s'", sectype);
+ *input_line_pointer = c;
+ }
+
+ if (*input_line_pointer == ',')
+ {
+ char *seccmd;
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ seccmd = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcasecmp (seccmd, "absolute") == 0)
+ {
+ as_bad ("absolute sections are not supported");
+ *input_line_pointer = c;
+ ignore_rest_of_line ();
+ return;
+ }
+ else if (strcasecmp (seccmd, "align") == 0)
+ {
+ int align;
+
+ *input_line_pointer = c;
+ align = get_absolute_expression ();
+ record_alignment (seg, align);
+ }
+ else
+ {
+ as_warn ("unrecognized section command `%s'", seccmd);
+ *input_line_pointer = c;
+ }
+ }
+
+ demand_empty_rest_of_line ();
+
+#else /* ! TC_I960 */
+ /* The MRI assembler seems to use different forms of .sect for
+ different targets. */
+ abort ();
+#endif /* ! TC_I960 */
+#endif /* ! TC_M68K */
+}
+
+/* Handle the .print pseudo-op. */
+
+void
+s_print (ignore)
+ int ignore;
+{
+ char *s;
+ int len;
+
+ s = demand_copy_C_string (&len);
+ printf ("%s\n", s);
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .purgem pseudo-op. */
+
+void
+s_purgem (ignore)
+ int ignore;
+{
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ do
+ {
+ char *name;
+ char c;
+
+ SKIP_WHITESPACE ();
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ delete_macro (name);
+ *input_line_pointer = c;
+ SKIP_WHITESPACE ();
+ }
+ while (*input_line_pointer++ == ',');
+
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .rept pseudo-op. */
+
+void
+s_rept (ignore)
+ int ignore;
+{
+ int count;
+ sb one;
+ sb many;
+
+ count = get_absolute_expression ();
+
+ sb_new (&one);
+ if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb))
+ {
+ as_bad ("rept without endr");
+ return;
+ }
+
+ sb_new (&many);
+ while (count-- > 0)
+ sb_add_sb (&many, &one);
+
+ sb_kill (&one);
+
+ input_scrub_include_sb (&many, input_line_pointer);
+ sb_kill (&many);
+ buffer_limit = input_scrub_next_buffer (&input_line_pointer);
+}
+
+void
+s_set (ignore)
+ int ignore;
{
register char *name;
register char delim;
/* Turn '. = mumble' into a .org mumble */
register segT segment;
expressionS exp;
- register char *ptr;
segment = get_known_segmented_expression (&exp);
if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment),
- segment_name (now_seg));
- ptr = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *ptr = 0;
- } /* if (ok to make frag) */
+ do_org (segment, &exp, 0);
*end_name = delim;
return;
s_space (mult)
int mult;
{
- long temp_repeat;
- register long temp_fill;
- register char *p;
+ expressionS exp;
+ expressionS val;
+ char *p = 0;
+ char *stop = NULL;
+ char stopc;
+ int bytes;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
- /* Just like .fill, but temp_size = 1 */
- if (get_absolute_expression_and_terminator (&temp_repeat) == ',')
+ /* In m68k MRI mode, we need to align to a word boundary, unless
+ this is ds.b. */
+ if (flag_m68k_mri && mult > 1)
{
- temp_fill = get_absolute_expression ();
+ if (now_seg == absolute_section)
+ {
+ abs_section_offset += abs_section_offset & 1;
+ if (line_label != NULL)
+ S_SET_VALUE (line_label, abs_section_offset);
+ }
+ else if (mri_common_symbol != NULL)
+ {
+ valueT val;
+
+ val = S_GET_VALUE (mri_common_symbol);
+ if ((val & 1) != 0)
+ {
+ S_SET_VALUE (mri_common_symbol, val + 1);
+ if (line_label != NULL)
+ {
+ know (line_label->sy_value.X_op == O_symbol);
+ know (line_label->sy_value.X_add_symbol == mri_common_symbol);
+ line_label->sy_value.X_add_number += 1;
+ }
+ }
+ }
+ else
+ {
+ do_align (1, (char *) NULL, 0, 0);
+ if (line_label != NULL)
+ {
+ line_label->sy_frag = frag_now;
+ S_SET_VALUE (line_label, frag_now_fix ());
+ }
+ }
+ }
+
+ bytes = mult;
+
+ expression (&exp);
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ expression (&val);
}
else
{
- input_line_pointer--; /* Backup over what was not a ','. */
- temp_fill = 0;
+ val.X_op = O_constant;
+ val.X_add_number = 0;
}
- if (mult)
+
+ if (val.X_op != O_constant
+ || val.X_add_number < - 0x80
+ || val.X_add_number > 0xff
+ || (mult != 0 && mult != 1 && val.X_add_number != 0))
{
- temp_repeat *= mult;
+ if (exp.X_op != O_constant)
+ as_bad ("Unsupported variable size or fill value");
+ else
+ {
+ offsetT i;
+
+ if (mult == 0)
+ mult = 1;
+ bytes = mult * exp.X_add_number;
+ for (i = 0; i < exp.X_add_number; i++)
+ emit_expr (&val, mult);
+ }
}
- if (temp_repeat <= 0)
+ else
{
- as_warn ("Repeat < 0, .space ignored");
+ if (exp.X_op == O_constant)
+ {
+ long repeat;
+
+ repeat = exp.X_add_number;
+ if (mult)
+ repeat *= mult;
+ bytes = repeat;
+ if (repeat <= 0)
+ {
+ if (! flag_mri || repeat < 0)
+ as_warn (".space repeat count is %s, ignored",
+ repeat ? "negative" : "zero");
+ goto getout;
+ }
+
+ /* If we are in the absolute section, just bump the offset. */
+ if (now_seg == absolute_section)
+ {
+ abs_section_offset += repeat;
+ goto getout;
+ }
+
+ /* If we are secretly in an MRI common section, then
+ creating space just increases the size of the common
+ symbol. */
+ if (mri_common_symbol != NULL)
+ {
+ S_SET_VALUE (mri_common_symbol,
+ S_GET_VALUE (mri_common_symbol) + repeat);
+ goto getout;
+ }
+
+ if (!need_pass_2)
+ p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
+ repeat, (char *) 0);
+ }
+ else
+ {
+ if (now_seg == absolute_section)
+ {
+ as_bad ("space allocation too complex in absolute section");
+ subseg_set (text_section, 0);
+ }
+ if (mri_common_symbol != NULL)
+ {
+ as_bad ("space allocation too complex in common section");
+ mri_common_symbol = NULL;
+ }
+ if (!need_pass_2)
+ p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
+ make_expr_symbol (&exp), 0L, (char *) 0);
+ }
+
+ if (p)
+ *p = val.X_add_number;
+ }
+
+ getout:
+
+ /* In MRI mode, after an odd number of bytes, we must align to an
+ even word boundary, unless the next instruction is a dc.b, ds.b
+ or dcb.b. */
+ if (flag_mri && (bytes & 1) != 0)
+ mri_pending_align = 1;
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* This is like s_space, but the value is a floating point number with
+ the given precision. This is for the MRI dcb.s pseudo-op and
+ friends. */
+
+void
+s_float_space (float_type)
+ int float_type;
+{
+ offsetT count;
+ int flen;
+ char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ count = get_absolute_expression ();
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer != ',')
+ {
+ as_bad ("missing value");
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
ignore_rest_of_line ();
return;
}
- if (!need_pass_2)
+
+ ++input_line_pointer;
+
+ SKIP_WHITESPACE ();
+
+ /* Skip any 0{letter} that may be present. Don't even check if the
+ * letter is legal. */
+ if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
+ input_line_pointer += 2;
+
+ /* Accept :xxxx, where the x's are hex digits, for a floating point
+ with the exact digits specified. */
+ if (input_line_pointer[0] == ':')
+ {
+ flen = hex_float (float_type, temp);
+ if (flen < 0)
+ {
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+ else
+ {
+ char *err;
+
+ err = md_atof (float_type, temp, &flen);
+ know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
+ know (flen > 0);
+ if (err)
+ {
+ as_bad ("Bad floating literal: %s", err);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+
+ while (--count >= 0)
{
- p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
- temp_repeat, (char *) 0);
- *p = temp_fill;
+ char *p;
+
+ p = frag_more (flen);
+ memcpy (p, temp, (unsigned int) flen);
}
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .struct pseudo-op, as found in MIPS assemblers. */
+
+void
+s_struct (ignore)
+ int ignore;
+{
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+ abs_section_offset = get_absolute_expression ();
+ subseg_set (absolute_section, 0);
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
-} /* s_space() */
+}
void
-s_text ()
+s_text (ignore)
+ int ignore;
{
register int temp;
temp = get_absolute_expression ();
-#ifdef BFD_ASSEMBLER
subseg_set (text_section, (subsegT) temp);
-#else
- subseg_new (text_section, (subsegT) temp);
-#endif
demand_empty_rest_of_line ();
+#ifdef OBJ_VMS
+ const_flag &= ~IN_DEFAULT_SECTION;
+#endif
} /* s_text() */
\f
demand_empty_rest_of_line ()
{
SKIP_WHITESPACE ();
- if (is_end_of_line[*input_line_pointer])
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
{
input_line_pointer++;
}
void
ignore_rest_of_line () /* For suspect lines: gives warning. */
{
- if (!is_end_of_line[*input_line_pointer])
+ if (!is_end_of_line[(unsigned char) *input_line_pointer])
{
if (isprint (*input_line_pointer))
as_bad ("Rest of line ignored. First ignored character is `%c'.",
as_bad ("Rest of line ignored. First ignored character valued 0x%x.",
*input_line_pointer);
while (input_line_pointer < buffer_limit
- && !is_end_of_line[*input_line_pointer])
+ && !is_end_of_line[(unsigned char) *input_line_pointer])
{
input_line_pointer++;
}
}
input_line_pointer++; /* Return pointing just after end-of-line. */
- know (is_end_of_line[input_line_pointer[-1]]);
+ know (is_end_of_line[(unsigned char) input_line_pointer[-1]]);
}
/*
* Out: Input_line_pointer->just after any whitespace after expression.
* Tried to set symbol to value of expression.
* Will change symbols type, value, and frag;
- * May set need_pass_2 == 1.
*/
void
pseudo_set (symbolP)
symbolS *symbolP;
{
expressionS exp;
- register segT segment;
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER)
int ext;
#endif /* OBJ_AOUT or OBJ_BOUT */
know (symbolP); /* NULL pointer is logic error. */
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
- /* @@ Fix this right for BFD. */
+#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER)
ext = S_IS_EXTERNAL (symbolP);
#endif /* OBJ_AOUT or OBJ_BOUT */
- if ((segment = expression (&exp)) == absent_section)
+ (void) expression (&exp);
+
+ if (exp.X_op == O_illegal)
+ as_bad ("illegal expression; zero assumed");
+ else if (exp.X_op == O_absent)
+ as_bad ("missing expression; zero assumed");
+ else if (exp.X_op == O_big)
+ as_bad ("%s number invalid; zero assumed",
+ exp.X_add_number > 0 ? "bignum" : "floating point");
+ else if (exp.X_op == O_subtract
+ && (S_GET_SEGMENT (exp.X_add_symbol)
+ == S_GET_SEGMENT (exp.X_op_symbol))
+ && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol))
+ && exp.X_add_symbol->sy_frag == exp.X_op_symbol->sy_frag)
{
- as_bad ("Missing expression: absolute 0 assumed");
- exp.X_seg = absolute_section;
- exp.X_add_number = 0;
+ exp.X_op = O_constant;
+ exp.X_add_number = (S_GET_VALUE (exp.X_add_symbol)
+ - S_GET_VALUE (exp.X_op_symbol));
}
- if (segment == reg_section)
+ switch (exp.X_op)
{
- S_SET_SEGMENT (symbolP, reg_section);
- S_SET_VALUE (symbolP, exp.X_add_number);
- symbolP->sy_frag = &zero_address_frag;
- }
- else if (segment == big_section)
- {
- as_bad ("%s number invalid. Absolute 0 assumed.",
- exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
- S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
- /* @@ Fix this right for BFD. */
- ext ? S_SET_EXTERNAL (symbolP) :
- S_CLEAR_EXTERNAL (symbolP);
-#endif /* OBJ_AOUT or OBJ_BOUT */
- S_SET_VALUE (symbolP, 0);
- symbolP->sy_frag = &zero_address_frag;
- }
- else if (segment == absent_section)
- {
- as_warn ("No expression: Using absolute 0");
+ case O_illegal:
+ case O_absent:
+ case O_big:
+ exp.X_add_number = 0;
+ /* Fall through. */
+ case O_constant:
S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
- /* @@ Fix this right for BFD. */
- ext ? S_SET_EXTERNAL (symbolP) :
- S_CLEAR_EXTERNAL (symbolP);
-#endif /* OBJ_AOUT or OBJ_BOUT */
- S_SET_VALUE (symbolP, 0);
- symbolP->sy_frag = &zero_address_frag;
- }
- else if (segment == diff_section)
- {
- if (exp.X_add_symbol && exp.X_subtract_symbol
- && (S_GET_SEGMENT (exp.X_add_symbol) ==
- S_GET_SEGMENT (exp.X_subtract_symbol)))
- {
- if (exp.X_add_symbol->sy_frag == exp.X_subtract_symbol->sy_frag)
- {
- exp.X_add_number += S_GET_VALUE (exp.X_add_symbol) -
- S_GET_VALUE (exp.X_subtract_symbol);
- goto abs;
- }
- symbolP->sy_value = exp;
- }
+#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER)
+ if (ext)
+ S_SET_EXTERNAL (symbolP);
else
- {
- as_bad ("Complex expression. Absolute segment assumed.");
- goto abs;
- }
- }
- else if (segment == absolute_section)
- {
- abs:
- S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
- /* @@ Fix this right for BFD. */
- ext ? S_SET_EXTERNAL (symbolP) :
S_CLEAR_EXTERNAL (symbolP);
#endif /* OBJ_AOUT or OBJ_BOUT */
- S_SET_VALUE (symbolP, exp.X_add_number);
+ S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
symbolP->sy_frag = &zero_address_frag;
- }
- else if (segment == pass1_section)
- {
- symbolP->sy_value.X_add_symbol = exp.X_add_symbol;
- symbolP->sy_value.X_subtract_symbol = NULL;
- symbolP->sy_value.X_add_number = 0;
- symbolP->sy_value.X_seg = undefined_section;
- as_bad ("Unknown expression");
- know (need_pass_2 == 1);
- }
- else if (segment == undefined_section)
- {
- symbolP->sy_value.X_add_symbol = exp.X_add_symbol;
- symbolP->sy_value.X_subtract_symbol = NULL;
- symbolP->sy_value.X_add_number = 0;
- symbolP->sy_value.X_seg = undefined_section;
- }
- else
- {
-#ifndef BFD_ASSEMBLER
-#ifndef MANY_SEGMENTS
- switch (segment)
- {
- case SEG_DATA:
- case SEG_TEXT:
- case SEG_BSS:
- break;
+ break;
- default:
- as_fatal ("failed sanity check.");
- } /* switch on segment */
-#endif
-#endif
- S_SET_SEGMENT (symbolP, segment);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
- /* @@ Fix this right for BFD! */
- if (ext)
- {
- S_SET_EXTERNAL (symbolP);
- }
+ case O_register:
+ S_SET_SEGMENT (symbolP, reg_section);
+ S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
+ symbolP->sy_frag = &zero_address_frag;
+ break;
+
+ case O_symbol:
+ if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section
+ || exp.X_add_number != 0)
+ symbolP->sy_value = exp;
else
{
- S_CLEAR_EXTERNAL (symbolP);
- } /* if external */
+ symbolS *s = exp.X_add_symbol;
+
+ S_SET_SEGMENT (symbolP, S_GET_SEGMENT (s));
+#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER)
+ if (ext)
+ S_SET_EXTERNAL (symbolP);
+ else
+ S_CLEAR_EXTERNAL (symbolP);
#endif /* OBJ_AOUT or OBJ_BOUT */
+ S_SET_VALUE (symbolP,
+ exp.X_add_number + S_GET_VALUE (s));
+ symbolP->sy_frag = s->sy_frag;
+ copy_symbol_attributes (symbolP, s);
+ }
+ break;
- S_SET_VALUE (symbolP, exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
- symbolP->sy_frag = exp.X_add_symbol->sy_frag;
+ default:
+ /* The value is some complex expression.
+ FIXME: Should we set the segment to anything? */
+ symbolP->sy_value = exp;
+ break;
}
}
\f
*
* CONStruct more frag of .bytes, or .words etc.
* Should need_pass_2 be 1 then emit no frag(s).
- * This understands EXPRESSIONS, as opposed to big_cons().
+ * This understands EXPRESSIONS.
*
* Bug (?)
*
are defined, which is the normal case, then only simple expressions
are permitted. */
+static void
+parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes));
+
#ifndef TC_PARSE_CONS_EXPRESSION
#ifdef BITFIELD_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
static void
parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes));
#endif
-#ifdef MRI
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_mri_cons (EXP)
-static void
-parse_mri_cons PARAMS ((expressionS *exp));
-#endif
#ifdef REPEAT_CONS_EXPRESSIONS
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
static void
/* worker to do .byte etc statements */
/* clobbers input_line_pointer, checks */
/* end-of-line. */
-void
-cons (nbytes)
- register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */
+static void
+cons_worker (nbytes, rva)
+ register int nbytes; /* 1=.byte, 2=.word, 4=.long */
+ int rva;
{
+ int c;
expressionS exp;
+ char *stop = NULL;
+ char stopc;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
if (is_it_end_of_statement ())
{
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
return;
}
+#ifdef md_cons_align
+ md_cons_align (nbytes);
+#endif
+
+ c = 0;
do
{
- TC_PARSE_CONS_EXPRESSION (&exp, nbytes);
- emit_expr (&exp, nbytes);
+ if (flag_m68k_mri)
+ parse_mri_cons (&exp, (unsigned int) nbytes);
+ else
+ TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
+
+ if (rva)
+ {
+ if (exp.X_op == O_symbol)
+ exp.X_op = O_symbol_rva;
+ else
+ as_fatal ("rva without symbol");
+ }
+ emit_expr (&exp, (unsigned int) nbytes);
+ ++c;
}
while (*input_line_pointer++ == ',');
+ /* In MRI mode, after an odd number of bytes, we must align to an
+ even word boundary, unless the next instruction is a dc.b, ds.b
+ or dcb.b. */
+ if (flag_mri && nbytes == 1 && (c & 1) != 0)
+ mri_pending_align = 1;
+
input_line_pointer--; /* Put terminator back into stream. */
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
demand_empty_rest_of_line ();
-} /* cons() */
+}
+
+
+void
+cons (size)
+ int size;
+{
+ cons_worker (size, 0);
+}
+
+void
+s_rva (size)
+ int size;
+{
+ cons_worker (size, 1);
+}
+
/* Put the contents of expression EXP into the object file using
NBYTES bytes. If need_pass_2 is 1, this does nothing. */
expressionS *exp;
unsigned int nbytes;
{
- segT segment;
+ operatorT op;
register char *p;
+ valueT extra_digit = 0;
/* Don't do anything if we are going to make another pass. */
if (need_pass_2)
return;
- segment = exp->X_seg;
+ op = exp->X_op;
- /* Don't call this if we are going to junk this pass anyway! */
- know (segment != pass1_section);
+ /* Allow `.word 0' in the absolute section. */
+ if (now_seg == absolute_section)
+ {
+ if (op != O_constant || exp->X_add_number != 0)
+ as_bad ("attempt to store value in absolute section");
+ abs_section_offset += nbytes;
+ return;
+ }
- if (segment == diff_section && exp->X_add_symbol == NULL)
+ /* Handle a negative bignum. */
+ if (op == O_uminus
+ && exp->X_add_number == 0
+ && exp->X_add_symbol->sy_value.X_op == O_big
+ && exp->X_add_symbol->sy_value.X_add_number > 0)
{
- as_bad ("Subtracting symbol \"%s\" (segment \"%s\") is too hard. Absolute segment assumed.",
- S_GET_NAME (exp->X_subtract_symbol),
- segment_name (S_GET_SEGMENT (exp->X_subtract_symbol)));
- segment = absolute_section;
- /* Leave exp->X_add_number alone. */
+ int i;
+ unsigned long carry;
+
+ exp = &exp->X_add_symbol->sy_value;
+
+ /* Negate the bignum: one's complement each digit and add 1. */
+ carry = 1;
+ for (i = 0; i < exp->X_add_number; i++)
+ {
+ unsigned long next;
+
+ next = (((~ (generic_bignum[i] & LITTLENUM_MASK))
+ & LITTLENUM_MASK)
+ + carry);
+ generic_bignum[i] = next & LITTLENUM_MASK;
+ carry = next >> LITTLENUM_NUMBER_OF_BITS;
+ }
+
+ /* We can ignore any carry out, because it will be handled by
+ extra_digit if it is needed. */
+
+ extra_digit = (valueT) -1;
+ op = O_big;
}
- else if (segment == absent_section)
+
+ if (op == O_absent || op == O_illegal)
{
- as_warn ("0 assumed for missing expression");
+ as_warn ("zero assumed for missing expression");
exp->X_add_number = 0;
- know (exp->X_add_symbol == NULL);
- segment = absolute_section;
+ op = O_constant;
}
- else if (segment == big_section)
+ else if (op == O_big && exp->X_add_number <= 0)
{
- as_bad ("%s number invalid. Absolute 0 assumed.",
- exp->X_add_number > 0 ? "Bignum" : "Floating-Point");
+ as_bad ("floating point number invalid; zero assumed");
exp->X_add_number = 0;
- segment = absolute_section;
+ op = O_constant;
+ }
+ else if (op == O_register)
+ {
+ as_warn ("register value used as expression");
+ op = O_constant;
}
- p = frag_more (nbytes);
+ p = frag_more ((int) nbytes);
#ifndef WORKING_DOT_WORD
/* If we have the difference of two symbols in a word, save it on
the broken_words list. See the code in write.c. */
- if (segment == diff_section && nbytes == 2)
+ if (op == O_subtract && nbytes == 2)
{
struct broken_word *x;
x->word_goes_here = p;
x->dispfrag = 0;
x->add = exp->X_add_symbol;
- x->sub = exp->X_subtract_symbol;
+ x->sub = exp->X_op_symbol;
x->addnum = exp->X_add_number;
x->added = 0;
new_broken_words++;
}
#endif
- if (segment == absolute_section)
+ /* If we have an integer, but the number of bytes is too large to
+ pass to md_number_to_chars, handle it as a bignum. */
+ if (op == O_constant && nbytes > sizeof (valueT))
+ {
+ valueT val;
+ int gencnt;
+
+ if (! exp->X_unsigned && exp->X_add_number < 0)
+ extra_digit = (valueT) -1;
+ val = (valueT) exp->X_add_number;
+ gencnt = 0;
+ do
+ {
+ generic_bignum[gencnt] = val & LITTLENUM_MASK;
+ val >>= LITTLENUM_NUMBER_OF_BITS;
+ ++gencnt;
+ }
+ while (val != 0);
+ op = exp->X_op = O_big;
+ exp->X_add_number = gencnt;
+ }
+
+ if (op == O_constant)
{
- register long get;
- register long use;
- register long mask;
- register long unmask;
+ register valueT get;
+ register valueT use;
+ register valueT mask;
+ valueT hibit;
+ register valueT unmask;
/* JF << of >= number of bits in the object is undefined. In
particular SPARC (Sun 4) has problems */
- if (nbytes >= sizeof (long))
- mask = 0;
+ if (nbytes >= sizeof (valueT))
+ {
+ mask = 0;
+ if (nbytes > sizeof (valueT))
+ hibit = 0;
+ else
+ hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+ }
else
- mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+ {
+ /* Don't store these bits. */
+ mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes);
+ hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1);
+ }
unmask = ~mask; /* Do store these bits. */
get = exp->X_add_number;
use = get & unmask;
- if ((get & mask) != 0 && (get & mask) != mask)
+ if ((get & mask) != 0
+ && ((get & mask) != mask
+ || (get & hibit) == 0))
{ /* Leading bits contain both 0s & 1s. */
- as_warn ("Value 0x%x truncated to 0x%x.", get, use);
+ as_warn ("Value 0x%lx truncated to 0x%lx.",
+ (unsigned long) get, (unsigned long) use);
+ }
+ /* put bytes in right order. */
+ md_number_to_chars (p, use, (int) nbytes);
+ }
+ else if (op == O_big)
+ {
+ int size;
+ LITTLENUM_TYPE *nums;
+
+ know (nbytes % CHARS_PER_LITTLENUM == 0);
+
+ size = exp->X_add_number * CHARS_PER_LITTLENUM;
+ if (nbytes < size)
+ {
+ as_warn ("Bignum truncated to %d bytes", nbytes);
+ size = nbytes;
+ }
+
+ if (target_big_endian)
+ {
+ while (nbytes > size)
+ {
+ md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM);
+ nbytes -= CHARS_PER_LITTLENUM;
+ p += CHARS_PER_LITTLENUM;
+ }
+
+ nums = generic_bignum + size / CHARS_PER_LITTLENUM;
+ while (size > 0)
+ {
+ --nums;
+ md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM);
+ size -= CHARS_PER_LITTLENUM;
+ p += CHARS_PER_LITTLENUM;
+ }
+ }
+ else
+ {
+ nums = generic_bignum;
+ while (size > 0)
+ {
+ md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM);
+ ++nums;
+ size -= CHARS_PER_LITTLENUM;
+ p += CHARS_PER_LITTLENUM;
+ nbytes -= CHARS_PER_LITTLENUM;
+ }
+
+ while (nbytes > 0)
+ {
+ md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM);
+ nbytes -= CHARS_PER_LITTLENUM;
+ p += CHARS_PER_LITTLENUM;
+ }
}
- md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
}
else
{
- md_number_to_chars (p, (long) 0, nbytes);
+ memset (p, 0, nbytes);
/* Now we need to generate a fixS to record the symbol value.
This is easy for BFD. For other targets it can be more
defined, and otherwise uses 0. */
#ifdef BFD_ASSEMBLER
- fix_new (frag_now, p - frag_now->fr_literal, nbytes,
- exp->X_add_symbol, exp->X_subtract_symbol,
- exp->X_add_number, 0,
- /* @@ Should look at CPU word size. */
- BFD_RELOC_32);
+#ifdef TC_CONS_FIX_NEW
+ TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
+#else
+ {
+ bfd_reloc_code_real_type r;
+
+ switch (nbytes)
+ {
+ case 1:
+ r = BFD_RELOC_8;
+ break;
+ case 2:
+ r = BFD_RELOC_16;
+ break;
+ case 4:
+ r = BFD_RELOC_32;
+ break;
+ case 8:
+ r = BFD_RELOC_64;
+ break;
+ default:
+ as_bad ("unsupported BFD relocation size %u", nbytes);
+ r = BFD_RELOC_32;
+ break;
+ }
+ fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp,
+ 0, r);
+ }
+#endif
#else
#ifdef TC_CONS_FIX_NEW
TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
#define TC_CONS_RELOC 0
#endif
#endif
- fix_new (frag_now, p - frag_now->fr_literal, nbytes,
- exp->X_add_symbol, exp->X_subtract_symbol,
- exp->X_add_number, 0, TC_CONS_RELOC);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0,
+ TC_CONS_RELOC);
#endif /* TC_CONS_FIX_NEW */
#endif /* BFD_ASSEMBLER */
}
{
unsigned int bits_available = BITS_PER_CHAR * nbytes;
char *hold = input_line_pointer;
- segT segment;
- segment = expression (exp);
+ (void) expression (exp);
if (*input_line_pointer == ':')
{ /* bitfields */
widths, positions, and masks which most
of our current object formats don't
support.
-
+
In the specific case where a symbol
*is* defined in this assembly, we
*could* build fixups and track it, but
you can use a previous .set or
.equ type symbol. xoxorich. */
- if (segment == absent_section)
+ if (exp->X_op == O_absent)
{
- as_warn ("Using a bit field width of zero.");
+ as_warn ("using a bit field width of zero");
exp->X_add_number = 0;
- segment = absolute_section;
+ exp->X_op = O_constant;
} /* implied zero width bitfield */
- if (segment != absolute_section)
+ if (exp->X_op != O_constant)
{
*input_line_pointer = '\0';
- as_bad ("Field width \"%s\" too complex for a bitfield.\n", hold);
+ as_bad ("field width \"%s\" too complex for a bitfield", hold);
*input_line_pointer = ':';
demand_empty_rest_of_line ();
return;
if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes))
{
- as_warn ("Field width %d too big to fit in %d bytes: truncated to %d bits.",
+ as_warn ("field width %lu too big to fit in %d bytes: truncated to %d bits",
width, nbytes, (BITS_PER_CHAR * nbytes));
width = BITS_PER_CHAR * nbytes;
} /* too big */
hold = ++input_line_pointer; /* skip ':' */
- if ((segment = expression (exp)) != absolute_section)
+ (void) expression (exp);
+ if (exp->X_op != O_constant)
{
char cache = *input_line_pointer;
*input_line_pointer = '\0';
- as_bad ("Field value \"%s\" too complex for a bitfield.\n", hold);
+ as_bad ("field value \"%s\" too complex for a bitfield", hold);
*input_line_pointer = cache;
demand_empty_rest_of_line ();
return;
} /* too complex */
- value |= (~(-1 << width) & exp->X_add_number)
- << ((BITS_PER_CHAR * nbytes) - bits_available);
+ value |= ((~(-1 << width) & exp->X_add_number)
+ << ((BITS_PER_CHAR * nbytes) - bits_available));
if ((bits_available -= width) == 0
|| is_it_end_of_statement ()
} /* all the bitfields we're gonna get */
hold = ++input_line_pointer;
- segment = expression (exp);
+ (void) expression (exp);
} /* forever loop */
exp->X_add_number = value;
- exp->X_seg = absolute_section;
+ exp->X_op = O_constant;
+ exp->X_unsigned = 1;
} /* if looks like a bitfield */
} /* parse_bitfield_cons() */
#endif /* BITFIELD_CONS_EXPRESSIONS */
\f
-#ifdef MRI
+/* Handle an MRI style string expression. */
static void
parse_mri_cons (exp, nbytes)
expressionS *exp;
unsigned int nbytes;
{
- if (*input_line_pointer == '\'')
+ if (*input_line_pointer != '\''
+ && (input_line_pointer[1] != '\''
+ || (*input_line_pointer != 'A'
+ && *input_line_pointer != 'E')))
+ TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+ else
{
- /* An MRI style string, cut into as many bytes as will fit into
- a nbyte chunk, left justify if necessary, and separate with
- commas so we can try again later */
int scan = 0;
unsigned int result = 0;
+
+ /* An MRI style string. Cut into as many bytes as will fit into
+ a nbyte chunk, left justify if necessary, and separate with
+ commas so we can try again later. */
+ if (*input_line_pointer == 'A')
+ ++input_line_pointer;
+ else if (*input_line_pointer == 'E')
+ {
+ as_bad ("EBCDIC constants are not supported");
+ ++input_line_pointer;
+ }
+
input_line_pointer++;
for (scan = 0; scan < nbytes; scan++)
{
scan++;
}
/* Create correct expression */
- exp->X_add_symbol = 0;
+ exp->X_op = O_constant;
exp->X_add_number = result;
- exp->X_seg = absolute_section;
/* Fake it so that we can read the next char too */
if (input_line_pointer[0] != '\'' ||
(input_line_pointer[0] == '\'' && input_line_pointer[1] == '\''))
else
input_line_pointer++;
}
- else
- expression (&exp);
}
-
-#endif /* MRI */
\f
#ifdef REPEAT_CONS_EXPRESSIONS
unsigned int nbytes;
{
expressionS count;
- segT segment;
register int i;
expression (exp);
}
++input_line_pointer;
- segment = expression (&count);
- if (segment != absolute_section
+ expression (&count);
+ if (count.X_op != O_constant
|| count.X_add_number <= 0)
{
as_warn ("Unresolvable or nonpositive repeat count; using 1");
#endif /* REPEAT_CONS_EXPRESSIONS */
\f
-/*
- * big_cons()
- *
- * CONStruct more frag(s) of .quads, or .octa etc.
- * Makes 0 or more new frags.
- * If need_pass_2 == 1, generate no frag.
- * This understands only bignums, not expressions. Cons() understands
- * expressions.
- *
- * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
- *
- * This creates objects with struct obstack_control objs, destroying
- * any context objs held about a partially completed object. Beware!
- *
- *
- * I think it sucks to have 2 different types of integers, with 2
- * routines to read them, store them etc.
- * It would be nicer to permit bignums in expressions and only
- * complain if the result overflowed. However, due to "efficiency"...
- */
-/* worker to do .quad etc statements */
-/* clobbers input_line_pointer, checks */
-/* end-of-line. */
-/* 8=.quad 16=.octa ... */
-
-void
-big_cons (nbytes)
- register int nbytes;
+/* Parse a floating point number represented as a hex constant. This
+ permits users to specify the exact bits they want in the floating
+ point number. */
+
+static int
+hex_float (float_type, bytes)
+ int float_type;
+ char *bytes;
{
- register char c; /* input_line_pointer->c. */
- register int radix;
- register long length; /* Number of chars in an object. */
- register int digit; /* Value of 1 digit. */
- register int carry; /* For multi-precision arithmetic. */
- register int work; /* For multi-precision arithmetic. */
- register char *p; /* For multi-precision arithmetic. */
-
- extern const char hex_value[]; /* In hex_value.c. */
+ int length;
+ int i;
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement ())
+ switch (float_type)
{
- c = 0; /* Skip loop. */
- }
- else
- {
- c = ','; /* Do loop. */
- --input_line_pointer;
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ length = 4;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ length = 8;
+ break;
+
+ case 'x':
+ case 'X':
+ length = 12;
+ break;
+
+ case 'p':
+ case 'P':
+ length = 12;
+ break;
+
+ default:
+ as_bad ("Unknown floating type type '%c'", float_type);
+ return -1;
}
- while (c == ',')
+
+ /* It would be nice if we could go through expression to parse the
+ hex constant, but if we get a bignum it's a pain to sort it into
+ the buffer correctly. */
+ i = 0;
+ while (hex_p (*input_line_pointer) || *input_line_pointer == '_')
{
- ++input_line_pointer;
- SKIP_WHITESPACE ();
- c = *input_line_pointer;
- /* C contains 1st non-blank character of what we hope is a number. */
- if (c == '0')
- {
- c = *++input_line_pointer;
- if (c == 'x' || c == 'X')
- {
- c = *++input_line_pointer;
- radix = 16;
- }
- else
- {
- radix = 8;
- }
- }
- else
- {
- radix = 10;
- }
- /*
- * This feature (?) is here to stop people worrying about
- * mysterious zero constants: which is what they get when
- * they completely omit digits.
- */
- if (hex_value[c] >= radix)
+ int d;
+
+ /* The MRI assembler accepts arbitrary underscores strewn about
+ through the hex constant, so we ignore them as well. */
+ if (*input_line_pointer == '_')
{
- as_bad ("Missing digits. 0 assumed.");
+ ++input_line_pointer;
+ continue;
}
- bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
- for (; (digit = hex_value[c]) < radix; c = *++input_line_pointer)
+
+ if (i >= length)
{
- /* Multiply existing number by radix, then add digit. */
- carry = digit;
- for (p = bignum_low; p <= bignum_high; p++)
- {
- work = (*p & MASK_CHAR) * radix + carry;
- *p = work & MASK_CHAR;
- carry = work >> BITS_PER_CHAR;
- }
- if (carry)
- {
- grow_bignum ();
- *bignum_high = carry & MASK_CHAR;
- know ((carry & ~MASK_CHAR) == 0);
- }
+ as_warn ("Floating point constant too large");
+ return -1;
}
- length = bignum_high - bignum_low + 1;
- if (length > nbytes)
+ d = hex_value (*input_line_pointer) << 4;
+ ++input_line_pointer;
+ while (*input_line_pointer == '_')
+ ++input_line_pointer;
+ if (hex_p (*input_line_pointer))
{
- as_warn ("Most significant bits truncated in integer constant.");
+ d += hex_value (*input_line_pointer);
+ ++input_line_pointer;
}
+ if (target_big_endian)
+ bytes[i] = d;
else
- {
- register long leading_zeroes;
-
- for (leading_zeroes = nbytes - length;
- leading_zeroes;
- leading_zeroes--)
- {
- grow_bignum ();
- *bignum_high = 0;
- }
- }
- if (!need_pass_2)
- {
- char *src = bignum_low;
- p = frag_more (nbytes);
- if (target_big_endian)
- {
- int i;
- for (i = nbytes - 1; i >= 0; i--)
- p[i] = *src++;
- }
- else
- bcopy (bignum_low, p, (int) nbytes);
- }
- /* C contains character after number. */
- SKIP_WHITESPACE ();
- c = *input_line_pointer;
- /* C contains 1st non-blank character after number. */
+ bytes[length - i - 1] = d;
+ ++i;
}
- demand_empty_rest_of_line ();
-} /* big_cons() */
-
-/* Extend bignum by 1 char. */
-static void
-grow_bignum ()
-{
- register long length;
- bignum_high++;
- if (bignum_high >= bignum_limit)
+ if (i < length)
{
- length = bignum_limit - bignum_low;
- bignum_low = xrealloc (bignum_low, length + length);
- bignum_high = bignum_low + length;
- bignum_limit = bignum_low + length + length;
+ if (target_big_endian)
+ memset (bytes + i, 0, length - i);
+ else
+ memset (bytes, 0, length - i);
}
-} /* grow_bignum(); */
-\f
+
+ return length;
+}
+
/*
* float_cons()
*
*
*/
-void /* JF was static, but can't be if VAX.C is goning to use it */
-float_cons (float_type) /* Worker to do .float etc statements. */
+void
+float_cons (float_type)
/* Clobbers input_line-pointer, checks end-of-line. */
register int float_type; /* 'f':.ffloat ... 'F':.float ... */
{
register char *p;
- register char c;
int length; /* Number of chars in an object. */
register char *err; /* Error from scanning floating literal. */
char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
if (is_it_end_of_statement ())
{
- c = 0; /* Skip loop. */
- ++input_line_pointer; /*->past termintor. */
- }
- else
- {
- c = ','; /* Do loop. */
+ demand_empty_rest_of_line ();
+ return;
}
- while (c == ',')
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ do
{
/* input_line_pointer->1st char of a flonum (we hope!). */
SKIP_WHITESPACE ();
+
/* Skip any 0{letter} that may be present. Don't even check if the
* letter is legal. Someone may invent a "z" format and this routine
* has no use for such information. Lusers beware: you get
* diagnostics if your input is ill-conditioned.
*/
-
if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
input_line_pointer += 2;
- err = md_atof (float_type, temp, &length);
- know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
- know (length > 0);
- if (err && *err)
+ /* Accept :xxxx, where the x's are hex digits, for a floating
+ point with the exact digits specified. */
+ if (input_line_pointer[0] == ':')
{
- as_bad ("Bad floating literal: %s", err);
- ignore_rest_of_line ();
- /* Input_line_pointer->just after end-of-line. */
- c = 0; /* Break out of loop. */
+ ++input_line_pointer;
+ length = hex_float (float_type, temp);
+ if (length < 0)
+ {
+ ignore_rest_of_line ();
+ return;
+ }
}
else
{
- if (!need_pass_2)
+ err = md_atof (float_type, temp, &length);
+ know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
+ know (length > 0);
+ if (err)
+ {
+ as_bad ("Bad floating literal: %s", err);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+
+ if (!need_pass_2)
+ {
+ int count;
+
+ count = 1;
+
+#ifdef REPEAT_CONS_EXPRESSIONS
+ if (*input_line_pointer == ':')
+ {
+ expressionS count_exp;
+
+ ++input_line_pointer;
+ expression (&count_exp);
+ if (count_exp.X_op != O_constant
+ || count_exp.X_add_number <= 0)
+ {
+ as_warn ("unresolvable or nonpositive repeat count; using 1");
+ }
+ else
+ count = count_exp.X_add_number;
+ }
+#endif
+
+ while (--count >= 0)
{
p = frag_more (length);
- bcopy (temp, p, length);
+ memcpy (p, temp, (unsigned int) length);
}
- SKIP_WHITESPACE ();
- c = *input_line_pointer++;
- /* C contains 1st non-white character after number. */
- /* input_line_pointer->just after terminator (c). */
}
+ SKIP_WHITESPACE ();
}
- --input_line_pointer; /*->terminator (is not ','). */
+ while (*input_line_pointer++ == ',');
+
+ --input_line_pointer; /* Put terminator back into stream. */
demand_empty_rest_of_line ();
} /* float_cons() */
\f
{
register unsigned int c;
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
/*
* The following awkward logic is to parse ZERO or more strings,
* comma seperated. Recall a string expression includes spaces
c = NOT_A_CHAR;
break;
+ case '\n':
+ as_warn ("Unterminated string: Newline inserted.");
+ bump_line_counters ();
+ break;
+
+#ifndef NO_STRING_ESCAPES
case '\\':
switch (c = *input_line_pointer++)
{
c = '\t';
break;
-#ifdef BACKSLASH_V
case 'v':
c = '\013';
break;
-#endif
case '\\':
case '"':
case '9':
{
long number;
+ int i;
- for (number = 0; isdigit (c); c = *input_line_pointer++)
+ for (i = 0, number = 0; isdigit (c) && i < 3; c = *input_line_pointer++, i++)
{
number = number * 8 + c - '0';
}
--input_line_pointer;
break;
+ case 'x':
+ case 'X':
+ {
+ long number;
+
+ number = 0;
+ c = *input_line_pointer++;
+ while (isxdigit (c))
+ {
+ if (isdigit (c))
+ number = number * 16 + c - '0';
+ else if (isupper (c))
+ number = number * 16 + c - 'A' + 10;
+ else
+ number = number * 16 + c - 'a' + 10;
+ c = *input_line_pointer++;
+ }
+ c = number & 0xff;
+ --input_line_pointer;
+ }
+ break;
+
case '\n':
/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
as_warn ("Unterminated string: Newline inserted.");
c = '\n';
+ bump_line_counters ();
break;
default:
break;
} /* switch on escaped char */
break;
+#endif /* ! defined (NO_STRING_ESCAPES) */
default:
break;
register segT retval;
retval = expression (expP);
- if (retval == pass1_section
- || retval == absent_section
- || retval == big_section)
+ if (expP->X_op == O_illegal
+ || expP->X_op == O_absent
+ || expP->X_op == O_big)
{
- as_bad ("Expected address expression: absolute 0 assumed");
- retval = expP->X_seg = absolute_section;
+ as_bad ("expected address expression; zero assumed");
+ expP->X_op = O_constant;
expP->X_add_number = 0;
- expP->X_add_symbol = expP->X_subtract_symbol = 0;
+ retval = absolute_section;
}
- return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
+ return retval;
}
static segT
register expressionS *expP;
{
register segT retval;
- register CONST char *name1;
- register CONST char *name2;
if ((retval = get_segmented_expression (expP)) == undefined_section)
{
- name1 = expP->X_add_symbol ? S_GET_NAME (expP->X_add_symbol) : "";
- name2 = expP->X_subtract_symbol ?
- S_GET_NAME (expP->X_subtract_symbol) :
- "";
- if (name1 && name2)
- {
- as_warn ("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
- name1, name2);
- }
+ /* There is no easy way to extract the undefined symbol from the
+ expression. */
+ if (expP->X_add_symbol != NULL
+ && S_GET_SEGMENT (expP->X_add_symbol) != expr_section)
+ as_warn ("symbol \"%s\" undefined; zero assumed",
+ S_GET_NAME (expP->X_add_symbol));
else
- {
- as_warn ("Symbol \"%s\" undefined: absolute 0 assumed.",
- name1 ? name1 : name2);
- }
- retval = expP->X_seg = absolute_section;
+ as_warn ("some symbol undefined; zero assumed");
+ retval = absolute_section;
+ expP->X_op = O_constant;
expP->X_add_number = 0;
- expP->X_add_symbol = expP->X_subtract_symbol = NULL;
}
- know (retval == absolute_section
- || retval == diff_section
- || SEG_NORMAL (retval));
+ know (retval == absolute_section || SEG_NORMAL (retval));
return (retval);
-
} /* get_known_segmented_expression() */
-
-
-/* static */ long /* JF was static, but can't be if the MD pseudos are to use it */
+offsetT
get_absolute_expression ()
{
expressionS exp;
- register segT s;
- if ((s = expression (&exp)) != absolute_section)
+ expression (&exp);
+ if (exp.X_op != O_constant)
{
- if (s != absent_section)
- {
- as_bad ("Bad Absolute Expression, absolute 0 assumed.");
- }
+ if (exp.X_op != O_absent)
+ as_bad ("bad or irreducible absolute expression; zero assumed");
exp.X_add_number = 0;
}
- return (exp.X_add_number);
+ return exp.X_add_number;
}
char /* return terminator */
get_absolute_expression_and_terminator (val_pointer)
long *val_pointer; /* return value of expression */
{
- *val_pointer = get_absolute_expression ();
+ /* FIXME: val_pointer should probably be offsetT *. */
+ *val_pointer = (long) get_absolute_expression ();
return (*input_line_pointer++);
}
\f
{
register int len;
- for (len = *len_pointer;
- len > 0;
- len--)
+ for (len = *len_pointer; len > 0; len--)
{
if (*s == 0)
{
}
}
}
- return (s);
+ return s;
}
\f
/*
* Demand string, but return a safe (=private) copy of the string.
* Return NULL if we can't read a string here.
*/
-static char *
+char *
demand_copy_string (lenP)
int *lenP;
{
obstack_1grow (¬es, c);
len++;
}
- /* JF this next line is so demand_copy_C_string will return a null
- termanated string. */
+ /* JF this next line is so demand_copy_C_string will return a
+ null terminated string. */
obstack_1grow (¬es, '\0');
retval = obstack_finish (¬es);
}
is_it_end_of_statement ()
{
SKIP_WHITESPACE ();
- return (is_end_of_line[*input_line_pointer]);
+ return (is_end_of_line[(unsigned char) *input_line_pointer]);
} /* is_it_end_of_statement() */
void
-equals (sym_name)
+equals (sym_name, reassign)
char *sym_name;
+ int reassign;
{
register symbolS *symbolP; /* symbol we are working with */
+ char *stop;
+ char stopc;
input_line_pointer++;
if (*input_line_pointer == '=')
while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
input_line_pointer++;
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
if (sym_name[0] == '.' && sym_name[1] == '\0')
{
/* Turn '. = mumble' into a .org mumble */
register segT segment;
expressionS exp;
- register char *p;
segment = get_known_segmented_expression (&exp);
if (!need_pass_2)
- {
- if (segment != now_seg && segment != absolute_section)
- as_warn ("Illegal segment \"%s\". Segment \"%s\" assumed.",
- segment_name (segment),
- segment_name (now_seg));
- p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
- exp.X_add_number, (char *) 0);
- *p = 0;
- } /* if (ok to make frag) */
+ do_org (segment, &exp, 0);
}
else
{
symbolP = symbol_find_or_make (sym_name);
+ /* Permit register names to be redefined. */
+ if (! reassign
+ && S_IS_DEFINED (symbolP)
+ && S_GET_SEGMENT (symbolP) != reg_section)
+ as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP));
pseudo_set (symbolP);
}
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
} /* equals() */
/* .include -- include a file at this point. */
FILE *try;
char *path;
- filename = demand_copy_string (&i);
+ if (! flag_m68k_mri)
+ filename = demand_copy_string (&i);
+ else
+ {
+ SKIP_WHITESPACE ();
+ i = 0;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer]
+ && *input_line_pointer != ' '
+ && *input_line_pointer != '\t')
+ {
+ obstack_1grow (¬es, *input_line_pointer);
+ ++input_line_pointer;
+ ++i;
+ }
+ obstack_1grow (¬es, '\0');
+ filename = obstack_finish (¬es);
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
demand_empty_rest_of_line ();
- path = xmalloc (i + include_dir_maxlen + 5 /* slop */ );
+ path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ );
for (i = 0; i < include_dir_count; i++)
{
strcpy (path, include_dirs[i]);
s_ignore (arg)
int arg;
{
- while (!is_end_of_line[*input_line_pointer])
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
{
++input_line_pointer;
}
++input_line_pointer;
+}
- return;
-} /* s_ignore() */
+
+void
+read_print_statistics (file)
+ FILE *file;
+{
+ hash_print_statistics (file, "pseudo-op table", po_hash);
+}
/* end of read.c */