Assorted code cleanup and fixes for hppa. Re-enable elf32-hppa as
[deliverable/binutils-gdb.git] / gas / macro.c
index 13dd4af651698ecf8780075c30c82b412b024b75..df01bc5ca0c43d5015ff1a8ffffa24227aea294a 100644 (file)
@@ -1,5 +1,5 @@
 /* macro.c - macro support for gas and gasp
-   Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
 
    Written by Steve and Judy Chamberlain of Cygnus Support,
       sac@cygnus.com
    02111-1307, USA. */
 
 #include "config.h"
+
+/* AIX requires this to be the first thing in the file.  */
+#ifdef __GNUC__
+# ifndef alloca
+#  ifdef __STDC__
+extern void *alloca ();
+#  else
+extern char *alloca ();
+#  endif
+# endif
+#else
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+#    if !defined (__STDC__) && !defined (__hpux)
+extern char *alloca ();
+#    else
+extern void *alloca ();
+#    endif /* __STDC__, __hpux */
+#   endif /* alloca */
+#  endif /* _AIX */
+# endif /* HAVE_ALLOCA_H */
+#endif
+
 #include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
 #include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "libiberty.h"
 #include "sb.h"
 #include "hash.h"
 #include "macro.h"
 
+#include "asintl.h"
+
 /* The routines in this file handle macro definition and expansion.
    They are called by both gasp and gas.  */
 
-/* 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;
-
-/* Other values found in the index field of a formal_entry.  */
-#define QUAL_INDEX (-1)
-#define NARG_INDEX (-2)
-#define LOCAL_INDEX (-3)
-
-/* 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 */
-    struct hash_control *formal_hash; /* hash table of formals. */
-  }
-macro_entry;
-
 /* Internal functions.  */
 
 static int get_token PARAMS ((int, sb *, sb *));
@@ -84,7 +87,8 @@ static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int));
 
 #define ISSEP(x) \
  ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \
-  || (x) == '<' || (x) == '>' || (x) == ')' || (x) == '(')
+  || (x) == ')' || (x) == '(' \
+  || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>')))
 
 #define ISBASE(x) \
   ((x) == 'b' || (x) == 'B' \
@@ -108,6 +112,10 @@ static int macro_alternate;
 
 static int macro_mri;
 
+/* Whether we should strip '@' characters.  */
+
+static int macro_strip_at;
+
 /* Function to use to parse an expression.  */
 
 static int (*macro_expr) PARAMS ((const char *, int, sb *, int *));
@@ -119,18 +127,29 @@ static int macro_number;
 /* Initialize macro processing.  */
 
 void
-macro_init (alternate, mri, expr)
+macro_init (alternate, mri, strip_at, expr)
      int alternate;
      int mri;
+     int strip_at;
      int (*expr) PARAMS ((const char *, int, sb *, int *));
 {
   macro_hash = hash_new ();
   macro_defined = 0;
   macro_alternate = alternate;
   macro_mri = mri;
+  macro_strip_at = strip_at;
   macro_expr = expr;
 }
 
+/* Switch in and out of MRI mode on the fly.  */
+
+void
+macro_mri_mode (mri)
+     int mri;
+{
+  macro_mri = mri;
+}
+
 /* Read input lines till we get to a TO string.
    Increase nesting depth if we get a FROM string.
    Put the results into sb at PTR.
@@ -190,9 +209,11 @@ buffer_and_nest (from, to, ptr, get_line)
        {
          if (ptr->ptr[i] == '.')
              i++;
-         if (strncasecmp (ptr->ptr + i, from, from_len) == 0)
+         if (strncasecmp (ptr->ptr + i, from, from_len) == 0
+             && (ptr->len == (i + from_len) || ! isalnum (ptr->ptr[i + from_len])))
            depth++;
-         if (strncasecmp (ptr->ptr + i, to, to_len) == 0)
+         if (strncasecmp (ptr->ptr + i, to, to_len) == 0
+             && (ptr->len == (i + to_len) || ! isalnum (ptr->ptr[i + to_len])))
            {
              depth--;
              if (depth == 0)
@@ -254,49 +275,31 @@ getstring (idx, in, acc)
 
   while (idx < in->len
         && (in->ptr[idx] == '"' 
-            || in->ptr[idx] == '<' 
+            || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
             || (in->ptr[idx] == '\'' && macro_alternate)))
     {
       if (in->ptr[idx] == '<')
        {
-         if (macro_alternate || macro_mri)
+         int nest = 0;
+         idx++;
+         while ((in->ptr[idx] != '>' || nest)
+                && idx < in->len)
            {
-             int nest = 0;
-             idx++;
-             while ((in->ptr[idx] != '>' || nest)
-                    && idx < in->len)
+             if (in->ptr[idx] == '!')
                {
-                 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++  ;
+                 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
-           {
-             int code;
-             idx++;
-             idx = ((*macro_expr)
-                    ("character code in string must be absolute expression",
-                     idx, in, &code));
-             sb_add_char (acc, code);
-
-#if 0
-             if (in->ptr[idx] != '>')
-               ERROR ((stderr, "Missing > for character code.\n"));
-#endif
-             idx++;
            }
+         idx++;
        }
       else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
        {
@@ -360,7 +363,7 @@ get_any_string (idx, in, out, expand, pretend_quoted)
          int val;
          char buf[20];
          /* Turns the next expression into a string */
-         idx = (*macro_expr) ("% operator needs absolute expression",
+         idx = (*macro_expr) (_("% operator needs absolute expression"),
                               idx + 1,
                               in,
                               &val);
@@ -368,10 +371,12 @@ get_any_string (idx, in, out, expand, pretend_quoted)
          sb_add_string (out, buf);
        }
       else if (in->ptr[idx] == '"'
-              || in->ptr[idx] == '<'
+              || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
               || (macro_alternate && in->ptr[idx] == '\''))
        {
-         if (macro_alternate && expand)
+         if (macro_alternate
+             && ! macro_strip_at
+             && expand)
            {
              /* Keep the quotes */
              sb_add_char (out,  '\"');
@@ -393,7 +398,8 @@ get_any_string (idx, in, out, expand, pretend_quoted)
                     || (in->ptr[idx] != ' '
                         && in->ptr[idx] != '\t'
                         && in->ptr[idx] != ','
-                        && in->ptr[idx] != '<')))
+                        && (in->ptr[idx] != '<'
+                            || (! macro_alternate && ! macro_mri)))))
            {
              if (in->ptr[idx] == '"' 
                  || in->ptr[idx] == '\'')
@@ -465,6 +471,7 @@ do_formals (macro, idx, in)
   if (macro_mri)
     {
       formal_entry *formal;
+      const char *name;
 
       /* Add a special NARG formal, which macro_expand will set to the
          number of arguments.  */
@@ -474,10 +481,17 @@ do_formals (macro, idx, in)
       sb_new (&formal->def);
       sb_new (&formal->actual);
 
-      sb_add_string (&formal->name, "NARG");
+      /* The same MRI assemblers which treat '@' characters also use
+         the name $NARG.  At least until we find an exception.  */
+      if (macro_strip_at)
+       name = "$NARG";
+      else
+       name = "NARG";
+
+      sb_add_string (&formal->name, name);
 
       /* Add to macro's hash table */
-      hash_jam (macro->formal_hash, "NARG", formal);
+      hash_jam (macro->formal_hash, name, formal);
 
       formal->index = NARG_INDEX;
       *p = formal;
@@ -488,17 +502,20 @@ do_formals (macro, idx, in)
 }
 
 /* Define a new macro.  Returns NULL on success, otherwise returns an
-   error message.  */
+   error message.  If NAMEP is not NULL, *NAMEP is set to the name of
+   the macro which was defined.  */
 
 const char *
-define_macro (idx, in, label, get_line)
+define_macro (idx, in, label, get_line, namep)
      int idx;
      sb *in;
      sb *label;
      int (*get_line) PARAMS ((sb *));
+     const char **namep;
 {
   macro_entry *macro;
   sb name;
+  const char *namestr;
 
   macro = (macro_entry *) xmalloc (sizeof (macro_entry));
   sb_new (&macro->sub);
@@ -509,16 +526,16 @@ define_macro (idx, in, label, get_line)
 
   idx = sb_skip_white (idx, in);
   if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
-    return "unexpected end of file in macro definition";
+    return _("unexpected end of file in macro definition");
   if (label != NULL && label->len != 0)
     {
       sb_add_sb (&name, label);
-      if (in->ptr[idx] == '(')
+      if (idx < in->len && in->ptr[idx] == '(')
        {
          /* It's the label: MACRO (formals,...)  sort */
          idx = do_formals (macro, idx + 1, in);
          if (in->ptr[idx] != ')')
-           return "missing ) after formals";
+           return _("missing ) after formals");
        }
       else
        {
@@ -529,18 +546,22 @@ define_macro (idx, in, label, get_line)
   else
     {
       idx = get_token (idx, in, &name);
-      idx = sb_skip_white (idx, in);
+      idx = sb_skip_comma (idx, in);
       idx = do_formals (macro, idx, in);
     }
 
   /* and stick it in the macro hash table */
   for (idx = 0; idx < name.len; idx++)
-    if (isupper (name.ptr[idx]))
+    if (isupper ((unsigned char) name.ptr[idx]))
       name.ptr[idx] = tolower (name.ptr[idx]);
-  hash_jam (macro_hash, sb_terminate (&name), (PTR) macro);
+  namestr = sb_terminate (&name);
+  hash_jam (macro_hash, namestr, (PTR) macro);
 
   macro_defined = 1;
 
+  if (namep != NULL)
+    *namep = namestr;
+
   return NULL;
 }
 
@@ -554,7 +575,10 @@ get_apost_token (idx, in, name, kind)
      int kind;
 {
   idx = get_token (idx, in, name);
-  if (idx < in->len && in->ptr[idx] == kind && ! macro_mri)
+  if (idx < in->len
+      && in->ptr[idx] == kind
+      && (! macro_mri || macro_strip_at)
+      && (! macro_strip_at || kind == '@'))
     idx++;
   return idx;
 }
@@ -562,8 +586,8 @@ get_apost_token (idx, in, name, kind)
 /* Substitute the actual value for a formal parameter.  */
 
 static int
-sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere)
-     int src;
+sub_actual (start, in, t, formal_hash, kind, out, copyifnotthere)
+     int start;
      sb *in;
      sb *t;
      struct hash_control *formal_hash;
@@ -571,11 +595,18 @@ sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere)
      sb *out;
      int copyifnotthere;
 {
+  int src;
   formal_entry *ptr;
 
-  src = get_apost_token (src, in, t, kind);
-  /* See if it's in the macro's hash table */
-  ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
+  src = get_apost_token (start, in, t, kind);
+  /* See if it's in the macro's hash table, unless this is
+     macro_strip_at and kind is '@' and the token did not end in '@'.  */
+  if (macro_strip_at
+      && kind == '@'
+      && (src == start || in->ptr[src - 1] != '@'))
+    ptr = NULL;
+  else
+    ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
   if (ptr)
     {
       if (ptr->actual.len)
@@ -587,6 +618,11 @@ sub_actual (src, in, t, formal_hash, kind, out, copyifnotthere)
          sb_add_sb (out, &ptr->def);
        }
     }
+  else if (kind == '&')
+    {
+      /* Doing this permits people to use & in macro bodies.  */
+      sb_add_char (out, '&');
+    }
   else if (copyifnotthere)
     {
       sb_add_sb (out, t);
@@ -622,12 +658,16 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
       if (in->ptr[src] == '&')
        {
          sb_reset (&t);
-         if (macro_mri && src + 1 < in->len && in->ptr[src + 1] == '&')
+         if (macro_mri)
            {
-             src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
+             if (src + 1 < in->len && in->ptr[src + 1] == '&')
+               src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
+             else
+               sb_add_char (out, in->ptr[src++]);
            }
          else
            {
+             /* FIXME: Why do we do this?  */
              src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
            }
        }
@@ -652,15 +692,15 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
              if (in->ptr[src] == ')')
                src++;
              else
-               return "missplaced )";
+               return _("missplaced )");
            }
          else if (in->ptr[src] == '@')
            {
              /* Sub in the macro invocation number */
 
-             char buffer[6];
+             char buffer[10];
              src++;
-             sprintf (buffer, "%05d", macro_number);
+             sprintf (buffer, "%d", macro_number);
              sb_add_string (out, buffer);
            }
          else if (in->ptr[src] == '&')
@@ -705,7 +745,10 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
       else if ((macro_alternate || macro_mri)
               && (isalpha ((unsigned char) in->ptr[src])
                   || in->ptr[src] == '_'
-                  || in->ptr[src] == '$'))
+                  || in->ptr[src] == '$')
+              && (! inquote
+                  || ! macro_strip_at
+                  || (src > 0 && in->ptr[src - 1] == '@')))
        {
          if (! locals
              || src + 5 >= in->len
@@ -713,7 +756,9 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
              || ! ISWHITE (in->ptr[src + 5]))
            {
              sb_reset (&t);
-             src = sub_actual (src, in, &t, formal_hash, '\'', out, 1);
+             src = sub_actual (src, in, &t, formal_hash,
+                               (macro_strip_at && inquote) ? '@' : '\'',
+                               out, 1);
            }
          else
            {
@@ -764,6 +809,16 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
          inquote = !inquote;
          sb_add_char (out, in->ptr[src++]);
        }
+      else if (in->ptr[src] == '@' && macro_strip_at)
+       {
+         ++src;
+         if (src < in->len
+             && in->ptr[src] == '@')
+           {
+             sb_add_char (out, '@');
+             ++src;
+           }
+       }
       else if (macro_mri
               && in->ptr[src] == '='
               && src + 1 < in->len
@@ -775,7 +830,19 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
          src = get_token (src + 2, in, &t);
          ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
          if (ptr == NULL)
-           return "macro formal argument does not exist";
+           {
+             /* FIXME: We should really return a warning string here,
+                 but we can't, because the == might be in the MRI
+                 comment field, and, since the nature of the MRI
+                 comment field depends upon the exact instruction
+                 being used, we don't have enough information here to
+                 figure out whether it is or not.  Instead, we leave
+                 the == in place, which should cause a syntax error if
+                 it is not in a comment.  */
+             sb_add_char (out, '=');
+             sb_add_char (out, '=');
+             sb_add_sb (out, &t);
+           }
          else
            {
              if (ptr->actual.len)
@@ -801,6 +868,9 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
       formal_entry *f;
 
       f = loclist->next;
+      /* Setting the value to NULL effectively deletes the entry.  We
+         avoid calling hash_delete because it doesn't reclaim memory.  */
+      hash_jam (formal_hash, sb_terminate (&loclist->name), NULL);
       sb_kill (&loclist->name);
       sb_kill (&loclist->def);
       sb_kill (&loclist->actual);
@@ -870,25 +940,26 @@ macro_expand (idx, in, m, out, comment_char)
       scan = idx;
       while (scan < in->len
             && !ISSEP (in->ptr[scan])
+            && !(macro_mri && in->ptr[scan] == '\'')
             && (!macro_alternate && in->ptr[scan] != '='))
        scan++;
       if (scan < in->len && !macro_alternate && in->ptr[scan] == '=')
        {
          is_keyword = 1;
-         if (is_positional)
-           return "can't mix positional and keyword arguments";
+
+         /* It's OK to go from positional to keyword.  */
 
          /* 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] != '=')
-           return "confusion in formal parameters";
+           return _("confusion in formal parameters");
 
          /* Lookup the formal in the macro's list */
          ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
          if (!ptr)
-           return "macro formal argument does not exist";
+           return _("macro formal argument does not exist");
          else
            {
              /* Insert this value into the right place */
@@ -903,7 +974,7 @@ macro_expand (idx, in, m, out, comment_char)
          /* This is a positional arg */
          is_positional = 1;
          if (is_keyword)
-           return "can't mix positional and keyword arguments";
+           return _("can't mix positional and keyword arguments");
 
          if (!f)
            {
@@ -911,7 +982,7 @@ macro_expand (idx, in, m, out, comment_char)
              int c;
 
              if (!macro_mri)
-               return "too many positional arguments";
+               return _("too many positional arguments");
 
              f = (formal_entry *) xmalloc (sizeof (formal_entry));
              sb_new (&f->name);
@@ -940,7 +1011,15 @@ macro_expand (idx, in, m, out, comment_char)
          while (f != NULL && f->index < 0);
        }
 
-      idx = sb_skip_comma (idx, in);
+      if (! macro_mri)
+       idx = sb_skip_comma (idx, in);
+      else
+       {
+         if (in->ptr[idx] == ',')
+           ++idx;
+         if (ISWHITE (in->ptr[idx]))
+           break;
+       }
     }
 
   if (macro_mri)
@@ -948,7 +1027,7 @@ macro_expand (idx, in, m, out, comment_char)
       char buffer[20];
 
       sb_reset (&t);
-      sb_add_string (&t, "NARG");
+      sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
       ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
       sb_reset (&ptr->actual);
       sprintf (buffer, "%d", narg);
@@ -993,11 +1072,12 @@ macro_expand (idx, in, m, out, comment_char)
    gasp.  Return 1 if a macro is found, 0 otherwise.  */
 
 int
-check_macro (line, expand, comment_char, error)
+check_macro (line, expand, comment_char, error, info)
      const char *line;
      sb *expand;
      int comment_char;
      const char **error;
+     macro_entry **info;
 {
   const char *s;
   char *copy, *cs;
@@ -1016,11 +1096,11 @@ check_macro (line, expand, comment_char, error)
         || *s == '$')
     ++s;
 
-  copy = (char *) xmalloc (s - line + 1);
+  copy = (char *) alloca (s - line + 1);
   memcpy (copy, line, s - line);
   copy[s - line] = '\0';
   for (cs = copy; *cs != '\0'; cs++)
-    if (isupper (*cs))
+    if (isupper ((unsigned char) *cs))
       *cs = tolower (*cs);
 
   macro = (macro_entry *) hash_find (macro_hash, copy);
@@ -1038,9 +1118,22 @@ check_macro (line, expand, comment_char, error)
 
   sb_kill (&line_sb);
 
+  /* export the macro information if requested */
+  if (info)
+    *info = macro;
+
   return 1;
 }
 
+/* Delete a macro.  */
+
+void
+delete_macro (name)
+     const char *name;
+{
+  hash_delete (macro_hash, name);
+}
+
 /* Handle the MRI IRP and IRPC pseudo-ops.  These are handled as a
    combined macro definition and execution.  This returns NULL on
    success, or an error message otherwise.  */
@@ -1069,7 +1162,7 @@ expand_irp (irpc, idx, in, out, get_line, comment_char)
 
   sb_new (&sub);
   if (! buffer_and_nest (mn, "ENDR", &sub, get_line))
-    return "unexpected end of file in irp or irpc";
+    return _("unexpected end of file in irp or irpc");
   
   sb_new (&f.name);
   sb_new (&f.def);
@@ -1077,7 +1170,7 @@ expand_irp (irpc, idx, in, out, get_line, comment_char)
 
   idx = get_token (idx, in, &f.name);
   if (f.name.len == 0)
-    return "missing model parameter";
+    return _("missing model parameter");
 
   h = hash_new ();
   err = hash_jam (h, sb_terminate (&f.name), &f);
@@ -1099,12 +1192,25 @@ expand_irp (irpc, idx, in, out, get_line, comment_char)
     }
   else
     {
+      if (irpc && in->ptr[idx] == '"')
+       ++idx;
       while (idx < in->len && in->ptr[idx] != comment_char)
        {
          if (!irpc)
            idx = get_any_string (idx, in, &f.actual, 1, 0);
          else
            {
+             if (in->ptr[idx] == '"')
+               {
+                 int nxt;
+
+                 nxt = sb_skip_white (idx + 1, in);
+                 if (nxt >= in->len || in->ptr[nxt] == comment_char)
+                   {
+                     idx = nxt;
+                     break;
+                   }
+               }
              sb_reset (&f.actual);
              sb_add_char (&f.actual, in->ptr[idx]);
              ++idx;
This page took 0.031263 seconds and 4 git commands to generate.