gas: drop function pointer parameter from macro_init()
[binutils-gdb.git] / gas / macro.c
index c8ebcab0f07022d9d57fc90172eaf6db832c09d9..fec806d91ea308e009747661cebbadb1fb425790 100644 (file)
@@ -1,5 +1,5 @@
 /* macro.c - macro support for gas
-   Copyright (C) 1994-2022 Free Software Foundation, Inc.
+   Copyright (C) 1994-2023 Free Software Foundation, Inc.
 
    Written by Steve and Judy Chamberlain of Cygnus Support,
       sac@cygnus.com
@@ -44,7 +44,7 @@
 
 /* The macro hash table.  */
 
-struct htab *macro_hash;
+htab_t macro_hash;
 
 /* Whether any macros have been defined.  */
 
@@ -62,27 +62,36 @@ static int macro_mri;
 
 static int macro_strip_at;
 
-/* Function to use to parse an expression.  */
-
-static size_t (*macro_expr) (const char *, size_t, sb *, offsetT *);
-
 /* Number of macro expansions that have been done.  */
 
 static int macro_number;
 
+static void free_macro (macro_entry *);
+
+static void
+macro_del_f (void *ent)
+{
+  string_tuple_t *tuple = ent;
+  free_macro ((macro_entry *) tuple->value);
+}
+
 /* Initialize macro processing.  */
 
 void
-macro_init (int alternate, int mri, int strip_at,
-           size_t (*exp) (const char *, size_t, sb *, offsetT *))
+macro_init (int alternate, int mri, int strip_at)
 {
-  macro_hash = htab_create_alloc (16, hash_macro_entry, eq_macro_entry,
-                                 NULL, xcalloc, free);
+  macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+                                 macro_del_f, notes_calloc, NULL);
   macro_defined = 0;
   macro_alternate = alternate;
   macro_mri = mri;
   macro_strip_at = strip_at;
-  macro_expr = exp;
+}
+
+void
+macro_end (void)
+{
+  htab_delete (macro_hash);
 }
 
 /* Switch in and out of alternate mode on the fly.  */
@@ -115,8 +124,7 @@ buffer_and_nest (const char *from, const char *to, sb *ptr,
   size_t from_len;
   size_t to_len = strlen (to);
   int depth = 1;
-  size_t line_start = ptr->len;
-  size_t more = get_line (ptr);
+  size_t line_start, more;
 
   if (to_len == 4 && strcasecmp (to, "ENDR") == 0)
     {
@@ -126,21 +134,24 @@ buffer_and_nest (const char *from, const char *to, sb *ptr,
   else
     from_len = strlen (from);
 
-  /* Except for macros record the present source position, such that
-     diagnostics and debug info will be properly associated with the
-     respective original lines, rather than with the line of the ending
-     directive (TO).  */
-  if (from == NULL || strcasecmp (from, "MACRO") != 0)
-    {
-      unsigned int line;
-      char *linefile;
-
-      as_where (&line);
-      linefile = xasprintf ("\t.linefile %u .\n", line);
-      sb_add_buffer (ptr, linefile, strlen (linefile));
-      xfree (linefile);
-    }
-
+  /* Record the present source position, such that diagnostics and debug info
+     can be properly associated with the respective original lines, rather
+     than with the line of the ending directive (TO).  */
+  {
+    unsigned int line;
+    char *linefile;
+
+    as_where_top (&line);
+    if (!flag_m68k_mri)
+      linefile = xasprintf ("\t.linefile %u .", line + 1);
+    else
+      linefile = xasprintf ("\tlinefile %u .", line + 1);
+    sb_add_string (ptr, linefile);
+    xfree (linefile);
+  }
+
+  line_start = ptr->len;
+  more = get_line (ptr);
   while (more)
     {
       /* Try to find the first pseudo op on the line.  */
@@ -241,25 +252,18 @@ buffer_and_nest (const char *from, const char *to, sb *ptr,
            }
 
          /* PR gas/16908
-            Apply and discard .linefile directives that appear within
-            the macro.  For long macros, one might want to report the
-            line number information associated with the lines within
-            the macro definition, but we would need more infrastructure
-            to make that happen correctly (e.g. resetting the line
-            number when expanding the macro), and since for short
-            macros we clearly prefer reporting the point of expansion
-            anyway, there's not an obviously better fix here.  */
+            Apply .linefile directives that appear within the macro, alongside
+            keeping them for later expansion of the macro.  */
          if (from != NULL && strcasecmp (from, "MACRO") == 0
              && len >= 8 && strncasecmp (ptr->ptr + i, "linefile", 8) == 0)
            {
-             char saved_eol_char = ptr->ptr[ptr->len];
-
-             ptr->ptr[ptr->len] = '\0';
-             temp_ilp (ptr->ptr + i + 8);
+             sb_add_char (ptr, more);
+             temp_ilp (sb_terminate (ptr) + i + 8);
              s_linefile (0);
              restore_ilp ();
-             ptr->ptr[ptr->len] = saved_eol_char;
-             ptr->len = line_start;
+             line_start = ptr->len;
+             more = get_line (ptr);
+             continue;
            }
        }
 
@@ -402,16 +406,21 @@ get_any_string (size_t idx, sb *in, sb *out)
        }
       else if (in->ptr[idx] == '%' && macro_alternate)
        {
-         offsetT val;
+         /* Turn the following expression into a string.  */
+         expressionS ex;
          char buf[64];
 
-         /* Turns the next expression into a string.  */
-         /* xgettext: no-c-format */
-         idx = (*macro_expr) (_("% operator needs absolute expression"),
-                              idx + 1,
-                              in,
-                              &val);
-         sprintf (buf, "%" BFD_VMA_FMT "d", val);
+         sb_terminate (in);
+
+         temp_ilp (in->ptr + idx + 1);
+         expression_and_evaluate (&ex);
+         idx = input_line_pointer - in->ptr;
+         restore_ilp ();
+
+         if (ex.X_op != O_constant)
+           as_bad (_("%% operator needs absolute expression"));
+
+         sprintf (buf, "%" PRId64, (int64_t) ex.X_add_number);
          sb_add_string (out, buf);
        }
       else if (in->ptr[idx] == '"'
@@ -533,7 +542,6 @@ do_formals (macro_entry *macro, size_t idx, sb *in)
     {
       formal_entry *formal = new_formal ();
       size_t cidx;
-      formal_hash_entry_t *elt;
 
       idx = get_token (idx, in, &formal->name);
       if (formal->name.len == 0)
@@ -596,10 +604,8 @@ do_formals (macro_entry *macro, size_t idx, sb *in)
        }
 
       /* Add to macro's hash table.  */
-      elt = formal_entry_alloc (name, formal);
-      if (htab_insert (macro->formal_hash, elt, 0) != NULL)
+      if (str_hash_insert (macro->formal_hash, name, formal, 0) != NULL)
        {
-         free (elt);
          as_bad_where (macro->file, macro->line,
                        _("A parameter named `%s' "
                          "already exists for macro `%s'"),
@@ -623,7 +629,6 @@ do_formals (macro_entry *macro, size_t idx, sb *in)
   if (macro_mri)
     {
       formal_entry *formal = new_formal ();
-      formal_hash_entry_t *elt;
 
       /* Add a special NARG formal, which macro_expand will set to the
         number of arguments.  */
@@ -637,10 +642,8 @@ do_formals (macro_entry *macro, size_t idx, sb *in)
       sb_add_string (&formal->name, name);
 
       /* Add to macro's hash table.  */
-      elt = formal_entry_alloc (name, formal);
-      if (htab_insert (macro->formal_hash, elt, 0) != NULL)
+      if (str_hash_insert (macro->formal_hash, name, formal, 0) != NULL)
        {
-         free (elt);
          as_bad_where (macro->file, macro->line,
                        _("Reserved word `%s' used as parameter in macro `%s'"),
                        name, macro->name);
@@ -670,35 +673,30 @@ free_macro (macro_entry *macro)
     }
   htab_delete (macro->formal_hash);
   sb_kill (&macro->sub);
+  free ((char *) macro->name);
   free (macro);
 }
 
-/* Define a new macro.  Returns NULL on success, otherwise returns an
-   error message.  If NAMEP is not NULL, *NAMEP is set to the name of
-   the macro which was defined.  */
+/* Define a new macro.  */
 
-const char *
-define_macro (size_t idx, sb *in, sb *label,
-             size_t (*get_line) (sb *),
-             const char *file, unsigned int line,
-             const char **namep)
+macro_entry *
+define_macro (sb *in, sb *label, size_t (*get_line) (sb *))
 {
   macro_entry *macro;
   sb name;
+  size_t idx;
   const char *error = NULL;
 
   macro = XNEW (macro_entry);
   sb_new (&macro->sub);
   sb_new (&name);
-  macro->file = file;
-  macro->line = line;
+  macro->file = as_where (&macro->line);
 
   macro->formal_count = 0;
   macro->formals = 0;
-  macro->formal_hash = htab_create_alloc (7, hash_formal_entry, eq_formal_entry,
-                                         NULL, xcalloc, free);
+  macro->formal_hash = str_htab_create ();
 
-  idx = sb_skip_white (idx, in);
+  idx = sb_skip_white (0, in);
   if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
     error = _("unexpected end of file in macro `%s' definition");
   if (label != NULL && label->len != 0)
@@ -743,23 +741,20 @@ define_macro (size_t idx, sb *in, sb *label,
     name.ptr[idx] = TOLOWER (name.ptr[idx]);
   if (!error)
     {
-      macro_hash_entry_t *elt = macro_entry_alloc (macro->name, macro);
-      if (htab_insert (macro_hash, elt, 0) != NULL)
-       {
-         free (elt);
-         error = _("Macro `%s' was already defined");
-       }
+      if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
+       error = _("Macro `%s' was already defined");
     }
 
-  if (namep != NULL)
-    *namep = macro->name;
-
   if (!error)
     macro_defined = 1;
   else
-    free_macro (macro);
+    {
+      as_bad_where (macro->file, macro->line, error, macro->name);
+      free_macro (macro);
+      macro = NULL;
+    }
 
-  return error;
+  return macro;
 }
 
 /* Scan a token, and then skip KIND.  */
@@ -793,7 +788,7 @@ sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
       && (src == start || in->ptr[src - 1] != '@'))
     ptr = NULL;
   else
-    ptr = formal_entry_find (formal_hash, sb_terminate (t));
+    ptr = str_hash_find (formal_hash, sb_terminate (t));
   if (ptr)
     {
       if (ptr->actual.len)
@@ -948,14 +943,11 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
                {
                  const char *name;
                  formal_entry *f = new_formal ();
-                 formal_hash_entry_t *elt;
 
                  src = get_token (src, in, &f->name);
                  name = sb_terminate (&f->name);
-                 elt = formal_entry_alloc (name, f);
-                 if (htab_insert (formal_hash, elt, 0) != NULL)
+                 if (str_hash_insert (formal_hash, name, f, 0) != NULL)
                    {
-                     free (elt);
                      as_bad_where (macro->file, macro->line + macro_line,
                                    _("`%s' was already used as parameter "
                                      "(or another local) name"), name);
@@ -1003,7 +995,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
 
          sb_reset (&t);
          src = get_token (src + 2, in, &t);
-         ptr = formal_entry_find (formal_hash, sb_terminate (&t));
+         ptr = str_hash_find (formal_hash, sb_terminate (&t));
          if (ptr == NULL)
            {
              /* FIXME: We should really return a warning string here,
@@ -1047,12 +1039,13 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
 
       f = loclist->next;
       name = sb_terminate (&loclist->name);
-      formal_hash_entry_t needle = { name, NULL };
-      htab_remove_elt (formal_hash, &needle);
+      str_hash_delete (formal_hash, name);
       del_formal (loclist);
       loclist = f;
     }
 
+  if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n'))
+    sb_add_char (out, '\n');
   return err;
 }
 
@@ -1126,14 +1119,14 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
             then the actual stuff.  */
          sb_reset (&t);
          idx = get_token (idx, in, &t);
-         if (in->ptr[idx] != '=')
+         if (idx >= in->len || in->ptr[idx] != '=')
            {
              err = _("confusion in formal parameters");
              break;
            }
 
          /* Lookup the formal in the macro's list.  */
-         ptr = formal_entry_find (m->formal_hash, sb_terminate (&t));
+         ptr = str_hash_find (m->formal_hash, sb_terminate (&t));
          if (!ptr)
            {
              as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
@@ -1190,7 +1183,7 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
 
          if (f->type != FORMAL_VARARG)
            idx = get_any_string (idx, in, &f->actual);
-         else
+         else if (idx < in->len)
            {
              sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx);
              idx = in->len;
@@ -1208,9 +1201,9 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
        idx = sb_skip_comma (idx, in);
       else
        {
-         if (in->ptr[idx] == ',')
+         if (idx < in->len && in->ptr[idx] == ',')
            ++idx;
-         if (ISWHITE (in->ptr[idx]))
+         if (idx < in->len && ISWHITE (in->ptr[idx]))
            break;
        }
     }
@@ -1227,13 +1220,14 @@ macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
 
       if (macro_mri)
        {
-         char buffer[20];
-
-         sb_reset (&t);
-         sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
-         ptr = formal_entry_find (m->formal_hash, sb_terminate (&t));
-         sprintf (buffer, "%d", narg);
-         sb_add_string (&ptr->actual, buffer);
+         ptr = str_hash_find (m->formal_hash,
+                              macro_strip_at ? "$NARG" : "NARG");
+         if (ptr)
+           {
+             char buffer[20];
+             sprintf (buffer, "%d", narg);
+             sb_add_string (&ptr->actual, buffer);
+           }
        }
 
       err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
@@ -1291,7 +1285,7 @@ check_macro (const char *line, sb *expand,
   for (cls = copy; *cls != '\0'; cls ++)
     *cls = TOLOWER (*cls);
 
-  macro = macro_entry_find (macro_hash, copy);
+  macro = str_hash_find (macro_hash, copy);
   free (copy);
 
   if (macro == NULL)
@@ -1321,8 +1315,7 @@ delete_macro (const char *name)
 {
   char *copy;
   size_t i, len;
-  void **slot;
-  macro_hash_entry_t needle;
+  macro_entry *macro;
 
   len = strlen (name);
   copy = XNEWVEC (char, len + 1);
@@ -1330,14 +1323,9 @@ delete_macro (const char *name)
     copy[i] = TOLOWER (name[i]);
   copy[i] = '\0';
 
-  needle.name = copy;
-  needle.macro = NULL;
-  slot = htab_find_slot (macro_hash, &needle, NO_INSERT);
-  if (slot)
-    {
-      free_macro (((macro_hash_entry_t *) *slot)->macro);
-      htab_clear_slot (macro_hash, slot);
-    }
+  macro = str_hash_find (macro_hash, copy);
+  if (macro != NULL)
+    str_hash_delete (macro_hash, copy);
   else
     as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
   free (copy);
@@ -1369,10 +1357,9 @@ expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
   if (f.name.len == 0)
     return _("missing model parameter");
 
-  h = htab_create_alloc (16, hash_formal_entry, eq_formal_entry,
-                        NULL, xcalloc, free);
+  h = str_htab_create ();
 
-  htab_insert (h, formal_entry_alloc (sb_terminate (&f.name), &f), 0);
+  str_hash_insert (h, sb_terminate (&f.name), &f, 0);
 
   f.index = 1;
   f.next = NULL;