@item .macro @var{macname}
@itemx .macro @var{macname} @var{macargs} @dots{}
@cindex @code{macro} directive
-Begin the definition of a macro called @var{macname}. Macro names are case
-insensitive. Macro definitions can be nested, although their behaviour is
-sometimes counter intuitive. Nested macros only have scope within their
-defining macro.
-
-If your macro
+Begin the definition of a macro called @var{macname}. If your macro
definition requires arguments, specify their names after the macro name,
separated by commas or spaces. You can qualify the macro argument to
indicate whether all invocations must specify a non-blank value (through
concatenated when determining macro arguments, even if they're only separated
by white space. This is unlike certain other pseudo ops, e.g. @code{.ascii}.
-Nested macros can access the arguments of their parents. But also if their
-argument names clash with those of their parents, their versions are used. So
-for example:
-
-@smallexample
-.macro OUTER arg1, arg2, arg3:vararg
- .macro INNER arg4 arg2
- .dc.a \arg2
- .dc.a \arg3
- .endm
- INNER \arg1 bert
- .dc.a \arg2
-.endm
-
-OUTER fred, jim, harry\arg4
-@end smallexample
-
-This will generate references to symbols called @samp{jim} - from the
-definition of the OUTER macro, @samp{bert} - from the definition in INNER
-where arg2 has been overridden and @samp{harryfred} - from the definition in
-INNER where the value of arg3 from OUTER is used, but with the value of arg4
-substituted into the symbol.
-
@item .endm
@cindex @code{endm} directive
Mark the end of a macro definition.
executed in this pseudo-variable; you can copy that number to your
output with @samp{\@@}, but @emph{only within a macro definition}.
-Note - the @samp{\@@} counter is incremented at the end of the expansion of a
-macro, but before the contents of any nested macros are evaluated. This can
-lead to counter-intuitive behaviour when nested macros are used. For example:
-
-@smallexample
- .macro o
- .macro i
- _i\@@_:
- .endm
- i
- _o\@@_:
- .endm
- o
-@end smallexample
-
-Produces two symbols @samp{_o0_} and @samp{_i1_}. This happens because the
-@samp{o} macro executes entirely first, putting the definition and invocation
-of the @samp{i} macro into the input buffer. It also puts the definition of
-the @samp{_o\@@_} symbol into the input buffer, evaluating the @samp{\@@}
-counter in the process and so generating a symbol called @samp{_o0_}.
-
-That finishes the invocation of @samp{o} so the @samp{\@@} counter is
-incremented. Then the input buffer is re-evaluated and the definition and
-invocation of macro @samp{i} is found. This results in @samp{_i\@@_} being put
-into the input buffer and this time @samp{\@@} evaluates to 1, so the symbol
-created is @samp{_i1_}.
-
@cindex number of times a macro has been executed
@cindex macro, execution count
@item \+
Undefine the macro @var{name}, so that later uses of the string will not be
expanded. @xref{Macro}.
-Note - nested macros are automatically purged at the end of the macro that
-defines them.
-
@ifset ELF
@node PushSection
@section @code{.pushsection @var{name} [, @var{subsection}] [, "@var{flags}"[, @@@var{type}[,@var{arguments}]]]}
/* The macro hash table. */
-/* Macro nesting depth. Similar to macro_nest defined in sb.c, but this
- counter is specific to macros, whereas macro_nest also counts repeated
- string blocks. */
-static unsigned int macro_nesting_depth;
+htab_t macro_hash;
-/* Maximum nesting depth. Ideally the same as the value of max_macro_nest
- as defined in as.c (ie 100). But there is one test in the assembler
- testsuite (bfin/allinsn16.s) that nests macros to a depth of 8192. So
- we have a ridiculously large number here. */
-#define MAX_MACRO_DEPTH 8193
+/* Whether any macros have been defined. */
-static htab_t macro_hash[MAX_MACRO_DEPTH];
-
-/* Whether any macros have been defined.
- FIXME: This could be a counter that is incremented
- with .macro and decremented with .purgem. */
-
-static bool macros_defined = false;
+int macro_defined;
/* Whether we should strip '@' characters. */
static void free_macro (macro_entry *);
-bool
-add_macro (macro_entry * macro, bool replace)
-{
- if (str_hash_insert (macro_hash [macro_nesting_depth],
- macro->name, macro, replace) == NULL)
- {
- macros_defined = true;
- return true;
- }
- return false;
-}
-
static void
macro_del_f (void *ent)
{
void
macro_init (void)
{
- int i;
-
- for (i = 0; i < MAX_MACRO_DEPTH; i++)
- macro_hash[i] = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
- macro_del_f, notes_calloc, NULL);
- macros_defined = false;
+ macro_hash = htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
+ macro_del_f, notes_calloc, NULL);
+ macro_defined = 0;
}
void
macro_end (void)
{
- int i;
-
- for (i = MAX_MACRO_DEPTH; i--;)
- htab_delete (macro_hash[i]);
-
- macros_defined = false;
+ htab_delete (macro_hash);
}
/* Read input lines till we get to a TO string.
free (macro);
}
-static macro_entry * last_recorded_macro = NULL;
-void
-macro_record_invocation (macro_entry * macro)
-{
- last_recorded_macro = macro;
-}
-
/* Define a new macro. */
macro_entry *
/* And stick it in the macro hash table. */
for (idx = 0; idx < name.len; idx++)
name.ptr[idx] = TOLOWER (name.ptr[idx]);
-
- if (macro_nesting_depth > 0)
- macro->parent = last_recorded_macro;
- else
- macro->parent = NULL;
-
if (!error)
{
- if (! add_macro (macro, false))
+ if (str_hash_insert (macro_hash, macro->name, macro, 0) != NULL)
error = _("Macro `%s' was already defined");
}
- if (error != NULL)
+ if (!error)
+ macro_defined = 1;
+ else
{
as_bad_where (macro->file, macro->line, error, macro->name);
free_macro (macro);
return idx;
}
-static const char *
-macro_expand_body (sb *, sb *, formal_entry *, struct htab *,
- const macro_entry *, unsigned int);
-
-/* Find the actual value for a formal parameter starting at START inside IN.
- Appends the value of parameter onto OUT.
- The hash table of formal parameters is provided by FORMAL_HASH.
- The character that indicated the presense of a formal parameter is passed
- in KIND.
- If COPYIFNOTTHERE is true and the parameter is not found in the hash table
- then it is appended as plain text onto OUT.
- The macro containing the formal parameters is passed in MACRO.
- This can be empty.
- Returns the offset inside IN after advanceing past the parameter.
- Also stores the parameter's name into T. */
+/* Substitute the actual value for a formal parameter. */
static size_t
sub_actual (size_t start, sb *in, sb *t, struct htab *formal_hash,
- int kind, sb *out, int copyifnotthere, const macro_entry * macro)
+ int kind, sb *out, int copyifnotthere)
{
size_t src;
formal_entry *ptr;
ptr = NULL;
else
ptr = str_hash_find (formal_hash, sb_terminate (t));
-
if (ptr)
{
- sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
-
- sb_add_sb (out, add);
+ if (ptr->actual.len)
+ {
+ sb_add_sb (out, &ptr->actual);
+ }
+ else
+ {
+ sb_add_sb (out, &ptr->def);
+ }
}
else if (kind == '&')
{
{
sb_add_sb (out, t);
}
- else if (!macro_strip_at
- && macro_nesting_depth > 0
- && macro != NULL
- && macro->parent != NULL)
- {
- const macro_entry * orig_macro = macro;
- bool success = false;
-
- /* We have failed to find T, but we are inside nested macros. So check
- the parent macros so see if they have a FORMAL that matches T. */
- while (macro->parent != NULL)
- {
- macro = macro->parent;
-
- ptr = str_hash_find (macro->formal_hash, t->ptr);
- if (ptr == NULL)
- continue;
-
- sb * add = ptr->actual.len ? &ptr->actual : &ptr->def;
-
- /* The parent's FORMALs might contain parameters that need further
- substitution. See gas/testsuite/gas/arm/macro-vld1.s for an
- example of this. */
- if (memchr (add->ptr, '\\', add->len))
- {
- sb newadd;
-
- sb_new (&newadd);
- /* FIXME: Should we do something if the call to
- macro_expand_body returns an error message ? */
- (void) macro_expand_body (add, &newadd, NULL, NULL,
- orig_macro, orig_macro->count);
- sb_add_sb (out, &newadd);
- sb_kill (&newadd);
- }
- else
- {
- sb_add_sb (out, add);
- }
- success = true;
- break;
- }
- if (! success)
- {
- /* We reached the outermost macro and failed to find T, so
- just copy the entire parameter as is. */
- sb_add_char (out, '\\');
- sb_add_sb (out, t);
- }
- }
else
{
sb_add_char (out, '\\');
return src;
}
-/* Expands the body of a macro / block of text IN, copying it into OUT.
- Parameters for substitution are found in FORMALS and FORMAL_HASH or
- MACRO.
- The number of times that this macro / block of text have already been
- copied into the output is held in INSTANCE.
- Returns NULL upon success or an error message otherwise. */
+/* Expand the body of a macro. */
static const char *
macro_expand_body (sb *in, sb *out, formal_entry *formals,
int inquote = 0, macro_line = 0;
formal_entry *loclist = NULL;
const char *err = NULL;
- int nesting = 0;
- if (formals == NULL && macro != NULL)
- formals = macro->formals;
-
- if (formal_hash == NULL && macro != NULL)
- formal_hash = macro->formal_hash;
-
sb_new (&t);
while (src < in->len && !err)
{
- if (in->ptr[src] == '.')
- {
- /* Check to see if we have encountered ".macro" or ".endm" */
- if (in->len > src + 5
- && strncmp (in->ptr + src, ".macro", 6) == 0)
- ++ nesting;
-
- else if (in->len > src + 4
- && strncmp (in->ptr + src, ".endm", 5) == 0)
- -- nesting;
- }
-
if (in->ptr[src] == '&')
{
sb_reset (&t);
if (flag_mri)
{
if (src + 1 < in->len && in->ptr[src + 1] == '&')
- src = sub_actual (src + 2, in, &t, formal_hash,
- '\'', out, 1, macro);
+ src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
else
sb_add_char (out, in->ptr[src++]);
}
{
/* Permit macro parameter substitution delineated with
an '&' prefix and optional '&' suffix. */
- src = sub_actual (src + 1, in, &t, formal_hash,
- '&', out, 0, macro);
+ src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
}
}
else if (in->ptr[src] == '\\')
else
as_bad_where (macro->file, macro->line + macro_line, _("missing `)'"));
}
- else if (src < in->len
- && in->ptr[src] == '@'
- /* PR 32391: Do not perform the substition inside nested
- macros. Instead wait until they are re-evaluated and
- perform the substition then. */
- && ! nesting)
+ else if (src < in->len && in->ptr[src] == '@')
{
/* Sub in the total macro invocation number. */
sprintf (buffer, "%u", macro_number);
sb_add_string (out, buffer);
}
- else if (src < in->len
- && in->ptr[src] == '+'
- /* PR 32391: Do not perform the substition inside nested
- macros. Instead wait until they are re-evaluated and
- perform the substition then. */
- && ! nesting)
+ else if (src < in->len && in->ptr[src] == '+')
{
/* Sub in the current macro invocation number. */
else
{
sb_reset (&t);
-
- if (nesting)
- {
- src = get_apost_token (src, in, &t, '\'');
- sb_add_char (out, '\\');
- sb_add_sb (out, &t);
- }
- else
- {
- src = sub_actual (src, in, &t, formal_hash,
- '\'', out, 0, macro);
- }
+ src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
}
}
else if ((flag_macro_alternate || flag_mri)
sb_reset (&t);
src = sub_actual (src, in, &t, formal_hash,
(macro_strip_at && inquote) ? '@' : '\'',
- out, 1, macro);
+ out, 1);
}
else
{
if (!err && (out->len == 0 || out->ptr[out->len - 1] != '\n'))
sb_add_char (out, '\n');
-
return err;
}
}
}
- err = macro_expand_body (&m->sub, out, NULL, NULL, m, m->count);
+ err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m,
+ m->count);
}
/* Discard any unnamed formal arguments. */
}
/* Check for a macro. If one is found, put the expansion into
- *EXPAND. Return TRUE if a macro is found, FALSE otherwise. */
+ *EXPAND. Return 1 if a macro is found, 0 otherwise. */
-bool
+int
check_macro (const char *line, sb *expand,
const char **error, macro_entry **info)
{
const char *s;
char *copy, *cls;
+ macro_entry *macro;
sb line_sb;
- if (! macros_defined)
- return false;
-
if (! is_name_beginner (*line)
&& (! flag_mri || *line != '.'))
- return false;
+ return 0;
s = line + 1;
while (is_part_of_name (*s))
for (cls = copy; *cls != '\0'; cls ++)
*cls = TOLOWER (*cls);
- macro_entry *macro = NULL;
- for (int i = macro_nesting_depth; i >= 0; i--)
- {
- macro = str_hash_find (macro_hash[i], copy);
- if (macro != NULL)
- break;
- }
+ macro = str_hash_find (macro_hash, copy);
free (copy);
if (macro == NULL)
- return false;
+ return 0;
/* Wrap the line up in an sb. */
sb_new (&line_sb);
if (info)
*info = macro;
- return true;
+ return 1;
}
/* Delete a macro. */
copy[i] = TOLOWER (name[i]);
copy[i] = '\0';
- int j;
- for (j = macro_nesting_depth; j >= 0; j--)
- {
- macro = str_hash_find (macro_hash [j], copy);
- if (macro != NULL)
- {
- str_hash_delete (macro_hash[j], copy);
- break;
- }
- }
-
- if (j < 0)
+ 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);
}
return err;
}
-
-void
-increment_macro_nesting_depth (void)
-{
- if (macro_nesting_depth >= (MAX_MACRO_DEPTH - 1))
- as_fatal (_("macros nested too deeply"));
- else
- ++macro_nesting_depth;
-}
-
-void
-decrement_macro_nesting_depth (void)
-{
- if (macro_nesting_depth == 0)
- as_fatal (_("too much macro un-nesting"));
- else
- {
- /* FIXME: Potential memory leak here. */
- htab_empty (macro_hash [macro_nesting_depth]);
- --macro_nesting_depth;
- }
-}