diff options
author | Eric Blake <ebb9@byu.net> | 2008-12-18 11:02:39 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2008-12-18 11:03:59 -0700 |
commit | dac0f533e2fdd06e0ff5948b6f03042fea3d9402 (patch) | |
tree | a151f75e46c999c45e6edf011d5f5927f789009c | |
parent | 64df649442038cace6b063fa5bd36c7007193dcc (diff) | |
download | m4-dac0f533e2fdd06e0ff5948b6f03042fea3d9402.tar.gz |
Deal with M4 1.4.x limitation on builtin tokens.
* doc/m4.texinfo (Composition): Mention limitation on curry.
(Improved copy): New node.
(Stacks): Fix typo.
* examples/stack.m4: Likewise.
* examples/stack_sep.m4: New file.
* Makefile.am (dist_pkgdata_DATA): Distribute it.
Signed-off-by: Eric Blake <ebb9@byu.net>
(cherry picked from commit 92f059a8d7e6e6f96e791fcc14d6dcbdba7b3b9c)
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | doc/m4.texinfo | 113 | ||||
-rw-r--r-- | examples/stack.m4 | 4 | ||||
-rw-r--r-- | examples/stack_sep.m4 | 17 |
5 files changed, 140 insertions, 5 deletions
@@ -1,3 +1,13 @@ +2008-12-18 Eric Blake <ebb9@byu.net> + + Deal with M4 1.4.x limitation on builtin tokens. + * doc/m4.texinfo (Composition): Mention limitation on curry. + (Improved copy): New node. + (Stacks): Fix typo. + * examples/stack.m4: Likewise. + * examples/stack_sep.m4: New file. + * Makefile.am (dist_pkgdata_DATA): Distribute it. + 2008-12-15 Eric Blake <ebb9@byu.net> Double size of temp file cache. diff --git a/Makefile.am b/Makefile.am index 1b9130df..683a84e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -343,6 +343,7 @@ dist_pkgdata_DATA = \ examples/regexp.m4 \ examples/reverse.m4 \ examples/stack.m4 \ + examples/stack_sep.m4 \ examples/sysv-args.m4 \ examples/trace.m4 \ examples/translit.m4 \ diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 173921cc..3b78bc7e 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -291,6 +291,7 @@ Correct version of some examples * Improved exch:: Solution for @code{exch} * Improved forloop:: Solution for @code{forloop} * Improved foreach:: Solution for @code{foreach} +* Improved copy:: Solution for @code{copy} * Improved m4wrap:: Solution for @code{m4wrap} * Improved cleardivert:: Solution for @code{cleardivert} * Improved capitalize:: Solution for @code{capitalize} @@ -3839,13 +3840,13 @@ undefined during the algorithm. $ @kbd{m4 -I examples} undivert(`stack.m4')dnl @result{}divert(`-1') -@result{}# stack_foreach(action, macro) +@result{}# stack_foreach(macro, action) @result{}# Invoke ACTION with a single argument of each definition @result{}# from the definition stack of MACRO, starting with the oldest. @result{}define(`stack_foreach', @result{}`_stack_reverse(`$1', `tmp-$1')'dnl @result{}`_stack_reverse(`tmp-$1', `$1', `$2(defn(`$1'))')') -@result{}# stack_foreach_lifo(action, macro) +@result{}# stack_foreach_lifo(macro, action) @result{}# Invoke ACTION with a single argument of each definition @result{}# from the definition stack of MACRO, starting with the newest. @result{}define(`stack_foreach_lifo', @@ -3982,6 +3983,23 @@ undivert(`curry.m4')dnl @result{}divert`'dnl @end example +Unfortunately, with M4 1.4.x, @code{curry} is unable to handle builtin +tokens, which are silently flattened to the empty string when passed +through another text macro. The following example demonstrates a usage +of @code{curry} that works in M4 1.6, but is not portable to earlier +versions: + +@comment examples +@example +$ @kbd{m4 -I examples} +include(`curry.m4') +@result{} +curry(`define', `mylen')(defn(`len')) +@result{} +mylen(`abc') +@result{}3 +@end example + @cindex renaming macros @cindex copying macros @cindex macros, copying @@ -3997,7 +4015,10 @@ few macros, such as @code{copy} or @code{defn}, which cannot be copied via this macro. @end deffn -The implementation is relatively straightforward: +The implementation is relatively straightforward (although since it uses +@code{curry}, it is unable to copy builtin macros when used with M4 +1.4.x. See if you can design a portable version that works across all +M4 versions, or @pxref{Improved copy, , Answers}). @comment examples @example @@ -9191,6 +9212,7 @@ presented here. * Improved exch:: Solution for @code{exch} * Improved forloop:: Solution for @code{forloop} * Improved foreach:: Solution for @code{foreach} +* Improved copy:: Solution for @code{copy} * Improved m4wrap:: Solution for @code{m4wrap} * Improved cleardivert:: Solution for @code{cleardivert} * Improved capitalize:: Solution for @code{capitalize} @@ -9744,6 +9766,91 @@ foreachq(`x', ```active'', ``active''', `<x> @result{}<active> @end example +@node Improved copy +@section Solution for @code{copy} + +The macro @code{copy} presented above works with M4 1.6 and newer, but +is unable to handle builtin tokens with M4 1.4.x, because it tries to +pass the builtin token through the macro @code{curry}, where it is +silently flattened to an empty string (@pxref{Composition}). Rather +than using the problematic @code{curry} to work around the limitation +that @code{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 @code{pushdef} call sequence needed, so that we are no +longer passing a builtin token through a text macro. + +@deffn Composite stack_foreach_sep (@var{macro}, @var{pre}, @var{post}, @ + @var{sep}) +@deffnx Composite stack_foreach_sep_lifo (@var{macro}, @var{pre}, @ + @var{post}, @var{sep}) +For each of the @code{pushdef} definitions associated with @var{macro}, +expand the sequence @samp{@var{pre}`'definition`'@var{post}}. +Additionally, expand @var{sep} between definitions. +@code{stack_foreach_sep} visits the oldest definition first, while +@code{stack_foreach_sep_lifo} visits the current definition first. The +expansion may dereference @var{macro}, but should not modify it. There +are a few special macros, such as @code{defn}, which cannot be used as +the @var{macro} parameter. +@end deffn + +Note that @code{stack_foreach(`@var{macro}', `@var{action}')} is +equivalent to @code{stack_foreach_sep(`@var{macro}', `@var{action}(', +`)')}. By supplying explicit parentheses, split among the @var{pre} and +@var{post} arguments to @code{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 @var{pre} and @var{post} empty. The new macro also adds a +separator that is only output after the first iteration of the helper +@var{_stack_reverse_sep}, implemented by prepending the original +@var{sep} to @var{pre} and omitting a @var{sep} argument in subsequent +iterations. As an added bonus, using @code{stack_foreach_sep} to +implement @code{copy} performs fewer macro invocations. The improved +stack walking macros are available in +@file{m4-@value{VERSION}/@/examples/@/stack_sep.m4}: + +@comment examples +@example +$ @kbd{m4 -I examples} +include(`stack_sep.m4') +@result{} +define(`copy', `ifdef(`$2', `errprint(`$2 already defined +')m4exit(`1')', + `stack_foreach_sep(`$1', `pushdef(`$2',', `)')')')dnl +pushdef(`a', `1')pushdef(`a', defn(`divnum')) +@result{} +copy(`a', `b') +@result{} +b +@result{}0 +popdef(`b') +@result{} +b +@result{}1 +pushdef(`c', `1')pushdef(`c', `2') +@result{} +stack_foreach_sep_lifo(`c', `', `', `, ') +@result{}2, 1 +undivert(`stack_sep.m4')dnl +@result{}divert(`-1') +@result{}# stack_foreach_sep(macro, pre, post, sep) +@result{}# Invoke PRE`'defn`'POST with a single argument of each definition +@result{}# from the definition stack of MACRO, starting with the oldest, and +@result{}# separated by SEP between definitions. +@result{}define(`stack_foreach_sep', +@result{}`_stack_reverse_sep(`$1', `tmp-$1')'dnl +@result{}`_stack_reverse_sep(`tmp-$1', `$1', `$2`'defn(`$1')$3', `$4')') +@result{}# stack_foreach_sep_lifo(macro, pre, post, sep) +@result{}# Like stack_foreach_sep, but starting with the newest definition. +@result{}define(`stack_foreach_sep_lifo', +@result{}`_stack_reverse_sep(`$1', `tmp-$1', `$2`'defn(`$1')$3', `$4')'dnl +@result{}`_stack_reverse_sep(`tmp-$1', `$1')') +@result{}define(`_stack_reverse_sep', +@result{}`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0( +@result{} `$1', `$2', `$4`'$3')')') +@result{}divert`'dnl +@end example + @node Improved m4wrap @section Solution for @code{m4wrap} diff --git a/examples/stack.m4 b/examples/stack.m4 index ae3c48e7..c1b98333 100644 --- a/examples/stack.m4 +++ b/examples/stack.m4 @@ -1,11 +1,11 @@ divert(`-1') -# stack_foreach(action, macro) +# stack_foreach(macro, action) # Invoke ACTION with a single argument of each definition # from the definition stack of MACRO, starting with the oldest. define(`stack_foreach', `_stack_reverse(`$1', `tmp-$1')'dnl `_stack_reverse(`tmp-$1', `$1', `$2(defn(`$1'))')') -# stack_foreach_lifo(action, macro) +# stack_foreach_lifo(macro, action) # Invoke ACTION with a single argument of each definition # from the definition stack of MACRO, starting with the newest. define(`stack_foreach_lifo', diff --git a/examples/stack_sep.m4 b/examples/stack_sep.m4 new file mode 100644 index 00000000..b11bc839 --- /dev/null +++ b/examples/stack_sep.m4 @@ -0,0 +1,17 @@ +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 |