/* 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
/* The macro hash table. */
-struct htab *macro_hash;
+htab_t macro_hash;
/* Whether any macros have been defined. */
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. */
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)
{
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. */
}
/* 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;
}
}
}
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] == '"'
{
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)
}
/* 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'"),
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. */
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);
}
htab_delete (macro->formal_hash);
sb_kill (¯o->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 (¯o->sub);
sb_new (&name);
- macro->file = file;
- macro->line = line;
+ macro->file = as_where (¯o->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", ¯o->sub, get_line))
error = _("unexpected end of file in macro `%s' definition");
if (label != NULL && label->len != 0)
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. */
&& (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)
{
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);
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,
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;
}
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'"),
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;
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;
}
}
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);
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)
{
char *copy;
size_t i, len;
- void **slot;
- macro_hash_entry_t needle;
+ macro_entry *macro;
len = strlen (name);
copy = XNEWVEC (char, len + 1);
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);
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;