File: m4.info, Node: Improved copy, Next: Improved m4wrap, Prev: Improved foreach, Up: Answers 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 (*note Composition::). 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, while ‘stack_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 as ‘defn’, 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.20/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