m4: Defn

1 
1 5.5 Renaming macros
1 ===================
1 
1 It is possible to rename an already defined macro.  To do this, you need
1 the builtin 'defn':
1 
1  -- Builtin: defn (NAME...)
1      Expands to the _quoted definition_ of each NAME.  If an argument is
1      not a defined macro, the expansion for that argument is empty.
1 
1      If NAME is a user-defined macro, the quoted definition is simply
1      the quoted expansion text.  If, instead, there is only one NAME and
1      it is a builtin, the expansion is a special token, which points to
1      the builtin's internal definition.  This token is only meaningful
1      as the second argument to 'define' (and 'pushdef'), and is silently
1      converted to an empty string in most other contexts.  Combining a
1      builtin with anything else is not supported; a warning is issued
1      and the builtin is omitted from the final expansion.
1 
1      The macro 'defn' is recognized only with parameters.
1 
1    Its normal use is best understood through an example, which shows how
1 to rename 'undefine' to 'zap':
1 
1      define(`zap', defn(`undefine'))
1      =>
1      zap(`undefine')
1      =>
1      undefine(`zap')
1      =>undefine(zap)
1 
1    In this way, 'defn' can be used to copy macro definitions, and also
1 definitions of builtin macros.  Even if the original macro is removed,
1 the other name can still be used to access the definition.
1 
1    The fact that macro definitions can be transferred also explains why
1 you should use '$0', rather than retyping a macro's name in its
1 definition:
1 
1      define(`foo', `This is `$0'')
1      =>
1      define(`bar', defn(`foo'))
1      =>
1      bar
1      =>This is bar
1 
1    Macros used as string variables should be referred through 'defn', to
1 avoid unwanted expansion of the text:
1 
1      define(`string', `The macro dnl is very useful
1      ')
1      =>
1      string
1      =>The macro 
1      defn(`string')
1      =>The macro dnl is very useful
1      =>
1 
1    However, it is important to remember that 'm4' rescanning is purely
1 textual.  If an unbalanced end-quote string occurs in a macro
1 definition, the rescan will see that embedded quote as the termination
1 of the quoted string, and the remainder of the macro's definition will
1 be rescanned unquoted.  Thus it is a good idea to avoid unbalanced
1 end-quotes in macro definitions or arguments to macros.
1 
1      define(`foo', a'a)
1      =>
1      define(`a', `A')
1      =>
1      define(`echo', `$@')
1      =>
1      foo
1      =>A'A
1      defn(`foo')
1      =>aA'
1      echo(foo)
1      =>AA'
1 
1    On the other hand, it is possible to exploit the fact that 'defn' can
1 concatenate multiple macros prior to the rescanning phase, in order to
1 join the definitions of macros that, in isolation, have unbalanced
1 quotes.  This is particularly useful when one has used several macros to
1 accumulate text that M4 should rescan as a whole.  In the example below,
1 note how the use of 'defn' on 'l' in isolation opens a string, which is
1 not closed until the next line; but used on 'l' and 'r' together results
1 in nested quoting.
1 
1      define(`l', `<[>')define(`r', `<]>')
1      =>
1      changequote(`[', `]')
1      =>
1      defn([l])defn([r])
1      ])
1      =><[>]defn([r])
1      =>)
1      defn([l], [r])
1      =><[>][<]>
1 
1    Using 'defn' to generate special tokens for builtin macros outside of
1 expected contexts can sometimes trigger warnings.  But most of the time,
1 such tokens are silently converted to the empty string.
1 
1      $ m4 -d
1      defn(`defn')
1      =>
1      define(defn(`divnum'), `cannot redefine a builtin token')
1      error->m4:stdin:2: Warning: define: invalid macro name ignored
1      =>
1      divnum
1      =>0
1      len(defn(`divnum'))
1      =>0
1 
1    Also note that 'defn' with multiple arguments can only join text
1 macros, not builtins, although a future version of GNU M4 may lift this
1 restriction.
1 
1      $ m4 -d
1      define(`a', `A')define(`AA', `b')
1      =>
1      traceon(`defn', `define')
1      =>
1      defn(`a', `divnum', `a')
1      error->m4:stdin:3: Warning: cannot concatenate builtin `divnum'
1      error->m4trace: -1- defn(`a', `divnum', `a') -> ``A'`A''
1      =>AA
1      define(`mydivnum', defn(`divnum', `divnum'))mydivnum
1      error->m4:stdin:4: Warning: cannot concatenate builtin `divnum'
1      error->m4:stdin:4: Warning: cannot concatenate builtin `divnum'
1      error->m4trace: -2- defn(`divnum', `divnum')
1      error->m4trace: -1- define(`mydivnum', `')
1      =>
1      traceoff(`defn', `define')
1      =>
1