summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2008-12-18 11:02:39 -0700
committerEric Blake <ebb9@byu.net>2008-12-18 11:03:59 -0700
commitdac0f533e2fdd06e0ff5948b6f03042fea3d9402 (patch)
treea151f75e46c999c45e6edf011d5f5927f789009c
parent64df649442038cace6b063fa5bd36c7007193dcc (diff)
downloadm4-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--ChangeLog10
-rw-r--r--Makefile.am1
-rw-r--r--doc/m4.texinfo113
-rw-r--r--examples/stack.m44
-rw-r--r--examples/stack_sep.m417
5 files changed, 140 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index a73ba6e4..917c239e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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