aboutsummaryrefslogtreecommitdiff
path: root/gas/read.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2024-06-10 09:06:37 +0200
committerJan Beulich <jbeulich@suse.com>2024-06-10 09:06:37 +0200
commit1e3c814459d83247707f8c9840ac660726cfaae0 (patch)
tree9135b4011333ae2afc9c2b882a5f3f6f4d40cca8 /gas/read.c
parentd967140f8ca04a3fbe607382d615af35f9df9453 (diff)
downloadfsf-binutils-gdb-1e3c814459d83247707f8c9840ac660726cfaae0.zip
fsf-binutils-gdb-1e3c814459d83247707f8c9840ac660726cfaae0.tar.gz
fsf-binutils-gdb-1e3c814459d83247707f8c9840ac660726cfaae0.tar.bz2
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.
Diffstat (limited to 'gas/read.c')
-rw-r--r--gas/read.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/gas/read.c b/gas/read.c
index 8026a6c..40a91f4 100644
--- a/gas/read.c
+++ b/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)