summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog21
-rw-r--r--gas/NEWS3
-rw-r--r--gas/doc/as.texinfo11
-rw-r--r--gas/macro.c212
-rw-r--r--gas/macro.h6
-rw-r--r--gas/testsuite/ChangeLog7
-rw-r--r--gas/testsuite/gas/macros/badarg.l5
-rw-r--r--gas/testsuite/gas/macros/badarg.s16
-rw-r--r--gas/testsuite/gas/macros/macros.exp2
-rw-r--r--gas/testsuite/gas/macros/vararg.d13
-rw-r--r--gas/testsuite/gas/macros/vararg.s10
11 files changed, 235 insertions, 71 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 6da2330e69..e4cfd38664 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,26 @@
2005-05-06 Jan Beulich <jbeulich@novell.com>
+ * macro.c (new_formal, del_formal): New.
+ (do_formals): Use new_formal. Check for and parse qualifier. Warn if
+ required argument has default value. Stop looking for more formal
+ when there was a vararg one.
+ (macro_expand_body): Use new_formal and del_formal.
+ (macro_expand): Likewise. Initialize local variable err. Don't
+ return immediately when encountering an error. Warn when keyword
+ argument already had a value assigned. Eliminate duplicate clearing
+ of argument value. When current positional argument matches parameter
+ of vararg type, assign to it all the remaining arguments. Issue error
+ when required parameter does not have value.
+ (free_macro): Use del_formal.
+ (expand_irp): Initialize formal type. Free buffers associated with
+ formal prior to returning.
+ * macro.h (struct formal_struct): Add new field 'type' with new
+ enumeration type 'formal_type'.
+ * doc/as.texinfo: Document macro parameter qualifiers.
+ * NEWS: Mention new functionality.
+
+2005-05-06 Jan Beulich <jbeulich@novell.com>
+
* cond.c (s_ifb): New.
* read.c (potable): Add s_ifb as handler for .ifb and .ifnb.
* read.h (s_ifb): Prototype.
diff --git a/gas/NEWS b/gas/NEWS
index a95311f267..4b70aca165 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* Macros with a variable number of arguments are now supported. See the
+ documentation for how this works.
+
* Added --reduce-memory-overheads switch to reduce the size of the hash
tables used, at the expense of longer assembly times, and
--hash-size=<NUMBER> to set the size of the hash tables used by gas.
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index 8186aba388..4db81f64b5 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -4866,7 +4866,10 @@ With that definition, @samp{SUM 0,5} is equivalent to this assembly input:
@cindex @code{macro} directive
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 supply a default value for any
+separated by commas or spaces. You can qualify the macro argument to
+indicate whether all invocations must specify a non-blank value (through
+@samp{:@code{req}}), or whether it takes all of the remaining arguments
+(through @samp{:@code{vararg}}). You can supply a default value for any
macro argument by following the name with @samp{=@var{deflt}}. You
cannot define two macros with the same @var{macname} unless it has been
subject to the @code{.purgem} directive (@xref{Purgem}.) between the two
@@ -4893,6 +4896,12 @@ After the definition is complete, you can call the macro either as
@samp{0}, and @samp{\p2} evaluating to @var{b}).
@end table
+@item .macro m p1:req, p2=0, p3:vararg
+Begin the definition of a macro called @code{m}, with at least three
+arguments. The first argument must always have a value specified, but
+not the second, which instead has a default value. The third formal
+will get assigned all remaining arguments specified at invocation time.
+
When you call a macro, you can specify the argument values either by
position, or by keyword. For example, @samp{sum 9,17} is equivalent to
@samp{sum to=17, from=9}.
diff --git a/gas/macro.c b/gas/macro.c
index be73b98d9b..76e3664b22 100644
--- a/gas/macro.c
+++ b/gas/macro.c
@@ -71,6 +71,8 @@ extern void *alloca ();
static int get_token (int, sb *, sb *);
static int getstring (int, sb *, sb *);
static int get_any_string (int, sb *, sb *, int, int);
+static formal_entry *new_formal (void);
+static void del_formal (formal_entry *);
static int do_formals (macro_entry *, int, sb *);
static int get_apost_token (int, sb *, sb *, int);
static int sub_actual (int, sb *, sb *, struct hash_control *, int, sb *, int);
@@ -465,6 +467,34 @@ get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
return idx;
}
+/* Allocate a new formal. */
+
+static formal_entry *
+new_formal (void)
+{
+ formal_entry *formal;
+
+ formal = xmalloc (sizeof (formal_entry));
+
+ sb_new (&formal->name);
+ sb_new (&formal->def);
+ sb_new (&formal->actual);
+ formal->next = NULL;
+ formal->type = FORMAL_OPTIONAL;
+ return formal;
+}
+
+/* Free a formal. */
+
+static void
+del_formal (formal_entry *formal)
+{
+ sb_kill (&formal->actual);
+ sb_kill (&formal->def);
+ sb_kill (&formal->name);
+ free (formal);
+}
+
/* Pick up the formal parameters of a macro definition. */
static int
@@ -476,15 +506,9 @@ do_formals (macro_entry *macro, int idx, sb *in)
idx = sb_skip_white (idx, in);
while (idx < in->len)
{
- formal_entry *formal;
+ formal_entry *formal = new_formal ();
int cidx;
- formal = (formal_entry *) xmalloc (sizeof (formal_entry));
-
- sb_new (&formal->name);
- sb_new (&formal->def);
- sb_new (&formal->actual);
-
idx = get_token (idx, in, &formal->name);
if (formal->name.len == 0)
{
@@ -494,15 +518,57 @@ do_formals (macro_entry *macro, int idx, sb *in)
}
idx = sb_skip_white (idx, in);
/* This is a formal. */
+ name = sb_terminate (&formal->name);
+ if (! macro_mri
+ && idx < in->len
+ && in->ptr[idx] == ':'
+ && (! is_name_beginner (':')
+ || idx + 1 >= in->len
+ || ! is_part_of_name (in->ptr[idx + 1])))
+ {
+ /* Got a qualifier. */
+ sb qual;
+
+ sb_new (&qual);
+ idx = get_token (sb_skip_white (idx + 1, in), in, &qual);
+ sb_terminate (&qual);
+ if (qual.len == 0)
+ as_bad_where (macro->file,
+ macro->line,
+ _("Missing parameter qualifier for `%s' in macro `%s'"),
+ name,
+ macro->name);
+ else if (strcmp (qual.ptr, "req") == 0)
+ formal->type = FORMAL_REQUIRED;
+ else if (strcmp (qual.ptr, "vararg") == 0)
+ formal->type = FORMAL_VARARG;
+ else
+ as_bad_where (macro->file,
+ macro->line,
+ _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"),
+ qual.ptr,
+ name,
+ macro->name);
+ sb_kill (&qual);
+ idx = sb_skip_white (idx, in);
+ }
if (idx < in->len && in->ptr[idx] == '=')
{
/* Got a default. */
idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
idx = sb_skip_white (idx, in);
+ if (formal->type == FORMAL_REQUIRED)
+ {
+ sb_reset (&formal->def);
+ as_warn_where (macro->file,
+ macro->line,
+ _("Pointless default value for required parameter `%s' in macro `%s'"),
+ name,
+ macro->name);
+ }
}
/* Add to macro's hash table. */
- name = sb_terminate (&formal->name);
if (! hash_find (macro->formal_hash, name))
hash_jam (macro->formal_hash, name, formal);
else
@@ -513,6 +579,10 @@ do_formals (macro_entry *macro, int idx, sb *in)
macro->name);
formal->index = macro->formal_count++;
+ *p = formal;
+ p = &formal->next;
+ if (formal->type == FORMAL_VARARG)
+ break;
cidx = idx;
idx = sb_skip_comma (idx, in);
if (idx != cidx && idx >= in->len)
@@ -520,23 +590,14 @@ do_formals (macro_entry *macro, int idx, sb *in)
idx = cidx;
break;
}
- *p = formal;
- p = &formal->next;
- *p = NULL;
}
if (macro_mri)
{
- formal_entry *formal;
+ formal_entry *formal = new_formal ();
/* Add a special NARG formal, which macro_expand will set to the
number of arguments. */
- formal = (formal_entry *) xmalloc (sizeof (formal_entry));
-
- sb_new (&formal->name);
- sb_new (&formal->def);
- sb_new (&formal->actual);
-
/* The same MRI assemblers which treat '@' characters also use
the name $NARG. At least until we find an exception. */
if (macro_strip_at)
@@ -557,7 +618,6 @@ do_formals (macro_entry *macro, int idx, sb *in)
formal->index = NARG_INDEX;
*p = formal;
- formal->next = NULL;
}
return idx;
@@ -827,10 +887,8 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
while (in->ptr[src] != '\n')
{
const char *name;
- formal_entry *f;
+ formal_entry *f = new_formal ();
- f = (formal_entry *) xmalloc (sizeof (formal_entry));
- sb_new (&f->name);
src = get_token (src, in, &f->name);
name = sb_terminate (&f->name);
if (! hash_find (formal_hash, name))
@@ -838,8 +896,6 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
static int loccnt;
char buf[20];
- sb_new (&f->def);
- sb_new (&f->actual);
f->index = LOCAL_INDEX;
f->next = loclist;
loclist = f;
@@ -857,8 +913,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
macro->line + macro_line,
_("`%s' was already used as parameter (or another local) name"),
name);
- sb_kill (&f->name);
- free (f);
+ del_formal (f);
}
src = sb_skip_comma (src, in);
@@ -935,10 +990,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
/* Setting the value to NULL effectively deletes the entry. We
avoid calling hash_delete because it doesn't reclaim memory. */
hash_jam (formal_hash, sb_terminate (&loclist->name), NULL);
- sb_kill (&loclist->name);
- sb_kill (&loclist->def);
- sb_kill (&loclist->actual);
- free (loclist);
+ del_formal (loclist);
loclist = f;
}
@@ -957,7 +1009,7 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
int is_positional = 0;
int is_keyword = 0;
int narg = 0;
- const char *err;
+ const char *err = NULL;
sb_new (&t);
@@ -981,12 +1033,8 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
&& in->ptr[idx] != ' '
&& in->ptr[idx] != '\t')
{
- formal_entry *n;
+ formal_entry *n = new_formal ();
- n = (formal_entry *) xmalloc (sizeof (formal_entry));
- sb_new (&n->name);
- sb_new (&n->def);
- sb_new (&n->actual);
n->index = QUAL_INDEX;
n->next = m->formals;
@@ -1021,16 +1069,27 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
sb_reset (&t);
idx = get_token (idx, in, &t);
if (in->ptr[idx] != '=')
- return _("confusion in formal parameters");
+ {
+ err = _("confusion in formal parameters");
+ break;
+ }
/* Lookup the formal in the macro's list. */
ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
if (!ptr)
- return _("macro formal argument does not exist");
+ as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
+ t.ptr,
+ m->name);
else
{
/* Insert this value into the right place. */
- sb_reset (&ptr->actual);
+ if (ptr->actual.len)
+ {
+ as_warn (_("Value for parameter `%s' of macro `%s' was already specified"),
+ ptr->name.ptr,
+ m->name);
+ sb_reset (&ptr->actual);
+ }
idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0);
if (ptr->actual.len > 0)
++narg;
@@ -1041,7 +1100,10 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
/* This is a positional arg. */
is_positional = 1;
if (is_keyword)
- return _("can't mix positional and keyword arguments");
+ {
+ err = _("can't mix positional and keyword arguments");
+ break;
+ }
if (!f)
{
@@ -1049,13 +1111,12 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
int c;
if (!macro_mri)
- return _("too many positional arguments");
+ {
+ err = _("too many positional arguments");
+ break;
+ }
- f = (formal_entry *) xmalloc (sizeof (formal_entry));
- sb_new (&f->name);
- sb_new (&f->def);
- sb_new (&f->actual);
- f->next = NULL;
+ f = new_formal ();
c = -1;
for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
@@ -1067,8 +1128,13 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
f->index = c;
}
- sb_reset (&f->actual);
- idx = get_any_string (idx, in, &f->actual, 1, 0);
+ if (f->type != FORMAL_VARARG)
+ idx = get_any_string (idx, in, &f->actual, 1, 0);
+ else
+ {
+ sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx);
+ idx = in->len;
+ }
if (f->actual.len > 0)
++narg;
do
@@ -1089,19 +1155,29 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
}
}
- if (macro_mri)
+ if (! err)
{
- char buffer[20];
-
- sb_reset (&t);
- 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);
- sb_add_string (&ptr->actual, buffer);
- }
+ for (ptr = m->formals; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0)
+ as_bad (_("Missing value for required parameter `%s' of macro `%s'"),
+ ptr->name.ptr,
+ m->name);
+ }
- err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
+ if (macro_mri)
+ {
+ char buffer[20];
+
+ sb_reset (&t);
+ sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
+ ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
+ sprintf (buffer, "%d", narg);
+ sb_add_string (&ptr->actual, buffer);
+ }
+
+ err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
+ }
/* Discard any unnamed formal arguments. */
if (macro_mri)
@@ -1115,11 +1191,8 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
pf = &(*pf)->next;
else
{
- sb_kill (&(*pf)->name);
- sb_kill (&(*pf)->def);
- sb_kill (&(*pf)->actual);
f = (*pf)->next;
- free (*pf);
+ del_formal (*pf);
*pf = f;
}
}
@@ -1191,14 +1264,11 @@ free_macro(macro_entry *macro)
for (formal = macro->formals; formal; )
{
- void *ptr;
+ formal_entry *f;
- sb_kill (&formal->name);
- sb_kill (&formal->def);
- sb_kill (&formal->actual);
- ptr = formal;
+ f = formal;
formal = formal->next;
- free (ptr);
+ del_formal (f);
}
hash_die (macro->formal_hash);
sb_kill (&macro->sub);
@@ -1263,6 +1333,7 @@ expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
f.index = 1;
f.next = NULL;
+ f.type = FORMAL_OPTIONAL;
sb_reset (out);
@@ -1308,6 +1379,9 @@ expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
}
hash_die (h);
+ sb_kill (&f.actual);
+ sb_kill (&f.def);
+ sb_kill (&f.name);
sb_kill (&sub);
return err;
diff --git a/gas/macro.h b/gas/macro.h
index e6ade7cd80..4fdaa52d09 100644
--- a/gas/macro.h
+++ b/gas/macro.h
@@ -45,6 +45,12 @@ typedef struct formal_struct {
sb def; /* The default value. */
sb actual; /* The actual argument (changed on each expansion). */
int index; /* The index of the formal 0..formal_count - 1. */
+ enum formal_type
+ {
+ FORMAL_OPTIONAL,
+ FORMAL_REQUIRED,
+ FORMAL_VARARG
+ } type; /* The kind of the formal. */
} formal_entry;
/* Other values found in the index field of a formal_entry. */
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index d7365b44a2..eceba443c6 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,5 +1,12 @@
2005-05-06 Jan Beulich <jbeulich@novell.com>
+ * gas/macros/badarg.s: Add check for bad qualifier specification.
+ * gas/macros/badarg.l: Adjust.
+ * gas/macros/vararg.[sd]: New.
+ * gas/macros/macros.exp: Run new test.
+
+2005-05-06 Jan Beulich <jbeulich@novell.com>
+
* gas/all/cond.s: Also test .ifb/.ifnb.
* gas/all/cond.d: Adjust.
diff --git a/gas/testsuite/gas/macros/badarg.l b/gas/testsuite/gas/macros/badarg.l
index 602d3cecd4..cbf2429991 100644
--- a/gas/testsuite/gas/macros/badarg.l
+++ b/gas/testsuite/gas/macros/badarg.l
@@ -8,3 +8,8 @@
.*:19: Error: .*
.*:25: Error: .*
.*:30: Error: .*
+.*:38: Error: .*
+.*:41: Error: .*
+.*:44: Warning: .*
+.*:47: Error: .*
+.*:49: Error: .*
diff --git a/gas/testsuite/gas/macros/badarg.s b/gas/testsuite/gas/macros/badarg.s
index 3dec7eadfe..716a98f1ad 100644
--- a/gas/testsuite/gas/macros/badarg.s
+++ b/gas/testsuite/gas/macros/badarg.s
@@ -32,3 +32,19 @@
m6
m7
+
+ .noaltmacro
+
+ .macro m8, arg :
+ .endm
+
+ .macro m9, arg : qual
+ .endm
+
+ .macro m10, arg : req = def
+ .endm
+
+ m10
+
+ .macro m11, arg1 : vararg, arg2
+ .endm
diff --git a/gas/testsuite/gas/macros/macros.exp b/gas/testsuite/gas/macros/macros.exp
index ed8debe13f..cd19ff8183 100644
--- a/gas/testsuite/gas/macros/macros.exp
+++ b/gas/testsuite/gas/macros/macros.exp
@@ -27,9 +27,9 @@ if { ![istarget *c54x*-*-*] && ![istarget *c4x*-*-*] } {
run_dump_test irp
run_dump_test rept
run_dump_test repeat
+ run_dump_test vararg
}
-
gas_test_error "err.s" "" "macro infinite recursion"
# The tic4x-coff target fails the next test because it defines '&'
diff --git a/gas/testsuite/gas/macros/vararg.d b/gas/testsuite/gas/macros/vararg.d
new file mode 100644
index 0000000000..4b943fd18f
--- /dev/null
+++ b/gas/testsuite/gas/macros/vararg.d
@@ -0,0 +1,13 @@
+#objdump: -r
+#name: macro vararg
+
+.*: +file format .*
+
+RELOCATION RECORDS FOR .*
+OFFSET[ ]+TYPE[ ]+VALUE.*
+0+00[ ]+[a-zA-Z0-9_]+[ ]+foo1
+0+04[ ]+[a-zA-Z0-9_]+[ ]+foo2
+0+08[ ]+[a-zA-Z0-9_]+[ ]+foo3
+0+0c[ ]+[a-zA-Z0-9_]+[ ]+foo4
+0+10[ ]+[a-zA-Z0-9_]+[ ]+foo5
+0+14[ ]+[a-zA-Z0-9_]+[ ]+foo6
diff --git a/gas/testsuite/gas/macros/vararg.s b/gas/testsuite/gas/macros/vararg.s
new file mode 100644
index 0000000000..4bdf99a263
--- /dev/null
+++ b/gas/testsuite/gas/macros/vararg.s
@@ -0,0 +1,10 @@
+ .macro v1 arg1 : req, args : vararg
+ .long foo\arg1
+ .ifnb \args
+ v1 \args
+ .endif
+ .endm
+
+ v1 1
+ v1 2, 3
+ v1 4, 5, 6