[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
17.4 Solution for copy
The macro copy
presented above
is unable to handle builtin tokens with M4 1.4.x, because it tries to
pass the builtin token through the macro curry
, where it is
silently flattened to an empty string (see section Building macros with macros). Rather
than using the problematic curry
to work around the limitation
that stack_foreach
expects to invoke a macro that takes exactly
one argument, we can write a new macro that lets us form the exact
two-argument pushdef
call sequence needed, so that we are no
longer passing a builtin token through a text macro.
- Composite: stack_foreach_sep (macro, pre, post, sep)
- Composite: stack_foreach_sep_lifo (macro, pre, post, sep)
For each of the
pushdef
definitions associated with macro, expand the sequence ‘pre`'definition`'post’. Additionally, expand sep between definitions.stack_foreach_sep
visits the oldest definition first, whilestack_foreach_sep_lifo
visits the current definition first. The expansion may dereference macro, but should not modify it. There are a few special macros, such asdefn
, which cannot be used as the macro parameter.
Note that stack_foreach(`macro', `action')
is
equivalent to stack_foreach_sep(`macro', `action(',
`)')
. By supplying explicit parentheses, split among the pre and
post arguments to stack_foreach_sep
, it is now possible to
construct macro calls with more than one argument, without passing
builtin tokens through a macro call. It is likewise possible to
directly reference the stack definitions without a macro call, by
leaving pre and post empty. Thus, in addition to fixing
copy
on builtin tokens, it also executes with fewer macro
invocations.
The new macro also adds a separator that is only output after the first
iteration of the helper _stack_reverse_sep
, implemented by
prepending the original sep to pre and omitting a sep
argument in subsequent iterations. Note that the empty string that
separates sep from pre is provided as part of the fourth
argument when originally calling _stack_reverse_sep
, and not by
writing $4`'$3
as the third argument in the recursive call; while
the other approach would give the same output, it does so at the expense
of increasing the argument size on each iteration of
_stack_reverse_sep
, which results in quadratic instead of linear
execution time. The improved stack walking macros are available in
‘m4-1.4.17/examples/stack_sep.m4’:
$ m4 -I examples include(`stack_sep.m4') ⇒ define(`copy', `ifdef(`$2', `errprint(`$2 already defined ')m4exit(`1')', `stack_foreach_sep(`$1', `pushdef(`$2',', `)')')')dnl pushdef(`a', `1')pushdef(`a', defn(`divnum')) ⇒ copy(`a', `b') ⇒ b ⇒0 popdef(`b') ⇒ b ⇒1 pushdef(`c', `1')pushdef(`c', `2') ⇒ stack_foreach_sep_lifo(`c', `', `', `, ') ⇒2, 1 undivert(`stack_sep.m4')dnl ⇒divert(`-1') ⇒# stack_foreach_sep(macro, pre, post, sep) ⇒# Invoke PRE`'defn`'POST with a single argument of each definition ⇒# from the definition stack of MACRO, starting with the oldest, and ⇒# separated by SEP between definitions. ⇒define(`stack_foreach_sep', ⇒`_stack_reverse_sep(`$1', `tmp-$1')'dnl ⇒`_stack_reverse_sep(`tmp-$1', `$1', `$2`'defn(`$1')$3', `$4`'')') ⇒# stack_foreach_sep_lifo(macro, pre, post, sep) ⇒# Like stack_foreach_sep, but starting with the newest definition. ⇒define(`stack_foreach_sep_lifo', ⇒`_stack_reverse_sep(`$1', `tmp-$1', `$2`'defn(`$1')$3', `$4`'')'dnl ⇒`_stack_reverse_sep(`tmp-$1', `$1')') ⇒define(`_stack_reverse_sep', ⇒`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0( ⇒ `$1', `$2', `$4$3')')') ⇒divert`'dnl
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on September 29, 2013 using texi2html 5.0.