Increment and decrement of integers are supported using the builtins
incr and decr:
Expand to the numerical value of number, incremented or decremented, respectively, by one. Except for the empty string, the expansion is empty if number could not be parsed.
The macros incr and decr are recognized only with
parameters.
incr(`4') ⇒5 decr(`7') ⇒6 incr() error→m4:stdin:3: empty string treated as 0 in builtin `incr' ⇒1 decr() error→m4:stdin:4: empty string treated as 0 in builtin `decr' ⇒-1
It is possible to use incr to write a macro that produces a
different value each time it is invoked:
When invoked with one argument, reset the counter to seed (where an empty seed is silently treated like 0), without output. Without arguments, output and increment the internal counter.
define(`_counter', `-1')dnl define(`counter', `ifelse(`$#', `0', `define(`_$0', incr(_$0))_$0`'', `define(`_$0', eval(`$1-1'))')') ⇒ counter counter counter ⇒0 1 2 counter(`42') ⇒ counter counter ⇒42 43 counter()counter ⇒0
It is worth noting how the implementation treats a default empty string
as 0 - this is done by storing one less than seed into the
internal counter _counter, by using eval in a way that
works even when $1 is blank.