Control flow is limited to ifelse, but it's easy to construct loops by recursion. GNU m4 includes examples of macros implementing various general-purpose loops.

Quoting data values against premature or unwanted expansion can be a little tricky. The default quote characters are ` and '. If they would occur in text too often then changequote() can set something else. Autoconf changes to [ and ] since ` and ' occur often in its Bourne Shell output.

When a macro expands, its value (with $1 etc parameters substituted) is re-read as input. This is how macro definitions can contain further macros to expand.

define(`foo', `bar(`$1',x,`$2')')

Various m4 implementations, including BSD, have a fixed limit on the amount "push-back" text to be re-read. GNU m4 has no limit except available memory. A limit restricts the size of macro values and the data they might operate on. Cutting data into pieces can keep expansions to a reasonable size.

The simple text re-reading means that macro calls are "properly tail recursive". If an expansion ends with another macro call then that call can re-expand recursively or by co-routining endlessly. But a tail call must be the very last thing, no newline or other fixed text after. See Factorial for an example of such recursion.