/* macro.c - macro support for gas
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1994-2020 Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
sac@cygnus.com
/* The macro hash table. */
-struct hash_control *macro_hash;
+struct htab *macro_hash;
/* Whether any macros have been defined. */
/* Function to use to parse an expression. */
-static int (*macro_expr) (const char *, int, sb *, int *);
+static size_t (*macro_expr) (const char *, size_t, sb *, offsetT *);
/* Number of macro expansions that have been done. */
void
macro_init (int alternate, int mri, int strip_at,
- int (*exp) (const char *, int, sb *, int *))
+ size_t (*exp) (const char *, size_t, sb *, offsetT *))
{
- macro_hash = hash_new ();
+ macro_hash = htab_create_alloc (16, hash_macro_entry, eq_macro_entry,
+ NULL, xcalloc, free);
macro_defined = 0;
macro_alternate = alternate;
macro_mri = mri;
int
buffer_and_nest (const char *from, const char *to, sb *ptr,
- int (*get_line) (sb *))
+ size_t (*get_line) (sb *))
{
- int from_len;
- int to_len = strlen (to);
+ size_t from_len;
+ size_t to_len = strlen (to);
int depth = 1;
- int line_start = ptr->len;
+ size_t line_start = ptr->len;
+ size_t more = get_line (ptr);
- int more = get_line (ptr);
-
- if (to_len == 4 && strcasecmp(to, "ENDR") == 0)
+ if (to_len == 4 && strcasecmp (to, "ENDR") == 0)
{
from = NULL;
from_len = 0;
while (more)
{
/* Try to find the first pseudo op on the line. */
- int i = line_start;
+ size_t i = line_start;
bfd_boolean had_colon = FALSE;
/* With normal syntax we can suck what we want till we get
break;
}
}
+
+ /* 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. */
+ if (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);
+ s_app_line (0);
+ restore_ilp ();
+ ptr->ptr[ptr->len] = saved_eol_char;
+ ptr->len = line_start;
+ }
}
/* Add the original end-of-line char to the end and keep running. */
/* Pick up a token. */
-static int
-get_token (int idx, sb *in, sb *name)
+static size_t
+get_token (size_t idx, sb *in, sb *name)
{
if (idx < in->len
&& is_name_beginner (in->ptr[idx]))
/* Pick up a string. */
-static int
-getstring (int idx, sb *in, sb *acc)
+static size_t
+getstring (size_t idx, sb *in, sb *acc)
{
while (idx < in->len
&& (in->ptr[idx] == '"'
{
int nest = 0;
idx++;
- while ((in->ptr[idx] != '>' || nest)
- && idx < in->len)
+ while (idx < in->len
+ && (in->ptr[idx] != '>' || nest))
{
if (in->ptr[idx] == '!')
{
(string) -> return (string-including-whitespaces)
xyx<whitespace> -> return xyz. */
-static int
-get_any_string (int idx, sb *in, sb *out)
+static size_t
+get_any_string (size_t idx, sb *in, sb *out)
{
sb_reset (out);
idx = sb_skip_white (idx, in);
{
if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
{
- while (!ISSEP (in->ptr[idx]))
+ while (idx < in->len && !ISSEP (in->ptr[idx]))
sb_add_char (out, in->ptr[idx++]);
}
else if (in->ptr[idx] == '%' && macro_alternate)
{
- int val;
- char buf[20];
+ offsetT val;
+ char buf[64];
/* Turns the next expression into a string. */
/* xgettext: no-c-format */
idx + 1,
in,
&val);
- sprintf (buf, "%d", val);
+ sprintf (buf, "%" BFD_VMA_FMT "d", val);
sb_add_string (out, buf);
}
else if (in->ptr[idx] == '"'
}
else
{
- char *br_buf = (char *) xmalloc(1);
+ char *br_buf = XNEWVEC (char, 1);
char *in_br = br_buf;
*in_br = '\0';
&& in->ptr[idx] != tchar)
sb_add_char (out, in->ptr[idx++]);
if (idx == in->len)
- return idx;
+ {
+ free (br_buf);
+ return idx;
+ }
break;
case '(':
case '[':
--in_br;
else
{
- br_buf = (char *) xmalloc(strlen(in_br) + 2);
- strcpy(br_buf + 1, in_br);
- free(in_br);
+ br_buf = XNEWVEC (char, strlen (in_br) + 2);
+ strcpy (br_buf + 1, in_br);
+ free (in_br);
in_br = br_buf;
}
*in_br = tchar;
sb_add_char (out, tchar);
++idx;
}
- free(br_buf);
+ free (br_buf);
}
}
{
formal_entry *formal;
- formal = (formal_entry *) xmalloc (sizeof (formal_entry));
+ formal = XNEW (formal_entry);
sb_new (&formal->name);
sb_new (&formal->def);
/* Pick up the formal parameters of a macro definition. */
-static int
-do_formals (macro_entry *macro, int idx, sb *in)
+static size_t
+do_formals (macro_entry *macro, size_t idx, sb *in)
{
formal_entry **p = ¯o->formals;
const char *name;
while (idx < in->len)
{
formal_entry *formal = new_formal ();
- int cidx;
+ size_t cidx;
+ formal_hash_entry_t *elt;
idx = get_token (idx, in, &formal->name);
if (formal->name.len == 0)
{
if (macro->formal_count)
--idx;
+ del_formal (formal); /* 'formal' goes out of scope. */
break;
}
idx = sb_skip_white (idx, in);
}
/* Add to macro's hash table. */
- if (! hash_find (macro->formal_hash, name))
- hash_jam (macro->formal_hash, name, formal);
- else
- as_bad_where (macro->file,
- macro->line,
- _("A parameter named `%s' already exists for macro `%s'"),
- name,
- macro->name);
+ elt = formal_entry_alloc (name, formal);
+ if (htab_insert (macro->formal_hash, elt, 0) != NULL)
+ {
+ free (elt);
+ as_bad_where (macro->file, macro->line,
+ _("A parameter named `%s' "
+ "already exists for macro `%s'"),
+ name, macro->name);
+ }
formal->index = macro->formal_count++;
*p = formal;
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. */
+ number of arguments. */
/* The same MRI assemblers which treat '@' characters also use
- the name $NARG. At least until we find an exception. */
+ the name $NARG. At least until we find an exception. */
if (macro_strip_at)
name = "$NARG";
else
sb_add_string (&formal->name, name);
/* Add to macro's hash table. */
- if (hash_find (macro->formal_hash, name))
- as_bad_where (macro->file,
- macro->line,
- _("Reserved word `%s' used as parameter in macro `%s'"),
- name,
- macro->name);
- hash_jam (macro->formal_hash, name, formal);
+ elt = formal_entry_alloc (name, formal);
+ if (htab_insert (macro->formal_hash, elt, 0) != NULL)
+ {
+ free (elt);
+ as_bad_where (macro->file, macro->line,
+ _("Reserved word `%s' used as parameter in macro `%s'"),
+ name, macro->name);
+ }
formal->index = NARG_INDEX;
*p = formal;
formal = formal->next;
del_formal (f);
}
- hash_die (macro->formal_hash);
+ htab_delete (macro->formal_hash);
sb_kill (¯o->sub);
free (macro);
}
the macro which was defined. */
const char *
-define_macro (int idx, sb *in, sb *label,
- int (*get_line) (sb *),
- char *file, unsigned int line,
+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 *macro;
sb name;
const char *error = NULL;
- macro = (macro_entry *) xmalloc (sizeof (macro_entry));
+ macro = XNEW (macro_entry);
sb_new (¯o->sub);
sb_new (&name);
macro->file = file;
macro->formal_count = 0;
macro->formals = 0;
- macro->formal_hash = hash_new ();
+ macro->formal_hash = htab_create_alloc (7, hash_formal_entry, eq_formal_entry,
+ NULL, xcalloc, free);
idx = sb_skip_white (idx, in);
if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line))
}
else
{
- int cidx;
+ size_t cidx;
idx = get_token (idx, in, &name);
macro->name = sb_terminate (&name);
/* And stick it in the macro hash table. */
for (idx = 0; idx < name.len; idx++)
name.ptr[idx] = TOLOWER (name.ptr[idx]);
- if (hash_find (macro_hash, macro->name))
- error = _("Macro `%s' was already defined");
if (!error)
- error = hash_jam (macro_hash, macro->name, (void *) macro);
+ {
+ 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 (namep != NULL)
*namep = macro->name;
/* Scan a token, and then skip KIND. */
-static int
-get_apost_token (int idx, sb *in, sb *name, int kind)
+static size_t
+get_apost_token (size_t idx, sb *in, sb *name, int kind)
{
idx = get_token (idx, in, name);
if (idx < in->len
/* Substitute the actual value for a formal parameter. */
-static int
-sub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash,
+static size_t
+sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
int kind, sb *out, int copyifnotthere)
{
- int src;
+ size_t src;
formal_entry *ptr;
src = get_apost_token (start, in, t, kind);
&& (src == start || in->ptr[src - 1] != '@'))
ptr = NULL;
else
- ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
+ ptr = formal_entry_find (formal_hash, sb_terminate (t));
if (ptr)
{
if (ptr->actual.len)
/* Doing this permits people to use & in macro bodies. */
sb_add_char (out, '&');
sb_add_sb (out, t);
+ if (src != start && in->ptr[src - 1] == '&')
+ sb_add_char (out, '&');
}
else if (copyifnotthere)
{
static const char *
macro_expand_body (sb *in, sb *out, formal_entry *formals,
- struct hash_control *formal_hash, const macro_entry *macro)
+ struct htab *formal_hash, const macro_entry *macro)
{
sb t;
- int src = 0, inquote = 0, macro_line = 0;
+ size_t src = 0;
+ int inquote = 0, macro_line = 0;
formal_entry *loclist = NULL;
const char *err = NULL;
}
else
{
- /* FIXME: Why do we do this? */
- /* At least in alternate mode this seems correct; without this
- one can't append a literal to a parameter. */
+ /* Permit macro parameter substitution delineated with
+ an '&' prefix and optional '&' suffix. */
src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
}
}
{
/* Sub in the macro invocation number. */
- char buffer[10];
+ char buffer[12];
src++;
sprintf (buffer, "%d", macro_number);
sb_add_string (out, buffer);
{
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);
- if (! hash_find (formal_hash, name))
+ elt = formal_entry_alloc (name, f);
+ if (htab_insert (formal_hash, elt, 0) != NULL)
+ {
+ free (elt);
+ as_bad_where (macro->file, macro->line + macro_line,
+ _("`%s' was already used as parameter "
+ "(or another local) name"), name);
+ del_formal (f);
+ }
+ else
{
static int loccnt;
char buf[20];
sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", ++loccnt);
sb_add_string (&f->actual, buf);
-
- err = hash_jam (formal_hash, name, f);
- if (err != NULL)
- break;
- }
- else
- {
- as_bad_where (macro->file,
- macro->line + macro_line,
- _("`%s' was already used as parameter (or another local) name"),
- name);
- del_formal (f);
}
src = sb_skip_comma (src, in);
sb_reset (&t);
src = get_token (src + 2, in, &t);
- ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
+ ptr = formal_entry_find (formal_hash, sb_terminate (&t));
if (ptr == NULL)
{
/* 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. */
+ 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);
f = loclist->next;
name = sb_terminate (&loclist->name);
- hash_delete (formal_hash, name, f == NULL);
+ formal_hash_entry_t needle = { name, NULL };
+ htab_remove_elt (formal_hash, &needle);
del_formal (loclist);
loclist = f;
}
body. */
static const char *
-macro_expand (int idx, sb *in, macro_entry *m, sb *out)
+macro_expand (size_t idx, sb *in, macro_entry *m, sb *out)
{
sb t;
formal_entry *ptr;
if (macro_mri)
{
/* The macro may be called with an optional qualifier, which may
- be referred to in the macro body as \0. */
+ be referred to in the macro body as \0. */
if (idx < in->len && in->ptr[idx] == '.')
{
/* The Microtec assembler ignores this if followed by a white space.
idx = sb_skip_white (idx, in);
while (idx < in->len)
{
- int scan;
+ size_t scan;
/* Look and see if it's a positional or keyword arg. */
scan = idx;
}
/* Lookup the formal in the macro's list. */
- ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
+ ptr = formal_entry_find (m->formal_hash, sb_terminate (&t));
if (!ptr)
- as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
- t.ptr,
- m->name);
+ {
+ as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
+ t.ptr,
+ m->name);
+ sb_reset (&t);
+ idx = get_any_string (idx + 1, in, &t);
+ }
else
{
/* Insert this value into the right place. */
sb_reset (&t);
sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
- ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
+ ptr = formal_entry_find (m->formal_hash, sb_terminate (&t));
sprintf (buffer, "%d", narg);
sb_add_string (&ptr->actual, buffer);
}
if (is_name_ender (*s))
++s;
- copy = (char *) alloca (s - line + 1);
- memcpy (copy, line, s - line);
- copy[s - line] = '\0';
+ copy = xmemdup0 (line, s - line);
for (cls = copy; *cls != '\0'; cls ++)
*cls = TOLOWER (*cls);
- macro = (macro_entry *) hash_find (macro_hash, copy);
+ macro = macro_entry_find (macro_hash, copy);
+ free (copy);
if (macro == NULL)
return 0;
{
char *copy;
size_t i, len;
- macro_entry *macro;
+ void **slot;
+ macro_hash_entry_t needle;
len = strlen (name);
- copy = (char *) alloca (len + 1);
+ copy = XNEWVEC (char, len + 1);
for (i = 0; i < len; ++i)
copy[i] = TOLOWER (name[i]);
copy[i] = '\0';
- /* We can only ask hash_delete to free memory if we are deleting
- macros in reverse order to their definition.
- So just clear out the entry. */
- if ((macro = (macro_entry *) hash_find (macro_hash, copy)) != NULL)
+ needle.name = copy;
+ needle.macro = NULL;
+ slot = htab_find_slot (macro_hash, &needle, NO_INSERT);
+ if (slot)
{
- hash_jam (macro_hash, copy, NULL);
- free_macro (macro);
+ free_macro (((macro_hash_entry_t *) *slot)->macro);
+ htab_clear_slot (macro_hash, slot);
}
else
- as_warn (_("Attempt to purge non-existant macro `%s'"), copy);
+ as_warn (_("Attempt to purge non-existing macro `%s'"), copy);
+ free (copy);
}
/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a
success, or an error message otherwise. */
const char *
-expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
+expand_irp (int irpc, size_t idx, sb *in, sb *out, size_t (*get_line) (sb *))
{
sb sub;
formal_entry f;
- struct hash_control *h;
- const char *err;
+ struct htab *h;
+ const char *err = NULL;
idx = sb_skip_white (idx, in);
if (f.name.len == 0)
return _("missing model parameter");
- h = hash_new ();
- err = hash_jam (h, sb_terminate (&f.name), &f);
- if (err != NULL)
- return err;
+ h = htab_create_alloc (16, hash_formal_entry, eq_formal_entry,
+ NULL, xcalloc, free);
+
+ htab_insert (h, formal_entry_alloc (sb_terminate (&f.name), &f), 0);
f.index = 1;
f.next = NULL;
{
if (in->ptr[idx] == '"')
{
- int nxt;
+ size_t nxt;
if (irpc)
in_quotes = ! in_quotes;
-
+
nxt = sb_skip_white (idx + 1, in);
if (nxt >= in->len)
{
}
}
- hash_die (h);
+ htab_delete (h);
sb_kill (&f.actual);
sb_kill (&f.def);
sb_kill (&f.name);