diff options
-rw-r--r-- | gas/NEWS | 4 | ||||
-rw-r--r-- | gas/doc/as.texi | 7 | ||||
-rw-r--r-- | gas/read.c | 63 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/macros.exp | 1 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/rept-count.l | 15 | ||||
-rw-r--r-- | gas/testsuite/gas/macros/rept-count.s | 10 |
6 files changed, 93 insertions, 7 deletions
@@ -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. diff --git a/gas/doc/as.texi b/gas/doc/as.texi index 90898d7..33169a5 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -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}"} @@ -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) diff --git a/gas/testsuite/gas/macros/macros.exp b/gas/testsuite/gas/macros/macros.exp index fbe50f3..69914f7 100644 --- a/gas/testsuite/gas/macros/macros.exp +++ b/gas/testsuite/gas/macros/macros.exp @@ -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 diff --git a/gas/testsuite/gas/macros/rept-count.l b/gas/testsuite/gas/macros/rept-count.l new file mode 100644 index 0000000..a1a39ba --- /dev/null +++ b/gas/testsuite/gas/macros/rept-count.l @@ -0,0 +1,15 @@ +#... +>0< +>1< +>2< +>3< +>4< +>0< +>0:0< +>0:1< +>1< +>1:0< +>1:1< +>2< +>2:0< +>2:1< diff --git a/gas/testsuite/gas/macros/rept-count.s b/gas/testsuite/gas/macros/rept-count.s new file mode 100644 index 0000000..4f7b3c6 --- /dev/null +++ b/gas/testsuite/gas/macros/rept-count.s @@ -0,0 +1,10 @@ + .rept 5 + .print ">\+<" + .endr + + .rept 3 + .print ">\+<" + .rept 2 + .print ">\+:\\+<" + .endr + .endr |