* config/obj-coff.c (fixup_segment): Make sure that symbols are
[deliverable/binutils-gdb.git] / gas / read.c
index c06f35418d3a1c7334c912c8cd4f91f4b3936f70..12bfa6e93b10c0b3462edd8e2af50eda14d29145 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -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
-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
@@ -42,9 +42,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 #include "as.h"
 #include "subsegs.h"
-
+#include "sb.h"
+#include "macro.h"
+#include "libiberty.h"
 #include "obstack.h"
 #include "listing.h"
+#include "ecoff.h"
 
 #ifndef TC_START_LABEL
 #define TC_START_LABEL(x,y) (x==':')
@@ -83,13 +86,23 @@ die horribly;
 #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[] */
-const char lex_type[256] =
+char lex_type[256] =
 {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      /* @ABCDEFGHIJKLMNO */
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      /* PQRSTUVWXYZ[\]^_ */
-  0, 0, 0, 0, 3, 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 */
@@ -169,11 +182,35 @@ struct broken_word *broken_words;
 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));
-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 int get_line_sb PARAMS ((sb *));
 \f
 
 void
@@ -186,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.  */
-  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. */
+
+  if (flag_mri)
+    lex_type['?'] = 3;
 }
 \f
 /* set up pseudo-op tables */
 
-struct hash_control *po_hash;
+static struct hash_control *po_hash;
 
 static const pseudo_typeS potable[] =
 {
@@ -206,10 +246,37 @@ static const pseudo_typeS potable[] =
   {"ascii", stringer, 0},
   {"asciz", stringer, 1},
   {"balign", s_align_bytes, 0},
+  {"balignw", s_align_bytes, -2},
+  {"balignl", s_align_bytes, -4},
 /* block */
   {"byte", cons, 1},
   {"comm", s_comm, 0},
+  {"common", s_mri_common, 0},
+  {"common.s", s_mri_common, 1},
   {"data", s_data, 0},
+  {"dc", cons, 2},
+  {"dc.b", cons, 1},
+  {"dc.d", float_cons, 'd'},
+  {"dc.l", cons, 4},
+  {"dc.s", float_cons, 'f'},
+  {"dc.w", cons, 2},
+  {"dc.x", float_cons, 'x'},
+  {"dcb", s_space, 2},
+  {"dcb.b", s_space, 1},
+  {"dcb.d", s_float_space, 'd'},
+  {"dcb.l", s_space, 4},
+  {"dcb.s", s_float_space, 'f'},
+  {"dcb.w", s_space, 2},
+  {"dcb.x", s_float_space, 'x'},
+  {"ds", s_space, 2},
+  {"ds.b", s_space, 1},
+  {"ds.d", s_space, 8},
+  {"ds.l", s_space, 4},
+  {"ds.p", s_space, 12},
+  {"ds.s", s_space, 4},
+  {"ds.w", s_space, 2},
+  {"ds.x", s_space, 12},
+  {"debug", s_ignore, 0},
 #ifdef S_SET_DESC
   {"desc", s_desc, 0},
 #endif
@@ -218,41 +285,76 @@ static const pseudo_typeS potable[] =
 /* dsect */
   {"eject", listing_eject, 0}, /* Formfeed listing */
   {"else", s_else, 0},
+  {"elsec", s_else, 0},
   {"end", s_end, 0},
+  {"endc", s_endif, 0},
   {"endif", s_endif, 0},
 /* endef */
   {"equ", s_set, 0},
-/* err */
+  {"err", s_err, 0},
+  {"exitm", s_mexit, 0},
 /* extend */
   {"extern", s_ignore, 0},     /* We treat all undef as ext */
   {"appfile", s_app_file, 1},
   {"appline", s_app_line, 0},
+  {"fail", s_fail, 0},
   {"file", s_app_file, 0},
   {"fill", s_fill, 0},
   {"float", float_cons, 'f'},
+  {"format", s_ignore, 0},
   {"global", s_globl, 0},
   {"globl", s_globl, 0},
   {"hword", cons, 2},
-  {"if", s_if, 0},
+  {"if", s_if, (int) O_ne},
+  {"ifc", s_ifc, 0},
   {"ifdef", s_ifdef, 0},
+  {"ifeq", s_if, (int) O_eq},
   {"ifeqs", s_ifeqs, 0},
+  {"ifge", s_if, (int) O_ge},
+  {"ifgt", s_if, (int) O_gt},
+  {"ifle", s_if, (int) O_le},
+  {"iflt", s_if, (int) O_lt},
+  {"ifnc", s_ifc, 1},
   {"ifndef", s_ifdef, 1},
+  {"ifne", s_if, (int) O_ne},
   {"ifnes", s_ifeqs, 1},
   {"ifnotdef", s_ifdef, 1},
   {"include", s_include, 0},
   {"int", cons, 4},
+  {"irp", s_irp, 0},
+  {"irep", s_irp, 0},
+  {"irpc", s_irp, 1},
+  {"irepc", s_irp, 1},
   {"lcomm", s_lcomm, 0},
   {"lflags", listing_flags, 0},        /* Listing flags */
+  {"linkonce", s_linkonce, 0},
   {"list", listing_list, 1},   /* Turn listing on */
+  {"llen", listing_psize, 1},
   {"long", cons, 4},
   {"lsym", s_lsym, 0},
+  {"macro", s_macro, 0},
+  {"mexit", s_mexit, 0},
+  {"mri", s_mri, 0},
+  {".mri", s_mri, 0},  /* Special case so .mri works in MRI mode.  */
+  {"name", s_ignore, 0},
+  {"noformat", s_ignore, 0},
   {"nolist", listing_list, 0}, /* Turn listing off */
+  {"nopage", listing_nopage, 0},
   {"octa", cons, 16},
+  {"offset", s_struct, 0},
   {"org", s_org, 0},
   {"p2align", s_align_ptwo, 0},
+  {"p2alignw", s_align_ptwo, -2},
+  {"p2alignl", s_align_ptwo, -4},
+  {"page", listing_eject, 0},
+  {"plen", listing_psize, 0},
+  {"print", s_print, 0},
   {"psize", listing_psize, 0}, /* set paper size */
-/* print */
+  {"purgem", s_purgem, 0},
   {"quad", cons, 8},
+  {"rep", s_rept, 0},
+  {"rept", s_rept, 0},
+  {"rva", s_rva, 4},
   {"sbttl", listing_title, 1}, /* Subtitle of listing */
 /* scl */
 /* sect */
@@ -261,10 +363,13 @@ static const pseudo_typeS potable[] =
   {"single", float_cons, 'f'},
 /* size */
   {"space", s_space, 0},
+  {"skip", s_space, 0},
+  {"spc", s_ignore, 0},
   {"stabd", s_stab, 'd'},
   {"stabn", s_stab, 'n'},
   {"stabs", s_stab, 's'},
   {"string", stringer, 1},
+  {"struct", s_struct, 0},
 /* tag */
   {"text", s_text, 0},
 
@@ -279,9 +384,13 @@ static const pseudo_typeS potable[] =
   {"this_gcc_requires_the_gnu_assembler", s_ignore, 0},
 
   {"title", listing_title, 0}, /* Listing title */
+  {"ttl", listing_title, 0},
 /* type */
 /* use */
 /* val */
+  {"xcom", s_comm, 0},
+  {"xdef", s_globl, 0},
+  {"xref", s_ignore, 0},
   {"xstabs", s_xstab, 's'},
   {"word", cons, 2},
   {"zero", s_space, 0},
@@ -301,7 +410,8 @@ pop_insert (table)
     {
       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", pop_table_name);
+       as_fatal ("error constructing %s pseudo-op table: %s", pop_table_name,
+                 errtxt);
     }
 }
 
@@ -342,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
@@ -378,26 +506,61 @@ read_a_source_file (name)
           */
          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 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.
@@ -441,7 +604,27 @@ read_a_source_file (name)
               */
              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 ();
@@ -460,11 +643,6 @@ read_a_source_file (name)
                }
              else
                {               /* expect pseudo-op or machine instruction */
-#ifdef MRI
-                 if (!done_pseudo (s))
-
-#else
-
                  pop = NULL;
 
 #define IGNORE_OPCODE_CASE
@@ -480,14 +658,21 @@ read_a_source_file (name)
                  }
 #endif
 
+                 if (flag_m68k_mri
 #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
+                     )
+                   {
+                     /* 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.
@@ -500,6 +685,20 @@ read_a_source_file (name)
                      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)
                        {
@@ -522,19 +721,33 @@ read_a_source_file (name)
                       * 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
-#endif
                    {           /* 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]
+                            || inquote
 #ifdef TC_EOL_IN_INSN
                             || TC_EOL_IN_INSN (input_line_pointer)
 #endif
                             )
                        {
+                         if (flag_m68k_mri && *input_line_pointer == '\'')
+                           inquote = ! inquote;
                          input_line_pointer++;
                        }
 
@@ -557,6 +770,25 @@ read_a_source_file (name)
                        }
 #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;
@@ -573,8 +805,8 @@ read_a_source_file (name)
          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;
@@ -589,8 +821,8 @@ read_a_source_file (name)
                  ++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;
@@ -604,20 +836,17 @@ read_a_source_file (name)
                  colon (dollar_label_name (temp, 0));
                  continue;
                }
-#endif /* LOCAL_LABELS_DOLLAR */
 
-#ifdef LOCAL_LABELS_FB
-             if (*input_line_pointer++ == ':')
+             if (LOCAL_LABELS_FB
+                 && *input_line_pointer++ == ':')
                {
                  fb_label_instance_inc (temp);
                  colon (fb_label_name (temp, 0));
                  continue;
                }
-#endif /* LOCAL_LABELS_FB */
 
              input_line_pointer = backup;
            }                   /* local label  ("4:") */
-#endif /* LOCAL_LABELS_DOLLAR or LOCAL_LABELS_FB */
 
          if (c && strchr (line_comment_chars, c))
            {                   /* Its a comment.  Better say APP or NO_APP */
@@ -626,7 +855,6 @@ read_a_source_file (name)
              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;
@@ -678,26 +906,30 @@ read_a_source_file (name)
                {
                  input_line_pointer = ends + 8;
                }
-             new_buf = xmalloc (100);
-             new_length = 100;
-             new_tmp = new_buf;
 
              scrub_string = s;
-             scrub_last_string = ends;
+             scrub_string_end = ends;
+
+             new_length = ends - s;
+             new_buf = (char *) xmalloc (new_length);
+             new_tmp = new_buf;
              for (;;)
                {
-                 int ch;
+                 int space;
+                 int size;
+
+                 space = (new_buf + new_length) - new_tmp;
+                 size = do_scrub_chars (scrub_from_string, new_tmp, space);
 
-                 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)
+                 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)
@@ -713,12 +945,23 @@ read_a_source_file (name)
 
          HANDLE_CONDITIONAL_ASSEMBLY ();
 
+#ifdef tc_unrecognized_line
+         if (tc_unrecognized_line (c))
+           continue;
+#endif
+
          /* as_warn("Junk character %d.",c);  Now done by ignore_rest */
          input_line_pointer--; /* Report unknown char as ignored. */
          ignore_rest_of_line ();
        }                       /* while (input_line_pointer<buffer_limit) */
+
+#ifdef md_after_pass_hook
+      md_after_pass_hook ();
+#endif
+
       if (old_buffer)
        {
+         free (buffer);
          bump_line_counters ();
          if (old_input != 0)
            {
@@ -730,10 +973,71 @@ read_a_source_file (name)
            }
        }
     }                          /* while (more buffers to scan) */
+
+ quit:
   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 
 s_abort (ignore)
      int ignore;
@@ -743,12 +1047,13 @@ s_abort (ignore)
 
 /* Guts of .align directive.  */
 static void 
-do_align (n, fill)
+do_align (n, fill, len)
      int n;
      char *fill;
+     int len;
 {
 #ifdef md_do_align
-  md_do_align (n, fill, just_record_alignment);
+  md_do_align (n, fill, len, just_record_alignment);
 #endif
   if (!fill)
     {
@@ -764,10 +1069,17 @@ do_align (n, fill)
        {
          fill = &zero;
        }
+      len = 1;
     }
+
   /* 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:
@@ -785,9 +1097,19 @@ s_align_bytes (arg)
   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])
-    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 ();
 
@@ -809,24 +1131,56 @@ s_align_bytes (arg)
   temp = i;
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       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
-    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 
-s_align_ptwo (ignore)
-     int ignore;
+s_align_ptwo (arg)
+     int arg;
 {
   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)
@@ -838,12 +1192,39 @@ s_align_ptwo (ignore)
     }
   if (*input_line_pointer == ',')
     {
+      offsetT fillval;
+      int len;
+
       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
-    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 ();
 }
@@ -857,6 +1238,11 @@ s_comm (ignore)
   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 ();
@@ -867,6 +1253,8 @@ s_comm (ignore)
   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;
     }
@@ -874,6 +1262,8 @@ s_comm (ignore)
   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;
     }
@@ -884,6 +1274,8 @@ s_comm (ignore)
     {
       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;
     }
@@ -908,9 +1300,119 @@ s_comm (ignore)
   }
 #endif /* not OBJ_VMS */
   know (symbolP->sy_frag == &zero_address_frag);
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+
   demand_empty_rest_of_line ();
 }                              /* s_comm() */
 
+/* The MRI COMMON pseudo-op.  We handle this by creating a common
+   symbol with the appropriate name.  We make s_space do the right
+   thing by increasing the size.  */
+
+void
+s_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;
@@ -936,11 +1438,11 @@ s_data (ignore)
 }
 
 /* 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)
@@ -956,6 +1458,14 @@ s_app_file (appfile)
         the buffer.  Passing -2 to new_logical_line tells it to
         account for it.  */
       new_logical_line (s, appfile ? -2 : -1);
+
+      /* In MRI mode, the preprocessor may have inserted an extraneous
+         backquote.  */
+      if (flag_m68k_mri
+         && *input_line_pointer == '\''
+         && is_end_of_line[(unsigned char) input_line_pointer[1]])
+       ++input_line_pointer;
+
       demand_empty_rest_of_line ();
 #ifdef LISTING
       if (listing)
@@ -968,9 +1478,9 @@ s_app_file (appfile)
 }
 
 /* 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)
@@ -995,6 +1505,60 @@ s_app_line (ignore)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .end pseudo-op.  Actually, the real work is done in
+   read_a_source_file.  */
+
+void
+s_end (ignore)
+     int ignore;
+{
+  if (flag_mri)
+    {
+      /* The MRI assembler permits the start symbol to follow .end,
+         but we don't support that.  */
+      SKIP_WHITESPACE ();
+      if (! is_end_of_line[(unsigned char) *input_line_pointer]
+         && *input_line_pointer != '*'
+         && *input_line_pointer != '!')
+       as_warn ("start address not supported");
+    }
+}
+
+/* Handle the .err pseudo-op.  */
+
+void
+s_err (ignore)
+     int ignore;
+{
+  as_bad (".err encountered");
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI fail pseudo-op.  */
+
+void
+s_fail (ignore)
+     int ignore;
+{
+  offsetT temp;
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
+
+  temp = get_absolute_expression ();
+  if (temp >= 500)
+    as_warn (".fail %ld encountered", (long) temp);
+  else
+    as_bad (".fail %ld encountered", (long) temp);
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+
+  demand_empty_rest_of_line ();
+}
+
 void 
 s_fill (ignore)
      int ignore;
@@ -1004,6 +1568,9 @@ s_fill (ignore)
   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 == ',')
@@ -1030,7 +1597,8 @@ s_fill (ignore)
     }
   else if (temp_repeat <= 0)
     {
-      as_warn ("Repeat < 0, .fill ignored");
+      if (temp_repeat < 0)
+       as_warn ("Repeat < 0, .fill ignored");
       temp_size = 0;
     }
 
@@ -1063,6 +1631,11 @@ s_globl (ignore)
   char *name;
   int c;
   symbolS *symbolP;
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
 
   do
     {
@@ -1081,6 +1654,118 @@ s_globl (ignore)
        }
     }
   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 ();
 }
 
@@ -1129,14 +1814,21 @@ s_lcomm (needs_align)
     }
 
 #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
    if (!needs_align)
      {
@@ -1148,7 +1840,12 @@ s_lcomm (needs_align)
        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);
      }
@@ -1186,7 +1883,7 @@ s_lcomm (needs_align)
   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;
@@ -1234,6 +1931,10 @@ s_lcomm (needs_align)
          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'.",
@@ -1306,45 +2007,446 @@ s_lsym (ignore)
   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;
 {
-  register segT segment;
-  expressionS exp;
-  register long temp_fill;
-  register char *p;
-  /* 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.
+  register segT segment;
+  expressionS exp;
+  register long temp_fill;
+
+  /* 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.
+
+     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;
 
-     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.
+  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)
@@ -1383,20 +2485,11 @@ s_set (ignore)
       /* Turn '. = mumble' into a .org mumble */
       register segT segment;
       expressionS exp;
-      register char *ptr;
 
       segment = get_known_segmented_expression (&exp);
 
       if (!need_pass_2)
-       {
-         if (segment != now_seg && segment != absolute_section)
-           as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
-                   segment_name (segment),
-                   segment_name (now_seg));
-         ptr = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
-                         exp.X_add_number, (char *) 0);
-         *ptr = 0;
-       }                       /* if (ok to make frag) */
+       do_org (segment, &exp, 0);
 
       *end_name = delim;
       return;
@@ -1425,50 +2518,249 @@ s_space (mult)
      int mult;
 {
   expressionS exp;
-  long temp_fill;
+  expressionS val;
   char *p = 0;
+  char *stop = NULL;
+  char stopc;
 
-  /* Just like .fill, but temp_size = 1 */
-  expression (&exp);
-  if (exp.X_op == O_constant)
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  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)
     {
-      long repeat;
+      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;
 
-      repeat = exp.X_add_number;
-      if (mult)
-       repeat *= mult;
-      if (repeat <= 0)
+         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
        {
-         as_warn (".space repeat count is %s, ignored",
-                  repeat ? "negative" : "zero");
-         ignore_rest_of_line ();
-         return;
+         do_align (1, (char *) NULL, 0);
+         if (line_label != NULL)
+           {
+             line_label->sy_frag = frag_now;
+             S_SET_VALUE (line_label, frag_now_fix ());
+           }
        }
+    }
 
-      if (!need_pass_2)
-       p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
-                     repeat, (char *) 0);
+  expression (&exp);
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression (&val);
     }
   else
     {
-      if (!need_pass_2)
-       p = frag_var (rs_space, 1, 1, (relax_substateT) 0,
-                     make_expr_symbol (&exp), 0L, (char *) 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);
+       }
+    }
+  else
+    {
+      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;
+    }
+
+ 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_bad ("missing value");
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
+      ignore_rest_of_line ();
+      return;
     }
+
+  ++input_line_pointer;
+
   SKIP_WHITESPACE ();
-  if (*input_line_pointer == ',')
+
+  /* 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] == ':')
     {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
+      flen = hex_float (float_type, temp);
+      if (flen < 0)
+       {
+         if (flag_mri)
+           mri_comment_end (stop, stopc);
+         ignore_rest_of_line ();
+         return;
+       }
     }
   else
     {
-      temp_fill = 0;
+      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;
+       }
     }
-  if (p)
+
+  while (--count >= 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 ();
 }
 
@@ -1647,17 +2939,15 @@ pseudo_set (symbolP)
    are defined, which is the normal case, then only simple expressions
    are permitted.  */
 
+static void
+parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes));
+
 #ifndef TC_PARSE_CONS_EXPRESSION
 #ifdef BITFIELD_CONS_EXPRESSIONS
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
 static void 
 parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes));
 #endif
-#ifdef MRI
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_mri_cons (EXP)
-static void
-parse_mri_cons PARAMS ((expressionS *exp));
-#endif
 #ifdef REPEAT_CONS_EXPRESSIONS
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
 static void
@@ -1673,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. */
-void 
-cons (nbytes)
+static void 
+cons_worker (nbytes, rva)
      register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
+     int rva;
 {
+  int c;
   expressionS exp;
+  char *stop = NULL;
+  char stopc;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
 
   if (is_it_end_of_statement ())
     {
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
       demand_empty_rest_of_line ();
       return;
     }
 
+#ifdef md_cons_align
+  md_cons_align (nbytes);
+#endif
+
+  c = 0;
   do
     {
-      TC_PARSE_CONS_EXPRESSION (&exp, (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);
+      ++c;
     }
   while (*input_line_pointer++ == ',');
 
+  /* In MRI mode, after an odd number of bytes, we must align to an
+     even word boundary, unless the next instruction is a dc.b, ds.b
+     or dcb.b.  */
+  if (flag_mri && nbytes == 1 && (c & 1) != 0)
+    mri_pending_align = 1;
+
   input_line_pointer--;                /* Put terminator back into stream. */
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+
   demand_empty_rest_of_line ();
 }
 
+
+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.  */
 
@@ -1714,6 +3060,15 @@ emit_expr (exp, nbytes)
 
   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
@@ -1834,7 +3189,8 @@ emit_expr (exp, nbytes)
       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);
@@ -1908,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
-      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
@@ -2060,20 +3436,34 @@ parse_bitfield_cons (exp, nbytes)
 
 #endif /* BITFIELD_CONS_EXPRESSIONS */
 \f
-#ifdef MRI
+/* Handle an MRI style string expression.  */
 
 static void
 parse_mri_cons (exp, nbytes)
      expressionS *exp;
      unsigned int nbytes;
 {
-  if (*input_line_pointer == '\'')
+  if (*input_line_pointer != '\''
+      && (input_line_pointer[1] != '\''
+         || (*input_line_pointer != 'A'
+             && *input_line_pointer != 'E')))
+    TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+  else
     {
-      /* An MRI style string, cut into as many bytes as will fit into
-        a nbyte chunk, left justify if necessary, and separate with
-        commas so we can try again later */
       int scan = 0;
       unsigned int result = 0;
+
+      /* An MRI style string.  Cut into as many bytes as will fit into
+        a nbyte chunk, left justify if necessary, and separate with
+        commas so we can try again later.  */
+      if (*input_line_pointer == 'A')
+       ++input_line_pointer;
+      else if (*input_line_pointer == 'E')
+       {
+         as_bad ("EBCDIC constants are not supported");
+         ++input_line_pointer;
+       }
+
       input_line_pointer++;
       for (scan = 0; scan < nbytes; scan++)
        {
@@ -2109,11 +3499,7 @@ parse_mri_cons (exp, nbytes)
       else
        input_line_pointer++;
     }
-  else
-    expression (&exp);
 }
-
-#endif /* MRI */
 \f
 #ifdef REPEAT_CONS_EXPRESSIONS
 
@@ -2156,6 +3542,97 @@ parse_repeat_cons (exp, nbytes)
 
 #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()
  *
@@ -2192,6 +3669,10 @@ float_cons (float_type)
       return;
     }
 
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
   do
     {
       /* input_line_pointer->1st char of a flonum (we hope!). */
@@ -2205,14 +3686,29 @@ float_cons (float_type)
       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)
@@ -2268,6 +3764,10 @@ stringer (append_zero)           /* Worker to do .ascii etc statements. */
 {
   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
@@ -2340,6 +3840,11 @@ next_char_of_string ()
       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++)
@@ -2364,11 +3869,9 @@ next_char_of_string ()
          c = '\t';
          break;
 
-#ifdef BACKSLASH_V
        case 'v':
          c = '\013';
          break;
-#endif
 
        case '\\':
        case '"':
@@ -2423,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';
+         bump_line_counters ();
          break;
 
        default:
@@ -2526,9 +4030,7 @@ demand_copy_C_string (len_pointer)
     {
       register int len;
 
-      for (len = *len_pointer;
-          len > 0;
-          len--)
+      for (len = *len_pointer; len > 0; len--)
        {
          if (*s == 0)
            {
@@ -2539,7 +4041,7 @@ demand_copy_C_string (len_pointer)
            }
        }
     }
-  return (s);
+  return s;
 }
 \f
 /*
@@ -2567,8 +4069,8 @@ demand_copy_string (lenP)
          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);
     }
@@ -2603,6 +4105,8 @@ equals (sym_name)
      char *sym_name;
 {
   register symbolS *symbolP;   /* symbol we are working with */
+  char *stop;
+  char stopc;
 
   input_line_pointer++;
   if (*input_line_pointer == '=')
@@ -2611,30 +4115,27 @@ equals (sym_name)
   while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
     input_line_pointer++;
 
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
+
   if (sym_name[0] == '.' && sym_name[1] == '\0')
     {
       /* Turn '. = mumble' into a .org mumble */
       register segT segment;
       expressionS exp;
-      register char *p;
 
       segment = get_known_segmented_expression (&exp);
       if (!need_pass_2)
-       {
-         if (segment != now_seg && segment != absolute_section)
-           as_warn ("Illegal segment \"%s\". Segment \"%s\" assumed.",
-                    segment_name (segment),
-                    segment_name (now_seg));
-         p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
-                       exp.X_add_number, (char *) 0);
-         *p = 0;
-       }                       /* if (ok to make frag) */
+       do_org (segment, &exp, 0);
     }
   else
     {
       symbolP = symbol_find_or_make (sym_name);
       pseudo_set (symbolP);
     }
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
 }                              /* equals() */
 
 /* .include -- include a file at this point. */
@@ -2650,7 +4151,25 @@ s_include (arg)
   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++)
@@ -2710,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 */
This page took 0.048981 seconds and 4 git commands to generate.