add more direct/unpack code
[deliverable/binutils-gdb.git] / gas / macro.c
index 13dd4af651698ecf8780075c30c82b412b024b75..e03b0f710b3c623e7756ddd8bb83142d0b689714 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, 1997 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__
+#ifdef __STDC__
+extern void *alloca ();
+#else
+extern char *alloca ();
+#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"
@@ -108,6 +143,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,15 +158,17 @@ 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;
 }
 
@@ -371,7 +412,9 @@ get_any_string (idx, in, out, expand, pretend_quoted)
               || in->ptr[idx] == '<'
               || (macro_alternate && in->ptr[idx] == '\''))
        {
-         if (macro_alternate && expand)
+         if (macro_alternate
+             && ! macro_strip_at
+             && expand)
            {
              /* Keep the quotes */
              sb_add_char (out,  '\"');
@@ -465,6 +508,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 +518,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 +539,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);
@@ -513,7 +567,7 @@ define_macro (idx, in, label, get_line)
   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);
@@ -529,7 +583,7 @@ 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);
     }
 
@@ -537,10 +591,14 @@ define_macro (idx, in, label, get_line)
   for (idx = 0; idx < name.len; idx++)
     if (isupper (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 +612,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 +623,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 +632,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)
@@ -622,12 +690,17 @@ 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?  It prevents people from
+                 using the & operator in a macro.  */
              src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
            }
        }
@@ -705,7 +778,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 +789,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 +842,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 +863,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 +901,7 @@ macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
       formal_entry *f;
 
       f = loclist->next;
+      hash_delete (formal_hash, sb_terminate (&loclist->name));
       sb_kill (&loclist->name);
       sb_kill (&loclist->def);
       sb_kill (&loclist->actual);
@@ -870,6 +971,7 @@ 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] == '=')
@@ -940,7 +1042,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 +1058,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);
@@ -1016,7 +1126,7 @@ 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++)
@@ -1041,6 +1151,15 @@ check_macro (line, expand, comment_char, error)
   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.  */
@@ -1099,12 +1218,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.027676 seconds and 4 git commands to generate.