m4-patches
[Top][All Lists]
Advanced

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

Re: more doc merges


From: Eric Blake
Subject: Re: more doc merges
Date: Wed, 30 Aug 2006 13:33:31 +0000

> A few more nodes merged (or enhanced), and a pass at some of the
> matching macros in modules/m4.c to comply with the branch
> behavior.

Next round.  I also found a core dump that will need fixing eventually,
which was not inherited from the branch:

$ tests/m4
define(bar,1)define(baz,2)renamesyms(^ba.,baa)dumpdef(`bar',`baz',`baa')
^D
tests/m4: line 28:  2340 Segmentation fault      (core dumped) 
"/home/eblake/m4-head/src/m4" --module-directory="/home/eblake/m4-head/modules" 
${1+"$@"} 2>/tmp/m4-$$
m4:stdin:3: Warning: dumpdef: undefined macro: bar
m4:stdin:3: Warning: dumpdef: undefined macro: baz
baa:    2

Perhaps it would be nice if we made renamesyms refuse to rename any
macro if another macro by that name already exists.  But that also begs
the question of whether:
define(a,1)define(aa,2)renamesyms(`^a+$',`\&a') would process aa first
and result in aa=>1 and aaa=>2, or process a first, detect the collision of
a to aa, and result in a=>1 and aaa=>2.

2006-08-30  Eric Blake  <address@hidden>

        * doc/m4.texinfo (Undefine, Defn, Pushdef): More doc merges from
        the branch.
        (Defn): Add failing test case for mixing text and builtin.
        (Renamesyms): Improve wording, and identify core dump that needs
        fixing.
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.37
diff -u -p -r1.37 m4.texinfo
--- doc/m4.texinfo      30 Aug 2006 04:25:42 -0000      1.37
+++ doc/m4.texinfo      30 Aug 2006 13:25:49 -0000
@@ -1440,7 +1440,7 @@ Macros can have arguments.  The @var{n}t
 @code{$n} in the expansion text, and is replaced by the @var{n}th actual
 argument, when the macro is expanded.  Replacement of arguments happens
 before rescanning, regardless of how many nesting levels of quoting
-appear in the expansion.  Here is a example of a macro with
+appear in the expansion.  Here is an example of a macro with
 two arguments.  It simply exchanges the order of the two arguments.
 
 @example
@@ -1642,27 +1642,43 @@ foo(`arg')
 @cindex macros, how to delete
 @cindex deleting macros
 @cindex undefining macros
address@hidden {Builtin (m4)} undefine (@var{name})
-A macro definition can be removed with @code{undefine}, which removes
-the macro @var{name}.  The macro name must necessarily be quoted, since
-it will be expanded otherwise.
+A macro definition can be removed with @code{undefine}:
 
-The expansion of @code{undefine} is void.
address@hidden {Builtin (m4)} undefine (@address@hidden)
+For each argument, remove the macro @var{name}.  The macro names must
+necessarily be quoted, since they will be expanded otherwise.
 
+The expansion of @code{undefine} is void.
 The macro @code{undefine} is recognized only with parameters.
 @end deffn
 
 @example
-foo
address@hidden
-define(`foo', `expansion text')
+foo bar blah
address@hidden bar blah
+define(`foo', `some')define(`bar', `other')define(`blah', `text')
 @result{}
-foo
address@hidden text
+foo bar blah
address@hidden other text
 undefine(`foo')
 @result{}
-foo
address@hidden
+foo bar blah
address@hidden other text
+undefine(`bar', `blah')
address@hidden
+foo bar blah
address@hidden bar blah
address@hidden example
+
+Undefining a macro inside that macro's expansion is safe; the macro
+still expands to the definition that was in effect at the @samp{(}.
+
address@hidden
+define(`f', ``$0':$1')
address@hidden
+f(f(f(undefine(`f')`hello world')))
address@hidden:f:f:hello world
+f(`bye')
address@hidden(bye)
 @end example
 
 It is not an error for @var{name} to have no macro definition.  In that
@@ -1673,21 +1689,27 @@ case, @code{undefine} does nothing.
 
 @cindex macros, how to rename
 @cindex renaming macros
address@hidden {Builtin (m4)} defn (@var{name})
 It is possible to rename an already defined macro.  To do this, you need
-the builtin @code{defn}, which expands to the @emph{quoted definition}
-of @var{name}.  If the argument is not a defined macro, the expansion is
-void.
-
-If @var{name} is a builtin, the expansion is a special token, which
-points to the builtin's internal definition.  This token is only
-meaningful as the second argument to @code{define} (and @code{pushdef}),
-and is ignored in any other context.
-
address@hidden can be given any number of arguments; it expands to the
-concatenation of the quoted definitions of each argument.  The
-usefulness of this behavior is unclear, but @acronym{POSIX} requires
-it.
+the builtin @code{defn}:
+
address@hidden {Builtin (m4)} defn (@address@hidden)
+Expands to the @emph{quoted definition} of each @var{name}.  If an
+argument is not a defined macro, the expansion for that argument is
+empty and triggers a warning.
+
+If @var{name} is a user-defined macro, the quoted definition is simply
+the quoted expansion text.  If, instead, @var{name} is a builtin, the
+expansion is a special token, which points to the builtin's internal
+definition.  This token is only meaningful as the second argument to
address@hidden (and @code{pushdef}), and is silently converted to an
+empty string in most other contexts.
address@hidden FIXME - Other implementations, such as Solaris, can pass a
address@hidden builtin token around to other macros, flattening it only on 
output:
address@hidden  define(foo, a`'defn(`divnum')b)
address@hidden  len(foo) => 3
address@hidden  index(foo, defn(`divnum') => 1
address@hidden  foo => ab
address@hidden It may be worth making some changes to support this behavior.
 
 The macro @code{defn} is recognized only with parameters.
 @end deffn
@@ -1704,13 +1726,22 @@ undefine(`zap')
 @result{}undefine(zap)
 @end example
 
-In this way, @code{defn} can be used to copy definitions of builtin
-macros.  Even if the original macro is removed, the other name can still
-be used to access the definition.
-
-If, instead, @var{name} is a user-defined macro, the expansion is simply
-the quoted text of the macro, and @code{defn} can therefore be used to
-copy user macro definitions as well.
+In this way, @code{defn} can be used to copy macro definitions, and also
+definitions of builtin macros.  Even if the original macro is removed,
+the other name can still be used to access the definition.
+
+The fact that macro definitions can be transferred also explains why you
+should use @code{$0}, rather than retyping a macro's name in its
+definition:
+
address@hidden
+define(`foo', `This is `$0'')
address@hidden
+define(`bar', defn(`foo'))
address@hidden
+bar
address@hidden is bar
address@hidden example
 
 Macros used as string variables should be referred through @code{defn},
 to avoid unwanted expansion of the text:
@@ -1726,6 +1757,60 @@ defn(`string')
 @result{}
 @end example
 
+However, it is important to remember that @code{m4} rescanning is purely
+textual.  If an unbalanced end-quote string occurs in a macro
+definition, the rescan will see that embedded quote as the termination
+of the quoted string, and the remainder of the macro's definition will
+be rescanned unquoted.  Thus it is a good idea to avoid unbalanced
+end-quotes in macro definitions or arguments to macros.
+
address@hidden
+define(`foo', a'a)
address@hidden
+define(`a', `A')
address@hidden
+define(`echo', `$@')
address@hidden
+foo
address@hidden'A
+defn(`foo')
address@hidden'
+echo(foo)
address@hidden'
address@hidden example
+
+Using @code{defn} to generate special tokens for builtin macros outside
+of expected contexts can sometimes trigger warnings.
+
address@hidden
+define(defn(`divnum'), `cannot redefine a builtin token')
address@hidden:input.m4:1: Warning: define: invalid macro name ignored
address@hidden
+divnum
address@hidden
address@hidden example
+
+Since @code{defn} can take more than one argument, it can be used to
+concatenate multiple macros into one.
address@hidden FIXME - we don't yet handle mixing text and builtins.  This
address@hidden example passes under Solaris (minus the warning).
+
address@hidden
+defn(`foo')
address@hidden:input.m4:1: Warning: defn: undefined macro: foo
address@hidden
+define(`foo', `a')
address@hidden
+define(`bar', defn(`foo', `divnum'))
address@hidden
+define(`blah', defn(`divnum', `foo'))
address@hidden
+bar
address@hidden
+blah
address@hidden
address@hidden example
+
 @node Pushdef
 @section Temporarily redefining macros
 
@@ -1733,12 +1818,11 @@ defn(`string')
 @cindex temporary redefinition of macros
 @cindex redefinition of macros, temporary
 It is possible to redefine a macro temporarily, reverting to the
-previous definition at a later time.
-
-This is done with the builtins @code{pushdef} and @code{popdef}:
+previous definition at a later time.  This is done with the builtins
address@hidden and @code{popdef}:
 
address@hidden {Builtin (m4)} pushdef (@var{name}, @w{opt @var{expansion})}
address@hidden {Builtin (m4)} popdef @w{(@var{name})}
address@hidden {Builtin (m4)} pushdef (@var{name}, @ovar{expansion})
address@hidden {Builtin (m4)} popdef (@address@hidden)
 Analogous to @code{define} and @code{undefine}.
 
 These macros work in a stack-like fashion.  A macro is temporarily
@@ -1747,16 +1831,15 @@ redefined with @code{pushdef}, which rep
 installed.  If there is no previous definition, @code{pushdef} behaves
 exactly like @code{define}.
 
-The expansion of both @code{pushdef} and @code{popdef} is void.
+If a macro has several definitions (of which only one is accessible),
+the topmost definition can be removed with @code{popdef}.  If there is
+no previous definition, @code{popdef} behaves like @code{undefine}.
 
+The expansion of both @code{pushdef} and @code{popdef} is void.
 The macros @code{pushdef} and @code{popdef} are recognized only with
 parameters.
 @end deffn
 
-If a macro has several definitions (of which only one is accessible),
-the topmost definition can be removed with @code{popdef}.  If there is
-no previous definition, @code{popdef} behaves like @code{undefine}.
-
 @example
 define(`foo', `Expansion one.')
 @result{}
@@ -1766,10 +1849,19 @@ pushdef(`foo', `Expansion two.')
 @result{}
 foo
 @result{}Expansion two.
+pushdef(`foo', `Expansion three.')
address@hidden
+pushdef(`foo', `Expansion four.')
address@hidden
 popdef(`foo')
 @result{}
 foo
 @result{}Expansion one.
address@hidden three.
+popdef(`foo', `foo')
address@hidden
+foo
address@hidden one.
 popdef(`foo')
 @result{}
 foo
@@ -1816,11 +1908,19 @@ and @code{defn}.
 @cindex regular expressions
 @cindex macros, how to rename
 @cindex renaming macros
address@hidden GNU extensions
address@hidden {Builtin (gnu)} renamesyms (@var{regexp}, @var{replacement}, 
@w{opt @var{resyntax})}
address@hidden @acronym{GNU} extensions
+Sometimes it is desirable to rename multiple symbols without having to
+use a long sequence of calls to @code{define}.  The @code{renamesyms}
+builtin allows this:
+
address@hidden {Builtin (gnu)} renamesyms (@var{regexp}, @var{replacement}, @
+  @ovar{resyntax})
 Global renaming of macros is done by @code{renamesyms}, which selects
 all macros with names that match @var{regexp}, and renames each match
-according to @var{replacement}.
+according to @var{replacement}.  It is unspecified what happens if the
+rename causes multiple macros to map to the same name.
address@hidden FIXME - right now, collisions cause a core dump on some 
platforms:
address@hidden define(bar,1)define(baz,2)renamesyms(^ba., baa)dumpdef(`baa')
 
 If @var{resyntax} is given, the particular flavor of regular
 expression understood with respect to @var{regexp} can be changed from
@@ -1842,14 +1942,15 @@ the text matched by the @var{n}th parent
 @var{regexp}, and @samp{\&} being the text matched by the entire
 regular expression.
 
-The builtin macro @code{renamesyms} is recognized only when given
-arguments.
+The expansion of @code{renamesyms} is void.
+The macro @code{renamesyms} is recognized only with parameters.
 @end deffn
 
 Here is an example that performs the same renaming as the
address@hidden option.  Where @option{--prefix-builtins}
-only renames M4 builtin macros, @code{renamesyms} will rename any
-macros that match when it runs, including text macros.
address@hidden option (or @option{-P}).  Where
address@hidden only renames M4 builtin macros,
address@hidden will rename any macros that match when it runs,
+including text macros.
 
 @example
 renamesyms(`^.*$', `m4_\&')
@@ -1859,10 +1960,9 @@ renamesyms(`^.*$', `m4_\&')
 If @var{resyntax} is given, @var{regexp} must be given according to
 the syntax chosen, though the default regular expression syntax
 remains unchanged for other invocations.  Here is a more realistic
-example that performs a similar renaming on macros with lowercase
-names, except that it ignores macros with names that begin with
address@hidden, and avoids creating macros with names that begin with
address@hidden
+example that performs a similar renaming on macros, except that it
+ignores macros with names that begin with @samp{_}, and avoids creating
+macros with names that begin with @samp{m4_m4}.
 
 @example
 renamesyms(`^[^_]\w*$', `m4_\&')
@@ -1871,7 +1971,6 @@ m4_renamesyms(`^m4_m4(\w*)$', `m4_\1', `
 @result{}
 @end example
 
-
 @node Indir
 @section Indirect call of macros
 

reply via email to

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