diff options
-rw-r--r-- | gas/ChangeLog | 21 | ||||
-rw-r--r-- | gas/NEWS | 3 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 11 | ||||
-rw-r--r-- | gas/macro.c | 212 | ||||
-rw-r--r-- | gas/macro.h | 6 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/badarg.l | 5 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/badarg.s | 16 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/macros.exp | 2 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/vararg.d | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/vararg.s | 10 |
11 files changed, 235 insertions, 71 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 6da2330..e4cfd38 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. @@ -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 8186aba..4db81f6 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 be73b98..76e3664 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 (¯o->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 e6ade7c..4fdaa52 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 d7365b4..eceba44 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 602d3ce..cbf2429 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 3dec7ea..716a98f 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 ed8debe..cd19ff8 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 0000000..4b943fd --- /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 0000000..4bdf99a --- /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 |