m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Changes to m4/doc/m4.texinfo,v


From: Eric Blake
Subject: Changes to m4/doc/m4.texinfo,v
Date: Tue, 05 Sep 2006 13:25:25 +0000

CVSROOT:        /sources/m4
Module name:    m4
Changes by:     Eric Blake <ericb>      06/09/05 13:25:24

Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- doc/m4.texinfo      31 Aug 2006 03:21:35 -0000      1.39
+++ doc/m4.texinfo      5 Sep 2006 13:25:24 -0000       1.40
@@ -124,7 +124,7 @@
 * File Inclusion::              File inclusion
 * Diversions::                  Diverting and undiverting output
 
-* Modules::                     Extending m4 with dynamic runtime modules
+* Modules::                     Extending M4 with dynamic runtime modules
 
 * Text handling::               Macros for text handling
 * Arithmetic::                  Macros for doing arithmetic
@@ -132,8 +132,7 @@
 * Miscellaneous::               Miscellaneous builtin macros
 * Frozen files::                Fast loading of frozen state
 
-* Compatibility::               Compatibility with other versions of m4
-* Experiments::                 Experimental features in GNU M4
+* Compatibility::               Compatibility with other versions of @code{m4}
 * Answers::                     Correct version of some examples
 * Copying This Manual::         How to make copies of this manual
 * Indices::                     Indices of concepts and macros
@@ -152,11 +151,11 @@
 Lexical and syntactic conventions
 
 * Names::                       Macro names
-* Quoted strings::              Quoting input to m4
-* Comments::                    Comments in m4 input
+* Quoted strings::              Quoting input to @code{m4}
+* Comments::                    Comments in @code{m4} input
 * Other tokens::                Other kinds of input tokens
-* Input processing::            How m4 copies input to output
-* Regular expression syntax::   How m4 interprets regular expressions
+* Input processing::            How @code{m4} copies input to output
+* Regular expression syntax::   How @code{m4} interprets regular expressions
 
 How to invoke macros
 
@@ -170,7 +169,7 @@
 
 * Define::                      Defining a new macro
 * Arguments::                   Arguments to macros
-* Pseudo Arguments::            Pseudo arguments to macros
+* Pseudo Arguments::            Special arguments to macros
 * Undefine::                    Deleting a macro
 * Defn::                        Renaming macros
 * Pushdef::                     Temporarily redefining macros
@@ -178,14 +177,15 @@
 
 * Indir::                       Indirect call of macros
 * Builtin::                     Indirect call of builtins
-
 * Symbols::                     Getting the defined macro names
 
 Conditionals, loops, and recursion
 
 * Ifdef::                       Testing if a macro is defined
 * Ifelse::                      If-else construct, or multibranch
-* Loops::                       Loops and recursion in m4
+* Shift::                       Recursion in @code{m4}
+* Forloop::                     Iteration by counting
+* Foreach::                     Iteration by list contents
 
 How to debug macros and input
 
@@ -201,7 +201,7 @@
 * Changecom::                   Changing the comment delimiters
 * Changeresyntax::              Changing the regular expression syntax
 * Changesyntax::                Changing the lexical structure of the input
-* M4wrap::                      Saving input until end of input
+* M4wrap::                      Saving text until end of input
 
 File inclusion
 
@@ -215,7 +215,7 @@
 * Divnum::                      Diversion numbers
 * Cleardiv::                    Discarding diverted text
 
-Extending m4 with dynamic runtime modules
+Extending M4 with dynamic runtime modules
 
 * Listing Modules::             Listing loaded modules
 * Load::                        Loading additional modules
@@ -238,19 +238,19 @@
 * Eval::                        Evaluating integer expressions
 * Mpeval::                      Multiple precision arithmetic
 
-Running shell commands
+Macros for running shell commands
 
 * Platform macros::             Determining the platform
 * Syscmd::                      Executing simple commands
 * Esyscmd::                     Reading the output of commands
 * Sysval::                      Exit status
-* Maketemp::                    Making names for temporary files
+* Maketemp::                    Making temporary files
 
 Miscellaneous builtin macros
 
 * Errprint::                    Printing error messages
 * Location::                    Printing current location
-* M4exit::                      Exiting from m4
+* M4exit::                      Exiting from @code{m4}
 * Syncoutput::                  Turning on and off sync lines
 
 Fast loading of frozen state
@@ -263,15 +263,16 @@
 
 * Extensions::                  Extensions in @acronym{GNU} M4
 * Incompatibilities::           Other incompatibilities
+* Experiments::                 Experimental features in @acronym{GNU} M4
 
-Copying This Manual
+How to make copies of this manual
 
 * GNU Free Documentation License::  License for copying this manual
 
-Indices
+Indices of concepts and macros
 
 * Concept index::               Index for many concepts
-* Macro index::                 Index for all m4 macros
+* Macro index::                 Index for all @code{m4} macros
 
 @end detailmenu
 @end menu
@@ -811,15 +812,15 @@
 
 @menu
 * Names::                       Macro names
-* Quoted strings::              Quoting input to m4
-* Comments::                    Comments in m4 input
+* Quoted strings::              Quoting input to @code{m4}
+* Comments::                    Comments in @code{m4} input
 * Other tokens::                Other kinds of input tokens
-* Input processing::            How m4 copies input to output
-* Regular expression syntax::   How m4 interprets regular expressions
+* Input processing::            How @code{m4} copies input to output
+* Regular expression syntax::   How @code{m4} interprets regular expressions
 @end menu
 
 @node Names
address@hidden Names
address@hidden Macro names
 
 @cindex names
 A name is any sequence of letters, digits, and the character @kbd{_}
@@ -835,7 +836,7 @@
 @xref{Changesyntax}, for more information.
 
 @node Quoted strings
address@hidden Quoted strings
address@hidden Quoting input to @code{m4}
 
 @cindex quoted string
 A quoted string is a sequence of characters surrounded by quote
@@ -864,7 +865,7 @@
 (@pxref{Changesyntax}).
 
 @node Comments
address@hidden Comments
address@hidden Comments in @code{m4} input
 
 @cindex comments
 Comments in @code{m4} are normally delimited by the characters @samp{#}
@@ -900,7 +901,7 @@
 @code{changesyntax} (@pxref{Changesyntax}).
 
 @node Other tokens
address@hidden Other tokens
address@hidden Other kinds of input tokens
 
 Any character, that is neither a part of a name, nor of a quoted string,
 nor a comment, is a token by itself.  When not in the context of macro
@@ -912,7 +913,7 @@
 can be adjusted with @code{changesyntax} (@pxref{Changesyntax}).
 
 @node Input processing
address@hidden Input Processing
address@hidden How @code{m4} copies input to output
 
 As @code{m4} reads the input token by token, it will copy each token
 directly to the output immediately.
@@ -968,7 +969,7 @@
 all the input has been consumed.
 
 @node Regular expression syntax
address@hidden Regular Expression Syntax
address@hidden How @code{m4} interprets regular expressions
 
 There are several contexts where @code{m4} parses an argument as a
 regular expression.  This section describes the various flavors of
@@ -1253,14 +1254,15 @@
 
 It is an error if the end of file occurs while collecting arguments.
 
address@hidden status: 1
 @example
 define(
 ^D
address@hidden:stdin:1: ERROR: end of file in argument list
address@hidden:stdin:1: end of file in argument list
 @end example
 
 @node Quoting Arguments
address@hidden Quoting macro arguments
address@hidden On Quoting Arguments to macros
 
 @cindex quoted macro arguments
 @cindex macros, quoted arguments to
@@ -1335,7 +1337,7 @@
 @menu
 * Define::                      Defining a new macro
 * Arguments::                   Arguments to macros
-* Pseudo Arguments::            Pseudo arguments to macros
+* Pseudo Arguments::            Special arguments to macros
 * Undefine::                    Deleting a macro
 * Defn::                        Renaming macros
 * Pushdef::                     Temporarily redefining macros
@@ -1343,7 +1345,6 @@
 
 * Indir::                       Indirect call of macros
 * Builtin::                     Indirect call of builtins
-
 * Symbols::                     Getting the defined macro names
 @end menu
 
@@ -1780,11 +1781,14 @@
 @end example
 
 Using @code{defn} to generate special tokens for builtin macros outside
-of expected contexts can sometimes trigger warnings.
+of expected contexts can sometimes trigger warnings.  But most of the
+time, such tokens are silently converted to the empty string.
 
 @example
+defn(`defn')
address@hidden
 define(defn(`divnum'), `cannot redefine a builtin token')
address@hidden:stdin:1: Warning: define: invalid macro name ignored
address@hidden:stdin:2: Warning: define: invalid macro name ignored
 @result{}
 divnum
 @result{}0
@@ -2003,6 +2007,25 @@
 defined, that will not be called by accident.  They can @emph{only} be
 called through the builtin @code{indir}.
 
+One other point to observe is that argument collection occurs before
address@hidden invokes @var{name}, so if argument collection changes the
+value of @var{name}, that will be reflected in the final expansion.
+This is different than the behavior when invoking macros directly,
+where the definition that was in effect before argument collection is
+used.
+
address@hidden
+define(`f', `1')
address@hidden
+f(define(`f', `2'))
address@hidden
+indir(`f', define(`f', `3'))
address@hidden
+indir(`f', undefine(`f'))
address@hidden:stdin:4: Warning: indir: undefined macro `f'
address@hidden
address@hidden example
+
 @node Builtin
 @section Indirect call of builtins
 
@@ -2124,11 +2147,13 @@
 @menu
 * Ifdef::                       Testing if a macro is defined
 * Ifelse::                      If-else construct, or multibranch
-* Loops::                       Loops and recursion in m4
+* Shift::                       Recursion in @code{m4}
+* Forloop::                     Iteration by counting
+* Foreach::                     Iteration by list contents
 @end menu
 
 @node Ifdef
address@hidden Testing macro definitions
address@hidden Testing if a macro is defined
 
 @cindex conditionals
 There are two different builtin conditionals in @code{m4}.  The first is
@@ -2156,7 +2181,7 @@
 @end example
 
 @node Ifelse
address@hidden Comparing strings
address@hidden If-else construct, or multibranch
 
 @cindex comparing strings
 The other conditional, @code{ifelse}, is much more powerful.  It can be
@@ -2164,13 +2189,30 @@
 as a multibranch, depending on the number of arguments supplied:
 
 @deffn {Builtin (m4)} ifelse (@var{comment})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2}, 
@var{equal}, @w{opt @var{not-equal})}
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2}, 
@var{equal}, @dots{})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2}, 
@var{equal}, @
+  @ovar{not-equal})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2}, 
@var{equal-1}, @
+  @var{string-3}, @var{string-4}, @var{equal-2}, @dots{})
 Used with only one argument, the @code{ifelse} simply discards it and
-produces no output.  This is a common @code{m4} idiom for introducing a
+produces no output.
+
+If called with three or four arguments, @code{ifelse} expands into
address@hidden, if @var{string-1} and @var{string-2} are equal (character
+for character), otherwise it expands to @var{not-equal}.  A final fifth
+argument is ignored, after triggering a warning.
+
+If called with six or more arguments, and @var{string-1} and
address@hidden are equal, @code{ifelse} expands into @var{equal-1},
+otherwise the first three arguments are discarded and the processing
+starts again.
+
+The macro @code{ifelse} is recognized only with parameters.
address@hidden deffn
+
+Using only one argument is a common @code{m4} idiom for introducing a
 block comment, as an alternative to repeatedly using @code{dnl}.  This
-special usage is recognized by GNU @code{m4}, so that in this case, the
-warning about missing arguments is never triggered.
+special usage is recognized by @acronym{GNU} @code{m4}, so that in this
+case, the warning about missing arguments is never triggered.
 
 @example
 ifelse(`some comments')
@@ -2180,43 +2222,64 @@
 @result{}
 @end example
 
-If called with three or four arguments, @code{ifelse} expands into
address@hidden, if @var{string-1} and @var{string-2} are equal (character
-for character), otherwise it expands to @var{not-equal}.
+Using three or four arguments provides decision points.
 
 @example
 ifelse(`foo', `bar', `true')
 @result{}
 ifelse(`foo', `foo', `true')
 @result{}true
-ifelse(`foo', `bar', `true', `false')
address@hidden
-ifelse(`foo', `foo', `true', `false')
+define(`foo', `bar')
address@hidden
+ifelse(foo, `bar', `true', `false')
 @result{}true
+ifelse(foo, `foo', `true', `false')
address@hidden
address@hidden example
+
+Notice how the first argument was used unquoted; it is common to compare
+the expansion of a macro with a string.  With this macro, you can now
+reproduce the behavior of many of the builtins, where the macro is
+recognized only with arguments.
+
address@hidden
+define(`foo', `ifelse(`$#', `0', ``$0'', `arguments:$#')')
address@hidden
+foo
address@hidden
+foo()
address@hidden:1
+foo(`a', `b', `c')
address@hidden:3
 @end example
 
 @cindex multibranches
 However, @code{ifelse} can take more than four arguments.  If given more
 than four arguments, @code{ifelse} works like a @code{case} or @code{switch}
 statement in traditional programming languages.  If @var{string-1} and
address@hidden are equal, @code{ifelse} expands into @var{equal}, otherwise
address@hidden are equal, @code{ifelse} expands into @var{equal-1}, otherwise
 the procedure is repeated with the first three arguments discarded.  This
 calls for an example:
 
 @example
+ifelse(`foo', `bar', `third', `gnu', `gnats')
address@hidden:stdin:1: Warning: ifelse: extra arguments ignored: 5 > 4
address@hidden
+ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth')
address@hidden
 ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth', `seventh')
 @result{}seventh
+ifelse(`foo', `bar', `3', `gnu', `gnats', `6', `7', `8')
address@hidden:stdin:4: Warning: ifelse: extra arguments ignored: 8 > 7
address@hidden
 @end example
 
-The macro @code{ifelse} is recognized only with parameters.
address@hidden deffn
-
 Naturally, the normal case will be slightly more advanced than these
 examples.  A common use of @code{ifelse} is in macros implementing loops
 of various kinds.
 
address@hidden Loops
address@hidden Loops and recursion
address@hidden Shift
address@hidden Recursion in @code{m4}
 
 @cindex recursive macros
 @cindex macros, recursive
@@ -2231,9 +2294,12 @@
 There is a builtin macro, @code{shift}, which can, among other things,
 be used for iterating through the actual arguments to a macro:
 
address@hidden {Builtin (m4)} shift (@dots{})
address@hidden takes any number of arguments, and expands to all but the first
-argument, separated by commas, with each argument quoted.
address@hidden {Builtin (m4)} shift (@var{arg1}, @dots{})
+Takes any number of arguments, and expands to all its arguments except
address@hidden, separated by commas, with each argument quoted.
+
+The macro @code{shift} is recognized only with parameters.
address@hidden deffn
 
 @example
 shift
@@ -2243,10 +2309,14 @@
 shift(`foo', `bar', `baz')
 @result{}bar,baz
 @end example
+
+An example of the use of @code{shift} is this macro:
+
address@hidden Composite reverse (@dots{})
+Takes any number of arguments, and reverse their order.
 @end deffn
 
-An example of the use of @code{shift} is this macro, which reverses the
-order of its arguments:
+It is implemented as:
 
 @example
 define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'',
@@ -2261,14 +2331,66 @@
 @end example
 
 While not a very interesting macro, it does show how simple loops can be
-made with @code{shift}, @code{ifelse} and recursion.
+made with @code{shift}, @code{ifelse} and recursion.  It also shows
+that @code{shift} is usually used with @samp{$@@}.  Sometimes, a
+recursive algorithm requires adding quotes to each element:
+
address@hidden Composite quote (@dots{})
address@hidden Composite dquote (@dots{})
address@hidden Composite dquote_elt (@dots{})
+Takes any number of arguments, and quoting.  With @code{quote}, only one
+level of quoting is added, effectively removing whitespace after commas
+and turning the arguments into a string.  With @code{dquote}, two
+levels of quoting are added, one around each element, and one around
+the list.  And with @code{dquote_elt}, two levels of quoting are added
+around each element.
address@hidden deffn
+
+Here is an implementation, along with an example usage.
+
address@hidden FIXME - these macros are worth reusing in other examples;
address@hidden factor them into examples/quote.m4.
address@hidden
+define(`quote', `ifelse(`$#', `0', `', ``$*'')')dnl
+define(`dquote', ``$@@'')dnl
+define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''',
+                             ```$1'',dquote_elt(shift($@@))')')dnl
+-quote-dquote-dquote_elt-
address@hidden
+-quote(`1')-dquote(`1')-dquote_elt(`1')-
address@hidden'-`1'-
+-quote(`1',`2')-dquote(`1',`2')-dquote_elt(`1',`2')-
address@hidden,2-`1',`2'-`1',`2'-
+dquote(dquote_elt(`1',`2'))
address@hidden'',``2''
+dquote_elt(dquote(`1',`2'))
address@hidden',`2''
address@hidden example
+
+The last two lines show that when given two arguments, @code{dquote}
+results in one string, while @code{dquote_elt} results in two.
+
address@hidden Forloop
address@hidden Iteration by counting
 
address@hidden forloops
address@hidden for loops
 @cindex loops, counting
 @cindex counting loops
-Here is an example of a loop macro that implements a simple forloop.  It
-can, for example, be used for simple counting:
+Here is an example of a loop macro that implements a simple for loop.
address@hidden FIXME - this section still needs some work done
+
address@hidden Composite forloop (@var{iterator}, @var{start}, @var{end}, 
@var{text})
+Takes the name in @var{iterator}, which must be a valid macro name, and
+successively assign it each integer value from @var{start} to @var{end},
+inclusive.  For each assignment to @var{iterator}, append @var{text} to
+the expansion of the @code{forloop}.  @var{text} may refer to
address@hidden  Any definition of @var{iterator} prior to this
+invocation is restored.
address@hidden deffn
 
+It can, for example, be used for simple counting:
+
address@hidden FIXME - include(`forloop.m4')
 @comment ignore
 @example
 forloop(`i', 1, 8, `i ')
@@ -2325,12 +2447,69 @@
 like start value less than final value, and the first argument not being
 a name.  Correcting these errors are left as an exercise to the reader.
 
address@hidden FIXME - it would be nice to introduce foreach here, and even
address@hidden give an example like this for finding defined macros that meet
address@hidden a certain pattern (see examples/foreach.m4):
address@hidden define(`quote', ``$@'')
address@hidden foreach(`macro', (quote(symbols)),
address@hidden         `regexp(macro, `.*_.*', ``\&',')')
address@hidden Foreach
address@hidden Iteration by list contents
+
address@hidden for each loops
address@hidden loops, list iteration
address@hidden iterating over lists
+Here is an example of a loop macro that implements list iteration.
address@hidden FIXME - this section still needs some work done
+
address@hidden Composite foreach (@var{iterator}, @var{paren-list}, @var{text})
+Takes the name in @var{iterator}, which must be a valid macro name, and
+successively assign it each value from @var{paren-list}.
address@hidden is a comma-separated list of elements surrounded by
+parentheses.  For each assignment to @var{iterator}, append @var{text}
+to the expansion of @code{foreach}.  @var{text} may refer to
address@hidden  Any definition of @var{iterator} prior to this
+invocation is restored.
address@hidden deffn
+
+As an example, this displays each word in a list inside of a sentence.
+
address@hidden FIXME - include(`foreach.m4')
address@hidden ignore
address@hidden
+foreach(`x', `(foo, bar, foobar)', `Word was: x
+')
address@hidden was: foo
address@hidden was: bar
address@hidden was: foobar
address@hidden example
+
+The implementation of the @code{foreach} macro is a bit more involved;
+it is a wrapper around two helper macros.  First, @code{_arg1} is needed
+to grab the first element of a list.  Second, @code{_foreach} implements
+the recursion, successively walking through the original list.
+
+Here is an actual implementation of @code{forloop}, followed by a
+demonstration of using it to filter out a list of symbols that contain
address@hidden
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`_foreach',
+       `ifelse($2, `()', ,
+               `define(`$1',
+                       `_arg1$2')$3`'_foreach(`$1', `(shift$2)',
+                                              `$3')')')dnl
+define(`dquote', ``$@@'')
address@hidden
+foreach(`macro', (dquote(symbols)), `regexp(macro, `.*if.*', ``\&',')')
address@hidden,ifelse,shift,
address@hidden example
+
+The example had to use a helper @code{quote} to ensure that the output
+from @code{symbols} was double quoted; without it, the macro would have
+gone into an infinite loop thanks to macros being reinvoked during the
+rescanning.  Choosing @samp{()} as the list delimiters made this
+example rather awkward in terms of proper quoting.  (A different
+implementation can be acheived by changing @var{list} from a
+parenthesized list to a quoted list; try reimplementing @code{foreach}
+with these semantics yourself, then check @pxref{Answers}).
 
 @node Debugging
 @chapter How to debug macros and input
@@ -2534,7 +2713,7 @@
 * Changecom::                   Changing the comment delimiters
 * Changeresyntax::              Changing the regular expression syntax
 * Changesyntax::                Changing the lexical structure of the input
-* M4wrap::                      Saving input until end of input
+* M4wrap::                      Saving text until end of input
 @end menu
 
 @node Dnl
@@ -2630,7 +2809,7 @@
 the quoting mechanism.
 
 @node Changecom
address@hidden Changing comment delimiters
address@hidden Changing the comment delimiters
 
 @cindex changing comment delimiters
 @cindex comment delimiters, changing
@@ -3101,7 +3280,7 @@
 
 
 @node M4wrap
address@hidden Saving input
address@hidden Saving text until end of input
 
 @cindex saving input
 @cindex input, saving
@@ -3473,7 +3652,7 @@
 should try to see if you can find it and correct it.   @xref{Answers}.)
 
 @node Modules
address@hidden Runtime Dynamic Modules
address@hidden Extending M4 with dynamic runtime modules
 
 @cindex modules
 @sc{gnu} m4-1.4.x had a monolithic architecture.  All of its
@@ -3979,7 +4158,7 @@
 
 
 @node Format
address@hidden Formatted output
address@hidden Formatting strings (printf-like)
 
 @cindex formatted output
 @cindex output, formatted
@@ -4006,7 +4185,7 @@
 @result{}5000
 @end example
 
-Using the @code{forloop} macro defined in @xref{Loops}, this
+Using the @code{forloop} macro defined in @xref{Forloop}, this
 example shows how @code{format} can be used to produce tabular output.
 
 @comment ignore
@@ -4074,7 +4253,7 @@
 @end deffn
 
 @node Eval
address@hidden Evaluating integer or rational expressions
address@hidden Evaluating integer expressions
 
 @cindex integer expression evaluation
 @cindex evaluation, of integer expressions
@@ -4213,7 +4392,7 @@
 @end deffn
 
 @node Shell commands
address@hidden Running shell commands
address@hidden Macros for running shell commands
 
 @cindex executing shell commands
 @cindex running shell commands
@@ -4227,8 +4406,8 @@
 * Platform macros::             Determining the platform
 * Syscmd::                      Executing simple commands
 * Esyscmd::                     Reading the output of commands
-* Sysval::                      Exit codes
-* Maketemp::                    Making names for temporary files
+* Sysval::                      Exit status
+* Maketemp::                    Making temporary files
 @end menu
 
 @node Platform macros
@@ -4299,7 +4478,7 @@
 @end deffn
 
 @node Sysval
address@hidden Exit codes
address@hidden Exit status
 
 @cindex exit code from shell commands
 @cindex shell commands, exit code from
@@ -4323,7 +4502,7 @@
 @end example
 
 @node Maketemp
address@hidden Making names for temporary files
address@hidden Making temporary files
 
 @cindex temporary file names
 @cindex files, names of temporary
@@ -4357,7 +4536,7 @@
 @menu
 * Errprint::                    Printing error messages
 * Location::                    Printing current location
-* M4exit::                      Exiting from m4
+* M4exit::                      Exiting from @code{m4}
 * Syncoutput::                  Turning on and off sync lines
 @end menu
 
@@ -4433,7 +4612,7 @@
 (@pxref{M4wrap}) is not reread.
 
 @node Syncoutput
address@hidden Turning sync lines on and off within @code{m4}
address@hidden Turning on and off sync lines
 
 @cindex Toggling sync lines within @code{m4}
 @deffn {Builtin (gnu)} syncoutput (@var{truth})
@@ -4661,12 +4840,13 @@
 is made to summarize these here.
 
 @menu
-* Extensions::                  Extensions in GNU m4
+* Extensions::                  Extensions in @acronym{GNU} M4
 * Incompatibilities::           Other incompatibilities
+* Experiments::                 Experimental features in @acronym{GNU} M4
 @end menu
 
 @node Extensions
address@hidden Extensions in GNU @code{m4}
address@hidden Extensions in @acronym{GNU} M4
 
 @cindex GNU extensions
 @cindex @acronym{POSIX}
@@ -4835,7 +5015,7 @@
 
 
 @node  Experiments
address@hidden Experimental features in GNU M4
address@hidden Experimental features in @acronym{GNU} M4
 
 Certain features of GNU @code{m4} are experimental.
 
@@ -4877,6 +5057,82 @@
 Some of the examples in this manuals are buggy.  Correctly working
 macros are presented here.
 
+The @code{foreach} macro (@pxref{Foreach}) as presented required the
+user to use parentheses to delineate the list.  This approach is
+quadratic, because the entire list is propagated through each recursion,
+with additional invocations of the shift macro added on each iteration:
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden options: -d-V
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`_foreach',
+       `ifelse($2, `()', ,
+               `define(`$1',
+                       `_arg1$2')$3`'_foreach(`$1', `(shift$2)',
+                                              `$3')')')dnl
+define(`dquote', ``$@'')
address@hidden
+foreach(`macro', (dquote(symbols)), `regexp(macro, `shift', `\&')')
address@hidden
+traceon(`shift')
address@hidden
+foreach(`a', `(1,2,3)', `a
+')
address@hidden
address@hidden: -2- shift
address@hidden: -2- shift
address@hidden
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden
address@hidden: -4- shift
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden
address@hidden example
+
+An alternative implementation takes a quoted list, with semantics that
+the list is expanded once before iteration, and has the benefit that
+each iteration operates on a shorter list, giving linear performance on
+long lists.  Another way of viewing these semantics is that the
+outermost quotes delineates the list, then each element of the list must
+be quoted as though the list delimiters were not present.  Notice the
+difference when iterating over @code{symbols}; we must use
address@hidden instead of @code{dquote} to get the necessary quoting.
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden options: -d-V
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`quote', `ifelse(`$#', `0', `', ``$*'')')dnl
+define(`dquote', ``$@@'')dnl
+define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''',
+                             ```$1'',dquote_elt(shift($@@))')')dnl
+define(`_rest', `ifelse(`$#', `1', , `dquote(shift($@@))')')dnl
+define(`_foreach',
+       `ifelse(quote($2), , ,
+               `define(`$1',
+                       `_arg1($2)')$3`'_foreach(`$1', _rest($2),
+                                                `$3')')')dnl
+foreach(`macro', `dquote_elt(symbols)', `regexp(macro, `shift', `\&')')
address@hidden
+traceon(`shift')
address@hidden
+foreach(`a', ``1',`2',`3'', `a
+')
address@hidden
address@hidden: -3- shift
address@hidden
address@hidden: -3- shift
address@hidden
address@hidden
address@hidden example
+
 The @code{cleardivert} macro (@pxref{Cleardiv}) cannot, as it stands, be
 called without arguments to clear all pending diversions.  A macro that
 achieves that as well is:
@@ -4895,7 +5151,7 @@
 @c ========================================================== Appendices
 
 @node Copying This Manual
address@hidden Copying This Manual
address@hidden How to make copies of this manual
 @cindex License
 
 @menu
@@ -4905,20 +5161,20 @@
 @include fdl.texi
 
 @node Indices
address@hidden Indices
address@hidden Indices of concepts and macros
 
 @menu
 * Concept index::               Index for many concepts
-* Macro index::                 Index for all m4 macros
+* Macro index::                 Index for all @code{m4} macros
 @end menu
 
 @node Concept index
address@hidden Concept index
address@hidden Index for many concepts
 
 @printindex cp
 
 @node Macro index
address@hidden Macro index
address@hidden Index for all @code{m4} macros
 
 References are exclusively to the places where a builtin is introduced
 the first time.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]