Locale changes from Bruno Haible <haible@clisp.cons.org>.
[deliverable/binutils-gdb.git] / gas / gasp.c
index 11eb97e49a52af36a3d046ad0a2f45c1d5367121..4022408e51cc16d889b8d57addf40f7ff19b27e0 100644 (file)
@@ -1,5 +1,6 @@
 /* gasp.c - Gnu assembler preprocessor main program.
-   Copyright (C) 1994 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
    Written by Steve and Judy Chamberlain of Cygnus Support,
       sac@cygnus.com
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GASP; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+   along with GASP; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 /*
-
 This program translates the input macros and stuff into a form
 suitable for gas to consume.
 
-
-  gasp [-c] [-o <outfile>] <infile>*
-
-  -c copy source to output
-
+  gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
+
+  -s copy source to output
+  -c <char> comments are started with <char> instead of !
+  -u allow unreasonable stuff
+  -p print line numbers
+  -d print debugging stats
+  -s semi colons start comments
+  -a use alternate syntax
+     Pseudo ops can start with or without a .
+     Labels have to be in first column.
+  -I specify include dir
+    Macro arg parameters subsituted by name, don't need the &.
+     String can start with ' too.
+     Strings can be surrounded by <..>
+     A %<exp> in a string evaluates the expression
+     Literal char in a string with !
 */
 
+#include "config.h"
+#include "bin-bugs.h"
 
 #include <stdio.h>
-#include <ctype.h>
-#include "host.h"
-
-#define MAX_INCLUDES 30                /* Maximum include depth */
-#define MAX_REASONABLE 1000    /* Maximum number of expansions */
-
-int unreasonable;              /* -u on command line */
-int stats;                     /* -s on command line */
-int print_line_number;         /* -p flag on command line */
-int copysource;                        /* -c flag on command line */
-int warnings;                  /* Number of WARNINGs generated so far. */
-int errors;                    /* Number of ERRORs generated so far. */
-int fatals;                    /* Number of fatal ERRORs generated so far (either 0 or 1). */
-
-
+#include <string.h>
+#include <getopt.h>
 
-int radix = 10;                        /* Default radix */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 
-int had_end; /* Seen .END */
+#ifdef NEED_MALLOC_DECLARATION
+extern char *malloc ();
+#endif
 
-/* The output stream */
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "sb.h"
+#include "macro.h"
+#include "asintl.h"
+
+char *program_version = "1.2";
+
+/* This is normally declared in as.h, but we don't include that.  We
+   need the function because other files linked with gasp.c might call
+   it.  */
+extern void as_abort PARAMS ((const char *, int, const char *));
+
+/* The default obstack chunk size.  If we set this to zero, the
+   obstack code will use whatever will fit in a 4096 byte block.  This
+   is used by the hash table code used by macro.c.  */
+int chunksize = 0;
+
+#define MAX_INCLUDES 30                /* Maximum include depth.  */
+#define MAX_REASONABLE 1000    /* Maximum number of expansions.  */
+
+int unreasonable;              /* -u on command line.  */
+int stats;                     /* -d on command line.  */
+int print_line_number;         /* -p flag on command line.  */
+int copysource;                        /* -c flag on command line.  */
+int warnings;                  /* Number of WARNINGs generated so far.  */
+int errors;                    /* Number of ERRORs generated so far.  */
+int fatals;                    /* Number of fatal ERRORs generated so far (either 0 or 1).  */
+int alternate = 0;              /* -a on command line.  */
+int mri = 0;                   /* -M on command line.  */
+char comment_char = '!';
+int radix = 10;                        /* Default radix.  */
+
+int had_end; /* Seen .END.  */
+
+/* The output stream.  */
 FILE *outfile;
 
-
-/* Forward declarations. */
-static int condass_lookup_name();
-static int condass_on();
-static int get();
-static int get_and_process();
-static int get_token();
-static int getstring();
-static int include_next_index();
-static int macro_op();
-static int linecount();
-static int process_pseudo_op();
-static void include_pop();
-static void include_print_where_line();
-/* string blocks
-
-   I had a couple of choices when deciding upon this data structure.
-   gas uses null terminated strings for all its internal work.  This
-   often means that parts of the program that want to examine
-   substrings have to manipulate the data in the string to do the
-   right thing (a common operation is to single out a bit of text by
-   saving away the character after it, nulling it out, operating on
-   the substring and then replacing the character which was under the
-   null).  This is a pain and I remember a load of problems that I had with
-   code in gas which almost got this right.  Also, it's harder to grow and
-   allocate null terminated strings efficiently.
-
-   Obstacks provide all the functionality needed, but are too
-   complicated, hence the sb.
-
-   An sb is allocated by the caller, and is initialzed to point to an
-   sb_element.  sb_elements are kept on a free lists, and used when
-   needed, replaced onto the free list when unused.
- */
-
-#define max_power_two    30    /* don't allow strings more than
-                                  2^max_power_two long */
-/* structure of an sb */
-typedef struct sb
-  {
-    char *ptr;                 /* points to the current block. */
-    int len;                   /* how much is used. */
-    int pot;                   /* the maximum length is 1<<pot */
-    struct le *item;
-  }
-sb;
-
-/* Structure of the free list object of an sb */
-typedef struct le
-  {
-    struct le *next;
-    int size;
-    char data[1];
-  }
-sb_element;
-
-/* The free list */
-typedef struct
-  {
-    sb_element *size[max_power_two];
-  } sb_list_vector;
-
-sb_list_vector free_list;
-
-int string_count[max_power_two];
-
-/* the attributes of each character are stored as a bit pattern
-   chartype, which gives us quick tests. */
-
+/* The attributes of each character are stored as a bit pattern
+   chartype, which gives us quick tests.  */
 
 #define FIRSTBIT 1
 #define NEXTBIT  2
 #define SEPBIT   4
 #define WHITEBIT 8
-#define ISFIRSTCHAR(x)  (chartype[(unsigned)(x)] & FIRSTBIT)
-#define ISNEXTCHAR(x)   (chartype[(unsigned)(x)] & NEXTBIT)
-#define ISSEP(x)        (chartype[(unsigned)(x)] & SEPBIT)
-#define ISWHITE(x)      (chartype[(unsigned)(x)] & WHITEBIT)
-
+#define COMMENTBIT 16
+#define BASEBIT  32
+#define ISCOMMENTCHAR(x) (chartype[(unsigned char)(x)] & COMMENTBIT)
+#define ISFIRSTCHAR(x)  (chartype[(unsigned char)(x)] & FIRSTBIT)
+#define ISNEXTCHAR(x)   (chartype[(unsigned char)(x)] & NEXTBIT)
+#define ISSEP(x)        (chartype[(unsigned char)(x)] & SEPBIT)
+#define ISWHITE(x)      (chartype[(unsigned char)(x)] & WHITEBIT)
+#define ISBASE(x)       (chartype[(unsigned char)(x)] & BASEBIT)
 static char chartype[256];
 
-
 /* Conditional assembly uses the `ifstack'.  Each aif pushes another
    entry onto the stack, and sets the on flag if it should.  The aelse
    sets hadelse, and toggles on.  An aend pops a level.  We limit to
@@ -147,154 +124,224 @@ static char chartype[256];
    a bug in the user's macro structure.  */
 
 #define IFNESTING 100
-struct
-  {
-    int on;                    /* is the level being output */
-    int hadelse;               /* has an aelse been seen */
-  }
-ifstack[IFNESTING];
+struct {
+  int on;                      /* Is the level being output.  */
+  int hadelse;                 /* Has an aelse been seen.  */
+} ifstack[IFNESTING];
+
 int ifi;
 
 /* The final and intermediate results of expression evaluation are kept in
    exp_t's.  Note that a symbol is not an sb, but a pointer into the input
-   line.  It must be coped somewhere safe before the next line is read in. */
-
-typedef struct
-  {
-    char *name;
-    int len;
-  }
-symbol;
+   line.  It must be coped somewhere safe before the next line is read in.  */
 
-typedef struct
-  {
-    int value;                 /* constant part */
-    symbol add_symbol;         /* name part */
-    symbol sub_symbol;         /* name part */
-  }
-exp_t;
+typedef struct {
+  char *name;
+  int len;
+} symbol;
 
+typedef struct {
+  int value;                   /* Constant part.  */
+  symbol add_symbol;           /* Name part.  */
+  symbol sub_symbol;           /* Name part.  */
+} exp_t;
 
 /* Hashing is done in a pretty standard way.  A hash_table has a
    pointer to a vector of pointers to hash_entrys, and the size of the
    vector.  A hash_entry contains a union of all the info we like to
    store in hash table.  If there is a hash collision, hash_entries
-   with the same hash are kept in a chain. */
-
-/* What the data in a hash_entry means */
-typedef enum
-  {
-    hash_integer,              /* name->integer mapping */
-    hash_string,               /* name->string mapping */
-    hash_macro,                        /* name is a macro */
-    hash_formal                        /* name is a formal argument */
-  } hash_type;
-
-typedef struct hs
-  {
-    sb key;                    /* symbol name */
-    hash_type type;            /* symbol meaning */
-    union
-      {
-       sb s;
-       int i;
-       struct macro_struct *m;
-       struct formal_struct *f;
-      } value;
-    struct hs *next;           /* next hash_entry with same hash key */
-  } hash_entry;
-
-typedef struct
-  {
-    hash_entry **table;
-    int size;
-  } hash_table;
-
-
-/* Structures used to store macros. 
-
-   Each macro knows its name and included text.  It gets built with a
-   list of formal arguments, and also keeps a hash table which points
-   into the list to speed up formal search.  Each formal knows its
-   name and its default value.  Each time the macro is expanded, the
-   formals get the actual values attatched to them. */
-
-/* describe the formal arguments to a macro */
-
-typedef struct formal_struct
-  {
-    struct formal_struct *next;        /* next formal in list */
-    sb name;                   /* name of the formal */
-    sb def;                    /* the default value */
-    sb actual;                 /* the actual argument (changed on each expansion) */
-    int index;                 /* the index of the formal 0..formal_count-1 */
-  }
-formal_entry;
-
-/* describe the macro. */
-
-typedef struct macro_struct
-  {
-    sb sub;                    /* substitution text. */
-    int formal_count;          /* number of formal args. */
-    formal_entry *formals;     /* pointer to list of formal_structs */
-    hash_table formal_hash;    /* hash table of formals. */
-  }
-macro_entry;
-
-/* how we nest files and expand macros etc.
-
-   we keep a stack of of include_stack structs.  each include file
-   pushes a new level onto the stack.  we keep an sb with a pushback
+   with the same hash are kept in a chain.  */
+
+/* What the data in a hash_entry means.  */
+typedef enum {
+  hash_integer,                        /* Name->integer mapping.  */
+  hash_string,                 /* Name->string mapping.  */
+  hash_macro,                  /* Name is a macro.  */
+  hash_formal                  /* Name is a formal argument.  */
+} hash_type;
+
+typedef struct hs {
+  sb key;                      /* Symbol name.  */
+  hash_type type;              /* Symbol meaning.  */
+  union {
+    sb s;
+    int i;
+    struct macro_struct *m;
+    struct formal_struct *f;
+  } value;
+  struct hs *next;             /* Next hash_entry with same hash key.  */
+} hash_entry;
+
+typedef struct {
+  hash_entry **table;
+  int size;
+} hash_table;
+
+/* How we nest files and expand macros etc.
+
+   We keep a stack of of include_stack structs.  Each include file
+   pushes a new level onto the stack.  We keep an sb with a pushback
    too.  unget chars are pushed onto the pushback sb, getchars first
    checks the pushback sb before reading from the input stream.
 
-   small things are expanded by adding the text of the item onto the
-   pushback sb.  larger items are grown by pushing a new level and
-   allocating the entire pushback buf for the item.  each time
-   something like a macro is expanded, the stack index is changed. we
+   Small things are expanded by adding the text of the item onto the
+   pushback sb.  Larger items are grown by pushing a new level and
+   allocating the entire pushback buf for the item.  Each time
+   something like a macro is expanded, the stack index is changed.  We
    can then perform an exitm by popping all entries off the stack with
-   the same stack index.  if we're being reasonable, we can detect
-   recusive expansion by checking the index is reasonably small.
- */
-
-typedef enum
-  {
-    include_file, include_repeat, include_while, include_macro
-  } include_type;
-
-struct include_stack
-  {
-    sb pushback;               /* current pushback stream */
-    int pushback_index;                /* next char to read from stream */
-    FILE *handle;              /* open file */
-    sb name;                   /* name of file */
-    int linecount;             /* number of lines read so far */
-    include_type type;
-    int index;                 /* index of this layer */
-  }
-include_stack[MAX_INCLUDES];
+   the same stack index.  If we're being reasonable, we can detect
+   recusive expansion by checking the index is reasonably small.  */
+
+typedef enum {
+  include_file, include_repeat, include_while, include_macro
+} include_type;
+
+struct include_stack {
+  sb pushback;                 /* Current pushback stream.  */
+  int pushback_index;          /* Next char to read from stream.  */
+  FILE *handle;                        /* Open file.  */
+  sb name;                     /* Name of file.  */
+  int linecount;               /* Number of lines read so far.  */
+  include_type type;
+  int index;                   /* Index of this layer.  */
+} include_stack[MAX_INCLUDES];
 
 struct include_stack *sp;
 #define isp (sp - include_stack)
 
-#define dsize 5
-
-
-void include_print_where_line ();
-
-
-#define FATAL(x) \
-  do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0) 
-#define ERROR(x) \
-  do { include_print_where_line (stderr); fprintf x; errors++; } while(0)
-#define WARNING(x) \
-  do { include_print_where_line (stderr); fprintf x; warnings++;} while(0) 
-
-
+/* Include file list.  */
+
+typedef struct include_path {
+  struct include_path *next;
+  sb path;
+} include_path;
+
+include_path *paths_head;
+include_path *paths_tail;
+
+static void quit PARAMS ((void));
+static void hash_new_table PARAMS ((int, hash_table *));
+static int hash PARAMS ((sb *));
+static hash_entry *hash_create PARAMS ((hash_table *, sb *));
+static void hash_add_to_string_table PARAMS ((hash_table *, sb *, sb *, int));
+static void hash_add_to_int_table PARAMS ((hash_table *, sb *, int));
+static hash_entry *hash_lookup PARAMS ((hash_table *, sb *));
+static void checkconst PARAMS ((int, exp_t *));
+static int sb_strtol PARAMS ((int, sb *, int, int *));
+static int level_0 PARAMS ((int, sb *, exp_t *));
+static int level_1 PARAMS ((int, sb *, exp_t *));
+static int level_2 PARAMS ((int, sb *, exp_t *));
+static int level_3 PARAMS ((int, sb *, exp_t *));
+static int level_4 PARAMS ((int, sb *, exp_t *));
+static int level_5 PARAMS ((int, sb *, exp_t *));
+static int exp_parse PARAMS ((int, sb *, exp_t *));
+static void exp_string PARAMS ((exp_t *, sb *));
+static int exp_get_abs PARAMS ((const char *, int, sb *, int *));
+#if 0
+static void strip_comments PARAMS ((sb *));
+#endif
+static void unget PARAMS ((int));
+static void include_buf PARAMS ((sb *, sb *, include_type, int));
+static void include_print_where_line PARAMS ((FILE *));
+static void include_print_line PARAMS ((FILE *));
+static int get_line PARAMS ((sb *));
+static int grab_label PARAMS ((sb *, sb *));
+static void change_base PARAMS ((int, sb *, sb *));
+static void do_end PARAMS ((sb *));
+static void do_assign PARAMS ((int, int, sb *));
+static void do_radix PARAMS ((sb *));
+static int get_opsize PARAMS ((int, sb *, int *));
+static int eol PARAMS ((int, sb *));
+static void do_data PARAMS ((int, sb *, int));
+static void do_datab PARAMS ((int, sb *));
+static void do_align PARAMS ((int, sb *));
+static void do_res PARAMS ((int, sb *, int));
+static void do_export PARAMS ((sb *));
+static void do_print PARAMS ((int, sb *));
+static void do_heading PARAMS ((int, sb *));
+static void do_page PARAMS ((void));
+static void do_form PARAMS ((int, sb *));
+static int get_any_string PARAMS ((int, sb *, sb *, int, int));
+static int skip_openp PARAMS ((int, sb *));
+static int skip_closep PARAMS ((int, sb *));
+static int dolen PARAMS ((int, sb *, sb *));
+static int doinstr PARAMS ((int, sb *, sb *));
+static int dosubstr PARAMS ((int, sb *, sb *));
+static void process_assigns PARAMS ((int, sb *, sb *));
+static int get_and_process PARAMS ((int, sb *, sb *));
+static void process_file PARAMS ((void));
+static void free_old_entry PARAMS ((hash_entry *));
+static void do_assigna PARAMS ((int, sb *));
+static void do_assignc PARAMS ((int, sb *));
+static void do_reg PARAMS ((int, sb *));
+static int condass_lookup_name PARAMS ((sb *, int, sb *, int));
+static int whatcond PARAMS ((int, sb *, int *));
+static int istrue PARAMS ((int, sb *));
+static void do_aif PARAMS ((int, sb *));
+static void do_aelse PARAMS ((void));
+static void do_aendi PARAMS ((void));
+static int condass_on PARAMS ((void));
+static void do_if PARAMS ((int, sb *, int));
+static int get_mri_string PARAMS ((int, sb *, sb *, int));
+static void do_ifc PARAMS ((int, sb *, int));
+static void do_aendr PARAMS ((void));
+static void do_awhile PARAMS ((int, sb *));
+static void do_aendw PARAMS ((void));
+static void do_exitm PARAMS ((void));
+static void do_arepeat PARAMS ((int, sb *));
+static void do_endm PARAMS ((void));
+static void do_irp PARAMS ((int, sb *, int));
+static void do_local PARAMS ((int, sb *));
+static void do_macro PARAMS ((int, sb *));
+static int macro_op PARAMS ((int, sb *));
+static int getstring PARAMS ((int, sb *, sb *));
+static void do_sdata PARAMS ((int, sb *, int));
+static void do_sdatab PARAMS ((int, sb *));
+static int new_file PARAMS ((const char *));
+static void do_include PARAMS ((int, sb *));
+static void include_pop PARAMS ((void));
+static int get PARAMS ((void));
+static int linecount PARAMS ((void));
+static int include_next_index PARAMS ((void));
+static void chartype_init PARAMS ((void));
+static int process_pseudo_op PARAMS ((int, sb *, sb *));
+static void add_keyword PARAMS ((const char *, int));
+static void process_init PARAMS ((void));
+static void do_define PARAMS ((const char *));
+static void show_usage PARAMS ((FILE *, int));
+static void show_help PARAMS ((void));
+
+#define FATAL(x)                               \
+  do                                           \
+    {                                          \
+      include_print_where_line (stderr);       \
+      fprintf x;                               \
+      fatals++;                                        \
+      quit ();                                 \
+    }                                          \
+  while (0)
+
+#define ERROR(x)                               \
+  do                                           \
+    {                                          \
+      include_print_where_line (stderr);       \
+      fprintf x;                               \
+      errors++;                                        \
+    }                                          \
+  while (0)
+
+#define WARNING(x)                             \
+  do                                           \
+    {                                          \
+      include_print_where_line (stderr);       \
+      fprintf x;                               \
+      warnings++;                              \
+    }                                          \
+  while (0)
+
+/* Exit the program and return the right ERROR code.  */
 
-/* exit the program and return the right ERROR code. */
-void
+static void
 quit ()
 {
   int exitcode;
@@ -303,268 +350,37 @@ quit ()
   else
     exitcode = 0;
 
-  if (stats) 
+  if (stats)
     {
       int i;
-      for (i = 0; i < max_power_two; i++) 
+      for (i = 0; i < sb_max_power_two; i++)
        {
-         fprintf (stderr, "strings size %8d : %d\n", 1<<i, string_count[i]);
+         fprintf (stderr, "strings size %8d : %d\n",
+                  1 << i, string_count[i]);
        }
     }
   exit (exitcode);
 }
 
-static
-char *
-xmalloc (x)
-     int x;
-{
-  char *p = malloc (x);
-  if (!p)
-    FATAL ((stderr, "out of memory\n"));
-  memset (p, 0, x);
-  return p;
-}
-
-/* this program is about manipulating strings.
-   they are managed in things called `sb's which is an abbreviation
-   for string buffers.  an sb has to be created, things can be glued
-   on to it, and at the end of it's life it should be freed.  the
-   contents should never be pointed at whilst it is still growing,
-   since it could be moved at any time
-
-   eg:
-   sb_new (&foo);
-   sb_grow... (&foo,...);
-   use foo->ptr[*];
-   sb_kill (&foo);
-
-*/
-
-/* initializes an sb. */
-
-void
-sb_build (ptr, size)
-     sb *ptr;
-     int size;
-{
-  /* see if we can find one to allocate */
-  sb_element *e;
-
-  if (size > max_power_two)
-    {
-      FATAL ((stderr, "string longer than %d bytes requested.\n",
-             1 << max_power_two));
-    }
-  e = free_list.size[size];
-  if (!e)
-    {
-      /* nothing there, allocate one and stick into the free list */
-      e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
-      e->next = free_list.size[size];
-      e->size = 1 << size;
-      free_list.size[size] = e;
-      string_count[size]++;
-    }
-
-  /* remove from free list */
-
-  free_list.size[size] = e->next;
-
-  /* copy into callers world */
-  ptr->ptr = e->data;
-  ptr->pot = size;
-  ptr->len = 0;
-  ptr->item = e;
-}
-
-
-static void
-sb_new (ptr)
-     sb *ptr;
-{
-  sb_build (ptr, dsize);
-}
-
-/* deallocate the sb at ptr */
-
-static
-void
-sb_kill (ptr)
-     sb *ptr;
-{
-  /* return item to free list */
-  ptr->item->next = free_list.size[ptr->pot];
-  free_list.size[ptr->pot] = ptr->item;
-}
-
-/* add the sb at s to the end of the sb at ptr */
-
-static void sb_check ();
-
-static
-void
-sb_add_sb (ptr, s)
-     sb *ptr;
-     sb *s;
-{
-  sb_check (ptr, s->len);
-  memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
-  ptr->len += s->len;
-}
-
-/* make sure that the sb at ptr has room for another len characters,
-   and grow it if it doesn't. */
-
-static void
-sb_check (ptr, len)
-     sb *ptr;
-     int len;
-{
-  if (ptr->len + len >= 1 << ptr->pot)
-    {
-      sb tmp;
-      int pot = ptr->pot;
-      while (ptr->len + len >= 1 << pot)
-       pot++;
-      sb_build (&tmp, pot);
-      sb_add_sb (&tmp, ptr);
-      sb_kill (ptr);
-      *ptr = tmp;
-    }
-}
-
-/* make the sb at ptr point back to the beginning.  */
-
-static void
-sb_reset (ptr)
-     sb *ptr;
-{
-  ptr->len = 0;
-}
-
-/* add character c to the end of the sb at ptr. */
-
-void
-sb_add_char (ptr, c)
-     sb *ptr;
-     char c;
-{
-  sb_check (ptr, 1);
-  ptr->ptr[ptr->len++] = c;
-}
-
-/* add null terminated string s to the end of sb at ptr. */
-
-static void
-sb_add_string (ptr, s)
-     sb *ptr;
-     char *s;
-{
-  int len = strlen (s);
-  sb_check (ptr, len);
-  memcpy (ptr->ptr + ptr->len, s, len);
-  ptr->len += len;
-}
-
-/* add string at s of length len to sb at ptr */
-
-static void
-sb_add_buffer (ptr, s, len)
-     sb *ptr;
-     char *s;
-     int len;
-{
-  sb_check (ptr, len);
-  memcpy (ptr->ptr + ptr->len, s, len);
-  ptr->len += len;
-}
-
-
-/* print the sb at ptr to the output file */
-
-static
-void
-sb_print (ptr)
-     sb *ptr;
-{
-  int i;
-  int nc = 0;
-
-  for (i = 0; i < ptr->len; i++)
-    {
-      if (nc)
-       {
-         fprintf (outfile, ",");
-       }
-      fprintf (outfile, "%d", ptr->ptr[i]);
-      nc = 1;
-    }
-}
-
-/* put a null at the end of the sb at in and return the start of the
-   string, so that it can be used as an arg to printf %s. */
-
-static
-char *
-sb_name (in)
-     sb *in;
-{
-  /* stick a null on the end of the string */
-  sb_add_char (in, 0);
-  return in->ptr;
-}
-
-/* start at the index idx into the string in sb at ptr and skip
-   whitespace. return the index of the first non whitespace character */
-
-static int
-sb_skip_white (idx, ptr)
-     int idx;
-     sb *ptr;
-{
-  while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
-    idx++;
-  return idx;
-}
-
-/* start at the index idx into the sb at ptr. skips whitespace,
-   a comma and any following whitespace. returnes the index of the
-   next character. */
-
-static int
-sb_skip_comma (idx, ptr)
-     int idx;
-     sb *ptr;
-{
-  while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
-    idx++;
-
-  if (idx < ptr->len
-      && ptr->ptr[idx] == ',')
-    idx++;
-
-  while (idx < ptr->len && ISWHITE (ptr->ptr[idx]))
-    idx++;
-
-  return idx;
-}
-
+/* Hash table maintenance.  */
 
-/* hash table maintenance. */
-
-/* build a new hash table with size buckets, and fill in the info at ptr. */
+/* Build a new hash table with size buckets
+   and fill in the info at ptr.  */
 
 static void
 hash_new_table (size, ptr)
      int size;
      hash_table *ptr;
 {
+  int i;
   ptr->size = size;
   ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *)));
+  /* Fill with null-pointer, not zero-bit-pattern.  */
+  for (i = 0; i < size; i++)
+    ptr->table[i] = 0;
 }
 
-/* calculate and return the hash value of the sb at key. */
+/* Calculate and return the hash value of the sb at key.  */
 
 static int
 hash (key)
@@ -581,11 +397,10 @@ hash (key)
   return k & 0xf0fff;
 }
 
-/* lookup key in hash_table tab, if present, then return it, otherwise
-   build a new one and fill it with hash_integer. */
+/* Look up key in hash_table tab.  If present, then return it,
+   otherwise build a new one and fill it with hash_integer.  */
 
-static
-hash_entry *
+static hash_entry *
 hash_create (tab, key)
      hash_table *tab;
      sb *key;
@@ -616,11 +431,10 @@ hash_create (tab, key)
     }
 }
 
-/* add sb name with key into hash_table tab.  if replacing old value
-   and again, then ERROR. */
+/* Add sb name with key into hash_table tab.
+   If replacing old value and again, then ERROR.  */
 
-static
-void
+static void
 hash_add_to_string_table (tab, key, name, again)
      hash_table *tab;
      sb *key;
@@ -635,16 +449,18 @@ hash_add_to_string_table (tab, key, name, again)
   if (ptr->value.s.len)
     {
       if (!again)
-       ERROR ((stderr, "redefintion not allowed"));
+       ERROR ((stderr, _("redefinition not allowed\n")));
     }
+
+  ptr->type = hash_string;
   sb_reset (&ptr->value.s);
+
   sb_add_sb (&ptr->value.s, name);
 }
 
-/* add integer name to hash_table tab with sb key. */
+/* Add integer name to hash_table tab with sb key.  */
 
-static
-void
+static void
 hash_add_to_int_table (tab, key, name)
      hash_table *tab;
      sb *key;
@@ -654,11 +470,10 @@ hash_add_to_int_table (tab, key, name)
   ptr->value.i = name;
 }
 
-/* lookup sb key in hash_table tab.  if found return hash_entry result,
-   else 0. */
-   
-static
-hash_entry *
+/* Look up sb key in hash_table tab.
+   If found, return hash_entry result, else 0.  */
+
+static hash_entry *
 hash_lookup (tab, key)
      hash_table *tab;
      sb *key;
@@ -676,7 +491,6 @@ hash_lookup (tab, key)
   return 0;
 }
 
-
 /* expressions
 
    are handled in a really simple recursive decent way. each bit of
@@ -687,35 +501,31 @@ hash_lookup (tab, key)
  expression precedence:
   ( )
  unary + - ~
-* /
-+ -
-&
-| ~
-
+  * /
+  + -
+  &
+  | ~
 */
 
+/* Make sure that the exp_t at term is constant.
+   If not the give the op ERROR.  */
 
-/* make sure that the exp_t at term is constant, if not the give the op ERROR. */
-
-static
-void
+static void
 checkconst (op, term)
-     char op;
+     int op;
      exp_t *term;
 {
   if (term->add_symbol.len
       || term->sub_symbol.len)
     {
-      ERROR ((stderr, "the %c operator cannot take non-absolute arguments.\n", op));
+      ERROR ((stderr, _("the %c operator cannot take non-absolute arguments.\n"), op));
     }
 }
 
-/* turn the number in string at idx into a number of base,
-   fill in ptr and return the index of the first character not in the
-   number. */
+/* Turn the number in string at idx into a number of base, fill in
+   ptr, and return the index of the first character not in the number.  */
 
-static
-int
+static int
 sb_strtol (idx, string, base, ptr)
      int idx;
      sb *string;
@@ -729,12 +539,12 @@ sb_strtol (idx, string, base, ptr)
     {
       int ch = string->ptr[idx];
       int dig = 0;
-      if (isdigit (ch))
+      if (ISDIGIT (ch))
        dig = ch - '0';
       else if (ch >= 'a' && ch <= 'f')
        dig = ch - 'a' + 10;
-      else if (ch >= 'a' && ch <= 'f')
-       dig = ch - 'a' + 10;
+      else if (ch >= 'A' && ch <= 'F')
+       dig = ch - 'A' + 10;
       else
        break;
 
@@ -748,9 +558,7 @@ sb_strtol (idx, string, base, ptr)
   return idx;
 }
 
-static int level_5 ();
-
-int
+static int
 level_0 (idx, string, lhs)
      int idx;
      sb *string;
@@ -766,7 +574,7 @@ level_0 (idx, string, lhs)
 
   lhs->value = 0;
 
-  if (isdigit (string->ptr[idx]))
+  if (ISDIGIT (string->ptr[idx]))
     {
       idx = sb_strtol (idx, string, 10, &lhs->value);
     }
@@ -785,20 +593,18 @@ level_0 (idx, string, lhs)
     {
       sb acc;
       sb_new (&acc);
-      ERROR ((stderr, "string where expression expected.\n"));
+      ERROR ((stderr, _("string where expression expected.\n")));
       idx = getstring (idx, string, &acc);
       sb_kill (&acc);
     }
   else
     {
-      ERROR ((stderr, "can't find primary in expression.\n"));
+      ERROR ((stderr, _("can't find primary in expression.\n")));
       idx++;
     }
   return sb_skip_white (idx, string);
 }
 
-
-
 static int
 level_1 (idx, string, lhs)
      int idx;
@@ -831,7 +637,7 @@ level_1 (idx, string, lhs)
       idx++;
       idx = level_5 (sb_skip_white (idx, string), string, lhs);
       if (string->ptr[idx] != ')')
-       ERROR ((stderr, "misplaced closing parens.\n"));
+       ERROR ((stderr, _("misplaced closing parens.\n")));
       else
        idx++;
       break;
@@ -868,7 +674,7 @@ level_2 (idx, string, lhs)
          checkconst ('/', lhs);
          checkconst ('/', &rhs);
          if (rhs.value == 0)
-           ERROR ((stderr, "attempt to divide by zero.\n"));
+           ERROR ((stderr, _("attempt to divide by zero.\n")));
          else
            lhs->value /= rhs.value;
          break;
@@ -877,7 +683,6 @@ level_2 (idx, string, lhs)
   return sb_skip_white (idx, string);
 }
 
-
 static int
 level_3 (idx, string, lhs)
      int idx;
@@ -900,9 +705,9 @@ level_3 (idx, string, lhs)
          lhs->value += rhs.value;
          if (lhs->add_symbol.name && rhs.add_symbol.name)
            {
-             ERROR ((stderr, "can't add two relocatable expressions\n"));
+             ERROR ((stderr, _("can't add two relocatable expressions\n")));
            }
-         /* change nn+symbol to symbol + nn */
+         /* Change nn+symbol to symbol + nn.  */
          if (rhs.add_symbol.name)
            {
              lhs->add_symbol = rhs.add_symbol;
@@ -976,10 +781,9 @@ level_5 (idx, string, lhs)
   return sb_skip_white (idx, string);
 }
 
-
-/* parse the expression at offset idx into string, fill up res with
-   the result. return the index of the first char past the expression.
-   */
+/* Parse the expression at offset idx into string, fill up res with
+   the result.  Return the index of the first char past the
+   expression.  */
 
 static int
 exp_parse (idx, string, res)
@@ -990,9 +794,8 @@ exp_parse (idx, string, res)
   return level_5 (sb_skip_white (idx, string), string, res);
 }
 
-
-/* turn the expression at exp into text and glue it onto the end of
-   string. */
+/* Turn the expression at exp into text and glue it onto the end of
+   string.  */
 
 static void
 exp_string (exp, string)
@@ -1031,14 +834,13 @@ exp_string (exp, string)
     sb_add_char (string, '0');
 }
 
-
-/* parse the expression at offset idx into sb in, return the value in val.  
-   if the expression is not constant, give ERROR emsg.  returns the index
-   of the first character past the end of the expression. */
+/* Parse the expression at offset idx into sb in.  Return the value in
+   val.  If the expression is not constant, give ERROR emsg.  Return
+   the index of the first character past the end of the expression.  */
 
 static int
 exp_get_abs (emsg, idx, in, val)
-     char *emsg;
+     const char *emsg;
      int idx;
      sb *in;
      int *val;
@@ -1046,21 +848,27 @@ exp_get_abs (emsg, idx, in, val)
   exp_t res;
   idx = exp_parse (idx, in, &res);
   if (res.add_symbol.len || res.sub_symbol.len)
-    ERROR ((stderr, emsg));
+    ERROR ((stderr, "%s", emsg));
   *val = res.value;
   return idx;
 }
 
+/* Current label parsed from line.  */
+sb label;
+
+/* Hash table for all assigned variables.  */
+hash_table assign_hash_table;
 
-sb label; /* current label parsed from line */
-hash_table assign_hash_table;   /* hash table for all assigned variables */
-hash_table keyword_hash_table;  /* hash table for keyword */
-hash_table vars;  /* hash table for  eq variables */
+/* Hash table for keyword.  */
+hash_table keyword_hash_table;
+
+/* Hash table for eq variables.  */
+hash_table vars;
 
 #define in_comment ';'
 
 #if 0
-void
+static void
 strip_comments (out)
      sb *out;
 {
@@ -1068,7 +876,7 @@ strip_comments (out)
   int i = 0;
   for (i = 0; i < out->len; i++)
     {
-      if (s[i] == in_comment)
+      if (ISCOMMENTCHAR (s[i]))
        {
          out->len = i;
          return;
@@ -1077,9 +885,9 @@ strip_comments (out)
 }
 #endif
 
-/* push back character ch so that it can be read again. */
+/* Push back character ch so that it can be read again.  */
 
-void
+static void
 unget (ch)
      int ch;
 {
@@ -1093,10 +901,10 @@ unget (ch)
     sb_add_char (&sp->pushback, ch);
 }
 
-/* push the sb ptr onto the include stack, with the given name, type and index. */
+/* Push the sb ptr onto the include stack, with the given name, type
+   and index.  */
 
-static
-void
+static void
 include_buf (name, ptr, type, index)
      sb *name;
      sb *ptr;
@@ -1105,7 +913,7 @@ include_buf (name, ptr, type, index)
 {
   sp++;
   if (sp - include_stack >= MAX_INCLUDES)
-    FATAL ((stderr, "unreasonable nesting.\n"));
+    FATAL ((stderr, _("unreasonable nesting.\n")));
   sb_new (&sp->name);
   sb_add_sb (&sp->name, name);
   sp->handle = 0;
@@ -1117,10 +925,10 @@ include_buf (name, ptr, type, index)
   sb_add_sb (&sp->pushback, ptr);
 }
 
+/* Used in ERROR messages, print info on where the include stack is
+   onto file.  */
 
-/* used in ERROR messages, print info on where the include stack is onto file. */
-static 
-void
+static void
 include_print_where_line (file)
      FILE *file;
 {
@@ -1128,12 +936,13 @@ include_print_where_line (file)
 
   while (p <= sp)
     {
-      fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - ((p == sp) ? 1 : 0));
+      fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - 1);
       p++;
     }
 }
 
-/* used in listings, print the line number onto file. */
+/* Used in listings, print the line number onto file.  */
+
 static void
 include_print_line (file)
      FILE *file;
@@ -1155,8 +964,7 @@ include_print_line (file)
     }
 }
 
-
-/* read a line from the top of the include stack into sb in. */
+/* Read a line from the top of the include stack into sb in.  */
 
 static int
 get_line (in)
@@ -1167,7 +975,7 @@ get_line (in)
 
   if (copysource)
     {
-      putc ('!', outfile);
+      putc (comment_char, outfile);
       if (print_line_number)
        include_print_line (outfile);
     }
@@ -1183,11 +991,13 @@ get_line (in)
        {
          if (online)
            {
-             WARNING ((stderr, "end of file not at start of line.\n"));
+             WARNING ((stderr, _("End of file not at start of line.\n")));
              if (copysource)
                putc ('\n', outfile);
+             ch = '\n';
            }
-         more = 0;
+         else
+           more = 0;
          break;
        }
 
@@ -1202,10 +1012,10 @@ get_line (in)
          online = 0;
          if (ch == '+')
            {
-             /* continued line */
+             /* Continued line.  */
              if (copysource)
                {
-                 putc ('!', outfile);
+                 putc (comment_char, outfile);
                  putc ('+', outfile);
                }
              ch = get ();
@@ -1227,7 +1037,7 @@ get_line (in)
   return more;
 }
 
-/* find a label from sb in and put it in out. */
+/* Find a label from sb in and put it in out.  */
 
 static int
 grab_label (in, out)
@@ -1236,11 +1046,14 @@ grab_label (in, out)
 {
   int i = 0;
   sb_reset (out);
-  if (ISFIRSTCHAR (in->ptr[i]))
+  if (ISFIRSTCHAR (in->ptr[i]) || in->ptr[i] == '\\')
     {
       sb_add_char (out, in->ptr[i]);
       i++;
-      while (ISNEXTCHAR (in->ptr[i]) && i < in->len)
+      while ((ISNEXTCHAR (in->ptr[i])
+             || in->ptr[i] == '\\'
+             || in->ptr[i] == '&')
+            && i < in->len)
        {
          sb_add_char (out, in->ptr[i]);
          i++;
@@ -1249,8 +1062,8 @@ grab_label (in, out)
   return i;
 }
 
-/* find all strange base stuff and turn into decimal. also
-   find all the other numbers and convert them from the default radix */
+/* Find all strange base stuff and turn into decimal.  Also
+   find all the other numbers and convert them from the default radix */
 
 static void
 change_base (idx, in, out)
@@ -1262,7 +1075,21 @@ change_base (idx, in, out)
 
   while (idx < in->len)
     {
-      if (idx < in->len - 1 && in->ptr[idx + 1] == '\'')
+      if (in->ptr[idx] == '\\'
+         && idx + 1 < in->len
+         && in->ptr[idx + 1] == '(')
+       {
+         idx += 2;
+         while (idx < in->len
+                && in->ptr[idx] != ')')
+           {
+             sb_add_char (out, in->ptr[idx]);
+             idx++;
+           }
+         if (idx < in->len)
+           idx++;
+       }
+      else if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri)
        {
          int base;
          int value;
@@ -1285,7 +1112,7 @@ change_base (idx, in, out)
              base = 10;
              break;
            default:
-             ERROR ((stderr, "Illegal base character %c.\n", in->ptr[idx]));
+             ERROR ((stderr, _("Illegal base character %c.\n"), in->ptr[idx]));
              base = 10;
              break;
            }
@@ -1296,7 +1123,7 @@ change_base (idx, in, out)
        }
       else if (ISFIRSTCHAR (in->ptr[idx]))
        {
-         /* copy entire names through quickly */
+         /* Copy entire names through quickly.  */
          sb_add_char (out, in->ptr[idx]);
          idx++;
          while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
@@ -1305,25 +1132,37 @@ change_base (idx, in, out)
              idx++;
            }
        }
-      else if (isdigit (in->ptr[idx]))
+      else if (ISDIGIT (in->ptr[idx]))
        {
          int value;
-         /* all numbers must start with a digit, let's chew it and
-            spit out decimal */
+         /* All numbers must start with a digit, let's chew it and
+            spit out decimal */
          idx = sb_strtol (idx, in, radix, &value);
          sprintf (buffer, "%d", value);
          sb_add_string (out, buffer);
 
-         /* skip all undigsested letters */
+         /* Skip all undigsested letters.  */
          while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
            {
              sb_add_char (out, in->ptr[idx]);
              idx++;
            }
        }
+      else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
+       {
+         char tchar = in->ptr[idx];
+         /* Copy entire names through quickly.  */
+         sb_add_char (out, in->ptr[idx]);
+         idx++;
+         while (idx < in->len && in->ptr[idx] != tchar)
+           {
+             sb_add_char (out, in->ptr[idx]);
+             idx++;
+           }
+       }
       else
        {
-         /* nothing special, just pass it through */
+         /* Nothing special, just pass it through.  */
          sb_add_char (out, in->ptr[idx]);
          idx++;
        }
@@ -1331,14 +1170,18 @@ change_base (idx, in, out)
 
 }
 
-/* .end */
+/* .end  */
+
 static void
-do_end ()
+do_end (in)
+     sb *in;
 {
   had_end = 1;
+  if (mri)
+    fprintf (outfile, "%s\n", sb_name (in));
 }
 
-/* .assign */
+/* .assign  */
 
 static void
 do_assign (again, idx, in)
@@ -1346,7 +1189,7 @@ do_assign (again, idx, in)
      int idx;
      sb *in;
 {
-  /* stick label in symbol table with following value */
+  /* Stick label in symbol table with following value.  */
   exp_t e;
   sb acc;
 
@@ -1357,11 +1200,9 @@ do_assign (again, idx, in)
   sb_kill (&acc);
 }
 
+/* .radix [b|q|d|h]  */
 
-/* .radix [b|q|d|h] */
-
-static
-void
+static void
 do_radix (ptr)
      sb *ptr;
 {
@@ -1385,60 +1226,85 @@ do_radix (ptr)
       radix = 16;
       break;
     default:
-      ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix));
+      ERROR ((stderr, _("radix is %c must be one of b, q, d or h"), radix));
     }
 }
 
-
-/* Parse off a .b, .w or .l */
+/* Parse off a .b, .w or .l.  */
 
 static int
 get_opsize (idx, in, size)
-int idx;
-sb *in;
-int *size;
+     int idx;
+     sb *in;
+     int *size;
 {
   *size = 4;
   if (in->ptr[idx] == '.')
     {
       idx++;
-      switch (in->ptr[idx])
-       {
-       case 'b':
-       case 'B':
-         *size = 1;
-         break;
-       case 'w':
-       case 'W':
-         *size = 2;
-         break;
-       case 'l':
-       case 'L':
-         *size = 4;
-         break;
-       default:
-         ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx]));
-         break;
-       }
-      idx++;
     }
+  switch (in->ptr[idx])
+    {
+    case 'b':
+    case 'B':
+      *size = 1;
+      break;
+    case 'w':
+    case 'W':
+      *size = 2;
+      break;
+    case 'l':
+    case 'L':
+      *size = 4;
+      break;
+    case ' ':
+    case '\t':
+      break;
+    default:
+      ERROR ((stderr, _("size must be one of b, w or l, is %c.\n"), in->ptr[idx]));
+      break;
+    }
+  idx++;
+
   return idx;
 }
 
-/* .data [.b|.w|.l] <data>* */
+static int
+eol (idx, line)
+     int idx;
+     sb *line;
+{
+  idx = sb_skip_white (idx, line);
+  if (idx < line->len
+      && ISCOMMENTCHAR(line->ptr[idx]))
+    return 1;
+  if (idx >= line->len)
+    return 1;
+  return 0;
+}
+
+/* .data [.b|.w|.l] <data>*
+    or d[bwl] <data>*  */
 
 static void
-do_data (idx, in)
+do_data (idx, in, size)
      int idx;
      sb *in;
+     int size;
 {
   int opsize = 4;
-  char *opname;
+  char *opname = ".yikes!";
   sb acc;
   sb_new (&acc);
 
-  idx = get_opsize (idx, in, &opsize);
-
+  if (!size)
+    {
+      idx = get_opsize (idx, in, &opsize);
+    }
+  else
+    {
+      opsize = size;
+    }
   switch (opsize)
     {
     case 4:
@@ -1453,24 +1319,44 @@ do_data (idx, in)
     }
 
   fprintf (outfile, "%s\t", opname);
-  while (idx < in->len)
+
+  idx = sb_skip_white (idx, in);
+
+  if (alternate
+      && idx < in->len
+      && in->ptr[idx] == '"')
     {
-      exp_t e;
-      idx = exp_parse (idx, in, &e);
-      exp_string (&e, &acc);
-      sb_add_char (&acc, 0);
-      fprintf (outfile, acc.ptr);
-      if (idx < in->len && in->ptr[idx] == ',')
+      int i;
+      idx = getstring (idx, in, &acc);
+      for (i = 0; i < acc.len; i++)
        {
-         fprintf (outfile, ",");
-         idx++;
+         if (i)
+           fprintf (outfile, ",");
+         fprintf (outfile, "%d", acc.ptr[i]);
+       }
+    }
+  else
+    {
+      while (!eol (idx, in))
+       {
+         exp_t e;
+         idx = exp_parse (idx, in, &e);
+         exp_string (&e, &acc);
+         sb_add_char (&acc, 0);
+         fprintf (outfile, "%s", acc.ptr);
+         if (idx < in->len && in->ptr[idx] == ',')
+           {
+             fprintf (outfile, ",");
+             idx++;
+           }
        }
     }
   sb_kill (&acc);
+  sb_print_at (outfile, idx, in);
   fprintf (outfile, "\n");
 }
 
-/* .datab [.b|.w|.l] <repeat>,<fill> */
+/* .datab [.b|.w|.l] <repeat>,<fill>  */
 
 static void
 do_datab (idx, in)
@@ -1483,49 +1369,58 @@ do_datab (idx, in)
 
   idx = get_opsize (idx, in, &opsize);
 
-  idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat);
+  idx = exp_get_abs (_("datab repeat must be constant.\n"), idx, in, &repeat);
   idx = sb_skip_comma (idx, in);
-  idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill);
+  idx = exp_get_abs (_("datab data must be absolute.\n"), idx, in, &fill);
 
   fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
 }
 
-/* .align <size> */
+/* .align <size>  */
 
-void
+static void
 do_align (idx, in)
      int idx;
      sb *in;
 {
-  int al;
-  idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al);
+  int al, have_fill, fill;
 
-  if (al != 1
-      && al != 2
-      && al != 4)
-    WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n"));
+  idx = exp_get_abs (_("align needs absolute expression.\n"), idx, in, &al);
+  idx = sb_skip_white (idx, in);
+  have_fill = 0;
+  fill = 0;
+  if (! eol (idx, in))
+    {
+      idx = sb_skip_comma (idx, in);
+      idx = exp_get_abs (_(".align needs absolute fill value.\n"), idx, in,
+                        &fill);
+      have_fill = 1;
+    }
 
-  fprintf (outfile, ".align    %d\n", al);
+  fprintf (outfile, ".align    %d", al);
+  if (have_fill)
+    fprintf (outfile, ",%d", fill);
+  fprintf (outfile, "\n");
 }
 
-/* .res[.b|.w|.l] <size> */
+/* .res[.b|.w|.l] <size>  */
 
-void
+static void
 do_res (idx, in, type)
      int idx;
      sb *in;
-     char type;
+     int type;
 {
   int size = 4;
   int count = 0;
 
   idx = get_opsize (idx, in, &size);
-  while (idx < in->len)
+  while (!eol (idx, in))
     {
       idx = sb_skip_white (idx, in);
       if (in->ptr[idx] == ',')
        idx++;
-      idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count);
+      idx = exp_get_abs (_("res needs absolute expression for fill count.\n"), idx, in, &count);
 
       if (type == 'c' || type == 'z')
        count++;
@@ -1534,19 +1429,18 @@ do_res (idx, in, type)
     }
 }
 
+/* .export  */
 
-/* .export */
-
-void
+static void
 do_export (in)
      sb *in;
 {
   fprintf (outfile, ".global   %s\n", sb_name (in));
 }
 
-/* .print [list] [nolist] */
+/* .print [list] [nolist]  */
 
-void
+static void
 do_print (idx, in)
      int idx;
      sb *in;
@@ -1554,12 +1448,12 @@ do_print (idx, in)
   idx = sb_skip_white (idx, in);
   while (idx < in->len)
     {
-      if (strncmp (in->ptr + idx, "LIST", 4) == 0)
+      if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
        {
          fprintf (outfile, ".list\n");
          idx += 4;
        }
-      else if (strncmp (in->ptr + idx, "NOLIST", 6) == 0)
+      else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
        {
          fprintf (outfile, ".nolist\n");
          idx += 6;
@@ -1568,8 +1462,9 @@ do_print (idx, in)
     }
 }
 
-/* .head */
-void
+/* .head  */
+
+static void
 do_heading (idx, in)
      int idx;
      sb *in;
@@ -1581,16 +1476,17 @@ do_heading (idx, in)
   sb_kill (&head);
 }
 
-/* .page */
+/* .page  */
 
-void
+static void
 do_page ()
 {
   fprintf (outfile, ".eject\n");
 }
 
-/* .form [lin=<value>] [col=<value>] */
-void
+/* .form [lin=<value>] [col=<value>]  */
+
+static void
 do_form (idx, in)
      int idx;
      sb *in;
@@ -1602,16 +1498,16 @@ do_form (idx, in)
   while (idx < in->len)
     {
 
-      if (strncmp (in->ptr + idx, "LIN=", 4) == 0)
+      if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
        {
          idx += 4;
-         idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines);
+         idx = exp_get_abs (_("form LIN= needs absolute expresssion.\n"), idx, in, &lines);
        }
 
-      if (strncmp (in->ptr + idx, "COL=", 4) == 0)
+      if (strncasecmp (in->ptr + idx, _("COL="), 4) == 0)
        {
          idx += 4;
-         idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns);
+         idx = exp_get_abs (_("form COL= needs absolute expresssion.\n"), idx, in, &columns);
        }
 
       idx++;
@@ -1620,60 +1516,124 @@ do_form (idx, in)
 
 }
 
-int
-get_any_string (idx, in, out)
+/* Fetch string from the input stream,
+   rules:
+    'Bxyx<whitespace>          -> return 'Bxyza
+    %<char>            -> return string of decimal value of x
+    "<string>"         -> return string
+    xyx<whitespace>     -> return xyz
+*/
+
+static int
+get_any_string (idx, in, out, expand, pretend_quoted)
      int idx;
      sb *in;
      sb *out;
+     int expand;
+     int pretend_quoted;
 {
-  idx = sb_skip_white (idx, in);
-  if (idx < in->len && (in->ptr[idx] == '"'
-                       || in->ptr[idx] == '<'))
-    return getstring (idx, in, out);
-
   sb_reset (out);
+  idx = sb_skip_white (idx, in);
 
-  while (idx < in->len && !ISSEP (in->ptr[idx]))
+  if (idx < in->len)
     {
-      sb_add_char (out, in->ptr[idx++]);
+      if (in->len > 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
+       {
+         while (!ISSEP (in->ptr[idx]))
+           sb_add_char (out, in->ptr[idx++]);
+       }
+      else if (in->ptr[idx] == '%'
+              && alternate
+              && expand)
+       {
+         int val;
+         char buf[20];
+         /* Turns the next expression into a string.  */
+         idx = exp_get_abs (_("% operator needs absolute expression"),
+                            idx + 1,
+                            in,
+                            &val);
+         sprintf (buf, "%d", val);
+         sb_add_string (out, buf);
+       }
+      else if (in->ptr[idx] == '"'
+              || in->ptr[idx] == '<'
+              || (alternate && in->ptr[idx] == '\''))
+       {
+         if (alternate && expand)
+           {
+             /* Keep the quotes.  */
+             sb_add_char (out, '\"');
+
+             idx = getstring (idx, in, out);
+             sb_add_char (out, '\"');
+
+           }
+         else
+           {
+             idx = getstring (idx, in, out);
+           }
+       }
+      else
+       {
+         while (idx < in->len
+                && (in->ptr[idx] == '"'
+                    || in->ptr[idx] == '\''
+                    || pretend_quoted
+                    || !ISSEP (in->ptr[idx])))
+           {
+             if (in->ptr[idx] == '"'
+                 || in->ptr[idx] == '\'')
+               {
+                 char tchar = in->ptr[idx];
+                 sb_add_char (out, in->ptr[idx++]);
+                 while (idx < in->len
+                        && in->ptr[idx] != tchar)
+                   sb_add_char (out, in->ptr[idx++]);
+                 if (idx == in->len)
+                   return idx;
+               }
+             sb_add_char (out, in->ptr[idx++]);
+           }
+       }
     }
+
   return idx;
 }
 
+/* Skip along sb in starting at idx, suck off whitespace a ( and more
+   whitespace.  Return the idx of the next char.  */
 
-/* skip along sb in starting at idx, suck off whitespace a ( and more
-   whitespace.  return the idx of the next char */
-
-int
+static int
 skip_openp (idx, in)
      int idx;
      sb *in;
 {
   idx = sb_skip_white (idx, in);
   if (in->ptr[idx] != '(')
-    ERROR ((stderr, "misplaced ( .\n"));
+    ERROR ((stderr, _("misplaced ( .\n")));
   idx = sb_skip_white (idx + 1, in);
   return idx;
 }
 
-/* skip along sb in starting at idx, suck off whitespace a ) and more
-   whitespace.  return the idx of the next char */
+/* Skip along sb in starting at idx, suck off whitespace a ) and more
+   whitespace.  Return the idx of the next char.  */
 
-int
+static int
 skip_closep (idx, in)
      int idx;
      sb *in;
 {
   idx = sb_skip_white (idx, in);
   if (in->ptr[idx] != ')')
-    ERROR ((stderr, "misplaced ).\n"));
+    ERROR ((stderr, _("misplaced ).\n")));
   idx = sb_skip_white (idx + 1, in);
   return idx;
 }
 
-/* .len */
+/* .len  */
 
-int
+static int
 dolen (idx, in, out)
      int idx;
      sb *in;
@@ -1694,11 +1654,9 @@ dolen (idx, in, out)
   return idx;
 }
 
+/* .instr  */
 
-/* .instr */
-
-static
-int
+static int
 doinstr (idx, in, out)
      int idx;
      sb *in;
@@ -1718,9 +1676,9 @@ doinstr (idx, in, out)
   idx = sb_skip_comma (idx, in);
   idx = get_and_process (idx, in, &search);
   idx = sb_skip_comma (idx, in);
-  if (isdigit (in->ptr[idx]))
+  if (ISDIGIT (in->ptr[idx]))
     {
-      idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start);
+      idx = exp_get_abs (_(".instr needs absolute expresson.\n"), idx, in, &start);
     }
   else
     {
@@ -1743,7 +1701,6 @@ doinstr (idx, in, out)
   return idx;
 }
 
-
 static int
 dosubstr (idx, in, out)
      int idx;
@@ -1758,19 +1715,18 @@ dosubstr (idx, in, out)
   idx = skip_openp (idx, in);
   idx = get_and_process (idx, in, &string);
   idx = sb_skip_comma (idx, in);
-  idx = exp_get_abs ("need absolute position.\n", idx, in, &pos);
+  idx = exp_get_abs (_("need absolute position.\n"), idx, in, &pos);
   idx = sb_skip_comma (idx, in);
-  idx = exp_get_abs ("need absolute length.\n", idx, in, &len);
+  idx = exp_get_abs (_("need absolute length.\n"), idx, in, &len);
   idx = skip_closep (idx, in);
 
-
   if (len < 0 || pos < 0 ||
       pos > string.len
       || pos + len > string.len)
     {
       sb_add_string (out, " ");
     }
-  else 
+  else
     {
       sb_add_char (out, '"');
       while (len > 0)
@@ -1780,12 +1736,13 @@ dosubstr (idx, in, out)
        }
       sb_add_char (out, '"');
     }
-  sb_kill(&string);
+  sb_kill (&string);
   return idx;
 }
 
-/* scan line, change tokens in the hash table to their replacements */
-void
+/* Scan line, change tokens in the hash table to their replacements.  */
+
+static void
 process_assigns (idx, in, buf)
      int idx;
      sb *in;
@@ -1795,36 +1752,54 @@ process_assigns (idx, in, buf)
     {
       hash_entry *ptr;
       if (in->ptr[idx] == '\\'
+         && idx + 1 < in->len
+         && in->ptr[idx + 1] == '(')
+       {
+         do
+           {
+             sb_add_char (buf, in->ptr[idx]);
+             idx++;
+           }
+         while (idx < in->len && in->ptr[idx - 1] != ')');
+       }
+      else if (in->ptr[idx] == '\\'
+         && idx + 1 < in->len
          && in->ptr[idx + 1] == '&')
        {
-         idx = condass_lookup_name (in, idx + 2, buf);
+         idx = condass_lookup_name (in, idx + 2, buf, 1);
+       }
+      else if (in->ptr[idx] == '\\'
+              && idx + 1 < in->len
+              && in->ptr[idx + 1] == '$')
+       {
+         idx = condass_lookup_name (in, idx + 2, buf, 0);
        }
       else if (idx + 3 < in->len
               && in->ptr[idx] == '.'
-              && in->ptr[idx + 1] == 'L'
-              && in->ptr[idx + 2] == 'E'
-              && in->ptr[idx + 3] == 'N')
+              && TOUPPER (in->ptr[idx + 1]) == 'L'
+              && TOUPPER (in->ptr[idx + 2]) == 'E'
+              && TOUPPER (in->ptr[idx + 3]) == 'N')
        idx = dolen (idx + 4, in, buf);
       else if (idx + 6 < in->len
               && in->ptr[idx] == '.'
-              && in->ptr[idx + 1] == 'I'
-              && in->ptr[idx + 2] == 'N'
-              && in->ptr[idx + 3] == 'S'
-              && in->ptr[idx + 4] == 'T'
-              && in->ptr[idx + 5] == 'R')
+              && TOUPPER (in->ptr[idx + 1]) == 'I'
+              && TOUPPER (in->ptr[idx + 2]) == 'N'
+              && TOUPPER (in->ptr[idx + 3]) == 'S'
+              && TOUPPER (in->ptr[idx + 4]) == 'T'
+              && TOUPPER (in->ptr[idx + 5]) == 'R')
        idx = doinstr (idx + 6, in, buf);
       else if (idx + 7 < in->len
               && in->ptr[idx] == '.'
-              && in->ptr[idx + 1] == 'S'
-              && in->ptr[idx + 2] == 'U'
-              && in->ptr[idx + 3] == 'B'
-              && in->ptr[idx + 4] == 'S'
-              && in->ptr[idx + 5] == 'T'
-              && in->ptr[idx + 6] == 'R')
+              && TOUPPER (in->ptr[idx + 1]) == 'S'
+              && TOUPPER (in->ptr[idx + 2]) == 'U'
+              && TOUPPER (in->ptr[idx + 3]) == 'B'
+              && TOUPPER (in->ptr[idx + 4]) == 'S'
+              && TOUPPER (in->ptr[idx + 5]) == 'T'
+              && TOUPPER (in->ptr[idx + 6]) == 'R')
        idx = dosubstr (idx + 7, in, buf);
       else if (ISFIRSTCHAR (in->ptr[idx]))
        {
-         /* may be a simple name subsitution, see if we have a word */
+         /* May be a simple name subsitution, see if we have a word.  */
          sb acc;
          int cur = idx + 1;
          while (cur < in->len
@@ -1836,12 +1811,12 @@ process_assigns (idx, in, buf)
          ptr = hash_lookup (&assign_hash_table, &acc);
          if (ptr)
            {
-             /* Found a definition for it */
+             /* Found a definition for it */
              sb_add_sb (buf, &ptr->value.s);
            }
          else
            {
-             /* No definition, just copy the word */
+             /* No definition, just copy the word */
              sb_add_sb (buf, &acc);
            }
          sb_kill (&acc);
@@ -1862,52 +1837,89 @@ get_and_process (idx, in, out)
 {
   sb t;
   sb_new (&t);
-  idx = get_any_string (idx, in, &t);
+  idx = get_any_string (idx, in, &t, 1, 0);
   process_assigns (0, &t, out);
   sb_kill (&t);
   return idx;
 }
 
-static
-void
+static void
 process_file ()
 {
   sb line;
   sb t1, t2;
   sb acc;
+  sb label_in;
   int more;
 
   sb_new (&line);
   sb_new (&t1);
   sb_new (&t2);
-  sb_new(&acc);
-
+  sb_new (&acc);
+  sb_new (&label_in);
   sb_reset (&line);
   more = get_line (&line);
   while (more)
     {
-      /* Find any label and pseudo op that we're intested in */
+      /* Find any label and pseudo op that we're intested in */
       int l;
       if (line.len == 0)
        {
          if (condass_on ())
            fprintf (outfile, "\n");
        }
+      else if (mri
+              && (line.ptr[0] == '*'
+                  || line.ptr[0] == '!'))
+       {
+         /* MRI line comment.  */
+         fprintf (outfile, "%s", sb_name (&line));
+       }
       else
        {
+         l = grab_label (&line, &label_in);
+         sb_reset (&label);
 
-         l = grab_label (&line, &label);
          if (line.ptr[l] == ':')
            l++;
          while (ISWHITE (line.ptr[l]) && l < line.len)
            l++;
 
-         if (line.len)
+         if (label_in.len)
            {
-             if (process_pseudo_op (l, &line, &acc))
+             int do_assigns;
+
+             /* Munge the label, unless this is EQU or ASSIGN.  */
+             do_assigns = 1;
+             if (l < line.len
+                 && (line.ptr[l] == '.' || alternate || mri))
                {
+                 int lx = l;
+
+                 if (line.ptr[lx] == '.')
+                   ++lx;
+                 if (lx + 3 <= line.len
+                     && strncasecmp ("EQU", line.ptr + lx, 3) == 0
+                     && (lx + 3 == line.len
+                         || ! ISFIRSTCHAR (line.ptr[lx + 3])))
+                   do_assigns = 0;
+                 else if (lx + 6 <= line.len
+                          && strncasecmp ("ASSIGN", line.ptr + lx, 6) == 0
+                          && (lx + 6 == line.len
+                              || ! ISFIRSTCHAR (line.ptr[lx + 6])))
+                   do_assigns = 0;
+               }
 
+             if (do_assigns)
+               process_assigns (0, &label_in, &label);
+             else
+               sb_add_sb (&label, &label_in);
+           }
 
+         if (l < line.len)
+           {
+             if (process_pseudo_op (l, &line, &acc))
+               {
 
                }
              else if (condass_on ())
@@ -1915,7 +1927,6 @@ process_file ()
                  if (macro_op (l, &line))
                    {
 
-
                    }
                  else
                    {
@@ -1926,7 +1937,7 @@ process_file ()
                          }
                        else
                          fprintf (outfile, "\t");
-                       sb_reset(&t1);
+                       sb_reset (&t1);
                        process_assigns (l, &line, &t1);
                        sb_reset (&t2);
                        change_base (0, &t1, &t2);
@@ -1935,6 +1946,14 @@ process_file ()
                    }
                }
            }
+         else
+           {
+             /* Only a label on this line.  */
+             if (label.len && condass_on ())
+               {
+                 fprintf (outfile, "%s:\n", sb_name (&label));
+               }
+           }
        }
 
       if (had_end)
@@ -1943,14 +1962,10 @@ process_file ()
       more = get_line (&line);
     }
 
-  if (!had_end)
-    WARNING ((stderr, ".END missing from end of file.\n"));
+  if (!had_end && !mri)
+    WARNING ((stderr, _("END missing from end of file.\n")));
 }
 
-
-
-
-
 static void
 free_old_entry (ptr)
      hash_entry *ptr;
@@ -1958,13 +1973,13 @@ free_old_entry (ptr)
   if (ptr)
     {
       if (ptr->type == hash_string)
-       sb_kill(&ptr->value.s);
+       sb_kill (&ptr->value.s);
     }
 }
 
-/* name: .ASSIGNA <value> */
+/* name: .ASSIGNA <value>  */
 
-void
+static void
 do_assigna (idx, in)
      int idx;
      sb *in;
@@ -1974,11 +1989,11 @@ do_assigna (idx, in)
   sb_new (&tmp);
 
   process_assigns (idx, in, &tmp);
-  idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val);
+  idx = exp_get_abs (_(".ASSIGNA needs constant expression argument.\n"), 0, &tmp, &val);
 
   if (!label.len)
     {
-      ERROR ((stderr, ".ASSIGNA without label.\n"));
+      ERROR ((stderr, _(".ASSIGNA without label.\n")));
     }
   else
     {
@@ -1990,9 +2005,9 @@ do_assigna (idx, in)
   sb_kill (&tmp);
 }
 
-/* name: .ASSIGNC <string> */
+/* name: .ASSIGNC <string>  */
 
-void
+static void
 do_assignc (idx, in)
      int idx;
      sb *in;
@@ -2003,7 +2018,7 @@ do_assignc (idx, in)
 
   if (!label.len)
     {
-      ERROR ((stderr, ".ASSIGNS without label.\n"));
+      ERROR ((stderr, _(".ASSIGNS without label.\n")));
     }
   else
     {
@@ -2016,19 +2031,24 @@ do_assignc (idx, in)
   sb_kill (&acc);
 }
 
-
-/* name: .REG (reg) */
+/* name: .REG (reg)  */
 
 static void
 do_reg (idx, in)
      int idx;
      sb *in;
 {
-  /* remove reg stuff from inside parens */
+  /* Remove reg stuff from inside parens.  */
   sb what;
-  idx = skip_openp (idx, in);
+  if (!mri)
+    idx = skip_openp (idx, in);
+  else
+    idx = sb_skip_white (idx, in);
   sb_new (&what);
-  while (idx < in->len && in->ptr[idx] != ')')
+  while (idx < in->len
+        && (mri
+            ? ! eol (idx, in)
+            : in->ptr[idx] != ')'))
     {
       sb_add_char (&what, in->ptr[idx]);
       idx++;
@@ -2037,12 +2057,12 @@ do_reg (idx, in)
   sb_kill (&what);
 }
 
-
 static int
-condass_lookup_name (inbuf, idx, out)
+condass_lookup_name (inbuf, idx, out, warn)
      sb *inbuf;
      int idx;
      sb *out;
+     int warn;
 {
   hash_entry *ptr;
   sb condass_acc;
@@ -2057,9 +2077,17 @@ condass_lookup_name (inbuf, idx, out)
   if (inbuf->ptr[idx] == '\'')
     idx++;
   ptr = hash_lookup (&vars, &condass_acc);
+
   if (!ptr)
     {
-      WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc)));
+      if (warn)
+       {
+         WARNING ((stderr, _("Can't find preprocessor variable %s.\n"), sb_name (&condass_acc)));
+       }
+      else
+       {
+         sb_add_string (out, "0");
+       }
     }
   else
     {
@@ -2086,31 +2114,40 @@ condass_lookup_name (inbuf, idx, out)
 #define GT 6
 #define NEVER 7
 
-int
+static int
 whatcond (idx, in, val)
      int idx;
      sb *in;
      int *val;
 {
   int cond;
-  char *p;
+
   idx = sb_skip_white (idx, in);
-  p = in->ptr + idx;
-  if (p[0] == 'E' && p[1] == 'Q')
-    cond = EQ;
-  else if (p[0] == 'N' && p[1] == 'E')
-    cond = NE;
-  else if (p[0] == 'L' && p[1] == 'T')
-    cond = LT;
-  else if (p[0] == 'L' && p[1] == 'E')
-    cond = LE;
-  else if (p[0] == 'G' && p[1] == 'T')
-    cond = GT;
-  else if (p[0] == 'G' && p[1] == 'E')
-    cond = GE;
-  else
-    {
-      ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE"));
+  cond = NEVER;
+  if (idx + 1 < in->len)
+    {
+      char *p;
+      char a, b;
+
+      p = in->ptr + idx;
+      a = TOUPPER (p[0]);
+      b = TOUPPER (p[1]);
+      if (a == 'E' && b == 'Q')
+       cond = EQ;
+      else if (a == 'N' && b == 'E')
+       cond = NE;
+      else if (a == 'L' && b == 'T')
+       cond = LT;
+      else if (a == 'L' && b == 'E')
+       cond = LE;
+      else if (a == 'G' && b == 'T')
+       cond = GT;
+      else if (a == 'G' && b == 'E')
+       cond = GE;
+    }
+  if (cond == NEVER)
+    {
+      ERROR ((stderr, _("Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n")));
       cond = NEVER;
     }
   idx = sb_skip_white (idx + 2, in);
@@ -2118,7 +2155,7 @@ whatcond (idx, in, val)
   return idx;
 }
 
-int
+static int
 istrue (idx, in)
      int idx;
      sb *in;
@@ -2136,39 +2173,43 @@ istrue (idx, in)
     {
       int cond;
       int same;
-      /* This is a string comparision */
+      /* This is a string comparision */
       idx = getstring (idx, in, &acc_a);
       idx = whatcond (idx, in, &cond);
       idx = getstring (idx, in, &acc_b);
-      same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
+      same = acc_a.len == acc_b.len
+       && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
 
       if (cond != EQ && cond != NE)
        {
-         ERROR ((stderr, "Comparison operator for strings must be EQ or NE"));
+         ERROR ((stderr, _("Comparison operator for strings must be EQ or NE\n")));
          res = 0;
        }
       else
-       res = cond == EQ && same;
+       res = (cond != EQ) ^ same;
     }
   else
-    /* This is a numeric expression */
+    /* This is a numeric expression */
     {
       int vala;
       int valb;
       int cond;
-      idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala);
+      idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"), idx, in, &vala);
       idx = whatcond (idx, in, &cond);
       idx = sb_skip_white (idx, in);
       if (in->ptr[idx] == '"')
        {
-         WARNING ((stderr, "String compared against expression.\n"));
+         WARNING ((stderr, _("String compared against expression.\n")));
          res = 0;
        }
       else
        {
-         idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb);
+         idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"), idx, in, &valb);
          switch (cond)
            {
+           default:
+             res = 42;
+             break;
            case EQ:
              res = vala == valb;
              break;
@@ -2200,7 +2241,8 @@ istrue (idx, in)
   return res;
 }
 
-/* .AIF */
+/* .AIF  */
+
 static void
 do_aif (idx, in)
      int idx;
@@ -2208,28 +2250,28 @@ do_aif (idx, in)
 {
   if (ifi >= IFNESTING)
     {
-      FATAL ((stderr, "AIF nesting unreasonable.\n"));
+      FATAL ((stderr, _("AIF nesting unreasonable.\n")));
     }
   ifi++;
-  ifstack[ifi].on = istrue (idx, in);
+  ifstack[ifi].on = ifstack[ifi - 1].on ? istrue (idx, in) : 0;
   ifstack[ifi].hadelse = 0;
 }
 
+/* .AELSE  */
 
-/* .AELSE */
 static void
 do_aelse ()
 {
-  ifstack[ifi].on = !ifstack[ifi].on;
+  ifstack[ifi].on = ifstack[ifi - 1].on ? !ifstack[ifi].on : 0;
   if (ifstack[ifi].hadelse)
     {
-      ERROR ((stderr, "Multiple AELSEs in AIF.\n"));
+      ERROR ((stderr, _("Multiple AELSEs in AIF.\n")));
     }
   ifstack[ifi].hadelse = 1;
 }
 
+/* .AENDI  */
 
-/* .AENDI */
 static void
 do_aendi ()
 {
@@ -2239,7 +2281,7 @@ do_aendi ()
     }
   else
     {
-      ERROR ((stderr, "AENDI without AIF.\n"));
+      ERROR ((stderr, _("AENDI without AIF.\n")));
     }
 }
 
@@ -2249,106 +2291,157 @@ condass_on ()
   return ifstack[ifi].on;
 }
 
-
-/* Read input lines till we get to a TO string.
-   Increase nesting depth if we geta FROM string.
-   Put the results into sb at PTR. */
+/* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT.  */
 
 static void
-buffer_and_nest (from, to, ptr)
-     char *from;
-     char *to;
-     sb *ptr;
+do_if (idx, in, cond)
+     int idx;
+     sb *in;
+     int cond;
 {
-  int from_len = strlen (from);
-  int to_len = strlen (to);
-  int depth = 1;
-  int line_start = ptr->len;
-  int line = linecount ();
-
-  int more = get_line (ptr);
+  int val;
+  int res;
 
-  while (more)
+  if (ifi >= IFNESTING)
     {
-      /* Try and find the first pseudo op on the line */
-      int i = line_start;
+      FATAL ((stderr, _("IF nesting unreasonable.\n")));
+    }
 
-      /* Skip leading whitespace */
-      while (i < ptr->len
-            && ISWHITE (ptr->ptr[i]))
-       i++;
+  idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"),
+                    idx, in, &val);
+  switch (cond)
+    {
+    default:
+    case EQ: res = val == 0; break;
+    case NE: res = val != 0; break;
+    case LT: res = val <  0; break;
+    case LE: res = val <= 0; break;
+    case GE: res = val >= 0; break;
+    case GT: res = val >  0; break;
+    }
 
-      /* Skip over a label */
-      while (i < ptr->len
-            && ISNEXTCHAR (ptr->ptr[i]))
-       i++;
+  ifi++;
+  ifstack[ifi].on = ifstack[ifi - 1].on ? res : 0;
+  ifstack[ifi].hadelse = 0;
+}
 
-      /* And a colon */
-      if (i < ptr->len
-         && ptr->ptr[i] == ':')
-       i++;
+/* Get a string for the MRI IFC or IFNC pseudo-ops.  */
 
-      /* Skip trailing whitespace */
-      while (i < ptr->len
-            && ISWHITE (ptr->ptr[i]))
-       i++;
+static int
+get_mri_string (idx, in, val, terminator)
+     int idx;
+     sb *in;
+     sb *val;
+     int terminator;
+{
+  idx = sb_skip_white (idx, in);
 
-      if (i < ptr->len
-         && ptr->ptr[i] == '.')
+  if (idx < in->len
+      && in->ptr[idx] == '\'')
+    {
+      sb_add_char (val, '\'');
+      for (++idx; idx < in->len; ++idx)
        {
-         if (strncmp (ptr->ptr + i, from, from_len) == 0)
-           depth++;
-         if (strncmp (ptr->ptr + i, to, to_len) == 0)
+         sb_add_char (val, in->ptr[idx]);
+         if (in->ptr[idx] == '\'')
            {
-             depth--;
-             if (depth == 0)
-               {
-                 /* Reset the string to not include the ending rune */
-                 ptr->len = line_start;
-                 break;
-               }
+             ++idx;
+             if (idx >= in->len
+                 || in->ptr[idx] != '\'')
+               break;
            }
        }
+      idx = sb_skip_white (idx, in);
+    }
+  else
+    {
+      int i;
+
+      while (idx < in->len
+            && in->ptr[idx] != terminator)
+       {
+         sb_add_char (val, in->ptr[idx]);
+         ++idx;
+       }
+      i = val->len - 1;
+      while (i >= 0 && ISWHITE (val->ptr[i]))
+       --i;
+      val->len = i + 1;
+    }
+
+  return idx;
+}
+
+/* MRI IFC, IFNC  */
+
+static void
+do_ifc (idx, in, ifnc)
+     int idx;
+     sb *in;
+     int ifnc;
+{
+  sb first;
+  sb second;
+  int res;
+
+  if (ifi >= IFNESTING)
+    {
+      FATAL ((stderr, _("IF nesting unreasonable.\n")));
+    }
+
+  sb_new (&first);
+  sb_new (&second);
 
-      /* Add a CR to the end and keep running */
-      sb_add_char (ptr, '\n');
-      line_start = ptr->len;
-      more = get_line (ptr);
+  idx = get_mri_string (idx, in, &first, ',');
+
+  if (idx >= in->len || in->ptr[idx] != ',')
+    {
+      ERROR ((stderr, _("Bad format for IF or IFNC.\n")));
+      return;
     }
 
+  idx = get_mri_string (idx + 1, in, &second, ';');
 
-  if (depth)
-    FATAL ((stderr, "End of file whilst inside %s, started on line %d.\n", from, line));
+  res = (first.len == second.len
+        && strncmp (first.ptr, second.ptr, first.len) == 0);
+  res ^= ifnc;
+
+  ifi++;
+  ifstack[ifi].on = ifstack[ifi - 1].on ? res : 0;
+  ifstack[ifi].hadelse = 0;
 }
 
+/* .ENDR  */
 
-/* .ENDR */
-void
+static void
 do_aendr ()
 {
-  ERROR ((stderr, "AENDR without a AREPEAT.\n"));
+  if (!mri)
+    ERROR ((stderr, _("AENDR without a AREPEAT.\n")));
+  else
+    ERROR ((stderr, _("ENDR without a REPT.\n")));
 }
 
-/* .AWHILE */
+/* .AWHILE  */
 
-static
-void
+static void
 do_awhile (idx, in)
      int idx;
      sb *in;
 {
+  int line = linecount ();
   sb exp;
-
   sb sub;
-
   int doit;
+
   sb_new (&sub);
   sb_new (&exp);
 
   process_assigns (idx, in, &exp);
   doit = istrue (0, &exp);
 
-  buffer_and_nest (".AWHILE", ".AENDW", &sub);
+  if (! buffer_and_nest ("AWHILE", "AENDW", &sub, get_line))
+    FATAL ((stderr, _("AWHILE without a AENDW at %d.\n"), line - 1));
 
   /* Turn
        .AWHILE exp
@@ -2359,7 +2452,7 @@ do_awhile (idx, in)
        .AWHILE exp
        foo
        .ENDW
-   */
+  */
 
   if (doit)
     {
@@ -2372,7 +2465,7 @@ do_awhile (idx, in)
       sb_add_string (&copy, "\n");
       sb_add_sb (&copy, &sub);
       sb_add_string (&copy, "\t.AENDW\n");
-      /* Push another WHILE */
+      /* Push another WHILE */
       include_buf (&exp, &copy, include_while, index);
       sb_kill (&copy);
     }
@@ -2380,19 +2473,17 @@ do_awhile (idx, in)
   sb_kill (&sub);
 }
 
-
-/* .AENDW */
+/* .AENDW  */
 
 static void
 do_aendw ()
 {
-  ERROR ((stderr, "AENDW without a AENDW.\n"));
+  ERROR ((stderr, _("AENDW without a AENDW.\n")));
 }
 
-
 /* .EXITM
-   
-   Pop things off the include stack until the type and index changes */
+
+   Pop things off the include stack until the type and index changes */
 
 static void
 do_exitm ()
@@ -2412,24 +2503,32 @@ do_exitm ()
     }
 }
 
-/* .AREPEAT */
+/* .AREPEAT  */
 
 static void
 do_arepeat (idx, in)
      int idx;
      sb *in;
 {
-  sb exp;                      /* buffer with expression in it */
-  sb copy;                     /* expanded repeat block */
-  sb sub;                      /* contents of AREPEAT */
+  int line = linecount ();
+  sb exp;                      /* Buffer with expression in it.  */
+  sb copy;                     /* Expanded repeat block.  */
+  sb sub;                      /* Contents of AREPEAT.  */
   int rc;
+  int ret;
   char buffer[30];
+
   sb_new (&exp);
   sb_new (&copy);
   sb_new (&sub);
   process_assigns (idx, in, &exp);
-  idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc);
-  buffer_and_nest (".AREPEAT", ".AENDR", &sub);
+  idx = exp_get_abs (_("AREPEAT must have absolute operand.\n"), 0, &exp, &rc);
+  if (!mri)
+    ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line);
+  else
+    ret = buffer_and_nest ("REPT", "ENDR", &sub, get_line);
+  if (! ret)
+    FATAL ((stderr, _("AREPEAT without a AENDR at %d.\n"), line - 1));
   if (rc > 0)
     {
       /* Push back the text following the repeat, and another repeat block
@@ -2442,15 +2541,21 @@ do_arepeat (idx, in)
         .AREPEAT 19
         foo
         .AENDR
-        */
+      */
       int index = include_next_index ();
       sb_add_sb (&copy, &sub);
       if (rc > 1)
        {
-         sprintf (buffer, "\t.AREPEAT  %d\n", rc - 1);
+         if (!mri)
+           sprintf (buffer, "\t.AREPEAT        %d\n", rc - 1);
+         else
+           sprintf (buffer, "\tREPT    %d\n", rc - 1);
          sb_add_string (&copy, buffer);
          sb_add_sb (&copy, &sub);
-         sb_add_string (&copy, "       .AENDR\n");
+         if (!mri)
+           sb_add_string (&copy, "     .AENDR\n");
+         else
+           sb_add_string (&copy, "     ENDR\n");
        }
 
       include_buf (&exp, &copy, include_repeat, index);
@@ -2460,417 +2565,166 @@ do_arepeat (idx, in)
   sb_kill (&copy);
 }
 
-/* .ENDM */
+/* .ENDM  */
 
 static void
 do_endm ()
 {
-  ERROR ((stderr, ".ENDM without a matching .MACRO.\n"));
+  ERROR ((stderr, _(".ENDM without a matching .MACRO.\n")));
 }
 
+/* MRI IRP pseudo-op.  */
 
-/* MARRO PROCESSING */
-
-static int number;
-hash_table macro_table;
-
-/* Understand
-
-   .MACRO <name>
-   stuff
-   .ENDM
-*/
-
-static int
-do_formals (macro, idx, in)
-     macro_entry *macro;
+static void
+do_irp (idx, in, irpc)
      int idx;
      sb *in;
+     int irpc;
 {
-  formal_entry **p = &macro->formals;
-  macro->formal_count = 0;
-  hash_new_table (5, &macro->formal_hash);
-  while (idx < in->len)
-    {
-      formal_entry *formal;
+  const char *err;
+  sb out;
 
-      formal = (formal_entry *) xmalloc (sizeof (formal_entry));
+  sb_new (&out);
 
-      sb_new (&formal->name);
-      sb_new (&formal->def);
-      sb_new (&formal->actual);
+  err = expand_irp (irpc, idx, in, &out, get_line, comment_char);
+  if (err != NULL)
+    ERROR ((stderr, "%s\n", err));
 
-      idx = sb_skip_white (idx, in);
-      idx = get_token (idx, in, &formal->name);
-      if (formal->name.len == 0)
-       break;
-      idx = sb_skip_white (idx, in);
-      if (formal->name.len)
-       {
-         /* This is a formal */
-         if (idx < in->len && in->ptr[idx] == '=')
-           {
-             /* Got a default */
-             idx = get_any_string (idx + 1, in, &formal->def);
-           }
-       }
+  fprintf (outfile, "%s", sb_terminate (&out));
 
-      {
-       /* Add to macro's hash table */
+  sb_kill (&out);
+}
 
-       hash_entry *p = hash_create (&macro->formal_hash, &formal->name);
-       p->type = hash_formal;
-       p->value.f = formal;
-      }
+/* Macro processing.  */
 
-      formal->index = macro->formal_count;
-      idx = sb_skip_comma (idx, in);
-      macro->formal_count++;
-      *p = formal;
-      p = &formal->next;
-    }
-  return idx;
+/* Parse off LOCAL n1, n2,... Invent a label name for it.  */
+
+static void
+do_local (idx, line)
+     int idx ATTRIBUTE_UNUSED;
+     sb *line ATTRIBUTE_UNUSED;
+{
+  ERROR ((stderr, _("LOCAL outside of MACRO")));
 }
 
-static
-void
+static void
 do_macro (idx, in)
      int idx;
      sb *in;
 {
-  macro_entry *macro;
+  const char *err;
+  int line = linecount ();
+
+  err = define_macro (idx, in, &label, get_line, (const char **) NULL);
+  if (err != NULL)
+    ERROR ((stderr, _("macro at line %d: %s\n"), line - 1, err));
+}
+
+static int
+macro_op (idx, in)
+     int idx;
+     sb *in;
+{
+  const char *err;
+  sb out;
   sb name;
 
-  macro = (macro_entry *) xmalloc (sizeof (macro_entry));
-  sb_new (&macro->sub);
+  if (! macro_defined)
+    return 0;
+
+  sb_terminate (in);
+  if (! check_macro (in->ptr + idx, &out, comment_char, &err, NULL))
+    return 0;
+
+  if (err != NULL)
+    ERROR ((stderr, "%s\n", err));
+
   sb_new (&name);
+  sb_add_string (&name, _("macro expansion"));
 
-  macro->formal_count = 0;
-  macro->formals = 0;
+  include_buf (&name, &out, include_macro, include_next_index ());
 
-  idx = sb_skip_white (idx, in);
-  buffer_and_nest (".MACRO", ".ENDM", &macro->sub);
-  if (label.len)
-    {
-      /* It's the label: MACRO (formals,...)  sort */
-      sb_add_sb (&name, &label);
-      if (in->ptr[idx] == '(')
-       {
-         /* Got some formals */
-         idx = do_formals (macro, idx + 1, in);
-         if (in->ptr[idx] != ')')
-           ERROR ((stderr, "Missing ) after formals.\n"));
-       }
-    }
-  else
-    {
-      idx = get_token (idx, in, &name);
-      idx = sb_skip_white (idx, in);
-      idx = do_formals (macro, idx, in);
-    }
+  sb_kill (&name);
+  sb_kill (&out);
 
-  /* and stick it in the macro hash table */
-  hash_create (&macro_table, &name)->value.m = macro;
+  return 1;
 }
 
-static
-int
-get_token (idx, in, name)
+/* String handling.  */
+
+static int
+getstring (idx, in, acc)
      int idx;
      sb *in;
-     sb *name;
-{
-  if (idx < in->len
-      && ISFIRSTCHAR (in->ptr[idx]))
-    {
-      sb_add_char (name, in->ptr[idx++]);
-      while (idx < in->len
-            && ISNEXTCHAR (in->ptr[idx]))
-       {
-         sb_add_char (name, in->ptr[idx++]);
-       }
-    }
-  return idx;
-}
-
-/* Scan a token, but stop if a ' is seen */
-static int
-get_apost_token (idx, in, name, kind)
-     int idx;
-     sb *in;
-     sb *name;
-     int kind;
+     sb *acc;
 {
-  idx = get_token (idx, in, name);
-  if (idx < in->len && in->ptr[idx] == kind)
-    idx++;
-  return idx;
-}
+  idx = sb_skip_white (idx, in);
 
-static int
-sub_actual (src, in, t, m, kind, out)
-     int src;
-     sb *in;
-     sb *t;
-     macro_entry *m;
-     int kind;
-     sb *out;
-{
-  /* This is something to take care of */
-  hash_entry *ptr;
-  src = get_apost_token (src, in, t, kind);
-  /* See if it's in the macro's hash table */
-  ptr = hash_lookup (&m->formal_hash, t);
-  if (ptr)
+  while (idx < in->len
+        && (in->ptr[idx] == '"'
+            || in->ptr[idx] == '<'
+            || (in->ptr[idx] == '\'' && alternate)))
     {
-      if (ptr->value.f->actual.len)
-       {
-         sb_add_sb (out, &ptr->value.f->actual);
-       }
-      else
+      if (in->ptr[idx] == '<')
        {
-         sb_add_sb (out, &ptr->value.f->def);
-       }
-    }
-  else
-    {
-      sb_add_char (out, '\\');
-      sb_add_sb (out, t);
-    }
-  return src;
-}
-
-static
-void
-macro_expand (name, idx, in, m)
-     sb *name;
-     int idx;
-     sb *in;
-     macro_entry *m;
-{
-  sb t;
-  sb out;
-  hash_entry *ptr;
-  formal_entry *f;
-
-  int is_positional = 0;
-  int is_keyword = 0;
-
-  sb_new (&t);
-  sb_new (&out);
-  
-  /* Reset any old value the actuals may have */
-  for (f = m->formals; f; f = f->next)
-      sb_reset (&f->actual);
-  f = m->formals;
-  /* Peel off the actuals and store them away in the hash tables' actuals */
-  while (idx < in->len)
-    {
-      int scan;
-      idx = sb_skip_white (idx, in);
-      /* Look and see if it's a positional or keyword arg */
-      scan = idx;
-      while (scan < in->len
-            && !ISSEP (in->ptr[scan])
-            && in->ptr[scan] != '=')
-       scan++;
-      if (scan < in->len && in->ptr[scan] == '=')
-       {
-         is_keyword = 1;
-         if (is_positional)
-           {
-             ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
-             return;
-           }
-         /* This is a keyword arg, fetch the formal name and
-            then the actual stuff */
-         sb_reset (&t);
-         idx = get_token (idx, in, &t);
-         if (in->ptr[idx] != '=')
-           ERROR ((stderr, "confused about formal params.\n"));
-
-         /* Lookup the formal in the macro's list */
-         ptr = hash_lookup (&m->formal_hash, &t);
-         if (!ptr)
+         if (alternate || mri)
            {
-             ERROR ((stderr, "MACRO formal argument %s does not exist.\n", sb_name (&t)));
-             return;
+             int nest = 0;
+             idx++;
+             while ((in->ptr[idx] != '>' || nest)
+                    && idx < in->len)
+               {
+                 if (in->ptr[idx] == '!')
+                   {
+                     idx++;
+                     sb_add_char (acc, in->ptr[idx++]);
+                   }
+                 else
+                   {
+                     if (in->ptr[idx] == '>')
+                       nest--;
+                     if (in->ptr[idx] == '<')
+                       nest++;
+                     sb_add_char (acc, in->ptr[idx++]);
+                   }
+               }
+             idx++;
            }
          else
            {
-             /* Insert this value into the right place */
-             sb_reset (&ptr->value.f->actual);
-             idx = get_any_string (idx + 1, in, &ptr->value.f->actual);
-           }
-       }
-      else
-       {
-         /* This is a positional arg */
-         is_positional = 1;
-         if (is_keyword)
-           {
-             ERROR ((stderr, "Can't mix positional and keyword arguments.\n"));
-             return;
-           }
-         if (!f)
-           {
-             ERROR ((stderr, "Too many positional arguments.\n"));
-             return;
-           }
-
-         sb_reset (&f->actual);
-         idx = get_any_string (idx, in, &f->actual);
-         f = f->next;
-       }
-      idx = sb_skip_comma (idx, in);
-    }
-
-  /* Copy the stuff from the macro buffer into a safe place and substitute any args */
-
-  {
-    int src = 0;
-    sb *in = &m->sub;
-    sb_reset (&out);
-
-    while (src < in->len)
-      {
-       if (in->ptr[src] == '&')
-         {
-           sb_reset (&t);
-           src = sub_actual (src + 1, in, &t, m, '&', &out);
-         }
-       else if (in->ptr[src] == '\\')
-         {
-           src++;
-           if (in->ptr[src] == ';')
-             {
-               /* This is a comment, just drop the rest of the line */
-               while (src < in->len
-                      && in->ptr[src] != '\n')
-                 src++;
-
-             }
-           else if (in->ptr[src] == '(')
-             {
-               /* Sub in till the next ')' literally */
-               src++;
-               while (src < in->len && in->ptr[src] != ')')
-                 {
-                   sb_add_char (&out, in->ptr[src++]);
-                 }
-               if (in->ptr[src] == ')')
-                 src++;
-               else
-                 ERROR ((stderr, "Missplaced ).\n"));
-             }
-           else if (in->ptr[src] == '@')
-             {
-               /* Sub in the macro invocation number */
-
-               char buffer[6];
-               src++;
-               sprintf (buffer, "%05d", number);
-               sb_add_string (&out, buffer);
-             }
-           else if (in->ptr[src] == '&')
-             {
-               /* This is a preprocessor variable name, we don't do them
-                  here */
-               sb_add_char (&out, '\\');
-               sb_add_char (&out, '&');
-               src++;
-             }
-           else
-             {
-               sb_reset (&t);
-               src = sub_actual (src, in, &t, m, '\'', &out);
-             }
-         }
-       else
-         {
-           sb_add_char (&out, in->ptr[src++]);
-         }
-      }
-    include_buf (name, &out, include_macro, include_next_index ());
-  }
-  sb_kill (&t);
-  sb_kill (&out);
-  number++;
-}
-
-static int
-macro_op (idx, in)
-     int idx;
-     sb *in;
-{
-  int res = 0;
-  /* The macro name must be the first thing on the line */
-  if (idx < in->len)
-    {
-      sb name;
-      hash_entry *ptr;
-      sb_new (&name);
-      idx = get_token (idx, in, &name);
-
-      if (name.len)
-       {
-         /* Got a name, look it up */
-
-         ptr = hash_lookup (&macro_table, &name);
+             int code;
+             idx++;
+             idx = exp_get_abs (_("Character code in string must be absolute expression.\n"),
+                                idx, in, &code);
+             sb_add_char (acc, code);
 
-         if (ptr)
-           {
-             /* It's in the table, copy out the stuff and convert any macro args */
-             macro_expand (&name, idx, in, ptr->value.m);
-             res = 1;
+             if (in->ptr[idx] != '>')
+               ERROR ((stderr, _("Missing > for character code.\n")));
+             idx++;
            }
        }
-      sb_kill (&name);
-    }
-
-
-  return res;
-}
-
-
-/* STRING HANDLING */
-
-static int
-getstring (idx, in, acc)
-     int idx;
-     sb *in;
-     sb *acc;
-{
-  idx = sb_skip_white (idx, in);
-
-  while (idx < in->len
-        && (in->ptr[idx] == '"' || in->ptr[idx] == '<'))
-    {
-      if (in->ptr[idx] == '<')
-       {
-         int code;
-         idx++;
-         idx = exp_get_abs ("Character code in string must be absolute expression.\n",
-                            idx, in, &code);
-         sb_add_char (acc, code);
-
-         if (in->ptr[idx] != '>')
-           ERROR ((stderr, "Missing > for character code.\n"));
-         idx++;
-       }
-      else if (in->ptr[idx] == '"')
+      else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
        {
+         char tchar = in->ptr[idx];
          idx++;
          while (idx < in->len)
            {
-             if (in->ptr[idx] == '"')
+             if (alternate && in->ptr[idx] == '!')
                {
                  idx++;
-                 if (idx >= in->len || in->ptr[idx] != '"')
-                   break;
+                 sb_add_char (acc, in->ptr[idx++]);
+               }
+             else
+               {
+                 if (in->ptr[idx] == tchar)
+                   {
+                     idx++;
+                     if (idx >= in->len || in->ptr[idx] != tchar)
+                       break;
+                   }
+                 sb_add_char (acc, in->ptr[idx]);
+                 idx++;
                }
-             sb_add_char (acc, in->ptr[idx]);
-             idx++;
            }
        }
     }
@@ -2878,35 +2732,33 @@ getstring (idx, in, acc)
   return idx;
 }
 
-/* .SDATA[C|Z] <string> */
+/* .SDATA[C|Z] <string>  */
 
-static
-void
+static void
 do_sdata (idx, in, type)
      int idx;
      sb *in;
-     char type;
+     int type;
 {
   int nc = 0;
+  int pidx = -1;
   sb acc;
   sb_new (&acc);
   fprintf (outfile, ".byte\t");
 
-  while (idx < in->len)
+  while (!eol (idx, in))
     {
       int i;
       sb_reset (&acc);
       idx = sb_skip_white (idx, in);
-      while ((in->ptr[idx] == '"'
-             || in->ptr[idx] == '<')
-            && idx < in->len)
+      while (!eol (idx, in))
        {
-         idx = getstring (idx, in, &acc);
+         pidx = idx = get_any_string (idx, in, &acc, 0, 1);
          if (type == 'c')
            {
              if (acc.len > 255)
                {
-                 ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len));
+                 ERROR ((stderr, _("string for SDATAC longer than 255 characters (%d).\n"), acc.len));
                }
              fprintf (outfile, "%d", acc.len);
              nc = 1;
@@ -2928,12 +2780,15 @@ do_sdata (idx, in, type)
                fprintf (outfile, ",");
              fprintf (outfile, "0");
            }
-         idx = sb_skip_white (idx, in);
+         idx = sb_skip_comma (idx, in);
+         if (idx == pidx)
+           break;
        }
-      if (in->ptr[idx] != ',' && idx != in->len)
+      if (!alternate && in->ptr[idx] != ',' && idx != in->len)
        {
          fprintf (outfile, "\n");
-         ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx]));
+         ERROR ((stderr, _("illegal character in SDATA line (0x%x).\n"),
+                 in->ptr[idx]));
          break;
        }
       idx++;
@@ -2942,7 +2797,7 @@ do_sdata (idx, in, type)
   fprintf (outfile, "\n");
 }
 
-/* .SDATAB <count> <string> */
+/* .SDATAB <count> <string>  */
 
 static void
 do_sdatab (idx, in)
@@ -2954,10 +2809,10 @@ do_sdatab (idx, in)
   sb acc;
   sb_new (&acc);
 
-  idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat);
+  idx = exp_get_abs (_("Must have absolute SDATAB repeat count.\n"), idx, in, &repeat);
   if (repeat <= 0)
     {
-      ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat));
+      ERROR ((stderr, _("Must have positive SDATAB repeat count (%d).\n"), repeat));
       repeat = 1;
     }
 
@@ -2969,23 +2824,23 @@ do_sdatab (idx, in)
       if (i)
        fprintf (outfile, "\t");
       fprintf (outfile, ".byte\t");
-      sb_print (&acc);
+      sb_print (outfile, &acc);
       fprintf (outfile, "\n");
     }
   sb_kill (&acc);
 
 }
 
-int
+static int
 new_file (name)
-     char *name;
+     const char *name;
 {
   FILE *newone = fopen (name, "r");
   if (!newone)
     return 0;
 
   if (isp == MAX_INCLUDES)
-    FATAL ((stderr, "Unreasonable include depth (%d).\n", isp));
+    FATAL ((stderr, _("Unreasonable include depth (%ld).\n"), (long) isp));
 
   sp++;
   sp->handle = newone;
@@ -3007,14 +2862,41 @@ do_include (idx, in)
      sb *in;
 {
   sb t;
-  char *text;
+  sb cat;
+  include_path *includes;
+
   sb_new (&t);
-  idx = getstring (idx, in, &t);
-  text = sb_name (&t);
-  if (!new_file (text))
+  sb_new (&cat);
+
+  if (! mri)
+    idx = getstring (idx, in, &t);
+  else
     {
-      FATAL ((stderr, "Can't open include file `%s'.\n", text));
+      idx = sb_skip_white (idx, in);
+      while (idx < in->len && ! ISWHITE (in->ptr[idx]))
+       {
+         sb_add_char (&t, in->ptr[idx]);
+         ++idx;
+       }
+    }
+
+  for (includes = paths_head; includes; includes = includes->next)
+    {
+      sb_reset (&cat);
+      sb_add_sb (&cat, &includes->path);
+      sb_add_char (&cat, '/');
+      sb_add_sb (&cat, &t);
+      if (new_file (sb_name (&cat)))
+       {
+         break;
+       }
+    }
+  if (!includes)
+    {
+      if (! new_file (sb_name (&t)))
+       FATAL ((stderr, _("Can't open include file `%s'.\n"), sb_name (&t)));
     }
+  sb_kill (&cat);
   sb_kill (&t);
 }
 
@@ -3031,7 +2913,7 @@ include_pop ()
 
 /* Get the next character from the include stack.  If there's anything
    in the pushback buffer, take that first.  If we're at eof, pop from
-   the stack and try again.  Keep the linecount up to date. */
+   the stack and try again.  Keep the linecount up to date.  */
 
 static int
 get ()
@@ -3041,7 +2923,7 @@ get ()
   if (sp->pushback.len != sp->pushback_index)
     {
       r = (char) (sp->pushback.ptr[sp->pushback_index++]);
-      /* When they've all gone, reset the pointer */
+      /* When they've all gone, reset the pointer */
       if (sp->pushback_index == sp->pushback.len)
        {
          sp->pushback.len = 0;
@@ -3086,12 +2968,11 @@ include_next_index ()
   static int index;
   if (!unreasonable
       && index > MAX_REASONABLE)
-    FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n"));
+    FATAL ((stderr, _("Unreasonable expansion (-u turns off check).\n")));
   return ++index;
 }
 
-
-/* Initialize the chartype vector. */
+/* Initialize the chartype vector.  */
 
 static void
 chartype_init ()
@@ -3099,81 +2980,109 @@ chartype_init ()
   int x;
   for (x = 0; x < 256; x++)
     {
-      if (isalpha (x) || x == '_' || x == '$')
+      if (ISALPHA (x) || x == '_' || x == '$')
+       chartype[x] |= FIRSTBIT;
+
+      if (mri && x == '.')
        chartype[x] |= FIRSTBIT;
 
-      if (isdigit (x) || isalpha (x) || x == '_' || x == '$')
+      if (ISDIGIT (x) || ISALPHA (x) || x == '_' || x == '$')
        chartype[x] |= NEXTBIT;
 
       if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
          || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
        chartype[x] |= SEPBIT;
 
+      if (x == 'b' || x == 'B'
+         || x == 'q' || x == 'Q'
+         || x == 'h' || x == 'H'
+         || x == 'd' || x == 'D')
+       chartype [x] |= BASEBIT;
+
       if (x == ' ' || x == '\t')
        chartype[x] |= WHITEBIT;
-    }
-}
-
 
-/* What to do with all the keywords */
-#define PROCESS        0x1000  /* Run substitution over the line */
-#define LAB            0x2000  /* Spit out the label */
-
-#define K_EQU          PROCESS|1
-#define K_ASSIGN       PROCESS|2
-#define K_REG          PROCESS|3
-#define K_ORG          PROCESS|4
-#define K_RADIX        PROCESS|5
-#define K_DATA                 LAB|PROCESS|6
-#define K_DATAB        LAB|PROCESS|7
-#define K_SDATA        LAB|PROCESS|8
-#define K_SDATAB       LAB|PROCESS|9
-#define K_SDATAC       LAB|PROCESS|10
-#define K_SDATAZ       LAB|PROCESS|11
-#define K_RES          LAB|PROCESS|12
-#define K_SRES                 LAB|PROCESS|13
-#define K_SRESC        LAB|PROCESS|14
-#define K_SRESZ        LAB|PROCESS|15
-#define K_EXPORT       LAB|PROCESS|16
-#define K_GLOBAL       LAB|PROCESS|17
-#define K_PRINT        LAB|PROCESS|19
-#define K_FORM                 LAB|PROCESS|20
-#define K_HEADING      LAB|PROCESS|21
-#define K_PAGE         LAB|PROCESS|22
-#define K_IMPORT       LAB|PROCESS|23
-#define K_PROGRAM      LAB|PROCESS|24
-#define K_END          PROCESS|25
-#define K_INCLUDE      PROCESS|26
-#define K_IGNORED      PROCESS|27
-#define K_ASSIGNA      28
-#define K_ASSIGNC      29
-#define K_AIF          PROCESS|30
-#define K_AELSE                PROCESS|31
-#define K_AENDI                PROCESS|32
-#define K_AREPEAT      PROCESS|33
-#define K_AENDR                PROCESS|34
-#define K_AWHILE       35
-#define K_AENDW                PROCESS|36
-#define K_EXITM                37
-#define K_MACRO                PROCESS|38
-#define K_ENDM         39
-#define K_ALIGN                PROCESS|LAB|40
-
-
-static struct
-{
+      if (x == comment_char)
+       chartype[x] |= COMMENTBIT;
+    }
+}
+
+/* What to do with all the keywords.  */
+#define PROCESS        0x1000  /* Run substitution over the line.  */
+#define LAB            0x2000  /* Spit out the label.  */
+
+#define K_EQU          (PROCESS|1)
+#define K_ASSIGN       (PROCESS|2)
+#define K_REG          (PROCESS|3)
+#define K_ORG          (PROCESS|4)
+#define K_RADIX        (PROCESS|5)
+#define K_DATA                 (LAB|PROCESS|6)
+#define K_DATAB        (LAB|PROCESS|7)
+#define K_SDATA        (LAB|PROCESS|8)
+#define K_SDATAB       (LAB|PROCESS|9)
+#define K_SDATAC       (LAB|PROCESS|10)
+#define K_SDATAZ       (LAB|PROCESS|11)
+#define K_RES          (LAB|PROCESS|12)
+#define K_SRES                 (LAB|PROCESS|13)
+#define K_SRESC        (LAB|PROCESS|14)
+#define K_SRESZ        (LAB|PROCESS|15)
+#define K_EXPORT       (LAB|PROCESS|16)
+#define K_GLOBAL       (LAB|PROCESS|17)
+#define K_PRINT        (LAB|PROCESS|19)
+#define K_FORM                 (LAB|PROCESS|20)
+#define K_HEADING      (LAB|PROCESS|21)
+#define K_PAGE         (LAB|PROCESS|22)
+#define K_IMPORT       (LAB|PROCESS|23)
+#define K_PROGRAM      (LAB|PROCESS|24)
+#define K_END          (PROCESS|25)
+#define K_INCLUDE      (PROCESS|26)
+#define K_IGNORED      (PROCESS|27)
+#define K_ASSIGNA      (PROCESS|28)
+#define K_ASSIGNC      (29)
+#define K_AIF          (PROCESS|30)
+#define K_AELSE                (PROCESS|31)
+#define K_AENDI                (PROCESS|32)
+#define K_AREPEAT      (PROCESS|33)
+#define K_AENDR                (PROCESS|34)
+#define K_AWHILE       (35)
+#define K_AENDW                (PROCESS|36)
+#define K_EXITM                (37)
+#define K_MACRO                (PROCESS|38)
+#define K_ENDM         (39)
+#define K_ALIGN                (PROCESS|LAB|40)
+#define K_ALTERNATE     (41)
+#define K_DB           (LAB|PROCESS|42)
+#define K_DW           (LAB|PROCESS|43)
+#define K_DL           (LAB|PROCESS|44)
+#define K_LOCAL                (45)
+#define K_IFEQ         (PROCESS|46)
+#define K_IFNE         (PROCESS|47)
+#define K_IFLT         (PROCESS|48)
+#define K_IFLE         (PROCESS|49)
+#define K_IFGE         (PROCESS|50)
+#define K_IFGT         (PROCESS|51)
+#define K_IFC          (PROCESS|52)
+#define K_IFNC         (PROCESS|53)
+#define K_IRP          (PROCESS|54)
+#define K_IRPC         (PROCESS|55)
+
+struct keyword {
   char *name;
   int code;
   int extra;
-}
-kinfo[] =
-{
+};
+
+static struct keyword kinfo[] = {
   { "EQU", K_EQU, 0 },
+  { "ALTERNATE", K_ALTERNATE, 0 },
   { "ASSIGN", K_ASSIGN, 0 },
   { "REG", K_REG, 0 },
   { "ORG", K_ORG, 0 },
   { "RADIX", K_RADIX, 0 },
   { "DATA", K_DATA, 0 },
+  { "DB", K_DB, 0 },
+  { "DW", K_DW, 0 },
+  { "DL", K_DL, 0 },
   { "DATAB", K_DATAB, 0 },
   { "SDATA", K_SDATA, 0 },
   { "SDATAB", K_SDATAB, 0 },
@@ -3205,11 +3114,36 @@ kinfo[] =
   { "AWHILE", K_AWHILE, 0 },
   { "ALIGN", K_ALIGN, 0 },
   { "AENDW", K_AENDW, 0 },
+  { "ALTERNATE", K_ALTERNATE, 0 },
+  { "LOCAL", K_LOCAL, 0 },
+  { NULL, 0, 0 }
+};
+
+/* Although the conditional operators are handled by gas, we need to
+   handle them here as well, in case they are used in a recursive
+   macro to end the recursion.  */
+
+static struct keyword mrikinfo[] = {
+  { "IFEQ", K_IFEQ, 0 },
+  { "IFNE", K_IFNE, 0 },
+  { "IFLT", K_IFLT, 0 },
+  { "IFLE", K_IFLE, 0 },
+  { "IFGE", K_IFGE, 0 },
+  { "IFGT", K_IFGT, 0 },
+  { "IFC", K_IFC, 0 },
+  { "IFNC", K_IFNC, 0 },
+  { "ELSEC", K_AELSE, 0 },
+  { "ENDC", K_AENDI, 0 },
+  { "MEXIT", K_EXITM, 0 },
+  { "REPT", K_AREPEAT, 0 },
+  { "IRP", K_IRP, 0 },
+  { "IRPC", K_IRPC, 0 },
+  { "ENDR", K_AENDR, 0 },
   { NULL, 0, 0 }
 };
 
 /* Look for a pseudo op on the line. If one's there then call
-   its handler. */
+   its handler.  */
 
 static int
 process_pseudo_op (idx, line, acc)
@@ -3217,17 +3151,23 @@ process_pseudo_op (idx, line, acc)
      sb *line;
      sb *acc;
 {
-  char *in = line->ptr + idx;
+  int oidx = idx;
 
-  if (in[0] == '.')
+  if (line->ptr[idx] == '.' || alternate || mri)
     {
-      /* Scan forward and find pseudo name */
+      /* Scan forward and find pseudo name.  */
+      char *in;
       hash_entry *ptr;
 
-      char *s = in + 1;
-      char *e = s;
+      char *s;
+      char *e;
+      if (line->ptr[idx] == '.')
+       idx++;
+      in = line->ptr + idx;
+      s = in;
+      e = s;
       sb_reset (acc);
-      idx++;
+
       while (idx < line->len && *e && ISFIRSTCHAR (*e))
        {
          sb_add_char (acc, *e);
@@ -3239,11 +3179,17 @@ process_pseudo_op (idx, line, acc)
 
       if (!ptr)
        {
-         WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc)));
+#if 0
+         /* This one causes lots of pain when trying to preprocess
+            ordinary code.  */
+         WARNING ((stderr, _("Unrecognised pseudo op `%s'.\n"),
+                   sb_name (acc)));
+#endif
          return 0;
        }
       if (ptr->value.i & LAB)
-       {                       /* output the label */
+       {
+         /* Output the label.  */
          if (label.len)
            {
              fprintf (outfile, "%s:\t", sb_name (&label));
@@ -3252,13 +3198,25 @@ process_pseudo_op (idx, line, acc)
            fprintf (outfile, "\t");
        }
 
+      if (mri && ptr->value.i == K_END)
+       {
+         sb t;
+
+         sb_new (&t);
+         sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
+         fprintf (outfile, "\t%s", sb_name (&t));
+         sb_kill (&t);
+       }
+
       if (ptr->value.i & PROCESS)
        {
-         /* Polish the rest of the line before handling the pseudo op */
-/*           strip_comments(line);*/
+         /* Polish the rest of the line before handling the pseudo op.  */
+#if 0
+         strip_comments (line);
+#endif
          sb_reset (acc);
          process_assigns (idx, line, acc);
-         sb_reset(line);
+         sb_reset (line);
          change_base (0, acc, line);
          idx = 0;
        }
@@ -3266,6 +3224,9 @@ process_pseudo_op (idx, line, acc)
        {
          switch (ptr->value.i)
            {
+           case K_AIF:
+             do_aif (idx, line);
+             break;
            case K_AELSE:
              do_aelse ();
              break;
@@ -3279,6 +3240,10 @@ process_pseudo_op (idx, line, acc)
        {
          switch (ptr->value.i)
            {
+           case K_ALTERNATE:
+             alternate = 1;
+             macro_init (1, mri, 0, exp_get_abs);
+             return 1;
            case K_AELSE:
              do_aelse ();
              return 1;
@@ -3286,13 +3251,22 @@ process_pseudo_op (idx, line, acc)
              do_aendi ();
              return 1;
            case K_ORG:
-             ERROR ((stderr, "ORG command not allowed.\n"));
+             ERROR ((stderr, _("ORG command not allowed.\n")));
              break;
            case K_RADIX:
              do_radix (line);
              return 1;
+           case K_DB:
+             do_data (idx, line, 1);
+             return 1;
+           case K_DW:
+             do_data (idx, line, 2);
+             return 1;
+           case K_DL:
+             do_data (idx, line, 4);
+             return 1;
            case K_DATA:
-             do_data (idx, line);
+             do_data (idx, line, 0);
              return 1;
            case K_DATAB:
              do_datab (idx, line);
@@ -3310,7 +3284,7 @@ process_pseudo_op (idx, line, acc)
              do_sdata (idx, line, 'z');
              return 1;
            case K_ASSIGN:
-             do_assign (1, 0, line);
+             do_assign (0, 0, line);
              return 1;
            case K_AIF:
              do_aif (idx, line);
@@ -3328,7 +3302,7 @@ process_pseudo_op (idx, line, acc)
              do_aendr ();
              return 1;
            case K_EQU:
-             do_assign (0, idx, line);
+             do_assign (1, idx, line);
              return 1;
            case K_ALIGN:
              do_align (idx, line);
@@ -3342,6 +3316,9 @@ process_pseudo_op (idx, line, acc)
            case K_INCLUDE:
              do_include (idx, line);
              return 1;
+           case K_LOCAL:
+             do_local (idx, line);
+             return 1;
            case K_MACRO:
              do_macro (idx, line);
              return 1;
@@ -3375,7 +3352,7 @@ process_pseudo_op (idx, line, acc)
            case K_IGNORED:
              return 1;
            case K_END:
-             do_end ();
+             do_end (line);
              return 1;
            case K_ASSIGNA:
              do_assigna (idx, line);
@@ -3389,16 +3366,67 @@ process_pseudo_op (idx, line, acc)
            case K_REG:
              do_reg (idx, line);
              return 1;
+           case K_IFEQ:
+             do_if (idx, line, EQ);
+             return 1;
+           case K_IFNE:
+             do_if (idx, line, NE);
+             return 1;
+           case K_IFLT:
+             do_if (idx, line, LT);
+             return 1;
+           case K_IFLE:
+             do_if (idx, line, LE);
+             return 1;
+           case K_IFGE:
+             do_if (idx, line, GE);
+             return 1;
+           case K_IFGT:
+             do_if (idx, line, GT);
+             return 1;
+           case K_IFC:
+             do_ifc (idx, line, 0);
+             return 1;
+           case K_IFNC:
+             do_ifc (idx, line, 1);
+             return 1;
+           case K_IRP:
+             do_irp (idx, line, 0);
+             return 1;
+           case K_IRPC:
+             do_irp (idx, line, 1);
+             return 1;
            }
        }
     }
   return 0;
 }
 
+/* Add a keyword to the hash table.  */
 
+static void
+add_keyword (name, code)
+     const char *name;
+     int code;
+{
+  sb label;
+  int j;
+
+  sb_new (&label);
+  sb_add_string (&label, name);
+
+  hash_add_to_int_table (&keyword_hash_table, &label, code);
+
+  sb_reset (&label);
+  for (j = 0; name[j]; j++)
+    sb_add_char (&label, name[j] - 'A' + 'a');
+  hash_add_to_int_table (&keyword_hash_table, &label, code);
+
+  sb_kill (&label);
+}
 
 /* Build the keyword hash table - put each keyword in the table twice,
-   once upper and once lower case.*/
+   once upper and once lower case.  */
 
 static void
 process_init ()
@@ -3406,113 +3434,261 @@ process_init ()
   int i;
 
   for (i = 0; kinfo[i].name; i++)
+    add_keyword (kinfo[i].name, kinfo[i].code);
+
+  if (mri)
     {
-      sb label;
-      int j;
-      sb_new (&label);
-      sb_add_string (&label, kinfo[i].name);
+      for (i = 0; mrikinfo[i].name; i++)
+       add_keyword (mrikinfo[i].name, mrikinfo[i].code);
+    }
+}
 
-      hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
+static void
+do_define (string)
+     const char *string;
+{
+  sb label;
+  int res = 1;
+  hash_entry *ptr;
+  sb_new (&label);
 
-      sb_reset (&label);
-      for (j = 0; kinfo[i].name[j]; j++)
-       sb_add_char (&label, kinfo[i].name[j] - 'A' + 'a');
-      hash_add_to_int_table (&keyword_hash_table, &label, kinfo[i].code);
+  while (*string)
+    {
+      if (*string == '=')
+       {
+         sb value;
+         sb_new (&value);
+         string++;
+         while (*string)
+           {
+             sb_add_char (&value, *string);
+             string++;
+           }
+         exp_get_abs (_("Invalid expression on command line.\n"),
+                      0, &value, &res);
+         sb_kill (&value);
+         break;
+       }
+      sb_add_char (&label, *string);
 
-      sb_kill (&label);
+      string++;
     }
+
+  ptr = hash_create (&vars, &label);
+  free_old_entry (ptr);
+  ptr->type = hash_integer;
+  ptr->value.i = res;
+  sb_kill (&label);
 }
 
-int
-main (ac, av)
-     int ac;
-     char **av;
+char *program_name;
+
+/* The list of long options.  */
+static struct option long_options[] =
 {
-  int i;
+  { "alternate", no_argument, 0, 'a' },
+  { "include", required_argument, 0, 'I' },
+  { "commentchar", required_argument, 0, 'c' },
+  { "copysource", no_argument, 0, 's' },
+  { "debug", no_argument, 0, 'd' },
+  { "help", no_argument, 0, 'h' },
+  { "mri", no_argument, 0, 'M' },
+  { "output", required_argument, 0, 'o' },
+  { "print", no_argument, 0, 'p' },
+  { "unreasonable", no_argument, 0, 'u' },
+  { "version", no_argument, 0, 'v' },
+  { "define", required_argument, 0, 'd' },
+  { NULL, no_argument, 0, 0 }
+};
+
+/* Show a usage message and exit.  */
+static void
+show_usage (file, status)
+     FILE *file;
+     int status;
+{
+  fprintf (file, _("\
+Usage: %s \n\
+  [-a]      [--alternate]         enter alternate macro mode\n\
+  [-c char] [--commentchar char]  change the comment character from !\n\
+  [-d]      [--debug]             print some debugging info\n\
+  [-h]      [--help]              print this message\n\
+  [-M]      [--mri]               enter MRI compatibility mode\n\
+  [-o out]  [--output out]        set the output file\n\
+  [-p]      [--print]             print line numbers\n"), program_name);
+  fprintf (file, _("\
+  [-s]      [--copysource]        copy source through as comments \n\
+  [-u]      [--unreasonable]      allow unreasonable nesting\n\
+  [-v]      [--version]           print the program version\n\
+  [-Dname=value]                  create preprocessor variable called name, with value\n\
+  [-Ipath]                        add to include path list\n\
+  [in-file]\n"));
+  if (status == 0)
+    printf (_("Report bugs to %s\n"), REPORT_BUGS_TO);
+  exit (status);
+}
+
+/* Display a help message and exit.  */
 
+static void
+show_help ()
+{
+  printf (_("%s: Gnu Assembler Macro Preprocessor\n"), program_name);
+  show_usage (stdout, 0);
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int opt;
+  char *out_name = 0;
   sp = include_stack;
 
   ifstack[0].on = 1;
   ifi = 0;
 
-  chartype_init ();
+#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+  setlocale (LC_MESSAGES, "");
+#endif
+#if defined (HAVE_SETLOCALE)
+  setlocale (LC_CTYPE, "");
+#endif
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  program_name = argv[0];
+  xmalloc_set_program_name (program_name);
 
-  hash_new_table (101, &macro_table);
   hash_new_table (101, &keyword_hash_table);
   hash_new_table (101, &assign_hash_table);
   hash_new_table (101, &vars);
 
   sb_new (&label);
+
+  while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
+                            (int *) NULL))
+        != EOF)
+    {
+      switch (opt)
+       {
+       case 'o':
+         out_name = optarg;
+         break;
+       case 'u':
+         unreasonable = 1;
+         break;
+       case 'I':
+         {
+           include_path *p = (include_path *) xmalloc (sizeof (include_path));
+           p->next = NULL;
+           sb_new (&p->path);
+           sb_add_string (&p->path, optarg);
+           if (paths_tail)
+             paths_tail->next = p;
+           else
+             paths_head = p;
+           paths_tail = p;
+         }
+         break;
+       case 'p':
+         print_line_number = 1;
+         break;
+       case 'c':
+         comment_char = optarg[0];
+         break;
+       case 'a':
+         alternate = 1;
+         break;
+       case 's':
+         copysource = 1;
+         break;
+       case 'd':
+         stats = 1;
+         break;
+       case 'D':
+         do_define (optarg);
+         break;
+       case 'M':
+         mri = 1;
+         comment_char = ';';
+         break;
+       case 'h':
+         show_help ();
+         /* NOTREACHED  */
+       case 'v':
+         /* This output is intended to follow the GNU standards document.  */
+         printf (_("GNU assembler pre-processor %s\n"), program_version);
+         printf (_("Copyright 1996 Free Software Foundation, Inc.\n"));
+         printf (_("\
+This program is free software; you may redistribute it under the terms of\n\
+the GNU General Public License.  This program has absolutely no warranty.\n"));
+         exit (0);
+         /* NOTREACHED  */
+       case 0:
+         break;
+       default:
+         show_usage (stderr, 1);
+         /* NOTREACHED  */
+       }
+    }
+
   process_init ();
 
-  /* Find the output file */
-  for (i = 1; i < ac; i++)
+  macro_init (alternate, mri, 0, exp_get_abs);
+
+  if (out_name)
     {
-      if (av[i][0] == '-')
+      outfile = fopen (out_name, "w");
+      if (!outfile)
        {
-         if (av[i][1] == 'c' && av[i][2] == 0)
-           {
-             copysource = 1;
-           }
-         else if (av[i][1] == 'p' && av[i][2] == 0)
-           {
-             print_line_number = 1;
-           }
-         else if (av[i][1] == 'u' && av[i][2] == 0)
-           {
-             unreasonable = 1;
-           }
-         else if (av[i][1] == 's' && av[i][2] == 0)
-           {
-             stats = 1;
-           }
-         else if (av[i][1] == 'o' && av[i][2] == 0 & i + 1 < ac)
-           {
-             /* Got output file name */
-             i++;
-             outfile = fopen (av[i], "w");
-             if (!outfile)
-               {
-                 fprintf (stderr, "%s: Can't open output file `%s'.\n",
-                          av[0], av[i]);
-                 exit (1);
-               }
-           }
-         else
-           {
-             fprintf (stderr, "Usage: %s [-o filename] infile1 infile2...\n",
-                      av[0]);
-             exit (1);
-           }
+         fprintf (stderr, _("%s: Can't open output file `%s'.\n"),
+                  program_name, out_name);
+         exit (1);
        }
     }
+  else
+    {
+      outfile = stdout;
+    }
 
+  chartype_init ();
   if (!outfile)
     outfile = stdout;
 
-  /* Process all the input files */
+  /* Process all the input files */
 
-  for (i = 1; i < ac; i++)
+  while (optind < argc)
     {
-      if (av[i][0] == '-')
+      if (new_file (argv[optind]))
        {
-         if (av[i][1] == 'o')
-           i++;
+         process_file ();
        }
       else
        {
-         if (new_file (av[i]))
-           {
-             process_file ();
-           }
-         else
-           {
-             fprintf (stderr, "%s: Can't open input file `%s'.\n",
-                      av[0], av[i]);
-             exit (1);
-           }
+         fprintf (stderr, _("%s: Can't open input file `%s'.\n"),
+                  program_name, argv[optind]);
+         exit (1);
        }
+      optind++;
     }
+
   quit ();
   return 0;
 }
+
+/* This function is used because an abort in some of the other files
+   may be compiled into as_abort because they include as.h.  */
+
+void
+as_abort (file, line, fn)
+     const char *file, *fn;
+     int line;
+{
+  fprintf (stderr, _("Internal error, aborting at %s line %d"), file, line);
+  if (fn)
+    fprintf (stderr, " in %s", fn);
+  fprintf (stderr, _("\nPlease report this bug.\n"));
+  exit (1);
+}
This page took 0.070343 seconds and 4 git commands to generate.