forked from Imagelibrary/binutils-gdb
gas: extend \+ support to .rept
PR gas/31752 While not quite as macro-like as .irp / .irpc, this perhaps benefits from supporting \+ even more than those: It allows, where desired, to get away without maintaining an explicit count variable in source code. Keep .rep (and custom per-arch uses of s_rept() / do_repeat()) behavior unaltered.
This commit is contained in:
4
gas/NEWS
4
gas/NEWS
@@ -3,8 +3,8 @@
|
||||
* In x86 Intel syntax undue mnemonic suffixes are now warned about. This is
|
||||
a first step towards rejecting their use where unjustified.
|
||||
|
||||
* Assembler macros as well as the bodies of .irp / .irpc can now use the
|
||||
syntax \+ to access the number of times a given macro has been executed.
|
||||
* Assembler macros as well as the bodies of .irp / .irpc / .rept can now use
|
||||
the syntax \+ to access the number of times a given macro has been executed.
|
||||
This is similar to the already existing \@ syntax, except that the count is
|
||||
maintained on a per-macro basis.
|
||||
|
||||
|
||||
@@ -6739,6 +6739,13 @@ is equivalent to assembling
|
||||
A count of zero is allowed, but nothing is generated. Negative counts are not
|
||||
allowed and if encountered will be treated as if they were zero.
|
||||
|
||||
Much like for macros, @code{.irp}, and @code{.irpc} the @samp{\+} sequence can
|
||||
be used to substitute in the number of iterations done so far. In such cases,
|
||||
i.e. when any @samp{\+} character sequence is present between @code{.rept} and
|
||||
the corresponding @code{.endr}, other backslashes also need escaping by
|
||||
backslashes. Naturally the amount of escaping necessary may increase when
|
||||
using nested constructs.
|
||||
|
||||
@node Sbttl
|
||||
@section @code{.sbttl "@var{subheading}"}
|
||||
|
||||
|
||||
63
gas/read.c
63
gas/read.c
@@ -482,7 +482,7 @@ static const pseudo_typeS potable[] = {
|
||||
{"quad", cons, 8},
|
||||
{"reloc", s_reloc, 0},
|
||||
{"rep", s_rept, 0},
|
||||
{"rept", s_rept, 0},
|
||||
{"rept", s_rept, 1},
|
||||
{"rva", s_rva, 4},
|
||||
{"sbttl", listing_title, 1}, /* Subtitle of listing. */
|
||||
/* scl */
|
||||
@@ -3066,19 +3066,21 @@ s_bad_end (int endr)
|
||||
/* Handle the .rept pseudo-op. */
|
||||
|
||||
void
|
||||
s_rept (int ignore ATTRIBUTE_UNUSED)
|
||||
s_rept (int expand_count)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
count = (size_t) get_absolute_expression ();
|
||||
|
||||
do_repeat (count, "REPT", "ENDR", NULL);
|
||||
do_repeat (count, "REPT", "ENDR", expand_count ? "" : NULL);
|
||||
}
|
||||
|
||||
/* This function provides a generic repeat block implementation. It allows
|
||||
different directives to be used as the start/end keys. Any text matching
|
||||
the optional EXPANDER in the block is replaced by the remaining iteration
|
||||
count. */
|
||||
count. Except when EXPANDER is the empty string, in which case \+ will
|
||||
be looked for (as also recognized in macros as well as .irp and .irpc),
|
||||
where the replacement will be the number of iterations done so far. */
|
||||
|
||||
void
|
||||
do_repeat (size_t count, const char *start, const char *end,
|
||||
@@ -3101,7 +3103,58 @@ do_repeat (size_t count, const char *start, const char *end,
|
||||
return;
|
||||
}
|
||||
|
||||
if (expander == NULL || strstr (one.ptr, expander) == NULL)
|
||||
if (expander != NULL && !*expander && strstr (one.ptr, "\\+") != NULL)
|
||||
{
|
||||
/* The 3 here and below are arbitrary, added in an attempt to limit
|
||||
re-allocation needs in sb_add_...() for moderate repeat counts. */
|
||||
sb_build (&many, count * (one.len + 3));
|
||||
|
||||
for (size_t done = 0; count-- > 0; ++done)
|
||||
{
|
||||
const char *ptr, *bs;
|
||||
sb processed;
|
||||
|
||||
sb_build (&processed, one.len + 3);
|
||||
|
||||
for (ptr = one.ptr;
|
||||
(bs = memchr (ptr, '\\', one.ptr + one.len - ptr)) != NULL; )
|
||||
{
|
||||
sb_add_buffer (&processed, ptr, bs - ptr);
|
||||
switch (bs[1])
|
||||
{
|
||||
char scratch[24];
|
||||
|
||||
default:
|
||||
sb_add_char (&processed, '\\');
|
||||
sb_add_char (&processed, bs[1]);
|
||||
ptr = bs + 2;
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
as_warn (_("`\\' at end of line/statement; ignored"));
|
||||
ptr = bs + 1;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
sb_add_char (&processed, '\\');
|
||||
ptr = bs + 2;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
snprintf (scratch, ARRAY_SIZE (scratch), "%zu", done);
|
||||
sb_add_string (&processed, scratch);
|
||||
ptr = bs + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sb_add_buffer (&processed, ptr, one.ptr + one.len - ptr);
|
||||
|
||||
sb_add_sb (&many, &processed);
|
||||
sb_kill (&processed);
|
||||
}
|
||||
}
|
||||
else if (expander == NULL || !*expander || strstr (one.ptr, expander) == NULL)
|
||||
{
|
||||
sb_build (&many, count * one.len);
|
||||
while (count-- > 0)
|
||||
|
||||
@@ -105,3 +105,4 @@ run_list_test altmacro
|
||||
run_list_test count
|
||||
run_list_test irp-count
|
||||
run_list_test irpc-quote
|
||||
run_list_test rept-count
|
||||
|
||||
15
gas/testsuite/gas/macros/rept-count.l
Normal file
15
gas/testsuite/gas/macros/rept-count.l
Normal file
@@ -0,0 +1,15 @@
|
||||
#...
|
||||
>0<
|
||||
>1<
|
||||
>2<
|
||||
>3<
|
||||
>4<
|
||||
>0<
|
||||
>0:0<
|
||||
>0:1<
|
||||
>1<
|
||||
>1:0<
|
||||
>1:1<
|
||||
>2<
|
||||
>2:0<
|
||||
>2:1<
|
||||
10
gas/testsuite/gas/macros/rept-count.s
Normal file
10
gas/testsuite/gas/macros/rept-count.s
Normal file
@@ -0,0 +1,10 @@
|
||||
.rept 5
|
||||
.print ">\+<"
|
||||
.endr
|
||||
|
||||
.rept 3
|
||||
.print ">\+<"
|
||||
.rept 2
|
||||
.print ">\+:\\+<"
|
||||
.endr
|
||||
.endr
|
||||
Reference in New Issue
Block a user