* config/obj-coff.c (fixup_segment): Make sure that symbols are
[deliverable/binutils-gdb.git] / gas / read.c
index da2b3a6baa4ba1451fbc29d4aa22e6d18d8e2f1c..12bfa6e93b10c0b3462edd8e2af50eda14d29145 100644 (file)
@@ -1,5 +1,5 @@
 /* read.c - read a source file -
 /* read.c - read a source file -
-   Copyright (C) 1986, 1987, 1990, 1991, 1993, 1994
+   Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 1996
    Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
    Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
@@ -16,7 +16,7 @@ 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
 
 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. */
+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
 
 #if 0
 #define MASK_CHAR (0xFF)       /* If your chars aren't 8 bits, you will
@@ -42,9 +42,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "as.h"
 #include "subsegs.h"
 
 #include "as.h"
 #include "subsegs.h"
-
+#include "sb.h"
+#include "macro.h"
+#include "libiberty.h"
 #include "obstack.h"
 #include "listing.h"
 #include "obstack.h"
 #include "listing.h"
+#include "ecoff.h"
 
 #ifndef TC_START_LABEL
 #define TC_START_LABEL(x,y) (x==':')
 
 #ifndef TC_START_LABEL
 #define TC_START_LABEL(x,y) (x==':')
@@ -60,6 +63,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 char *input_line_pointer;      /*->next char of source file to parse. */
 
 
 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!)!  */
 #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!)!  */
@@ -81,13 +86,23 @@ die horribly;
 #define LEX_PCT 0
 #endif
 
 #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
+
 /* used by is_... macros. our ctype[] */
 /* 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, 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, 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, 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, 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 */
   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, 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 */
@@ -139,7 +154,17 @@ char is_end_of_line[256] =
 static char *buffer;   /* 1st char of each buffer of lines is here. */
 static char *buffer_limit;     /*->1 + last char in buffer. */
 
 static char *buffer;   /* 1st char of each buffer of lines is here. */
 static char *buffer_limit;     /*->1 + last char in buffer. */
 
-int target_big_endian;
+#ifdef TARGET_BYTES_BIG_ENDIAN
+/* Hack to deal with tc-*.h defining TARGET_BYTES_BIG_ENDIAN to empty
+   instead of to 0 or 1.  */
+#if 5 - TARGET_BYTES_BIG_ENDIAN - 5 == 10
+#undef  TARGET_BYTES_BIG_ENDIAN
+#define TARGET_BYTES_BIG_ENDIAN 1
+#endif
+int target_big_endian = TARGET_BYTES_BIG_ENDIAN;
+#else
+int target_big_endian /* = 0 */;
+#endif
 
 static char *old_buffer;       /* JF a hack */
 static char *old_input;
 
 static char *old_buffer;       /* JF a hack */
 static char *old_input;
@@ -157,11 +182,35 @@ struct broken_word *broken_words;
 int new_broken_words;
 #endif
 
 int new_broken_words;
 #endif
 
+/* 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 int scrub_from_string PARAMS ((char **));
+static void do_align PARAMS ((int, char *, int));
+static int hex_float PARAMS ((int, char *));
+static void do_org PARAMS ((segT, expressionS *, int));
 char *demand_copy_string PARAMS ((int *lenP));
 char *demand_copy_string PARAMS ((int *lenP));
-int is_it_end_of_statement PARAMS ((void));
 static segT get_segmented_expression PARAMS ((expressionS *expP));
 static segT get_known_segmented_expression PARAMS ((expressionS * expP));
 static void pobegin PARAMS ((void));
 static segT get_segmented_expression PARAMS ((expressionS *expP));
 static segT get_known_segmented_expression PARAMS ((expressionS * expP));
 static void pobegin PARAMS ((void));
+static int get_line_sb PARAMS ((sb *));
 \f
 
 void
 \f
 
 void
@@ -174,18 +223,21 @@ read_begin ()
 
   /* Something close -- but not too close -- to a multiple of 1024.
      The debugging malloc I'm using has 24 bytes of overhead.  */
 
   /* Something close -- but not too close -- to a multiple of 1024.
      The debugging malloc I'm using has 24 bytes of overhead.  */
-  obstack_begin (&notes, 5090);
-  obstack_begin (&cond_obstack, 990);
+  obstack_begin (&notes, chunksize);
+  obstack_begin (&cond_obstack, chunksize);
 
   /* Use machine dependent syntax */
   for (p = line_separator_chars; *p; p++)
     is_end_of_line[(unsigned char) *p] = 1;
   /* Use more.  FIXME-SOMEDAY. */
 
   /* Use machine dependent syntax */
   for (p = line_separator_chars; *p; p++)
     is_end_of_line[(unsigned char) *p] = 1;
   /* Use more.  FIXME-SOMEDAY. */
+
+  if (flag_mri)
+    lex_type['?'] = 3;
 }
 \f
 /* set up pseudo-op tables */
 
 }
 \f
 /* set up pseudo-op tables */
 
-struct hash_control *po_hash;
+static struct hash_control *po_hash;
 
 static const pseudo_typeS potable[] =
 {
 
 static const pseudo_typeS potable[] =
 {
@@ -193,10 +245,38 @@ static const pseudo_typeS potable[] =
   {"align", s_align_ptwo, 0},
   {"ascii", stringer, 0},
   {"asciz", stringer, 1},
   {"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},
 /* block */
   {"byte", cons, 1},
   {"comm", s_comm, 0},
+  {"common", s_mri_common, 0},
+  {"common.s", s_mri_common, 1},
   {"data", s_data, 0},
   {"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
 #ifdef S_SET_DESC
   {"desc", s_desc, 0},
 #endif
@@ -205,40 +285,76 @@ static const pseudo_typeS potable[] =
 /* dsect */
   {"eject", listing_eject, 0}, /* Formfeed listing */
   {"else", s_else, 0},
 /* dsect */
   {"eject", listing_eject, 0}, /* Formfeed listing */
   {"else", s_else, 0},
+  {"elsec", s_else, 0},
   {"end", s_end, 0},
   {"end", s_end, 0},
+  {"endc", s_endif, 0},
   {"endif", s_endif, 0},
 /* endef */
   {"equ", s_set, 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},
 /* 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'},
   {"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},
   {"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},
   {"ifdef", s_ifdef, 0},
+  {"ifeq", s_if, (int) O_eq},
   {"ifeqs", s_ifeqs, 0},
   {"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},
   {"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},
   {"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 */
   {"lcomm", s_lcomm, 0},
   {"lflags", listing_flags, 0},        /* Listing flags */
+  {"linkonce", s_linkonce, 0},
   {"list", listing_list, 1},   /* Turn listing on */
   {"list", listing_list, 1},   /* Turn listing on */
+  {"llen", listing_psize, 1},
   {"long", cons, 4},
   {"lsym", s_lsym, 0},
   {"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 */
   {"nolist", listing_list, 0}, /* Turn listing off */
+  {"nopage", listing_nopage, 0},
   {"octa", cons, 16},
   {"octa", cons, 16},
+  {"offset", s_struct, 0},
   {"org", s_org, 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 */
   {"psize", listing_psize, 0}, /* set paper size */
-/* print */
+  {"purgem", s_purgem, 0},
   {"quad", cons, 8},
   {"quad", cons, 8},
+  {"rep", s_rept, 0},
+  {"rept", s_rept, 0},
+  {"rva", s_rva, 4},
   {"sbttl", listing_title, 1}, /* Subtitle of listing */
 /* scl */
 /* sect */
   {"sbttl", listing_title, 1}, /* Subtitle of listing */
 /* scl */
 /* sect */
@@ -247,10 +363,13 @@ static const pseudo_typeS potable[] =
   {"single", float_cons, 'f'},
 /* size */
   {"space", s_space, 0},
   {"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},
   {"stabd", s_stab, 'd'},
   {"stabn", s_stab, 'n'},
   {"stabs", s_stab, 's'},
   {"string", stringer, 1},
+  {"struct", s_struct, 0},
 /* tag */
   {"text", s_text, 0},
 
 /* tag */
   {"text", s_text, 0},
 
@@ -265,75 +384,63 @@ static const pseudo_typeS potable[] =
   {"this_gcc_requires_the_gnu_assembler", s_ignore, 0},
 
   {"title", listing_title, 0}, /* Listing title */
   {"this_gcc_requires_the_gnu_assembler", s_ignore, 0},
 
   {"title", listing_title, 0}, /* Listing title */
+  {"ttl", listing_title, 0},
 /* type */
 /* use */
 /* val */
 /* 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 */
 };
 
   {"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;
 {
 {
-  const char *errtxt;                  /* error text */
+  const char *errtxt;
   const pseudo_typeS *pop;
   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. */
   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)
-       {
-         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. */
 
   /* 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)
-       {
-         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. */
 
   /* 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)
-       {
-         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 ())                                                 \
 \f
 #define HANDLE_CONDITIONAL_ASSEMBLY()                                  \
   if (ignore_input ())                                                 \
@@ -345,6 +452,24 @@ pobegin ()
     }
 
 
     }
 
 
+/* 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
 /*     read_a_source_file()
  *
  * We read the file, putting things into a web that
@@ -381,26 +506,61 @@ read_a_source_file (name)
           */
          if (is_end_of_line[(unsigned char) input_line_pointer[-1]])
            {
           */
          if (is_end_of_line[(unsigned char) input_line_pointer[-1]])
            {
+#ifdef md_start_line_hook
+             md_start_line_hook ();
+#endif
+
              if (input_line_pointer[-1] == '\n')
                bump_line_counters ();
 
              if (input_line_pointer[-1] == '\n')
                bump_line_counters ();
 
-#if defined (MRI) || defined (LABELS_WITHOUT_COLONS)
-             /* 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))
+             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;
+
+                     HANDLE_CONDITIONAL_ASSEMBLY ();
 
 
+                     c = get_symbol_end ();
+
+                     /* In MRI mode, the EQU pseudoop must be
+                        handled specially.  */
+                     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);
+                             continue;
+                           }
+                       }
+
+                     line_label = colon (line_start);
+
+                     *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.
          /*
           * We are at the begining of a line, or similar place.
           * We expect a well-formed assembler statement.
@@ -444,7 +604,27 @@ read_a_source_file (name)
               */
              if (TC_START_LABEL(c, 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);
+                         continue;
+                       }
+                   }
+
+                 line_label = colon (s);       /* user-defined label */
                  *input_line_pointer++ = ':';  /* Put ':' back for error messages' sake. */
                  /* Input_line_pointer->after ':'. */
                  SKIP_WHITESPACE ();
                  *input_line_pointer++ = ':';  /* Put ':' back for error messages' sake. */
                  /* Input_line_pointer->after ':'. */
                  SKIP_WHITESPACE ();
@@ -463,11 +643,6 @@ read_a_source_file (name)
                }
              else
                {               /* expect pseudo-op or machine instruction */
                }
              else
                {               /* expect pseudo-op or machine instruction */
-#ifdef MRI
-                 if (!done_pseudo (s))
-
-#else
-
                  pop = NULL;
 
 #define IGNORE_OPCODE_CASE
                  pop = NULL;
 
 #define IGNORE_OPCODE_CASE
@@ -483,14 +658,21 @@ read_a_source_file (name)
                  }
 #endif
 
                  }
 #endif
 
+                 if (flag_m68k_mri
 #ifdef NO_PSEUDO_DOT
 #ifdef NO_PSEUDO_DOT
-                 /* The m88k uses pseudo-ops without a period.  */
-                 pop = (pseudo_typeS *) hash_find (po_hash, s);
-                 if (pop != NULL && pop->poc_handler == NULL)
-                   pop = NULL;
+                     || 1
 #endif
 #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 || *s == '.')
+                 if (pop != NULL
+                     || (! flag_m68k_mri && *s == '.'))
                    {
                      /*
                       * PSEUDO - OP.
                    {
                      /*
                       * PSEUDO - OP.
@@ -503,6 +685,20 @@ read_a_source_file (name)
                      if (pop == NULL)
                        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))))
+                       {
+                         do_align (1, (char *) NULL, 0);
+                         mri_pending_align = 0;
+                       }
+
                      /* Print the error msg now, while we still can */
                      if (pop == NULL)
                        {
                      /* Print the error msg now, while we still can */
                      if (pop == NULL)
                        {
@@ -525,25 +721,74 @@ read_a_source_file (name)
                       * after pseudo-operation.
                       */
                      (*pop->poc_handler) (pop->poc_val);
                       * after pseudo-operation.
                       */
                      (*pop->poc_handler) (pop->poc_val);
+
+                     /* If that was .end, just get out now.  */
+                     if (pop->poc_handler == s_end)
+                       goto quit;
                    }
                  else
                    }
                  else
-#endif
                    {           /* machine instruction */
                    {           /* machine instruction */
+                     int inquote = 0;
+
+                     if (mri_pending_align)
+                       {
+                         do_align (1, (char *) NULL, 0);
+                         mri_pending_align = 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[(unsigned char) *input_line_pointer]
                      /* 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[(unsigned char) *input_line_pointer]
+                            || inquote
 #ifdef TC_EOL_IN_INSN
                             || TC_EOL_IN_INSN (input_line_pointer)
 #endif
                             )
                        {
 #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';
 
                          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;
+                           }
+                       }
+
                      md_assemble (s);  /* Assemble 1 instruction. */
 
                      *input_line_pointer++ = c;
                      md_assemble (s);  /* Assemble 1 instruction. */
 
                      *input_line_pointer++ = c;
@@ -560,8 +805,8 @@ read_a_source_file (name)
          if (is_end_of_line[(unsigned char) c])
            continue;
 
          if (is_end_of_line[(unsigned char) c])
            continue;
 
-#if defined(LOCAL_LABELS_DOLLAR) || defined(LOCAL_LABELS_FB)
-         if (isdigit (c))
+         if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB)
+             && isdigit (c))
            {
              /* local label  ("4:") */
              char *backup = input_line_pointer;
            {
              /* local label  ("4:") */
              char *backup = input_line_pointer;
@@ -576,8 +821,8 @@ read_a_source_file (name)
                  ++input_line_pointer;
                }               /* read the whole number */
 
                  ++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;
                  && *(input_line_pointer + 1) == ':')
                {
                  input_line_pointer += 2;
@@ -591,20 +836,17 @@ read_a_source_file (name)
                  colon (dollar_label_name (temp, 0));
                  continue;
                }
                  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;
                }
                {
                  fb_label_instance_inc (temp);
                  colon (fb_label_name (temp, 0));
                  continue;
                }
-#endif /* LOCAL_LABELS_FB */
 
              input_line_pointer = backup;
            }                   /* local label  ("4:") */
 
              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 */
 
          if (c && strchr (line_comment_chars, c))
            {                   /* Its a comment.  Better say APP or NO_APP */
@@ -613,7 +855,6 @@ read_a_source_file (name)
              char *new_tmp;
              unsigned int new_length;
              char *tmp_buf = 0;
              char *new_tmp;
              unsigned int new_length;
              char *tmp_buf = 0;
-             extern char *scrub_string, *scrub_last_string;
 
              bump_line_counters ();
              s = input_line_pointer;
 
              bump_line_counters ();
              s = input_line_pointer;
@@ -665,26 +906,30 @@ read_a_source_file (name)
                {
                  input_line_pointer = ends + 8;
                }
                {
                  input_line_pointer = ends + 8;
                }
-             new_buf = xmalloc (100);
-             new_length = 100;
-             new_tmp = new_buf;
 
              scrub_string = s;
 
              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 (;;)
                {
              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)
                }
 
              if (tmp_buf)
@@ -700,12 +945,23 @@ read_a_source_file (name)
 
          HANDLE_CONDITIONAL_ASSEMBLY ();
 
 
          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) */
          /* 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)
        {
       if (old_buffer)
        {
+         free (buffer);
          bump_line_counters ();
          if (old_input != 0)
            {
          bump_line_counters ();
          if (old_input != 0)
            {
@@ -717,8 +973,69 @@ read_a_source_file (name)
            }
        }
     }                          /* while (more buffers to scan) */
            }
        }
     }                          /* while (more buffers to scan) */
+
+ quit:
   input_scrub_close ();                /* Close the input file */
   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);
+
+  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 
 }
 
 void 
@@ -730,12 +1047,13 @@ s_abort (ignore)
 
 /* Guts of .align directive.  */
 static void 
 
 /* Guts of .align directive.  */
 static void 
-do_align (n, fill)
+do_align (n, fill, len)
      int n;
      char *fill;
      int n;
      char *fill;
+     int len;
 {
 #ifdef md_do_align
 {
 #ifdef md_do_align
-  md_do_align (n, fill, just_record_alignment);
+  md_do_align (n, fill, len, just_record_alignment);
 #endif
   if (!fill)
     {
 #endif
   if (!fill)
     {
@@ -751,10 +1069,17 @@ do_align (n, fill)
        {
          fill = &zero;
        }
        {
          fill = &zero;
        }
+      len = 1;
     }
     }
+
   /* Only make a frag if we HAVE to. . . */
   if (n && !need_pass_2)
   /* Only make a frag if we HAVE to. . . */
   if (n && !need_pass_2)
-    frag_align (n, *fill);
+    {
+      if (len <= 1)
+       frag_align (n, *fill);
+      else
+       frag_align_pattern (n, fill, len);
+    }
 
 #ifdef md_do_align
  just_record_alignment:
 
 #ifdef md_do_align
  just_record_alignment:
@@ -772,9 +1097,19 @@ s_align_bytes (arg)
   char temp_fill;
   unsigned int i = 0;
   unsigned long max_alignment = 1 << 15;
   char temp_fill;
   unsigned int i = 0;
   unsigned long max_alignment = 1 << 15;
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
 
   if (is_end_of_line[(unsigned char) *input_line_pointer])
 
   if (is_end_of_line[(unsigned char) *input_line_pointer])
-    temp = arg;                        /* Default value from pseudo-op table */
+    {
+      if (arg < 0)
+       temp = 0;
+      else
+       temp = arg;     /* Default value from pseudo-op table */
+    }
   else
     temp = get_absolute_expression ();
 
   else
     temp = get_absolute_expression ();
 
@@ -796,24 +1131,56 @@ s_align_bytes (arg)
   temp = i;
   if (*input_line_pointer == ',')
     {
   temp = i;
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       input_line_pointer++;
       input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      do_align (temp, &temp_fill);
+      fillval = get_absolute_expression ();
+      if (arg >= 0)
+       len = 1;
+      else
+       len = - arg;
+      if (len <= 1)
+       {
+         temp_fill = fillval;
+         do_align (temp, &temp_fill, len);
+       }
+      else
+       {
+         char ab[16];
+
+         if (len > sizeof ab)
+           abort ();
+         md_number_to_chars (ab, fillval, len);
+         do_align (temp, ab, len);
+       }
     }
   else
     }
   else
-    do_align (temp, (char *) 0);
+    {
+      if (arg < 0)
+       as_warn ("expected fill pattern missing");
+      do_align (temp, (char *) NULL, 0);
+    }
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
 
   demand_empty_rest_of_line ();
 }
 
 /* For machines where ".align 4" means align to 2**4 boundary. */
 void 
 
   demand_empty_rest_of_line ();
 }
 
 /* For machines where ".align 4" means align to 2**4 boundary. */
 void 
-s_align_ptwo (ignore)
-     int ignore;
+s_align_ptwo (arg)
+     int arg;
 {
   register int temp;
   char temp_fill;
   long max_alignment = 15;
 {
   register int temp;
   char temp_fill;
   long max_alignment = 15;
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
@@ -825,12 +1192,39 @@ s_align_ptwo (ignore)
     }
   if (*input_line_pointer == ',')
     {
     }
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       input_line_pointer++;
       input_line_pointer++;
-      temp_fill = get_absolute_expression ();
-      do_align (temp, &temp_fill);
+      fillval = get_absolute_expression ();
+      if (arg >= 0)
+       len = 1;
+      else
+       len = - arg;
+      if (len <= 1)
+       {
+         temp_fill = fillval;
+         do_align (temp, &temp_fill, len);
+       }
+      else
+       {
+         char ab[16];
+
+         if (len > sizeof ab)
+           abort ();
+         md_number_to_chars (ab, fillval, len);
+         do_align (temp, ab, len);
+       }
     }
   else
     }
   else
-    do_align (temp, (char *) 0);
+    {
+      if (arg < 0)
+       as_warn ("expected fill pattern missing");
+      do_align (temp, (char *) NULL, 0);
+    }
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
 
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
@@ -844,6 +1238,11 @@ s_comm (ignore)
   register char *p;
   offsetT temp;
   register symbolS *symbolP;
   register char *p;
   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 ();
 
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -854,6 +1253,8 @@ s_comm (ignore)
   if (*input_line_pointer != ',')
     {
       as_bad ("Expected comma after symbol-name: rest of line ignored.");
   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;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -861,6 +1262,8 @@ s_comm (ignore)
   if ((temp = get_absolute_expression ()) < 0)
     {
       as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
   if ((temp = get_absolute_expression ()) < 0)
     {
       as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -871,6 +1274,8 @@ s_comm (ignore)
     {
       as_bad ("Ignoring attempt to re-define symbol `%s'.",
              S_GET_NAME (symbolP));
     {
       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;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -895,9 +1300,119 @@ s_comm (ignore)
   }
 #endif /* not OBJ_VMS */
   know (symbolP->sy_frag == &zero_address_frag);
   }
 #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() */
 
   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_mri_common (small)
+     int small;
+{
+  char *name;
+  char c;
+  char *alc = NULL;
+  symbolS *sym;
+  offsetT align;
+  char *stop = NULL;
+  char stopc;
+
+  if (! flag_mri)
+    {
+      s_comm (0);
+      return;
+    }
+
+  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;
 void
 s_data (ignore)
      int ignore;
@@ -923,11 +1438,11 @@ s_data (ignore)
 }
 
 /* Handle the .appfile pseudo-op.  This is automatically generated by
 }
 
 /* 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)
 
 void 
 s_app_file (appfile)
@@ -943,24 +1458,29 @@ 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);
         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
     }
       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
 #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 (ignore)
 
 void
 s_app_line (ignore)
@@ -970,40 +1490,104 @@ s_app_line (ignore)
 
   /* The given number is that of the next line.  */
   l = get_absolute_expression () - 1;
 
   /* 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
 #ifdef LISTING
-  if (listing)
-    listing_source_line (l);
+      if (listing)
+       listing_source_line (l);
 #endif
 #endif
+    }
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-void 
-s_fill (ignore)
+/* Handle the .end pseudo-op.  Actually, the real work is done in
+   read_a_source_file.  */
+
+void
+s_end (ignore)
      int ignore;
 {
      int ignore;
 {
-  long temp_repeat = 0;
-  long temp_size = 1;
-  register long temp_fill = 0;
-  char *p;
-
-
-  temp_repeat = get_absolute_expression ();
-  if (*input_line_pointer == ',')
+  if (flag_mri)
     {
     {
-      input_line_pointer++;
-      temp_size = get_absolute_expression ();
-      if (*input_line_pointer == ',')
-       {
-         input_line_pointer++;
-         temp_fill = get_absolute_expression ();
-       }
+      /* 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");
     }
     }
-  /* This is to be compatible with BSD 4.2 AS, not for any rational reason.  */
-#define BSD_FILL_SIZE_CROCK_8 (8)
-  if (temp_size > BSD_FILL_SIZE_CROCK_8)
-    {
-      as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
+}
+
+/* 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 (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 == ',')
+    {
+      input_line_pointer++;
+      temp_size = get_absolute_expression ();
+      if (*input_line_pointer == ',')
+       {
+         input_line_pointer++;
+         temp_fill = get_absolute_expression ();
+       }
+    }
+  /* This is to be compatible with BSD 4.2 AS, not for any rational reason.  */
+#define BSD_FILL_SIZE_CROCK_8 (8)
+  if (temp_size > BSD_FILL_SIZE_CROCK_8)
+    {
+      as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
       temp_size = BSD_FILL_SIZE_CROCK_8;
     }
   if (temp_size < 0)
       temp_size = BSD_FILL_SIZE_CROCK_8;
     }
   if (temp_size < 0)
@@ -1013,7 +1597,8 @@ s_fill (ignore)
     }
   else if (temp_repeat <= 0)
     {
     }
   else if (temp_repeat <= 0)
     {
-      as_warn ("Repeat < 0, .fill ignored");
+      if (temp_repeat < 0)
+       as_warn ("Repeat < 0, .fill ignored");
       temp_size = 0;
     }
 
       temp_size = 0;
     }
 
@@ -1046,6 +1631,11 @@ s_globl (ignore)
   char *name;
   int c;
   symbolS *symbolP;
   char *name;
   int c;
   symbolS *symbolP;
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
 
   do
     {
 
   do
     {
@@ -1064,6 +1654,118 @@ s_globl (ignore)
        }
     }
   while (c == ',');
        }
     }
   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 ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -1112,14 +1814,21 @@ s_lcomm (needs_align)
     }
 
 #if defined (TC_MIPS) || defined (TC_ALPHA)
     }
 
 #if defined (TC_MIPS) || defined (TC_ALPHA)
-#if defined (OBJ_ECOFF) || defined (OBJ_ELF)
-  /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss.  */
-  if (temp <= bfd_get_gp_size (stdoutput))
+  if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+      || OUTPUT_FLAVOR == bfd_target_elf_flavour)
     {
     {
-      bss_seg = subseg_new (".sbss", 1);
-      seg_info (bss_seg)->bss = 1;
-    }
+      /* 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
+       }
+    }
 #endif
    if (!needs_align)
      {
 #endif
    if (!needs_align)
      {
@@ -1131,7 +1840,12 @@ s_lcomm (needs_align)
        else if (temp >= 2)
         align = 1;
        else
        else if (temp >= 2)
         align = 1;
        else
-        align = temp;
+        align = 0;
+
+#ifdef OBJ_EVAX
+       /* FIXME: This needs to be done in a more general fashion.  */
+       align = 3;
+#endif
 
        record_alignment(bss_seg, align);
      }
 
        record_alignment(bss_seg, align);
      }
@@ -1169,7 +1883,7 @@ s_lcomm (needs_align)
   else
     {
       /* Assume some objects may require alignment on some systems.  */
   else
     {
       /* Assume some objects may require alignment on some systems.  */
-#ifdef TC_ALPHA
+#if defined (TC_ALPHA) && ! defined (VMS)
       if (temp > 1)
        {
          align = ffs (temp) - 1;
       if (temp > 1)
        {
          align = ffs (temp) - 1;
@@ -1217,6 +1931,10 @@ s_lcomm (needs_align)
          S_SET_STORAGE_CLASS (symbolP, C_STAT);
        }
 #endif /* OBJ_COFF */
          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'.",
     }
   else
     as_bad ("Ignoring attempt to re-define symbol `%s'.",
@@ -1289,6 +2007,160 @@ s_lsym (ignore)
   demand_empty_rest_of_line ();
 }                              /* s_lsym() */
 
   demand_empty_rest_of_line ();
 }                              /* s_lsym() */
 
+/* Read a line into an sb.  */
+
+static int
+get_line_sb (line)
+     sb *line;
+{
+  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;
+    }
+
+  while (! is_end_of_line[(unsigned char) *input_line_pointer])
+    sb_add_char (line, *input_line_pointer++);
+  while (input_line_pointer < buffer_limit
+        && is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      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 (ignore)
      int ignore;
 void 
 s_org (ignore)
      int ignore;
@@ -1296,38 +2168,285 @@ s_org (ignore)
   register segT segment;
   expressionS exp;
   register long temp_fill;
   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
      segmented origin expression ("foo+42") had better be in the right
      segment or the .org is ignored.
 
   /* 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
      segmented origin expression ("foo+42") had better be in the right
      segment or the .org is ignored.
 
-     BSD 4.2 AS warns if you try to .org backwards. We cannot because
-     we never know sub-segment sizes when we are reading code.  BSD
-     will crash trying to emit negative numbers of filler bytes in
-     certain .orgs. We don't crash, but see as-write for that code.
+     BSD 4.2 AS warns if you try to .org backwards. We cannot because
+     we never know sub-segment sizes when we are reading code.  BSD
+     will crash trying to emit negative numbers of filler bytes in
+     certain .orgs. We don't crash, but see as-write for that code.
+
+     Don't make frag if need_pass_2==1.  */
+  segment = get_known_segmented_expression (&exp);
+  if (*input_line_pointer == ',')
+    {
+      input_line_pointer++;
+      temp_fill = get_absolute_expression ();
+    }
+  else
+    temp_fill = 0;
+
+  if (!need_pass_2)
+    do_org (segment, &exp, temp_fill);
+
+  demand_empty_rest_of_line ();
+}                              /* s_org() */
+
+/* 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 ();
 
 
-     Don't make frag if need_pass_2==1.  */
-  segment = get_known_segmented_expression (&exp);
-  if (*input_line_pointer == ',')
+  sb_new (&one);
+  if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb))
     {
     {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
+      as_bad ("rept without endr");
+      return;
     }
     }
-  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) */
-  demand_empty_rest_of_line ();
-}                              /* s_org() */
+
+  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)
 
 void 
 s_set (ignore)
@@ -1366,20 +2485,11 @@ s_set (ignore)
       /* Turn '. = mumble' into a .org mumble */
       register segT segment;
       expressionS exp;
       /* Turn '. = mumble' into a .org mumble */
       register segT segment;
       expressionS exp;
-      register char *ptr;
 
       segment = get_known_segmented_expression (&exp);
 
       if (!need_pass_2)
 
       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;
 
       *end_name = delim;
       return;
@@ -1407,38 +2517,252 @@ void
 s_space (mult)
      int mult;
 {
 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;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
 
 
-  /* Just like .fill, but temp_size = 1 */
-  if (get_absolute_expression_and_terminator (&temp_repeat) == ',')
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
+
+  /* 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);
+         if (line_label != NULL)
+           {
+             line_label->sy_frag = frag_now;
+             S_SET_VALUE (line_label, frag_now_fix ());
+           }
+       }
+    }
+
+  expression (&exp);
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression (&val);
     }
   else
     {
     }
   else
     {
-      input_line_pointer--;    /* Backup over what was not a ','. */
-      temp_fill = 0;
+      val.X_op = O_constant;
+      val.X_add_number = 0;
+    }
+
+  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))
+    {
+      if (exp.X_op != O_constant)
+       as_bad ("Unsupported variable size or fill value");
+      else
+       {
+         offsetT i;
+
+         if (mult == 0)
+           mult = 1;
+         for (i = 0; i < exp.X_add_number; i++)
+           emit_expr (&val, mult);
+       }
     }
     }
-  if (mult)
+  else
     {
     {
-      temp_repeat *= mult;
+      if (exp.X_op == O_constant)
+       {
+         long repeat;
+
+         repeat = exp.X_add_number;
+         if (mult)
+           repeat *= mult;
+         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;
     }
     }
-  if (temp_repeat <= 0)
+
+ getout:
+  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_warn ("Repeat < 0, .space ignored");
+      as_bad ("missing value");
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
       ignore_rest_of_line ();
       return;
     }
       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 ();
   demand_empty_rest_of_line ();
-}                              /* s_space() */
+}
 
 void
 s_text (ignore)
 
 void
 s_text (ignore)
@@ -1449,6 +2773,9 @@ s_text (ignore)
   temp = get_absolute_expression ();
   subseg_set (text_section, (subsegT) temp);
   demand_empty_rest_of_line ();
   temp = get_absolute_expression ();
   subseg_set (text_section, (subsegT) temp);
   demand_empty_rest_of_line ();
+#ifdef OBJ_VMS
+  const_flag &= ~IN_DEFAULT_SECTION;
+#endif
 }                              /* s_text() */
 \f
 
 }                              /* s_text() */
 \f
 
@@ -1503,13 +2830,12 @@ pseudo_set (symbolP)
      symbolS *symbolP;
 {
   expressionS exp;
      symbolS *symbolP;
 {
   expressionS exp;
-#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. */
   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 */
 
   ext = S_IS_EXTERNAL (symbolP);
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
@@ -1542,8 +2868,7 @@ pseudo_set (symbolP)
       /* Fall through.  */
     case O_constant:
       S_SET_SEGMENT (symbolP, absolute_section);
       /* Fall through.  */
     case O_constant:
       S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-      /* @@ Fix this right for BFD.  */
+#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER)
       if (ext)
        S_SET_EXTERNAL (symbolP);
       else
       if (ext)
        S_SET_EXTERNAL (symbolP);
       else
@@ -1560,21 +2885,24 @@ pseudo_set (symbolP)
       break;
 
     case O_symbol:
       break;
 
     case O_symbol:
-      if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
+      if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section
+         || exp.X_add_number != 0)
        symbolP->sy_value = exp;
       else
        {
        symbolP->sy_value = exp;
       else
        {
-         S_SET_SEGMENT (symbolP, S_GET_SEGMENT (exp.X_add_symbol));
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-         /* @@ Fix this right for BFD!  */
+         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,
          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 (exp.X_add_symbol));
-         symbolP->sy_frag = exp.X_add_symbol->sy_frag;
+                      exp.X_add_number + S_GET_VALUE (s));
+         symbolP->sy_frag = s->sy_frag;
+         copy_symbol_attributes (symbolP, s);
        }
       break;
 
        }
       break;
 
@@ -1611,17 +2939,15 @@ pseudo_set (symbolP)
    are defined, which is the normal case, then only simple expressions
    are permitted.  */
 
    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
 #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
 #ifdef REPEAT_CONS_EXPRESSIONS
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
 static void
@@ -1637,29 +2963,85 @@ parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes));
 /* worker to do .byte etc statements */
 /* clobbers input_line_pointer, checks */
 /* end-of-line. */
 /* worker to do .byte etc statements */
 /* clobbers input_line_pointer, checks */
 /* end-of-line. */
-void 
-cons (nbytes)
+static void 
+cons_worker (nbytes, rva)
      register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
      register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
+     int rva;
 {
 {
+  int c;
   expressionS exp;
   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 (is_it_end_of_statement ())
     {
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
       demand_empty_rest_of_line ();
       return;
     }
 
       demand_empty_rest_of_line ();
       return;
     }
 
+#ifdef md_cons_align
+  md_cons_align (nbytes);
+#endif
+
+  c = 0;
   do
     {
   do
     {
-      TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) 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);
       emit_expr (&exp, (unsigned int) nbytes);
+      ++c;
     }
   while (*input_line_pointer++ == ',');
 
     }
   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. */
   input_line_pointer--;                /* Put terminator back into stream. */
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
+
+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.  */
 
 /* Put the contents of expression EXP into the object file using
    NBYTES bytes.  If need_pass_2 is 1, this does nothing.  */
 
@@ -1678,6 +3060,15 @@ emit_expr (exp, nbytes)
 
   op = exp->X_op;
 
 
   op = exp->X_op;
 
+  /* 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;
+    }
+
   /* Handle a negative bignum.  */
   if (op == O_uminus
       && exp->X_add_number == 0
   /* Handle a negative bignum.  */
   if (op == O_uminus
       && exp->X_add_number == 0
@@ -1798,7 +3189,8 @@ emit_expr (exp, nbytes)
       use = get & unmask;
       if ((get & mask) != 0 && (get & mask) != mask)
        {               /* Leading bits contain both 0s & 1s. */
       use = get & unmask;
       if ((get & mask) != 0 && (get & mask) != mask)
        {               /* Leading bits contain both 0s & 1s. */
-         as_warn ("Value 0x%lx truncated to 0x%lx.", 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);
        }
       /* put bytes in right order. */
       md_number_to_chars (p, use, (int) nbytes);
@@ -1857,7 +3249,7 @@ emit_expr (exp, nbytes)
     }
   else
     {
     }
   else
     {
-      md_number_to_chars (p, (valueT) 0, (int) 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
 
       /* Now we need to generate a fixS to record the symbol value.
         This is easy for BFD.  For other targets it can be more
@@ -1872,11 +3264,31 @@ emit_expr (exp, nbytes)
 #ifdef TC_CONS_FIX_NEW
       TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
 #else
 #ifdef TC_CONS_FIX_NEW
       TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
 #else
-      fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0,
-                  /* @@ Should look at CPU word size.  */
-                  nbytes == 2 ? BFD_RELOC_16
-                  : nbytes == 8 ? BFD_RELOC_64
-                  : BFD_RELOC_32);
+      {
+       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
 #endif
 #else
 #ifdef TC_CONS_FIX_NEW
@@ -1947,7 +3359,7 @@ parse_bitfield_cons (exp, nbytes)
             widths, positions, and masks which most
             of our current object formats don't
             support.
             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
             In the specific case where a symbol
             *is* defined in this assembly, we
             *could* build fixups and track it, but
@@ -2024,20 +3436,34 @@ parse_bitfield_cons (exp, nbytes)
 
 #endif /* BITFIELD_CONS_EXPRESSIONS */
 \f
 
 #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;
 {
 
 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;
       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++)
        {
       input_line_pointer++;
       for (scan = 0; scan < nbytes; scan++)
        {
@@ -2073,11 +3499,7 @@ parse_mri_cons (exp, nbytes)
       else
        input_line_pointer++;
     }
       else
        input_line_pointer++;
     }
-  else
-    expression (&exp);
 }
 }
-
-#endif /* MRI */
 \f
 #ifdef REPEAT_CONS_EXPRESSIONS
 
 \f
 #ifdef REPEAT_CONS_EXPRESSIONS
 
@@ -2120,6 +3542,97 @@ parse_repeat_cons (exp, nbytes)
 
 #endif /* REPEAT_CONS_EXPRESSIONS */
 \f
 
 #endif /* REPEAT_CONS_EXPRESSIONS */
 \f
+/* 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;
+{
+  int length;
+  int i;
+
+  switch (float_type)
+    {
+    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;
+    }
+
+  /* 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 == '_')
+    {
+      int d;
+
+      /* The MRI assembler accepts arbitrary underscores strewn about
+        through the hex constant, so we ignore them as well. */
+      if (*input_line_pointer == '_')
+       {
+         ++input_line_pointer;
+         continue;
+       }
+
+      if (i >= length)
+       {
+         as_warn ("Floating point constant too large");
+         return -1;
+       }
+      d = hex_value (*input_line_pointer) << 4;
+      ++input_line_pointer;
+      while (*input_line_pointer == '_')
+       ++input_line_pointer;
+      if (hex_p (*input_line_pointer))
+       {
+         d += hex_value (*input_line_pointer);
+         ++input_line_pointer;
+       }
+      if (target_big_endian)
+       bytes[i] = d;
+      else
+       bytes[length - i - 1] = d;
+      ++i;
+    }
+
+  if (i < length)
+    {
+      if (target_big_endian)
+       memset (bytes + i, 0, length - i);
+      else
+       memset (bytes, 0, length - i);
+    }
+
+  return length;
+}
+
 /*
  *                     float_cons()
  *
 /*
  *                     float_cons()
  *
@@ -2156,6 +3669,10 @@ float_cons (float_type)
       return;
     }
 
       return;
     }
 
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
   do
     {
       /* input_line_pointer->1st char of a flonum (we hope!). */
   do
     {
       /* input_line_pointer->1st char of a flonum (we hope!). */
@@ -2169,14 +3686,29 @@ float_cons (float_type)
       if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
        input_line_pointer += 2;
 
       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)
+      /* 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 ();
-         return;
+         ++input_line_pointer;
+         length = hex_float (float_type, temp);
+         if (length < 0)
+           {
+             ignore_rest_of_line ();
+             return;
+           }
+       }
+      else
+       {
+         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)
        }
 
       if (!need_pass_2)
@@ -2232,6 +3764,10 @@ stringer (append_zero)           /* Worker to do .ascii etc statements. */
 {
   register unsigned int c;
 
 {
   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
   /*
    * The following awkward logic is to parse ZERO or more strings,
    * comma seperated. Recall a string expression includes spaces
@@ -2304,6 +3840,11 @@ next_char_of_string ()
       c = NOT_A_CHAR;
       break;
 
       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++)
 #ifndef NO_STRING_ESCAPES
     case '\\':
       switch (c = *input_line_pointer++)
@@ -2328,11 +3869,9 @@ next_char_of_string ()
          c = '\t';
          break;
 
          c = '\t';
          break;
 
-#ifdef BACKSLASH_V
        case 'v':
          c = '\013';
          break;
        case 'v':
          c = '\013';
          break;
-#endif
 
        case '\\':
        case '"':
 
        case '\\':
        case '"':
@@ -2387,6 +3926,7 @@ next_char_of_string ()
          /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
          as_warn ("Unterminated string: Newline inserted.");
          c = '\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;
 
        default:
@@ -2459,7 +3999,7 @@ get_absolute_expression ()
   if (exp.X_op != O_constant)
     {
       if (exp.X_op != O_absent)
   if (exp.X_op != O_constant)
     {
       if (exp.X_op != O_absent)
-       as_bad ("bad absolute expression; zero assumed");
+       as_bad ("bad or irreducible absolute expression; zero assumed");
       exp.X_add_number = 0;
     }
   return exp.X_add_number;
       exp.X_add_number = 0;
     }
   return exp.X_add_number;
@@ -2490,9 +4030,7 @@ demand_copy_C_string (len_pointer)
     {
       register int len;
 
     {
       register int len;
 
-      for (len = *len_pointer;
-          len > 0;
-          len--)
+      for (len = *len_pointer; len > 0; len--)
        {
          if (*s == 0)
            {
        {
          if (*s == 0)
            {
@@ -2503,7 +4041,7 @@ demand_copy_C_string (len_pointer)
            }
        }
     }
            }
        }
     }
-  return (s);
+  return s;
 }
 \f
 /*
 }
 \f
 /*
@@ -2531,8 +4069,8 @@ demand_copy_string (lenP)
          obstack_1grow (&notes, c);
          len++;
        }
          obstack_1grow (&notes, 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 (&notes, '\0');
       retval = obstack_finish (&notes);
     }
       obstack_1grow (&notes, '\0');
       retval = obstack_finish (&notes);
     }
@@ -2567,6 +4105,8 @@ equals (sym_name)
      char *sym_name;
 {
   register symbolS *symbolP;   /* symbol we are working with */
      char *sym_name;
 {
   register symbolS *symbolP;   /* symbol we are working with */
+  char *stop;
+  char stopc;
 
   input_line_pointer++;
   if (*input_line_pointer == '=')
 
   input_line_pointer++;
   if (*input_line_pointer == '=')
@@ -2575,30 +4115,27 @@ equals (sym_name)
   while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
     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;
   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)
 
       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);
       pseudo_set (symbolP);
     }
     }
   else
     {
       symbolP = symbol_find_or_make (sym_name);
       pseudo_set (symbolP);
     }
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
 }                              /* equals() */
 
 /* .include -- include a file at this point. */
 }                              /* equals() */
 
 /* .include -- include a file at this point. */
@@ -2614,7 +4151,25 @@ s_include (arg)
   FILE *try;
   char *path;
 
   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 (&notes, *input_line_pointer);
+         ++input_line_pointer;
+         ++i;
+       }
+      obstack_1grow (&notes, '\0');
+      filename = obstack_finish (&notes);
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
   demand_empty_rest_of_line ();
   path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ );
   for (i = 0; i < include_dir_count; i++)
   demand_empty_rest_of_line ();
   path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ );
   for (i = 0; i < include_dir_count; i++)
@@ -2622,7 +4177,7 @@ s_include (arg)
       strcpy (path, include_dirs[i]);
       strcat (path, "/");
       strcat (path, filename);
       strcpy (path, include_dirs[i]);
       strcat (path, "/");
       strcat (path, filename);
-      if (0 != (try = fopen (path, FOPEN_RT)))
+      if (0 != (try = fopen (path, "r")))
        {
          fclose (try);
          goto gotit;
        {
          fclose (try);
          goto gotit;
@@ -2674,4 +4229,11 @@ s_ignore (arg)
 }
 
 
 }
 
 
+void
+read_print_statistics (file)
+     FILE *file;
+{
+  hash_print_statistics (file, "pseudo-op table", po_hash);
+}
+
 /* end of read.c */
 /* end of read.c */
This page took 0.05669 seconds and 4 git commands to generate.