Eric Blake <ebb9 <at> byu.net> writes: > > > Here's a proposal for enhancing the 'builtin' macro to make it possible to > recover a builtin macro, even if all references to it have been undefined. > Hopefully, the proposed documentation in the patch will give some more > details on how this could be useful. Any objections to installing this?
I interpreted silence as consent, and installed this: 2006-10-27 Eric Blake <[EMAIL PROTECTED]> * m4/macro.c (expand_argument): Fix missing initialization. * m4/m4private.h (struct m4_symbol_value): Store entire m4_builtin, not just the func. (m4_get_symbol_value_func): Update. (m4_get_symbol_value_builtin, m4_set_symbol_value_builtin): New fast accessors. * m4/m4module.h (m4_get_symbol_value_builtin) (m4_get_symbol_builtin): New prototypes. (m4_set_symbol_value_func): Delete, replace with... (m4_set_symbol_value_builtin): New function. (m4_builtin_find_by_name): Change signature. * m4/symtab.c (m4_symbol_value_print): Simplify. (m4_get_symbol_value_func): Update. (m4_get_symbol_value_builtin): New function. (m4_set_symbol_value_func): Delete, replace with... (m4_set_symbol_value_builtin): New function. (dump_symbol_CB) [DEBUG_SYM]: Simplify. * m4/builtin.c (m4_builtin_find_by_name): Change signature. * m4/input.c (struct m4_input_block): Remove unused trace member. (m4_push_builtin, builtin_print, init_builtin_token): Update callers. * m4/module.c (install_builtin_table): Likewise. * src/freeze.c (reload_frozen_state): Likewise. * modules/gnu.c (builtin): Make it possible to retrieve a builtin token, even after the builtin has been undefined. * doc/m4.texinfo (Builtin): Document new capability. * NEWS: Likewise. Index: NEWS =================================================================== RCS file: /sources/m4/m4/NEWS,v retrieving revision 1.30 diff -u -r1.30 NEWS --- NEWS 26 Oct 2006 23:19:12 -0000 1.30 +++ NEWS 27 Oct 2006 16:57:18 -0000 @@ -35,6 +35,13 @@ - FIXME: This feature can cause core dumps when renaming multiple symbols to the same name. +* The `builtin' macro now has a special form, where if the first argument + is exactly the special token representing defn(`builtin'), the expansion + is the special token representing the builtin named in the second + argument. This allows regenerating a macro with a more efficient + mapping directly to a builtin function, rather than through textual + indirection through further expansions of `builtin'. + * New `-r'/`--regexp-syntax' command-line option changes the default regular expression syntax used by M4. Without this option, M4 continues to use EMACS style expressions. A new section in the info docs Index: doc/m4.texinfo =================================================================== RCS file: /sources/m4/m4/doc/m4.texinfo,v retrieving revision 1.73 diff -u -r1.73 m4.texinfo --- doc/m4.texinfo 25 Oct 2006 23:19:19 -0000 1.73 +++ doc/m4.texinfo 27 Oct 2006 16:57:19 -0000 @@ -2231,10 +2231,17 @@ Builtin macros can be called indirectly with @code{builtin}: @deffn {Builtin (gnu)} builtin (@var{name}, @[EMAIL PROTECTED]) [EMAIL PROTECTED] {Builtin (gnu)} builtin (@code{defn(`builtin')}, @var{name1}) Results in a call to the builtin @var{name}, which is passed the rest of the arguments @var{args}. If @var{name} does not name a builtin, a warning message is printed, and the expansion is void. +As a special case, if @var{name} is exactly the special token +representing the @code{builtin} macro, as obtained by @code{defn} +(@pxref{Defn}), then @var{args} must consist of a single @var{name1}, +and the expansion is the special token representing the builtin macro +named by @var{name1}. + The macro @code{builtin} is recognized only with parameters. @end deffn @@ -2311,6 +2318,65 @@ @result{}0 @end example +Normally, once a builtin macro is undefined, the only way to retrieve +its functionality is by defining a new macro that expands to [EMAIL PROTECTED] under the hood. But this extra layer of expansion is +slightly inefficient, not to mention the fact that it is not robust to +changes in the current quoting scheme due to @code{changequote} +(@pxref{Changequote}). On the other hand, defining a macro to the +special token produced by @code{defn} (@pxref{Defn}) is very efficient, +and avoids the need for quoting within the macro definition; but [EMAIL PROTECTED] only works if the desired macro is already defined by some +other name. So @code{builtin} provides a special case where it is +possible to retrieve the same special token representing a builtin as +what @code{defn} would provide, were the desired macro still defined. +This feature is activated by passing @code{defn(`builtin')} as the first +argument to builtin. Normally, passing a special token representing a +macro as @var{name} results in a warning and an empty expansion, but in +this case, if the second argument @var{name1} names a valid builtin, +there is no warning and the expansion is the appropriate special +token. In fact, with just the @code{builtin} macro accessible, it is +possible to reconstitute the entire startup state of @code{m4}. + +In the example below, compare the number of macro invocations performed +by @code{defn1} and @code{defn2}, and the differences once quoting is +changed. + [EMAIL PROTECTED] +$ @kbd{m4 -d} +undefine(`defn') [EMAIL PROTECTED] +define(`foo', `bar') [EMAIL PROTECTED] +define(`defn1', `builtin(`defn', $@@)') [EMAIL PROTECTED] +define(`defn2', builtin(builtin(`defn', `builtin'), `defn')) [EMAIL PROTECTED] +dumpdef(`defn1', `defn2') [EMAIL PROTECTED]:@tabchar{}`builtin(`defn', $@@)' [EMAIL PROTECTED]:@tabchar{}<defn> [EMAIL PROTECTED] +traceon [EMAIL PROTECTED] +defn1(`foo') [EMAIL PROTECTED]: -1- defn1(`foo') -> `builtin(`defn', `foo')' [EMAIL PROTECTED]: -1- builtin(`defn', `foo') -> ``bar'' [EMAIL PROTECTED] +defn2(`foo') [EMAIL PROTECTED]: -1- defn2(`foo') -> ``bar'' [EMAIL PROTECTED] +traceoff [EMAIL PROTECTED]: -1- traceoff -> `' [EMAIL PROTECTED] +changequote(`[', `]') [EMAIL PROTECTED] +defn1([foo]) [EMAIL PROTECTED]:stdin:11: Warning: builtin: undefined builtin ``defn'' [EMAIL PROTECTED] +defn2([foo]) [EMAIL PROTECTED] [EMAIL PROTECTED] example + @node M4symbols @section Getting the defined macro names Index: m4/builtin.c =================================================================== RCS file: /sources/m4/m4/m4/builtin.c,v retrieving revision 1.25 diff -u -r1.25 builtin.c --- m4/builtin.c 27 Oct 2005 16:04:03 -0000 1.25 +++ m4/builtin.c 27 Oct 2006 16:57:19 -0000 @@ -1,5 +1,6 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1989-1994, 1999, 2000, 2005 Free Software Foundation, Inc. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1999, 2000, 2005, + 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,9 +23,11 @@ #include "m4private.h" -/* Find the builtin which has NAME. If HANDLE argument is supplied - then search only in HANDLE's builtin table. */ -const m4_builtin * +/* Find the builtin which has NAME. If HANDLE is not NULL, then + search only in HANDLE's builtin table. The result is a malloc'd + symbol value, suitable for use in the symbol table or for an + argument to m4_push_builtin. */ +m4_symbol_value * m4_builtin_find_by_name (lt_dlhandle handle, const char *name) { lt_dlhandle cur = handle ? handle : m4__module_next (0); @@ -32,18 +35,27 @@ do { const m4_builtin *builtin = - (const m4_builtin *) lt_dlsym (cur, BUILTIN_SYMBOL); + (m4_builtin *) lt_dlsym (cur, BUILTIN_SYMBOL); if (builtin) { for (; builtin->name != NULL; builtin++) if (!strcmp (builtin->name, name)) - return builtin; + { + m4_symbol_value *token = xzalloc (sizeof *token); + + m4_set_symbol_value_builtin (token, builtin); + VALUE_HANDLE (token) = cur; + VALUE_FLAGS (token) = builtin->flags; + VALUE_MIN_ARGS (token) = builtin->min_args; + VALUE_MAX_ARGS (token) = builtin->max_args; + return token; + } } } while (!handle && (cur = m4__module_next (cur))); - return 0; + return NULL; } /* Find the builtin which has FUNC. If HANDLE argument is supplied Index: m4/input.c =================================================================== RCS file: /sources/m4/m4/m4/input.c,v retrieving revision 1.55 diff -u -r1.55 input.c --- m4/input.c 25 Oct 2006 23:19:19 -0000 1.55 +++ m4/input.c 27 Oct 2006 16:57:19 -0000 @@ -162,7 +162,7 @@ u_f; struct { - m4_builtin_func *func; /* pointer to builtin's function. */ + const m4_builtin *builtin; /* pointer to builtin's function. */ lt_dlhandle handle; /* originating module. */ int flags; /* flags associated with the builtin. */ m4_hash *arg_signature; /* argument signature for builtin. */ @@ -389,12 +389,9 @@ static void builtin_print (m4_input_block *me, m4 *context, m4_obstack *obs) { - const m4_builtin *bp; - const char *text; + const m4_builtin *bp = me->u.u_b.builtin; + const char *text = bp->name; - bp = m4_builtin_find_by_func (NULL, me->u.u_b.func); - assert (bp); - text = bp->name; obstack_1grow (obs, '<'); obstack_grow (obs, text, strlen (text)); obstack_1grow (obs, '>'); @@ -431,9 +428,9 @@ i->file = m4_get_current_file (context); i->line = m4_get_current_line (context); - i->u.u_b.func = m4_get_symbol_value_func (token); + i->u.u_b.builtin = m4_get_symbol_value_builtin (token); i->u.u_b.handle = VALUE_HANDLE (token); - i->u.u_b.arg_signature= VALUE_ARG_SIGNATURE (token); + i->u.u_b.arg_signature = VALUE_ARG_SIGNATURE (token); i->u.u_b.min_args = VALUE_MIN_ARGS (token); i->u.u_b.max_args = VALUE_MAX_ARGS (token); i->u.u_b.flags = VALUE_FLAGS (token); @@ -746,7 +743,7 @@ block = block->u.u_c.current; assert (block->funcs->read_func == builtin_read && ! block->u.u_b.read); - m4_set_symbol_value_func (token, block->u.u_b.func); + m4_set_symbol_value_builtin (token, block->u.u_b.builtin); VALUE_HANDLE (token) = block->u.u_b.handle; VALUE_FLAGS (token) = block->u.u_b.flags; VALUE_ARG_SIGNATURE (token) = block->u.u_b.arg_signature; Index: m4/m4module.h =================================================================== RCS file: /sources/m4/m4/m4/m4module.h,v retrieving revision 1.98 diff -u -r1.98 m4module.h --- m4/m4module.h 27 Oct 2006 04:03:28 -0000 1.98 +++ m4/m4module.h 27 Oct 2006 16:57:19 -0000 @@ -243,6 +243,8 @@ (m4_get_symbol_value_text (m4_get_symbol_value (symbol))) #define m4_get_symbol_func(symbol) \ (m4_get_symbol_value_func (m4_get_symbol_value (symbol))) +#define m4_get_symbol_builtin(symbol) \ + (m4_get_symbol_value_builtin (m4_get_symbol_value (symbol))) #define m4_get_symbol_placeholder(symbol) \ (m4_get_symbol_value_placeholder (m4_get_symbol_value (symbol))) #define m4_symbol_groks_macro(symbol) \ @@ -258,20 +260,21 @@ extern bool m4_is_symbol_value_void (m4_symbol_value *); extern const char *m4_get_symbol_value_text (m4_symbol_value *); extern m4_builtin_func *m4_get_symbol_value_func (m4_symbol_value *); -extern const char *m4_get_symbol_value_placeholder (m4_symbol_value *); +extern const m4_builtin *m4_get_symbol_value_builtin (m4_symbol_value *); +extern const char *m4_get_symbol_value_placeholder (m4_symbol_value *); extern void m4_set_symbol_value_text (m4_symbol_value *, - const char *); -extern void m4_set_symbol_value_func (m4_symbol_value *, - m4_builtin_func *); -extern void m4_set_symbol_value_placeholder (m4_symbol_value *, - const char *); + const char *); +extern void m4_set_symbol_value_builtin (m4_symbol_value *, + const m4_builtin *); +extern void m4_set_symbol_value_placeholder (m4_symbol_value *, + const char *); /* --- BUILTIN MANAGEMENT --- */ -extern const m4_builtin *m4_builtin_find_by_name (lt_dlhandle, const char *); -extern const m4_builtin *m4_builtin_find_by_func (lt_dlhandle, +extern m4_symbol_value *m4_builtin_find_by_name (lt_dlhandle, const char *); +extern const m4_builtin *m4_builtin_find_by_func (lt_dlhandle, m4_builtin_func *); Index: m4/m4private.h =================================================================== RCS file: /sources/m4/m4/m4/m4private.h,v retrieving revision 1.68 diff -u -r1.68 m4private.h --- m4/m4private.h 27 Oct 2006 04:03:28 -0000 1.68 +++ m4/m4private.h 27 Oct 2006 16:57:19 -0000 @@ -181,7 +181,7 @@ m4__symbol_type type; union { const char * text; /* Valid when type is TEXT, PLACEHOLDER. */ - m4_builtin_func * func; /* Valid when type is FUNC. */ + const m4_builtin * builtin; /* Valid when type is FUNC. */ } u; }; @@ -217,16 +217,18 @@ # define m4_is_symbol_value_placeholder(V) \ ((V)->type == M4_SYMBOL_PLACEHOLDER) # define m4_get_symbol_value_text(V) ((V)->u.text) -# define m4_get_symbol_value_func(V) ((V)->u.func) +# define m4_get_symbol_value_func(V) ((V)->u.builtin->func) +# define m4_get_symbol_value_builtin(V) ((V)->u.builtin) # define m4_get_symbol_value_placeholder(V) \ ((V)->u.text) +# define m4_get_symbol_value_module(V) (VALUE_HANDLE (V)) # define m4_symbol_value_groks_macro(V) (BIT_TEST ((V)->flags, \ VALUE_MACRO_ARGS_BIT)) # define m4_set_symbol_value_text(V, T) \ ((V)->type = M4_SYMBOL_TEXT, (V)->u.text = (T)) -# define m4_set_symbol_value_func(V, F) \ - ((V)->type = M4_SYMBOL_FUNC, (V)->u.func = (F)) +# define m4_set_symbol_value_builtin(V, B) \ + ((V)->type = M4_SYMBOL_FUNC, (V)->u.builtin = (B)) # define m4_set_symbol_value_placeholder(V, T) \ ((V)->type = M4_SYMBOL_PLACEHOLDER, (V)->u.text = (T)) #endif Index: m4/macro.c =================================================================== RCS file: /sources/m4/m4/m4/macro.c,v retrieving revision 1.61 diff -u -r1.61 macro.c --- m4/macro.c 27 Oct 2006 04:03:28 -0000 1.61 +++ m4/macro.c 27 Oct 2006 16:57:19 -0000 @@ -182,6 +182,7 @@ if (argp->type == M4_SYMBOL_VOID) { + VALUE_HANDLE (argp) = NULL; m4_set_symbol_value_text (argp, text); } return type == M4_TOKEN_COMMA; @@ -358,6 +359,7 @@ if (!groks_macro_args && m4_is_symbol_value_func (&token)) { + VALUE_HANDLE (&token) = NULL; m4_set_symbol_value_text (&token, ""); } tokenp = (m4_symbol_value *) obstack_copy (arguments, &token, Index: m4/module.c =================================================================== RCS file: /sources/m4/m4/m4/module.c,v retrieving revision 1.47 diff -u -r1.47 module.c --- m4/module.c 16 Oct 2006 22:12:07 -0000 1.47 +++ m4/module.c 27 Oct 2006 16:57:19 -0000 @@ -138,7 +138,7 @@ assert (context); assert (handle); - bp = (const m4_builtin *) lt_dlsym (handle, BUILTIN_SYMBOL); + bp = (m4_builtin *) lt_dlsym (handle, BUILTIN_SYMBOL); if (bp) { for (; bp->name != NULL; bp++) @@ -153,7 +153,7 @@ | M4_BUILTIN_SIDE_EFFECT)) == 0); assert ((bp->flags & ~M4_BUILTIN_FLAGS_MASK) == 0); - m4_set_symbol_value_func (value, bp->func); + m4_set_symbol_value_builtin (value, bp); VALUE_HANDLE (value) = handle; VALUE_FLAGS (value) = bp->flags; VALUE_MIN_ARGS (value) = bp->min_args; Index: m4/symtab.c =================================================================== RCS file: /sources/m4/m4/m4/symtab.c,v retrieving revision 1.66 diff -u -r1.66 symtab.c --- m4/symtab.c 27 Oct 2006 04:03:28 -0000 1.66 +++ m4/symtab.c 27 Oct 2006 16:57:19 -0000 @@ -480,9 +480,7 @@ } else if (m4_is_symbol_value_func (value)) { - const m4_builtin *bp; - bp = m4_builtin_find_by_func (NULL, m4_get_symbol_value_func (value)); - assert (bp); + const m4_builtin *bp = m4_get_symbol_value_builtin (value); text = bp->name; lquote = "<"; rquote = ">"; @@ -641,7 +639,15 @@ m4_get_symbol_value_func (m4_symbol_value *value) { assert (value && value->type == M4_SYMBOL_FUNC); - return value->u.func; + return value->u.builtin->func; +} + +#undef m4_get_symbol_value_builtin +const m4_builtin * +m4_get_symbol_value_builtin (m4_symbol_value *value) +{ + assert (value && value->type == M4_SYMBOL_FUNC); + return value->u.builtin; } #undef m4_get_symbol_value_placeholder @@ -652,6 +658,14 @@ return value->u.text; } +#undef m4_get_symbol_value_module +lt_dlhandle +m4_get_symbol_value_module (m4_symbol_value *value) +{ + assert (value); + return VALUE_HANDLE (value); +} + #undef m4_set_symbol_value_text void m4_set_symbol_value_text (m4_symbol_value *value, const char *text) @@ -663,15 +677,15 @@ value->u.text = text; } -#undef m4_set_symbol_value_func +#undef m4_set_symbol_value_builtin void -m4_set_symbol_value_func (m4_symbol_value *value, m4_builtin_func *func) +m4_set_symbol_value_builtin (m4_symbol_value *value, const m4_builtin *builtin) { assert (value); - assert (func); + assert (builtin); value->type = M4_SYMBOL_FUNC; - value->u.func = func; + value->u.builtin = builtin; } #undef m4_set_symbol_value_placeholder @@ -685,7 +699,6 @@ value->u.text = text; } - #ifdef DEBUG_SYM @@ -712,26 +725,16 @@ if (!value) fputs ("<!UNDEFINED!>", stderr); + else if (m4_is_symbol_value_void (value)) + fputs ("<!VOID!>", stderr); else - switch (value->type) - { - case M4_SYMBOL_TEXT: - fputs (m4_get_symbol_text (symbol), stderr); - break; - - case M4_SYMBOL_FUNC: - bp = m4_builtin_find_by_func (handle, m4_get_symbol_func (symbol)); - fprintf (stderr, "<%s>", - bp ? bp->name : "!ERROR!"); - break; - case M4_SYMBOL_PLACEHOLDER: - fprintf (stderr, "<placeholder for %s>", - m4_get_symbol_placeholder (symbol)); - break; - case M4_SYMBOL_VOID: - fputs ("<!VOID!>", stderr); - break; - } + { + m4_obstack obs; + obstack_init (&obs); + m4_symbol_value_print (value, &obs, false, NULL, NULL, 0, true); + fprintf (stderr, "%s", obstack_finish (&obs)); + obstack_free (&obs, NULL); + } fputc ('\n', stderr); return NULL; } Index: modules/gnu.c =================================================================== RCS file: /sources/m4/m4/modules/gnu.c,v retrieving revision 1.65 diff -u -r1.65 gnu.c --- modules/gnu.c 21 Oct 2006 22:15:52 -0000 1.65 +++ modules/gnu.c 27 Oct 2006 16:57:19 -0000 @@ -323,32 +323,68 @@ /* The builtin "builtin" allows calls to builtin macros, even if their definition has been overridden or shadowed. It is thus possible to - redefine builtins, and still access their original definition. */ + redefine builtins, and still access their original definition. A + special form allows one to retrieve the special token that defn + would normally return, even if that builtin is not currently + defined and hence can't be passed to defn. */ /** * builtin(MACRO, [...]) + * builtin(defn(`builtin'), MACRO) **/ M4BUILTIN_HANDLER (builtin) { + const char *name; + m4_symbol_value *value; + if (! m4_is_symbol_value_text (argv[1])) - m4_warn (context, 0, _("%s: invalid macro name ignored"), M4ARG (0)); + { + if (m4_is_symbol_value_func (argv[1]) + && m4_get_symbol_value_func (argv[1]) == builtin_builtin) + { + if (m4_bad_argc (context, argc, argv, 2, 2, false)) + return; + if (! m4_is_symbol_value_text (argv[2])) + { + m4_warn (context, 0, _("%s: invalid macro name ignored"), + M4ARG (0)); + return; + } + name = M4ARG (2); + value = m4_builtin_find_by_name (NULL, name); + if (value == NULL) + m4_warn (context, 0, _("%s: undefined builtin `%s'"), M4ARG (0), + name); + else + { + m4_push_builtin (context, value); + free (value); + } + } + else + m4_warn (context, 0, _("%s: invalid macro name ignored"), M4ARG (0)); + } else { - const char *name = M4ARG (1); - const m4_builtin *bp = m4_builtin_find_by_name (NULL, name); - - if (bp == NULL) + name = M4ARG (1); + value = m4_builtin_find_by_name (NULL, name); + if (value == NULL) m4_warn (context, 0, _("%s: undefined builtin `%s'"), M4ARG (0), name); - else if (!m4_bad_argc (context, argc - 1, argv + 1, - bp->min_args, bp->max_args, - (bp->flags & M4_BUILTIN_SIDE_EFFECT) != 0)) + else { - int i; - if ((bp->flags & M4_BUILTIN_GROKS_MACRO) == 0) - for (i = 2; i < argc; i++) - if (! m4_is_symbol_value_text (argv[i])) - m4_set_symbol_value_text (argv[i], ""); - bp->func (context, obs, argc - 1, argv + 1); + const m4_builtin *bp = m4_get_symbol_value_builtin (value); + if (!m4_bad_argc (context, argc - 1, argv + 1, + bp->min_args, bp->max_args, + (bp->flags & M4_BUILTIN_SIDE_EFFECT) != 0)) + { + int i; + if ((bp->flags & M4_BUILTIN_GROKS_MACRO) == 0) + for (i = 2; i < argc; i++) + if (! m4_is_symbol_value_text (argv[i])) + m4_set_symbol_value_text (argv[i], ""); + bp->func (context, obs, argc - 1, argv + 1); + } + free (value); } } } Index: src/freeze.c =================================================================== RCS file: /sources/m4/m4/src/freeze.c,v retrieving revision 1.53 diff -u -r1.53 freeze.c --- src/freeze.c 27 Oct 2006 04:03:28 -0000 1.53 +++ src/freeze.c 27 Oct 2006 16:57:19 -0000 @@ -531,26 +531,18 @@ /* Enter a macro having a builtin function as a definition. */ { - const m4_builtin *bp; lt_dlhandle handle = 0; - m4_symbol_value *token = xzalloc (sizeof *token); + m4_symbol_value *token; if (number[2] > 0) handle = m4__module_find (string[2]); + token = m4_builtin_find_by_name (handle, string[1]); - bp = m4_builtin_find_by_name (handle, string[1]); - VALUE_HANDLE (token) = handle; - - if (bp) - { - m4_set_symbol_value_func (token, bp->func); - VALUE_FLAGS (token) = bp->flags; - VALUE_MIN_ARGS (token) = bp->min_args; - VALUE_MAX_ARGS (token) = bp->max_args; - } - else + if (token == NULL) { + token = xzalloc (sizeof *token); m4_set_symbol_value_placeholder (token, xstrdup (string[1])); + VALUE_HANDLE (token) = handle; VALUE_MIN_ARGS (token) = 0; VALUE_MAX_ARGS (token) = -1; } _______________________________________________ M4-discuss mailing list M4-discuss@gnu.org http://lists.gnu.org/mailman/listinfo/m4-discuss