| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] | 
6.7 Building macros with macros
Since m4 is a macro language, it is possible to write macros that can build other macros. First on the list is a way to automate the creation of blind macros.
- Composite: define_blind (name, [value]@c)
- Defines name as a blind macro, such that name will expand to value only when given explicit arguments. value should not be the result of - defn(see section Renaming macros). This macro is only recognized with parameters, and results in an empty string.
Defining a macro to define another macro can be a bit tricky.  We want
to use a literal ‘$#’ in the argument to the nested define.
However, if ‘$’ and ‘#’ are adjacent in the definition of
define_blind, then it would be expanded as the number of
arguments to define_blind rather than the intended number of
arguments to name.  The solution is to pass the difficult
characters through extra arguments to a helper macro
_define_blind.  When composing macros, it is a common idiom to
need a helper macro to concatenate text that forms parameters in the
composed macro, rather than interpreting the text as a parameter of the
composing macro.
As for the limitation against using defn, there are two reasons.
If a macro was previously defined with define_blind, then it can
safely be renamed to a new blind macro using plain define; using
define_blind to rename it just adds another layer of
ifelse, occupying memory and slowing down execution.  And if a
macro is a builtin, then it would result in an attempt to define a macro
consisting of both text and a builtin token; this is not supported, and
the builtin token is flattened to an empty string.
With that explanation, here’s the definition, and some sample usage.
Notice that define_blind is itself a blind macro.
| $ m4 -d define(`define_blind', `ifelse(`$#', `0', ``$0'', `_$0(`$1', `$2', `$'`#', `$'`0')')') ⇒ define(`_define_blind', `define(`$1', `ifelse(`$3', `0', ``$4'', `$2')')') ⇒ define_blind ⇒define_blind define_blind(`foo', `arguments were $*') ⇒ foo ⇒foo foo(`bar') ⇒arguments were bar define(`blah', defn(`foo')) ⇒ blah ⇒blah blah(`a', `b') ⇒arguments were a,b defn(`blah') ⇒ifelse(`$#', `0', ``$0'', `arguments were $*') | 
Another interesting composition tactic is argument currying, or factoring a macro that takes multiple arguments for use in a context that provides exactly one argument.
- Composite: curry (macro, …)
- Expand to a macro call that takes exactly one argument, then appends that argument to the original arguments and invokes macro with the resulting list of arguments. 
A demonstration of currying makes the intent of this macro a little more
obvious.  The macro stack_foreach mentioned earlier is an example
of a context that provides exactly one argument to a macro name.  But
coupled with currying, we can invoke reverse with two arguments
for each definition of a macro stack.  This example uses the file
‘m4-1.4.16/examples/curry.m4’ included in the
distribution.
| $ m4 -I examples
include(`curry.m4')include(`stack.m4')
⇒
define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'',
                          `reverse(shift($@)), `$1'')')
⇒
pushdef(`a', `1')pushdef(`a', `2')pushdef(`a', `3')
⇒
stack_foreach(`a', `:curry(`reverse', `4')')
⇒:1, 4:2, 4:3, 4
curry(`curry', `reverse', `1')(`2')(`3')
⇒3, 2, 1
 | 
Now for the implementation.  Notice how curry leaves off with a
macro name but no open parenthesis, while still in the middle of
collecting arguments for ‘$1’.  The macro _curry is the
helper macro that takes one argument, then adds it to the list and
finally supplies the closing parenthesis.  The use of a comma inside the
shift call allows currying to also work for a macro that takes
one argument, although it often makes more sense to invoke that macro
directly rather than going through curry.
| $ m4 -I examples undivert(`curry.m4')dnl ⇒divert(`-1') ⇒# curry(macro, args) ⇒# Expand to a macro call that takes one argument, then invoke ⇒# macro(args, extra). ⇒define(`curry', `$1(shift($@,)_$0') ⇒define(`_curry', ``$1')') ⇒divert`'dnl | 
Unfortunately, with M4 1.4.x, curry is unable to handle builtin
tokens, which are silently flattened to the empty string when passed
through another text macro.  This limitation will be lifted in a future
release of M4.
Putting the last few concepts together, it is possible to copy or rename an entire stack of macro definitions.
- Composite: copy (source, dest)
- Composite: rename (source, dest)
- Ensure that dest is undefined, then define it to the same stack of definitions currently in source. - copyleaves source unchanged, while- renameundefines source. There are only a few macros, such as- copyor- defn, which cannot be copied via this macro.
The implementation is relatively straightforward (although since it uses
curry, it is unable to copy builtin macros, such as the second
definition of a as a synonym for divnum.  See if you can
design a version that works around this limitation, or see section Answers).
| $ m4 -I examples include(`curry.m4')include(`stack.m4') ⇒ define(`rename', `copy($@)undefine(`$1')')dnl define(`copy', `ifdef(`$2', `errprint(`$2 already defined ')m4exit(`1')', `stack_foreach(`$1', `curry(`pushdef', `$2')')')')dnl pushdef(`a', `1')pushdef(`a', defn(`divnum'))pushdef(`a', `2') ⇒ copy(`a', `b') ⇒ rename(`b', `c') ⇒ a b c ⇒2 b 2 popdef(`a', `c')c a ⇒ 0 popdef(`a', `c')a c ⇒1 1 | 
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] | 
