[1/18] argv_ref speedup: replace array with accessor struct
Eric Blake <[email protected]>
| Newsgroups | gmane.comp.gnu.m4.patches |
|---|---|
| Message-ID | <[email protected]> |
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I've finally ported the first of my series of 18 patches for $@ reference speedups to the head, so I'm committing the following to branch-1_4 and head. On the branch, this differs slightly from the argv_ref branch, in that it has a changelog entry and no // comments in the code. Still 17 to go, but I'll get there. I welcome any review on any stage of the patch series. The goal of this patch is a mechanical replacement - instead of passing a raw array of arguments to every builtin, we instead pass a pointer to a struct that wraps the array. No speedup from this patch and a slight memory penalty, but it is essential for future patches, when the wrapper struct can also point to a reference to multiple arguments in a single array slot, without having to adjust all the clients of the struct. 2007-11-24 Eric Blake <[email protected]> Stage 1: convert token_data** into new object. * m4/gnulib-cache.m4: Import flexmember module. * src/m4.h (struct macro_arguments, struct token_chain): New structs. (builtin_func): Alter signature. (token_data): Add new TOKEN_COMP alternative. * src/builtin.c: All builtins changed. (ARG, dump_args, define_macro, expand_user_macro): Update to use struct. * src/debug.c (trace_pre, trace_post): Likewise. * src/format.c (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE, format): Likewise. * src/macro.c (collect_arguments): Build new struct. (call_macro, expand_macro): Update to use new struct. - -- Don't work too hard, make some time for fun as well! Eric Blake [email protected] -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHSL+L84KuGfSFAYARAmW8AKDK2YiHz9n4HM8UeVUbcDeG3aeCcQCePhnu iOnmssti6SGFqJTuI7dNCIM= =O0RE -----END PGP SIGNATURE----- _______________________________________________ M4-patches mailing list [email protected] http://lists.gnu.org/mailman/listinfo/m4-patches
m4.patch297
(text/plain, 77.9 KB)
From 14b2ffbb82eb22cd36b1703a5501ee87ea51c45c Mon Sep 17 00:00:00 2001 From: Eric Blake <[email protected]> Date: Sat, 24 Nov 2007 16:23:47 -0700 Subject: [PATCH] Stage 1: convert m4_symbol_value** into new object. * ltdl/m4/gnulib-cache.m4: Import flexmember module. * m4/m4module.h (m4_macro_args): New type, will be opaque to modules later. (m4_builtin_func, M4BUILTIN, M4BUILTIN_HANDLER, m4_dump_args) (m4_macro_call): Alter signature to use m4_macro_args object. (M4ARG): Redefine to access new struct. * m4/m4private.h (M4_SYMBOL_COMP): New enumerator. (struct m4_symbol_chain): New type. (struct m4_symbol_value): Add chain alternative. * m4/macro.c (collect_arguments): Build new struct. (expand_macro, m4_macro_call, process_macro, trace_pre) (trace_post): Adjust implementation to use it. * m4/utility.c (m4_dump_args): Likewise. * modules/gnu.c (builtin, indir): Likewise. * modules/format.c (format): Likewise. * modules/m4.h (m4_dump_symbols_func): Likewise. * modules/m4.c (m4_dump_symbols, define, pushdef, defn, ifelse) (shift, include, errprint, m4wrap): Likewise. * modules/evalparse.c (m4_evaluate): Likewise. Signed-off-by: Eric Blake <[email protected]> --- ChangeLog | 21 ++++++++++ ltdl/m4/gnulib-cache.m4 | 4 +- m4/m4module.h | 72 ++++++++++++++++++++++------------ m4/m4private.h | 30 +++++++++++--- m4/macro.c | 97 ++++++++++++++++++++++++---------------------- m4/utility.c | 16 +++++--- modules/evalparse.c | 2 +- modules/format.c | 52 ++++++++++++------------- modules/gnu.c | 49 +++++++++++++++++------ modules/m4.c | 42 +++++++++++---------- modules/m4.h | 2 +- 11 files changed, 238 insertions(+), 149 deletions(-) diff --git a/ChangeLog b/ChangeLog index f71a00f..2fbe4ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,26 @@ 2007-11-24 Eric Blake <[email protected]> + Stage 1: convert m4_symbol_value** into new object. + * ltdl/m4/gnulib-cache.m4: Import flexmember module. + * m4/m4module.h (m4_macro_args): New type, will be opaque to + modules later. + (m4_builtin_func, M4BUILTIN, M4BUILTIN_HANDLER, m4_dump_args) + (m4_macro_call): Alter signature to use m4_macro_args object. + (M4ARG): Redefine to access new struct. + * m4/m4private.h (M4_SYMBOL_COMP): New enumerator. + (struct m4_symbol_chain): New type. + (struct m4_symbol_value): Add chain alternative. + * m4/macro.c (collect_arguments): Build new struct. + (expand_macro, m4_macro_call, process_macro, trace_pre) + (trace_post): Adjust implementation to use it. + * m4/utility.c (m4_dump_args): Likewise. + * modules/gnu.c (builtin, indir): Likewise. + * modules/format.c (format): Likewise. + * modules/m4.h (m4_dump_symbols_func): Likewise. + * modules/m4.c (m4_dump_symbols, define, pushdef, defn, ifelse) + (shift, include, errprint, m4wrap): Likewise. + * modules/evalparse.c (m4_evaluate): Likewise. + Pass only macro name to utility functions. * m4/m4module.h (m4_bad_argc, m4_numeric_arg): Adjust signature. * m4/utility.c (m4_bad_argc, m4_numeric_arg): Adjust diff --git a/ltdl/m4/gnulib-cache.m4 b/ltdl/m4/gnulib-cache.m4 index 9c17a78..1eefbd5 100644 --- a/ltdl/m4/gnulib-cache.m4 +++ b/ltdl/m4/gnulib-cache.m4 @@ -15,11 +15,11 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --local-dir=local --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=build-aux --with-tests --libtool --macro-prefix=M4 assert autobuild avltree-oset binary-io clean-temp cloexec close-stream closein config-h configmake dirname error exit fdl fflush filenamecat fopen-safer free fseeko gendocs gettext gnupload gpl-3.0 mkstemp obstack progname regex regexprops-generic sprintf-posix stdbool stdlib-safer strnlen strtol tempname unlocked-io verror xalloc xalloc-die xprintf-posix xstrndup xvasprintf-posix +# gnulib-tool --import --dir=. --local-dir=local --lib=libgnu --source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=build-aux --with-tests --libtool --macro-prefix=M4 assert autobuild avltree-oset binary-io clean-temp cloexec close-stream closein config-h configmake dirname error exit fdl fflush filenamecat flexmember fopen-safer free fseeko gendocs gettext gnupload gpl-3.0 mkstemp obstack progname regex regexprops-generic sprintf-posix stdbool stdlib-safer strnlen strtol tempname unlocked-io verror xalloc xalloc-die xprintf-posix xstrndup xvasprintf-posix # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([local]) -gl_MODULES([assert autobuild avltree-oset binary-io clean-temp cloexec close-stream closein config-h configmake dirname error exit fdl fflush filenamecat fopen-safer free fseeko gendocs gettext gnupload gpl-3.0 mkstemp obstack progname regex regexprops-generic sprintf-posix stdbool stdlib-safer strnlen strtol tempname unlocked-io verror xalloc xalloc-die xprintf-posix xstrndup xvasprintf-posix]) +gl_MODULES([assert autobuild avltree-oset binary-io clean-temp cloexec close-stream closein config-h configmake dirname error exit fdl fflush filenamecat flexmember fopen-safer free fseeko gendocs gettext gnupload gpl-3.0 mkstemp obstack progname regex regexprops-generic sprintf-posix stdbool stdlib-safer strnlen strtol tempname unlocked-io verror xalloc xalloc-die xprintf-posix xstrndup xvasprintf-posix]) gl_AVOID([]) gl_SOURCE_BASE([gnu]) gl_M4_BASE([ltdl/m4]) diff --git a/m4/m4module.h b/m4/m4module.h index 01514db..3f60cba 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -37,10 +37,11 @@ typedef struct m4_macro m4_macro; typedef struct m4_symbol_value m4_symbol_value; typedef struct m4_input_block m4_input_block; typedef struct m4_module m4_module; +typedef struct m4_macro_args m4_macro_args; typedef struct obstack m4_obstack; -typedef void m4_builtin_func (m4 *, m4_obstack *, int, m4_symbol_value **); +typedef void m4_builtin_func (m4 *, m4_obstack *, int, m4_macro_args *); /* The value of m4_builtin flags is built from these: */ enum { @@ -75,38 +76,58 @@ struct m4_macro const char *value; }; +/* FIXME - make this struct opaque. */ +struct m4_macro_args +{ + /* One more than the highest actual argument. May be larger than + arraylen since the array can refer to multiple arguments via a + single $@ reference. */ + unsigned int argc; + /* False unless the macro expansion refers to $@; determines whether + this object can be freed at end of macro expansion or must wait + until all references have been rescanned. */ + bool inuse; + const char *argv0; /* The macro name being expanded. */ + size_t arraylen; /* True length of allocated elements in array. */ + /* Used as a variable-length array, storing information about each + argument. */ + m4_symbol_value *array[FLEXIBLE_ARRAY_MEMBER]; +}; + -#define M4BUILTIN(name) \ - static void CONC(builtin_, name) \ - (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv); +#define M4BUILTIN(name) \ + static void CONC (builtin_, name) \ + (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv); -#define M4BUILTIN_HANDLER(name) \ - static void CONC(builtin_, name) \ - (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) +#define M4BUILTIN_HANDLER(name) \ + static void CONC (builtin_, name) \ + (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) -#define M4INIT_HANDLER(name) \ - void CONC(name, CONC(_LTX_, m4_init_module)) \ - (m4 *context, m4_module *module, m4_obstack *obs); \ - void CONC(name, CONC(_LTX_, m4_init_module)) \ +#define M4INIT_HANDLER(name) \ + void CONC (name, CONC (_LTX_, m4_init_module)) \ + (m4 *context, m4_module *module, m4_obstack *obs); \ + void CONC (name, CONC (_LTX_, m4_init_module)) \ (m4 *context, m4_module *module, m4_obstack *obs) -#define M4FINISH_HANDLER(name) \ - void CONC(name, CONC(_LTX_, m4_finish_module)) \ - (m4 *context, m4_module *module, m4_obstack *obs); \ - void CONC(name, CONC(_LTX_, m4_finish_module)) \ +#define M4FINISH_HANDLER(name) \ + void CONC (name, CONC (_LTX_, m4_finish_module)) \ + (m4 *context, m4_module *module, m4_obstack *obs); \ + void CONC (name, CONC (_LTX_, m4_finish_module)) \ (m4 *context, m4_module *module, m4_obstack *obs) -#define M4_MODULE_IMPORT(M, S) \ - CONC(S, _func) *S = (CONC(S, _func) *) \ - m4_module_import (context, STR(M), STR(S), obs) +#define M4_MODULE_IMPORT(M, S) \ + CONC (S, _func) *S = (CONC (S, _func) *) \ + m4_module_import (context, STR (M), STR (S), obs) -#define M4ARG(i) (argc > (i) ? m4_get_symbol_value_text (argv[i]) : "") +#define M4ARG(i) \ + ((i) == 0 ? argv->argv0 \ + : argv->argc > (i) ? m4_get_symbol_value_text (argv->array[(i) - 1]) : "") extern bool m4_bad_argc (m4 *, int, const char *, unsigned int, unsigned int, bool); extern bool m4_numeric_arg (m4 *, const char *, const char *, int *); extern void m4_dump_args (m4 *, m4_obstack *, int, - m4_symbol_value **, const char *, bool); + m4_macro_args *, const char *, bool); extern bool m4_parse_truth_arg (m4 *, const char *, const char *, bool); /* Error handling. */ @@ -164,14 +185,14 @@ extern void m4_delete (m4 *); #define M4FIELD(type, base, field) \ - extern type CONC(m4_get_, base) (m4 *context); \ - extern type CONC(m4_set_, base) (m4 *context, type value); + extern type CONC (m4_get_, base) (m4 *context); \ + extern type CONC (m4_set_, base) (m4 *context, type value); m4_context_field_table #undef M4FIELD #define M4OPT_BIT(bit, base) \ - extern bool CONC(m4_get_, base) (m4 *context); \ - extern bool CONC(m4_set_, base) (m4 *context, bool value); + extern bool CONC (m4_get_, base) (m4 *context); \ + extern bool CONC (m4_set_, base) (m4 *context, bool value); m4_context_opt_bit_table #undef M4OPT_BIT @@ -287,8 +308,7 @@ extern const m4_builtin *m4_builtin_find_by_func (m4_module *, extern void m4_macro_expand_input (m4 *); extern void m4_macro_call (m4 *, m4_symbol_value *, - m4_obstack *, int, - m4_symbol_value **); + m4_obstack *, int, m4_macro_args *); diff --git a/m4/m4private.h b/m4/m4private.h index b067254..63a9bc4 100644 --- a/m4/m4private.h +++ b/m4/m4private.h @@ -30,10 +30,11 @@ typedef struct m4__search_path_info m4__search_path_info; typedef enum { - M4_SYMBOL_VOID, /* Traced but undefined. */ - M4_SYMBOL_TEXT, /* Plain text. */ - M4_SYMBOL_FUNC, /* Builtin function. */ - M4_SYMBOL_PLACEHOLDER /* Placeholder for unknown builtin during -R. */ + M4_SYMBOL_VOID, /* Traced but undefined, u is invalid. */ + M4_SYMBOL_TEXT, /* Plain text, u.u_t is valid. */ + M4_SYMBOL_FUNC, /* Builtin function, u.func is valid. */ + M4_SYMBOL_PLACEHOLDER, /* Placeholder for unknown builtin from -R. */ + M4_SYMBOL_COMP /* Composite symbol, u.chain is valid. */ } m4__symbol_type; #define BIT_TEST(flags, bit) (((flags) & (bit)) == (bit)) @@ -171,13 +172,27 @@ extern m4_module * m4__module_find (const char *name); /* --- SYMBOL TABLE MANAGEMENT --- */ +typedef struct m4_symbol_chain m4_symbol_chain; + struct m4_symbol { bool traced; m4_symbol_value * value; }; -struct m4_symbol_value { +/* Composite symbols are built of a linked list of chain objects. */ +struct m4_symbol_chain +{ + m4_symbol_chain *next;/* Pointer to next link of chain. */ + char *str; /* NUL-terminated string if text, else NULL. */ + m4_macro_args *argv; /* Reference to earlier $@. */ + unsigned int index; /* Index within argv to start reading from. */ +}; + +/* A symbol value is used both for values associated with a macro + name, and for arguments to a macro invocation. */ +struct m4_symbol_value +{ m4_symbol_value * next; m4_module * module; unsigned int flags; @@ -189,8 +204,9 @@ struct m4_symbol_value { m4__symbol_type type; union { - const char * text; /* Valid when type is TEXT, PLACEHOLDER. */ - const m4_builtin * builtin; /* Valid when type is FUNC. */ + const char * text; /* Valid when type is TEXT, PLACEHOLDER. */ + const m4_builtin * builtin;/* Valid when type is FUNC. */ + m4_symbol_chain * chain; /* Valid when type is COMP. */ } u; }; diff --git a/m4/macro.c b/m4/macro.c index dd93152..c4ba1af 100644 --- a/m4/macro.c +++ b/m4/macro.c @@ -29,22 +29,23 @@ #include "intprops.h" -static void collect_arguments (m4 *, const char *, m4_symbol *, - m4_obstack *, m4_obstack *); +static m4_macro_args *collect_arguments (m4 *, const char *, m4_symbol *, + m4_obstack *, unsigned int, + m4_obstack *); static void expand_macro (m4 *, const char *, m4_symbol *); static void expand_token (m4 *, m4_obstack *, m4__token_type, m4_symbol_value *, int); static bool expand_argument (m4 *, m4_obstack *, m4_symbol_value *, const char *); static void process_macro (m4 *, m4_symbol_value *, m4_obstack *, int, - m4_symbol_value **); + m4_macro_args *); static void trace_prepre (m4 *, const char *, size_t, m4_symbol_value *); static void trace_pre (m4 *, const char *, size_t, int, - m4_symbol_value **); + m4_macro_args *); static void trace_post (m4 *, const char *, size_t, int, - m4_symbol_value **, m4_input_block *, bool); + m4_macro_args *, m4_input_block *, bool); static void trace_format (m4 *, const char *, ...) M4_GNUC_PRINTF (2, 3); @@ -126,11 +127,11 @@ expand_token (m4 *context, m4_obstack *obs, ++textp; symbol = m4_symbol_lookup (M4SYMTAB, textp); - assert (! symbol || ! m4_is_symbol_void (symbol)); + assert (!symbol || !m4_is_symbol_void (symbol)); if (symbol == NULL || (symbol->value->type == M4_SYMBOL_FUNC && BIT_TEST (SYMBOL_FLAGS (symbol), VALUE_BLIND_ARGS_BIT) - && ! m4__next_token_is_open (context))) + && !m4__next_token_is_open (context))) { m4_shipout_text (context, obs, text, strlen (text), line); } @@ -248,7 +249,7 @@ expand_macro (m4 *context, const char *name, m4_symbol *symbol) char *argc_base = NULL; /* Base of argc_stack on entry. */ unsigned int argc_size; /* Size of argc_stack on entry. */ unsigned int argv_size; /* Size of argv_stack on entry. */ - m4_symbol_value **argv; + m4_macro_args *argv; int argc; m4_obstack *expansion; m4_input_block *expanded; @@ -297,15 +298,12 @@ recursion limit of %zu exceeded, use -L<N> to change it"), if (traced && m4_is_debug_bit (context, M4_DEBUG_TRACE_CALL)) trace_prepre (context, name, my_call_id, value); - collect_arguments (context, name, symbol, &argv_stack, &argc_stack); - - argc = ((obstack_object_size (&argv_stack) - argv_size) - / sizeof (m4_symbol_value *)); - argv = (m4_symbol_value **) ((char *) obstack_base (&argv_stack) - + argv_size); + argv = collect_arguments (context, name, symbol, &argv_stack, argv_size, + &argc_stack); + argc = argv->argc; /* Calling collect_arguments invalidated name, but we copied it as argv[0]. */ - name = m4_get_symbol_value_text (argv[0]); + name = argv->argv0; loc_close_file = m4_get_current_file (context); loc_close_line = m4_get_current_line (context); @@ -331,32 +329,39 @@ recursion limit of %zu exceeded, use -L<N> to change it"), if (BIT_TEST (VALUE_FLAGS (value), VALUE_DELETED_BIT)) m4_symbol_value_delete (value); + /* TODO - pay attention to argv->inuse. */ if (0 < argc_size) obstack_regrow (&argc_stack, argc_base, argc_size); else - obstack_free (&argc_stack, argv[0]); - obstack_blank (&argv_stack, -argc * sizeof (m4_symbol_value *)); + obstack_free (&argc_stack, (void *) name); + obstack_blank (&argv_stack, argv_size - obstack_object_size (&argv_stack)); } -/* Collect all the arguments to a call of the macro SYMBOL (called NAME). - The arguments are stored on the obstack ARGUMENTS and a table of pointers - to the arguments on the obstack ARGPTR. */ -static void +/* Collect all the arguments to a call of the macro SYMBOL (called + NAME). The arguments are stored on the obstack ARGUMENTS and a + table of pointers to the arguments on the obstack ARGPTR. ARGPTR + is an incomplete object, currently occupying ARGV_BASE bytes. + Return the object describing all of the macro arguments. */ +static m4_macro_args * collect_arguments (m4 *context, const char *name, m4_symbol *symbol, - m4_obstack *argptr, m4_obstack *arguments) + m4_obstack *argptr, unsigned argv_base, + m4_obstack *arguments) { m4_symbol_value token; m4_symbol_value *tokenp; bool more_args; bool groks_macro_args; + m4_macro_args args; + m4_macro_args *argv; groks_macro_args = BIT_TEST (SYMBOL_FLAGS (symbol), VALUE_MACRO_ARGS_BIT); - tokenp = (m4_symbol_value *) obstack_alloc (arguments, sizeof *tokenp); - m4_set_symbol_value_text (tokenp, (char *) obstack_copy0 (arguments, name, - strlen (name))); - name = m4_get_symbol_value_text (tokenp); - obstack_ptr_grow (argptr, tokenp); + args.argc = 1; + args.inuse = false; + args.argv0 = (char *) obstack_copy0 (arguments, name, strlen (name)); + args.arraylen = 0; + obstack_grow (argptr, &args, offsetof (m4_macro_args, array)); + name = args.argv0; if (m4__next_token_is_open (context)) { @@ -373,9 +378,15 @@ collect_arguments (m4 *context, const char *name, m4_symbol *symbol, tokenp = (m4_symbol_value *) obstack_copy (arguments, &token, sizeof token); obstack_ptr_grow (argptr, tokenp); + args.arraylen++; + args.argc++; } while (more_args); } + argv = (m4_macro_args *) ((char *) obstack_base (argptr) + argv_base); + argv->argc = args.argc; + argv->arraylen = args.arraylen; + return argv; } @@ -387,30 +398,24 @@ collect_arguments (m4 *context, const char *name, m4_symbol *symbol, the obstack EXPANSION. Macro tracing is also handled here. */ void m4_macro_call (m4 *context, m4_symbol_value *value, m4_obstack *expansion, - int argc, m4_symbol_value **argv) + int argc, m4_macro_args *argv) { - if (m4_bad_argc (context, argc, m4_get_symbol_value_text (argv[0]), + if (m4_bad_argc (context, argc, argv->argv0, VALUE_MIN_ARGS (value), VALUE_MAX_ARGS (value), BIT_TEST (VALUE_FLAGS (value), VALUE_SIDE_EFFECT_ARGS_BIT))) return; if (m4_is_symbol_value_text (value)) - { - process_macro (context, value, expansion, argc, argv); - } + process_macro (context, value, expansion, argc, argv); else if (m4_is_symbol_value_func (value)) - { - (*m4_get_symbol_value_func (value)) (context, expansion, argc, argv); - } + m4_get_symbol_value_func (value) (context, expansion, argc, argv); else if (m4_is_symbol_value_placeholder (value)) - { - m4_warn (context, 0, M4ARG (0), - _("builtin `%s' requested by frozen file not found"), - m4_get_symbol_value_placeholder (value)); - } + m4_warn (context, 0, M4ARG (0), + _("builtin `%s' requested by frozen file not found"), + m4_get_symbol_value_placeholder (value)); else { - assert (!"INTERNAL ERROR: bad symbol type in call_macro ()"); + assert (!"INTERNAL ERROR: bad symbol type in m4_macro_call ()"); abort (); } } @@ -422,7 +427,7 @@ m4_macro_call (m4 *context, m4_symbol_value *value, m4_obstack *expansion, as usual. */ static void process_macro (m4 *context, m4_symbol_value *value, m4_obstack *obs, - int argc, m4_symbol_value **argv) + int argc, m4_macro_args *argv) { const char *text; int i; @@ -467,7 +472,7 @@ process_macro (m4 *context, m4_symbol_value *value, m4_obstack *obs, case '*': /* all arguments */ case '@': /* ... same, but quoted */ - m4_dump_args (context, obs, argc, argv, ",", *text == '@'); + m4_dump_args (context, obs, 1, argv, ",", *text == '@'); text++; break; @@ -649,7 +654,7 @@ trace_prepre (m4 *context, const char *name, size_t id, m4_symbol_value *value) actually expanded. Used from expand_macro (). */ static void trace_pre (m4 *context, const char *name, size_t id, - int argc, m4_symbol_value **argv) + int argc, m4_macro_args *argv) { int i; @@ -670,7 +675,7 @@ trace_pre (m4 *context, const char *name, size_t id, if (i != 1) trace_format (context, ", "); - m4_symbol_value_print (argv[i], &context->trace_messages, + m4_symbol_value_print (argv->array[i - 1], &context->trace_messages, quote, lquote, rquote, arg_length, module); } trace_format (context, ")"); @@ -681,7 +686,7 @@ trace_pre (m4 *context, const char *name, size_t id, expand_macro (). */ static void trace_post (m4 *context, const char *name, size_t id, - int argc, m4_symbol_value **argv, m4_input_block *expanded, + int argc, m4_macro_args *argv, m4_input_block *expanded, bool trace_expansion) { if (trace_expansion) diff --git a/m4/utility.c b/m4/utility.c index a8873f3..851da31 100644 --- a/m4/utility.c +++ b/m4/utility.c @@ -95,19 +95,23 @@ m4_numeric_arg (m4 *context, const char *caller, const char *arg, int *valuep) } -/* Print ARGC arguments from the table ARGV to obstack OBS, separated by - SEP, and quoted by the current quotes, if QUOTED is true. */ +/* Print arguments from the table ARGV to obstack OBS, starting at + index START, separated by SEP, and quoted by the current quotes, if + QUOTED is true. */ void -m4_dump_args (m4 *context, m4_obstack *obs, int argc, - m4_symbol_value **argv, const char *sep, bool quoted) +m4_dump_args (m4 *context, m4_obstack *obs, int start, + m4_macro_args *argv, const char *sep, bool quoted) { int i; size_t len = strlen (sep); + bool need_sep = false; - for (i = 1; i < argc; i++) + for (i = start; i < argv->argc; i++) { - if (i > 1) + if (need_sep) obstack_grow (obs, sep, len); + else + need_sep = true; m4_shipout_string (context, obs, M4ARG (i), 0, quoted); } diff --git a/modules/evalparse.c b/modules/evalparse.c index 260ee1a..31e1e4b 100644 --- a/modules/evalparse.c +++ b/modules/evalparse.c @@ -885,7 +885,7 @@ simple_term (m4 *context, eval_token et, number *v1) /* Main entry point, called from "eval" and "mpeval" builtins. */ void -m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) +m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) { const char * me = M4ARG (0); const char * str = M4ARG (1); diff --git a/modules/format.c b/modules/format.c index 8e5f670..ced3924 100644 --- a/modules/format.c +++ b/modules/format.c @@ -30,21 +30,17 @@ TODO - use xstrtoimax, not atoi, to catch overflow, non-numeric arguments, etc. */ -#define ARG_INT(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atoi (M4ARG (-1)))) +#define ARG_INT(i, argc, argv) \ + ((argc <= i++) ? 0 : atoi (M4ARG (i - 1))) -#define ARG_LONG(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atol (M4ARG (-1)))) +#define ARG_LONG(i, argc, argv) \ + ((argc <= i++) ? 0L : atol (M4ARG (i - 1))) -#define ARG_STR(argc, argv) \ - ((argc == 0) ? "" : \ - (--argc, argv++, M4ARG (-1))) +#define ARG_STR(i, argc, argv) \ + ((argc <= i++) ? "" : M4ARG (i - 1)) -#define ARG_DOUBLE(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atof (M4ARG (-1)))) +#define ARG_DOUBLE(i, argc, argv) \ + ((argc <= i++) ? 0.0 : atof (M4ARG (i - 1))) /* The main formatting function. Output is placed on the obstack OBS, @@ -54,14 +50,15 @@ format. */ static void -format (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) +format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) { - const char *name = ARG_STR (argc, argv); /* macro name */ - const char *f; /* format control string */ - const char *fmt; /* position within f */ - char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */ - char *p; /* position within fstart */ - unsigned char c; /* a simple character */ + const char *name = M4ARG (0); /* Macro name. */ + const char *f; /* Format control string. */ + const char *fmt; /* Position within f. */ + char fstart[] = "%'+- 0#*.*hhd"; /* Current format spec. */ + char *p; /* Position within fstart. */ + unsigned char c; /* A simple character. */ + int index = 1; /* Index within argc used so far. */ /* Flags. */ char flags; /* flags to use in fstart */ @@ -89,7 +86,7 @@ format (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) char *str; /* malloc'd buffer of formatted text */ enum {CHAR, INT, LONG, DOUBLE, STR} datatype; - f = fmt = ARG_STR (argc, argv); + f = fmt = ARG_STR (index, argc, argv); memset (ok, 0, sizeof ok); for (;;) { @@ -174,7 +171,7 @@ format (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) *p++ = '*'; if (*fmt == '*') { - width = ARG_INT (argc, argv); + width = ARG_INT (index, argc, argv); fmt++; } else @@ -194,7 +191,7 @@ format (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) ok['c'] = 0; if (*(++fmt) == '*') { - prec = ARG_INT (argc, argv); + prec = ARG_INT (index, argc, argv); ++fmt; } else @@ -279,23 +276,24 @@ format (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv) switch (datatype) { case CHAR: - str = xasprintf (fstart, width, ARG_INT (argc, argv)); + str = xasprintf (fstart, width, ARG_INT (index, argc, argv)); break; case INT: - str = xasprintf (fstart, width, prec, ARG_INT (argc, argv)); + str = xasprintf (fstart, width, prec, ARG_INT (index, argc, argv)); break; case LONG: - str = xasprintf (fstart, width, prec, ARG_LONG (argc, argv)); + str = xasprintf (fstart, width, prec, ARG_LONG (index, argc, argv)); break; case DOUBLE: - str = xasprintf (fstart, width, prec, ARG_DOUBLE (argc, argv)); + str = xasprintf (fstart, width, prec, + ARG_DOUBLE (index, argc, argv)); break; case STR: - str = xasprintf (fstart, width, prec, ARG_STR (argc, argv)); + str = xasprintf (fstart, width, prec, ARG_STR (index, argc, argv)); break; default: diff --git a/modules/gnu.c b/modules/gnu.c index e857632..6fd6623 100644 --- a/modules/gnu.c +++ b/modules/gnu.c @@ -409,14 +409,14 @@ M4BUILTIN_HANDLER (builtin) const char *name; m4_symbol_value *value; - if (!m4_is_symbol_value_text (argv[1])) + if (!m4_is_symbol_value_text (argv->array[1 - 1])) { - if (m4_is_symbol_value_func (argv[1]) - && m4_get_symbol_value_func (argv[1]) == builtin_builtin) + if (m4_is_symbol_value_func (argv->array[1 - 1]) + && m4_get_symbol_value_func (argv->array[1 - 1]) == builtin_builtin) { if (m4_bad_argc (context, argc, me, 2, 2, false)) return; - if (!m4_is_symbol_value_text (argv[2])) + if (!m4_is_symbol_value_text (argv->array[2 - 1])) { m4_warn (context, 0, me, _("invalid macro name ignored")); return; @@ -448,11 +448,22 @@ M4BUILTIN_HANDLER (builtin) (bp->flags & M4_BUILTIN_SIDE_EFFECT) != 0)) { int i; + /* TODO - make use of $@ reference */ + m4_macro_args *new_argv; + new_argv = xmalloc (offsetof (m4_macro_args, array) + + ((argc - 2) * sizeof (m4_symbol_value *))); + new_argv->argc = argc - 1; + new_argv->inuse = false; + new_argv->argv0 = name; + new_argv->arraylen = argc - 2; + memcpy (&new_argv->array[0], &argv->array[1], + (argc - 2) * sizeof (m4_symbol_value *)); 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); + if (!m4_is_symbol_value_text (argv->array[i - 1])) + m4_set_symbol_value_text (new_argv->array[i - 2], ""); + bp->func (context, obs, argc - 1, new_argv); + free (new_argv); } free (value); } @@ -667,24 +678,36 @@ M4BUILTIN_HANDLER (format) **/ M4BUILTIN_HANDLER (indir) { - if (!m4_is_symbol_value_text (argv[1])) - m4_warn (context, 0, M4ARG (0), _("invalid macro name ignored")); + const char *me = M4ARG (0); + if (!m4_is_symbol_value_text (argv->array[1 - 1])) + m4_warn (context, 0, me, _("invalid macro name ignored")); else { const char *name = M4ARG (1); m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, name); if (symbol == NULL) - m4_warn (context, 0, M4ARG (0), _("undefined macro `%s'"), name); + m4_warn (context, 0, me, _("undefined macro `%s'"), name); else { int i; + /* TODO - make use of $@ reference */ + m4_macro_args *new_argv; + new_argv = xmalloc (offsetof (m4_macro_args, array) + + ((argc - 2) * sizeof (m4_symbol_value *))); + new_argv->argc = argc - 1; + new_argv->inuse = false; + new_argv->argv0 = name; + new_argv->arraylen = argc - 2; + memcpy (&new_argv->array[0], &argv->array[1], + (argc - 2) * sizeof (m4_symbol_value *)); if (!m4_symbol_groks_macro (symbol)) for (i = 2; i < argc; i++) - if (!m4_is_symbol_value_text (argv[i])) - m4_set_symbol_value_text (argv[i], ""); + if (!m4_is_symbol_value_text (argv->array[i - 1])) + m4_set_symbol_value_text (new_argv->array[i - 2], ""); m4_macro_call (context, m4_get_symbol_value (symbol), obs, - argc - 1, argv + 1); + argc - 1, new_argv); + free (new_argv); } } } diff --git a/modules/m4.c b/modules/m4.c index bffb274..7c0d8ed 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -50,7 +50,7 @@ extern void m4_set_sysval (int value); extern void m4_sysval_flush (m4 *context, bool report); extern void m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, int argc, - m4_symbol_value **argv, bool complain); + m4_macro_args *argv, bool complain); extern const char *m4_expand_ranges (const char *s, m4_obstack *obs); extern void m4_make_temp (m4 *context, m4_obstack *obs, const char *macro, const char *name, bool dir); @@ -102,7 +102,7 @@ extern void m4_make_temp (m4 *context, m4_obstack *obs, const char *macro, typedef intmax_t number; typedef uintmax_t unumber; -static void include (m4 *context, int argc, m4_symbol_value **argv, +static void include (m4 *context, int argc, m4_macro_args *argv, bool silent); static int dumpdef_cmp_CB (const void *s1, const void *s2); static void * dump_symbol_CB (m4_symbol_table *ignored, const char *name, @@ -113,7 +113,7 @@ static void numb_obstack (m4_obstack *obs, number value, /* Generate prototypes for each builtin handler function. */ -#define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN(handler) +#define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN (handler) builtin_functions #undef BUILTIN @@ -122,7 +122,7 @@ static void numb_obstack (m4_obstack *obs, number value, m4_builtin m4_builtin_table[] = { #define BUILTIN(handler, macros, blind, side, min, max) \ - { CONC(builtin_, handler), STR(handler), \ + { CONC (builtin_, handler), STR (handler), \ ((macros ? M4_BUILTIN_GROKS_MACRO : 0) \ | (blind ? M4_BUILTIN_BLIND : 0) \ | (side ? M4_BUILTIN_SIDE_EFFECT : 0)), \ @@ -160,14 +160,14 @@ M4INIT_HANDLER (m4) M4BUILTIN_HANDLER (define) { - if (m4_is_symbol_value_text (argv[1])) + if (m4_is_symbol_value_text (argv->array[1 - 1])) { m4_symbol_value *value = m4_symbol_value_create (); if (argc == 2) m4_set_symbol_value_text (value, xstrdup ("")); else - m4_symbol_value_copy (value, argv[2]); + m4_symbol_value_copy (value, argv->array[2 - 1]); m4_symbol_define (M4SYMTAB, M4ARG (1), value); } @@ -191,14 +191,14 @@ M4BUILTIN_HANDLER (undefine) M4BUILTIN_HANDLER (pushdef) { - if (m4_is_symbol_value_text (argv[1])) + if (m4_is_symbol_value_text (argv->array[1 - 1])) { m4_symbol_value *value = m4_symbol_value_create (); if (argc == 2) m4_set_symbol_value_text (value, xstrdup ("")); else - m4_symbol_value_copy (value, argv[2]); + m4_symbol_value_copy (value, argv->array[2 - 1]); m4_symbol_pushdef (M4SYMTAB, M4ARG (1), value); } @@ -248,6 +248,7 @@ M4BUILTIN_HANDLER (ifelse) { const char *me = M4ARG (0); const char *result; + int index; /* The valid ranges of argc for ifelse is discontinuous, we cannot rely on the regular mechanisms. */ @@ -260,14 +261,14 @@ M4BUILTIN_HANDLER (ifelse) /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */ m4_bad_argc (context, argc, me, 0, argc - 2, false); - argv++; + index = 1; argc--; result = NULL; while (result == NULL) - if (strcmp (M4ARG (0), M4ARG (1)) == 0) - result = M4ARG (2); + if (strcmp (M4ARG (index), M4ARG (index + 1)) == 0) + result = M4ARG (index + 2); else switch (argc) @@ -277,12 +278,12 @@ M4BUILTIN_HANDLER (ifelse) case 4: case 5: - result = M4ARG (3); + result = M4ARG (index + 3); break; default: argc -= 3; - argv += 3; + index += 3; } obstack_grow (obs, result, strlen (result)); @@ -327,7 +328,7 @@ dump_symbol_CB (m4_symbol_table *ignored, const char *name, m4_symbol *symbol, symbols, otherwise, only the specified symbols. */ void m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, int argc, - m4_symbol_value **argv, bool complain) + m4_macro_args *argv, bool complain) { assert (obstack_object_size (data->obs) == 0); data->size = obstack_room (data->obs) / sizeof (const char *); @@ -394,15 +395,16 @@ M4BUILTIN_HANDLER (dumpdef) macro-definition token on the input stack. */ M4BUILTIN_HANDLER (defn) { + const char *me = M4ARG (0); int i; for (i = 1; i < argc; i++) { - const char *name = m4_get_symbol_value_text (argv[i]); + const char *name = M4ARG (i); m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, name); if (!symbol) - m4_warn (context, 0, M4ARG (0), _("undefined macro `%s'"), name); + m4_warn (context, 0, me, _("undefined macro `%s'"), name); else if (m4_is_symbol_text (symbol)) m4_shipout_string (context, obs, m4_get_symbol_text (symbol), 0, true); else if (m4_is_symbol_func (symbol)) @@ -647,7 +649,7 @@ M4BUILTIN_HANDLER (dnl) output argument is quoted with the current quotes. */ M4BUILTIN_HANDLER (shift) { - m4_dump_args (context, obs, argc - 1, argv + 1, ",", true); + m4_dump_args (context, obs, 2, argv, ",", true); } /* Change the current quotes. The function set_quotes () lives in @@ -676,7 +678,7 @@ M4BUILTIN_HANDLER (changecom) /* Generic include function. Include the file given by the first argument, if it exists. Complain about inaccesible files iff SILENT is false. */ static void -include (m4 *context, int argc, m4_symbol_value **argv, bool silent) +include (m4 *context, int argc, m4_macro_args *argv, bool silent) { FILE *fp; char *name = NULL; @@ -806,7 +808,7 @@ M4BUILTIN_HANDLER (mkstemp) M4BUILTIN_HANDLER (errprint) { assert (obstack_object_size (obs) == 0); - m4_dump_args (context, obs, argc, argv, " ", false); + m4_dump_args (context, obs, 1, argv, " ", false); obstack_1grow (obs, '\0'); m4_sysval_flush (context, false); fputs ((char *) obstack_finish (obs), stderr); @@ -861,7 +863,7 @@ M4BUILTIN_HANDLER (m4wrap) if (m4_get_posixly_correct_opt (context)) m4_shipout_string (context, obs, M4ARG (1), 0, false); else - m4_dump_args (context, obs, argc, argv, " ", false); + m4_dump_args (context, obs, 1, argv, " ", false); obstack_1grow (obs, '\0'); m4_push_wrapup (context, obstack_finish (obs)); } diff --git a/modules/m4.h b/modules/m4.h index 5c14e25..4214aed 100644 --- a/modules/m4.h +++ b/modules/m4.h @@ -39,7 +39,7 @@ typedef struct typedef void m4_sysval_flush_func (m4 *context, bool report); typedef void m4_set_sysval_func (int value); typedef void m4_dump_symbols_func (m4 *context, m4_dump_symbol_data *data, - int argc, m4_symbol_value **argv, + int argc, m4_macro_args *argv, bool complain); typedef const char *m4_expand_ranges_func (const char *s, m4_obstack *obs); typedef void m4_make_temp_func (m4 *context, m4_obstack *obs, -- 1.5.3.5 From ac8845562f0066ef07d74a1f5b0e749eceb19b89 Mon Sep 17 00:00:00 2001 From: Eric Blake <[email protected]> Date: Fri, 19 Oct 2007 07:43:34 -0600 Subject: [PATCH] Stage 1: convert token_data** into new object. * m4/gnulib-cache.m4: Import flexmember module. * src/m4.h (struct macro_arguments, struct token_chain): New structs. (builtin_func): Alter signature. (token_data): Add new TOKEN_COMP alternative. * src/builtin.c: All builtins changed. (ARG, dump_args, define_macro, expand_user_macro): Update to use struct. * src/debug.c (trace_pre, trace_post): Likewise. * src/format.c (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE, format): Likewise. * src/macro.c (collect_arguments): Build new struct. (call_macro, expand_macro): Update to use new struct. (cherry picked from commit 44f5da7de32ac8f71f26d9e441316fa563db30d6) Signed-off-by: Eric Blake <[email protected]> --- ChangeLog | 17 +++++ m4/gnulib-cache.m4 | 4 +- src/builtin.c | 201 ++++++++++++++++++++++++++++++---------------------- src/debug.c | 10 ++-- src/format.c | 45 +++++------- src/m4.h | 71 ++++++++++++++----- src/macro.c | 51 ++++++++------ 7 files changed, 243 insertions(+), 156 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9bbf726..14deb9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2007-11-24 Eric Blake <[email protected]> + + Stage 1: convert token_data** into new object. + * m4/gnulib-cache.m4: Import flexmember module. + * src/m4.h (struct macro_arguments, struct token_chain): New + structs. + (builtin_func): Alter signature. + (token_data): Add new TOKEN_COMP alternative. + * src/builtin.c: All builtins changed. + (ARG, dump_args, define_macro, expand_user_macro): Update to use + struct. + * src/debug.c (trace_pre, trace_post): Likewise. + * src/format.c (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE, format): + Likewise. + * src/macro.c (collect_arguments): Build new struct. + (call_macro, expand_macro): Update to use new struct. + 2007-11-22 Eric Blake <[email protected]> More error messages tied to macro names. diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 4d1727d..a89650c 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -15,11 +15,11 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --local-dir=local --lib=libm4 --source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush fopen-safer free fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf xvasprintf-posix +# gnulib-tool --import --dir=. --local-dir=local --lib=libm4 --source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer free fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf xvasprintf-posix # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([local]) -gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush fopen-safer free fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf xvasprintf-posix]) +gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer free fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf xvasprintf-posix]) gl_AVOID([]) gl_SOURCE_BASE([lib]) gl_M4_BASE([m4]) diff --git a/src/builtin.c b/src/builtin.c index cc4e469..eb66465 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -30,14 +30,16 @@ # include <sys/wait.h> #endif -#define ARG(i) (argc > (i) ? TOKEN_DATA_TEXT (argv[i]) : "") +#define ARG(i) \ + ((i) == 0 ? argv->argv0 \ + : argv->argc > (i) ? TOKEN_DATA_TEXT (argv->array[(i) - 1]) : "") /* Initialization of builtin and predefined macros. The table "builtin_tab" is both used for initialization, and by the "builtin" builtin. */ #define DECLARE(name) \ - static void name (struct obstack *, int, token_data **) + static void name (struct obstack *, int, macro_arguments *) DECLARE (m4___file__); DECLARE (m4___line__); @@ -602,16 +604,19 @@ shipout_int (struct obstack *obs, int val) `----------------------------------------------------------------------*/ static void -dump_args (struct obstack *obs, int argc, token_data **argv, +dump_args (struct obstack *obs, int start, macro_arguments *argv, const char *sep, bool quoted) { int i; + bool dump_sep = false; size_t len = strlen (sep); - for (i = 1; i < argc; i++) + for (i = start; i < argv->argc; i++) { - if (i > 1) + if (dump_sep) obstack_grow (obs, sep, len); + else + dump_sep = true; if (quoted) obstack_grow (obs, lquote.string, lquote.length); obstack_grow (obs, ARG (i), strlen (ARG (i))); @@ -623,14 +628,15 @@ dump_args (struct obstack *obs, int argc, token_data **argv, /* The rest of this file is code for builtins and expansion of user defined macros. All the functions for builtins have a prototype as: - void m4_MACRONAME (struct obstack *obs, int argc, char *argv[]); + void m4_MACRONAME (struct obstack *obs, int argc, macro_arguments *argv); - The function are expected to leave their expansion on the obstack OBS, - as an unfinished object. ARGV is a table of ARGC pointers to the - individual arguments to the macro. Please note that in general - argv[argc] != NULL. */ + The functions are expected to leave their expansion on the obstack OBS, + as an unfinished object. ARGV is an object representing ARGC pointers + to the individual arguments to the macro; the object may be compressed + due to references to $@ expansions, so accessors should be used. Please + note that in general argv[argc] != NULL. */ -/* The first section are macros for definining, undefining, examining, +/* The first section are macros for defining, undefining, examining, changing, ... other macros. */ /*-------------------------------------------------------------------------. @@ -641,7 +647,7 @@ dump_args (struct obstack *obs, int argc, token_data **argv, `-------------------------------------------------------------------------*/ static void -define_macro (int argc, token_data **argv, symbol_lookup mode) +define_macro (int argc, macro_arguments *argv, symbol_lookup mode) { const builtin *bp; const char *me = ARG (0); @@ -649,7 +655,7 @@ define_macro (int argc, token_data **argv, symbol_lookup mode) if (bad_argc (me, argc, 1, 2)) return; - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) + if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT) { m4_warn (0, me, _("invalid macro name ignored")); return; @@ -661,14 +667,14 @@ define_macro (int argc, token_data **argv, symbol_lookup mode) return; } - switch (TOKEN_DATA_TYPE (argv[2])) + switch (TOKEN_DATA_TYPE (argv->array[1])) { case TOKEN_TEXT: define_user_macro (ARG (1), ARG (2), mode); break; case TOKEN_FUNC: - bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[2])); + bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv->array[1])); if (bp == NULL) return; else @@ -682,13 +688,13 @@ define_macro (int argc, token_data **argv, symbol_lookup mode) } static void -m4_define (struct obstack *obs, int argc, token_data **argv) +m4_define (struct obstack *obs, int argc, macro_arguments *argv) { define_macro (argc, argv, SYMBOL_INSERT); } static void -m4_undefine (struct obstack *obs, int argc, token_data **argv) +m4_undefine (struct obstack *obs, int argc, macro_arguments *argv) { int i; if (bad_argc (ARG (0), argc, 1, -1)) @@ -698,13 +704,13 @@ m4_undefine (struct obstack *obs, int argc, token_data **argv) } static void -m4_pushdef (struct obstack *obs, int argc, token_data **argv) +m4_pushdef (struct obstack *obs, int argc, macro_arguments *argv) { - define_macro (argc, argv, SYMBOL_PUSHDEF); + define_macro (argc, argv, SYMBOL_PUSHDEF); } static void -m4_popdef (struct obstack *obs, int argc, token_data **argv) +m4_popdef (struct obstack *obs, int argc, macro_arguments *argv) { int i; if (bad_argc (ARG (0), argc, 1, -1)) @@ -718,7 +724,7 @@ m4_popdef (struct obstack *obs, int argc, token_data **argv) `---------------------*/ static void -m4_ifdef (struct obstack *obs, int argc, token_data **argv) +m4_ifdef (struct obstack *obs, int argc, macro_arguments *argv) { symbol *s; const char *result; @@ -739,10 +745,11 @@ m4_ifdef (struct obstack *obs, int argc, token_data **argv) } static void -m4_ifelse (struct obstack *obs, int argc, token_data **argv) +m4_ifelse (struct obstack *obs, int argc, macro_arguments *argv) { const char *result; const char *me; + int index; if (argc == 2) return; @@ -754,14 +761,14 @@ m4_ifelse (struct obstack *obs, int argc, token_data **argv) /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */ bad_argc (me, argc, 0, argc - 2); - argv++; + index = 1; argc--; result = NULL; while (result == NULL) - if (strcmp (ARG (0), ARG (1)) == 0) - result = ARG (2); + if (strcmp (ARG (index), ARG (index + 1)) == 0) + result = ARG (index + 2); else switch (argc) @@ -771,12 +778,12 @@ m4_ifelse (struct obstack *obs, int argc, token_data **argv) case 4: case 5: - result = ARG (3); + result = ARG (index + 3); break; default: argc -= 3; - argv += 3; + index += 3; } obstack_grow (obs, result, strlen (result)); @@ -826,7 +833,7 @@ dumpdef_cmp (const void *s1, const void *s2) `-------------------------------------------------------------------------*/ static void -m4_dumpdef (struct obstack *obs, int argc, token_data **argv) +m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); symbol *s; @@ -900,7 +907,7 @@ m4_dumpdef (struct obstack *obs, int argc, token_data **argv) `---------------------------------------------------------------------*/ static void -m4_builtin (struct obstack *obs, int argc, token_data **argv) +m4_builtin (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); const builtin *bp; @@ -908,7 +915,7 @@ m4_builtin (struct obstack *obs, int argc, token_data **argv) if (bad_argc (me, argc, 1, -1)) return; - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) + if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT) { m4_warn (0, me, _("invalid macro name ignored")); return; @@ -921,14 +928,25 @@ m4_builtin (struct obstack *obs, int argc, token_data **argv) else { int i; + /* TODO make use of $@ reference, instead of copying argv. */ + macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array) + + ((argc - 2) + * sizeof (token_data *))); + new_argv->argc = argc - 1; + new_argv->inuse = false; + new_argv->argv0 = name; + new_argv->arraylen = argc - 2; + memcpy (&new_argv->array[0], &argv->array[1], + (argc - 2) * sizeof (token_data *)); if (!bp->groks_macro_args) for (i = 2; i < argc; i++) - if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT) + if (TOKEN_DATA_TYPE (new_argv->array[i - 2]) != TOKEN_TEXT) { - TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT; - TOKEN_DATA_TEXT (argv[i]) = (char *) ""; + TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT; + TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) ""; } - bp->func (obs, argc - 1, argv + 1); + bp->func (obs, argc - 1, new_argv); + free (new_argv); } } @@ -940,7 +958,7 @@ m4_builtin (struct obstack *obs, int argc, token_data **argv) `------------------------------------------------------------------------*/ static void -m4_indir (struct obstack *obs, int argc, token_data **argv) +m4_indir (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); symbol *s; @@ -948,7 +966,7 @@ m4_indir (struct obstack *obs, int argc, token_data **argv) if (bad_argc (me, argc, 1, -1)) return; - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) + if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT) { m4_warn (0, me, _("invalid macro name ignored")); return; @@ -961,14 +979,25 @@ m4_indir (struct obstack *obs, int argc, token_data **argv) else { int i; + /* TODO make use of $@ reference, instead of copying argv. */ + macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array) + + ((argc - 2) + * sizeof (token_data *))); + new_argv->argc = argc - 1; + new_argv->inuse = false; + new_argv->argv0 = name; + new_argv->arraylen = argc - 2; + memcpy (&new_argv->array[0], &argv->array[1], + (argc - 2) * sizeof (token_data *)); if (!SYMBOL_MACRO_ARGS (s)) for (i = 2; i < argc; i++) - if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT) + if (TOKEN_DATA_TYPE (new_argv->array[i - 2]) != TOKEN_TEXT) { - TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT; - TOKEN_DATA_TEXT (argv[i]) = (char *) ""; + TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT; + TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) ""; } - call_macro (s, argc - 1, argv + 1, obs); + call_macro (s, argc - 1, new_argv, obs); + free (new_argv); } } @@ -979,7 +1008,7 @@ m4_indir (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_defn (struct obstack *obs, int argc, token_data **argv) +m4_defn (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); symbol *s; @@ -1060,7 +1089,7 @@ m4_defn (struct obstack *obs, int argc, token_data **argv) static int sysval; static void -m4_syscmd (struct obstack *obs, int argc, token_data **argv) +m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, 1)) { @@ -1084,7 +1113,7 @@ m4_syscmd (struct obstack *obs, int argc, token_data **argv) } static void -m4_esyscmd (struct obstack *obs, int argc, token_data **argv) +m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); FILE *pin; @@ -1114,7 +1143,7 @@ m4_esyscmd (struct obstack *obs, int argc, token_data **argv) } static void -m4_sysval (struct obstack *obs, int argc, token_data **argv) +m4_sysval (struct obstack *obs, int argc, macro_arguments *argv) { shipout_int (obs, (sysval == -1 ? 127 : (M4SYSVAL_EXITBITS (sysval) @@ -1127,7 +1156,7 @@ m4_sysval (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_eval (struct obstack *obs, int argc, token_data **argv) +m4_eval (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int32_t value = 0; @@ -1190,7 +1219,7 @@ m4_eval (struct obstack *obs, int argc, token_data **argv) } static void -m4_incr (struct obstack *obs, int argc, token_data **argv) +m4_incr (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int value; @@ -1205,7 +1234,7 @@ m4_incr (struct obstack *obs, int argc, token_data **argv) } static void -m4_decr (struct obstack *obs, int argc, token_data **argv) +m4_decr (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int value; @@ -1228,7 +1257,7 @@ m4_decr (struct obstack *obs, int argc, token_data **argv) `-----------------------------------------------------------------------*/ static void -m4_divert (struct obstack *obs, int argc, token_data **argv) +m4_divert (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int i = 0; @@ -1245,7 +1274,7 @@ m4_divert (struct obstack *obs, int argc, token_data **argv) `-----------------------------------------------------*/ static void -m4_divnum (struct obstack *obs, int argc, token_data **argv) +m4_divnum (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 0); shipout_int (obs, current_diversion); @@ -1259,7 +1288,7 @@ m4_divnum (struct obstack *obs, int argc, token_data **argv) `-----------------------------------------------------------------------*/ static void -m4_undivert (struct obstack *obs, int argc, token_data **argv) +m4_undivert (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int i; @@ -1303,7 +1332,7 @@ m4_undivert (struct obstack *obs, int argc, token_data **argv) `------------------------------------------------------------------------*/ static void -m4_dnl (struct obstack *obs, int argc, token_data **argv) +m4_dnl (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); @@ -1317,11 +1346,12 @@ m4_dnl (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_shift (struct obstack *obs, int argc, token_data **argv) +m4_shift (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, -1)) return; - dump_args (obs, argc - 1, argv + 1, ",", true); + /* TODO push a $@ reference. */ + dump_args (obs, 2, argv, ",", true); } /*--------------------------------------------------------------------------. @@ -1329,13 +1359,13 @@ m4_shift (struct obstack *obs, int argc, token_data **argv) `--------------------------------------------------------------------------*/ static void -m4_changequote (struct obstack *obs, int argc, token_data **argv) +m4_changequote (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 2); /* Explicit NULL distinguishes between empty and missing argument. */ set_quotes ((argc >= 2) ? ARG (1) : NULL, - (argc >= 3) ? ARG (2) : NULL); + (argc >= 3) ? ARG (2) : NULL); } /*--------------------------------------------------------------------. @@ -1344,7 +1374,7 @@ m4_changequote (struct obstack *obs, int argc, token_data **argv) `--------------------------------------------------------------------*/ static void -m4_changecom (struct obstack *obs, int argc, token_data **argv) +m4_changecom (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 2); @@ -1361,7 +1391,7 @@ m4_changecom (struct obstack *obs, int argc, token_data **argv) `-----------------------------------------------------------------------*/ static void -m4_changeword (struct obstack *obs, int argc, token_data **argv) +m4_changeword (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); @@ -1382,7 +1412,7 @@ m4_changeword (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -include (int argc, token_data **argv, bool silent) +include (int argc, macro_arguments *argv, bool silent) { const char *me = ARG (0); FILE *fp; @@ -1408,7 +1438,7 @@ include (int argc, token_data **argv, bool silent) `------------------------------------------------*/ static void -m4_include (struct obstack *obs, int argc, token_data **argv) +m4_include (struct obstack *obs, int argc, macro_arguments *argv) { include (argc, argv, false); } @@ -1418,7 +1448,7 @@ m4_include (struct obstack *obs, int argc, token_data **argv) `----------------------------------*/ static void -m4_sinclude (struct obstack *obs, int argc, token_data **argv) +m4_sinclude (struct obstack *obs, int argc, macro_arguments *argv) { include (argc, argv, true); } @@ -1462,7 +1492,7 @@ mkstemp_helper (struct obstack *obs, const char *me, const char *name) } static void -m4_maketemp (struct obstack *obs, int argc, token_data **argv) +m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); @@ -1507,7 +1537,7 @@ m4_maketemp (struct obstack *obs, int argc, token_data **argv) } static void -m4_mkstemp (struct obstack *obs, int argc, token_data **argv) +m4_mkstemp (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); @@ -1521,11 +1551,11 @@ m4_mkstemp (struct obstack *obs, int argc, token_data **argv) `----------------------------------------*/ static void -m4_errprint (struct obstack *obs, int argc, token_data **argv) +m4_errprint (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, -1)) return; - dump_args (obs, argc, argv, " ", false); + dump_args (obs, 1, argv, " ", false); obstack_1grow (obs, '\0'); debug_flush_files (); xfprintf (stderr, "%s", (char *) obstack_finish (obs)); @@ -1533,7 +1563,7 @@ m4_errprint (struct obstack *obs, int argc, token_data **argv) } static void -m4___file__ (struct obstack *obs, int argc, token_data **argv) +m4___file__ (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 0); obstack_grow (obs, lquote.string, lquote.length); @@ -1542,14 +1572,14 @@ m4___file__ (struct obstack *obs, int argc, token_data **argv) } static void -m4___line__ (struct obstack *obs, int argc, token_data **argv) +m4___line__ (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 0); shipout_int (obs, current_line); } static void -m4___program__ (struct obstack *obs, int argc, token_data **argv) +m4___program__ (struct obstack *obs, int argc, macro_arguments *argv) { bad_argc (ARG (0), argc, 0, 0); obstack_grow (obs, lquote.string, lquote.length); @@ -1567,7 +1597,7 @@ m4___program__ (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_m4exit (struct obstack *obs, int argc, token_data **argv) +m4_m4exit (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int exit_code = EXIT_SUCCESS; @@ -1600,14 +1630,14 @@ m4_m4exit (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_m4wrap (struct obstack *obs, int argc, token_data **argv) +m4_m4wrap (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, -1)) return; if (no_gnu_extensions) obstack_grow (obs, ARG (1), strlen (ARG (1))); else - dump_args (obs, argc, argv, " ", false); + dump_args (obs, 1, argv, " ", false); obstack_1grow (obs, '\0'); push_wrapup ((char *) obstack_finish (obs)); } @@ -1632,7 +1662,7 @@ set_trace (symbol *sym, void *data) } static void -m4_traceon (struct obstack *obs, int argc, token_data **argv) +m4_traceon (struct obstack *obs, int argc, macro_arguments *argv) { symbol *s; int i; @@ -1652,7 +1682,7 @@ m4_traceon (struct obstack *obs, int argc, token_data **argv) `------------------------------------------------------------------------*/ static void -m4_traceoff (struct obstack *obs, int argc, token_data **argv) +m4_traceoff (struct obstack *obs, int argc, macro_arguments *argv) { symbol *s; int i; @@ -1675,7 +1705,7 @@ m4_traceoff (struct obstack *obs, int argc, token_data **argv) `----------------------------------------------------------------------*/ static void -m4_debugmode (struct obstack *obs, int argc, token_data **argv) +m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); const char *str = ARG (1); @@ -1727,7 +1757,7 @@ m4_debugmode (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_debugfile (struct obstack *obs, int argc, token_data **argv) +m4_debugfile (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); @@ -1748,7 +1778,7 @@ m4_debugfile (struct obstack *obs, int argc, token_data **argv) `---------------------------------------------*/ static void -m4_len (struct obstack *obs, int argc, token_data **argv) +m4_len (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, 1)) return; @@ -1761,7 +1791,7 @@ m4_len (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_index (struct obstack *obs, int argc, token_data **argv) +m4_index (struct obstack *obs, int argc, macro_arguments *argv) { const char *haystack; const char *needle; @@ -1801,7 +1831,7 @@ m4_index (struct obstack *obs, int argc, token_data **argv) `-------------------------------------------------------------------------*/ static void -m4_substr (struct obstack *obs, int argc, token_data **argv) +m4_substr (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); int start = 0; @@ -1885,7 +1915,7 @@ expand_ranges (const char *s, struct obstack *obs) `----------------------------------------------------------------------*/ static void -m4_translit (struct obstack *obs, int argc, token_data **argv) +m4_translit (struct obstack *obs, int argc, macro_arguments *argv) { const char *data; const char *from; @@ -1950,7 +1980,7 @@ m4_translit (struct obstack *obs, int argc, token_data **argv) `--------------------------------------------------------------*/ static void -m4_format (struct obstack *obs, int argc, token_data **argv) +m4_format (struct obstack *obs, int argc, macro_arguments *argv) { if (bad_argc (ARG (0), argc, 1, -1)) return; @@ -2047,7 +2077,7 @@ init_pattern_buffer (struct re_pattern_buffer *buf, struct re_registers *regs) `------------------------------------------------------------------*/ static void -m4_regexp (struct obstack *obs, int argc, token_data **argv) +m4_regexp (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); const char *victim; /* first argument */ @@ -2117,7 +2147,7 @@ m4_regexp (struct obstack *obs, int argc, token_data **argv) `------------------------------------------------------------------*/ static void -m4_patsubst (struct obstack *obs, int argc, token_data **argv) +m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv) { const char *me = ARG (0); const char *victim; /* first argument */ @@ -2222,7 +2252,7 @@ m4_patsubst (struct obstack *obs, int argc, token_data **argv) `--------------------------------------------------------------------*/ void -m4_placeholder (struct obstack *obs, int argc, token_data **argv) +m4_placeholder (struct obstack *obs, int argc, macro_arguments *argv) { m4_warn (0, NULL, _("builtin `%s' requested by frozen file not found"), ARG (0)); @@ -2238,7 +2268,7 @@ m4_placeholder (struct obstack *obs, int argc, token_data **argv) void expand_user_macro (struct obstack *obs, symbol *sym, - int argc, token_data **argv) + int argc, macro_arguments *argv) { const char *text; int i; @@ -2263,7 +2293,7 @@ expand_user_macro (struct obstack *obs, symbol *sym, else { for (i = 0; isdigit (to_uchar (*text)); text++) - i = i*10 + (*text - '0'); + i = i * 10 + (*text - '0'); } if (i < argc) obstack_grow (obs, ARG (i), strlen (ARG (i))); @@ -2276,7 +2306,8 @@ expand_user_macro (struct obstack *obs, symbol *sym, case '*': /* all arguments */ case '@': /* ... same, but quoted */ - dump_args (obs, argc, argv, ",", *text == '@'); + /* TODO push a $@ reference. */ + dump_args (obs, 1, argv, ",", *text == '@'); text++; break; diff --git a/src/debug.c b/src/debug.c index c22a482..e5bd280 100644 --- a/src/debug.c +++ b/src/debug.c @@ -362,7 +362,7 @@ trace_prepre (const char *name, int id) `-----------------------------------------------------------------------*/ void -trace_pre (const char *name, int id, int argc, token_data **argv) +trace_pre (const char *name, int id, int argc, macro_arguments *argv) { int i; const builtin *bp; @@ -379,14 +379,14 @@ trace_pre (const char *name, int id, int argc, token_data **argv) if (i != 1) trace_format (", "); - switch (TOKEN_DATA_TYPE (argv[i])) + switch (TOKEN_DATA_TYPE (argv->array[i - 1])) { case TOKEN_TEXT: - trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i])); + trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv->array[i - 1])); break; case TOKEN_FUNC: - bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i])); + bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv->array[i - 1])); if (bp == NULL) { assert (!"trace_pre"); @@ -417,7 +417,7 @@ trace_pre (const char *name, int id, int argc, token_data **argv) `-------------------------------------------------------------------*/ void -trace_post (const char *name, int id, int argc, token_data **argv, +trace_post (const char *name, int id, int argc, macro_arguments *argv, const char *expanded) { if (debug_level & DEBUG_TRACE_CALL) diff --git a/src/format.c b/src/format.c index 96ac562..4c2b60a 100644 --- a/src/format.c +++ b/src/format.c @@ -27,21 +27,17 @@ /* Simple varargs substitute. We assume int and unsigned int are the same size; likewise for long and unsigned long. */ -#define ARG_INT(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1])))) +#define ARG_INT(i, argc, argv) \ + ((i == argc) ? 0 : atoi (TOKEN_DATA_TEXT (argv->array[i++ - 1]))) -#define ARG_LONG(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1])))) +#define ARG_LONG(i, argc, argv) \ + ((i == argc) ? 0L : atol (TOKEN_DATA_TEXT (argv->array[i++ - 1]))) -#define ARG_STR(argc, argv) \ - ((argc == 0) ? "" : \ - (--argc, argv++, TOKEN_DATA_TEXT (argv[-1]))) +#define ARG_STR(i, argc, argv) \ + ((i == argc) ? "" : TOKEN_DATA_TEXT (argv->array[i++ - 1])) -#define ARG_DOUBLE(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1])))) +#define ARG_DOUBLE(i, argc, argv) \ + ((i == argc) ? 0.0 : atof (TOKEN_DATA_TEXT (argv->array[i++ - 1]))) /*------------------------------------------------------------------. @@ -53,14 +49,15 @@ `------------------------------------------------------------------*/ void -format (struct obstack *obs, int argc, token_data **argv) +format (struct obstack *obs, int argc, macro_arguments *argv) { - const char *me = TOKEN_DATA_TEXT (argv[0]); + const char *me = argv->argv0; const char *f; /* format control string */ const char *fmt; /* position within f */ char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */ char *p; /* position within fstart */ unsigned char c; /* a simple character */ + int index = 1; /* index within argc used so far */ /* Flags. */ char flags; /* flags to use in fstart */ @@ -88,9 +85,7 @@ format (struct obstack *obs, int argc, token_data **argv) char *str; /* malloc'd buffer of formatted text */ enum {CHAR, INT, LONG, DOUBLE, STR} datatype; - argv++; - argc--; - f = fmt = ARG_STR (argc, argv); + f = fmt = ARG_STR (index, argc, argv); memset (ok, 0, sizeof ok); for (;;) { @@ -175,7 +170,7 @@ format (struct obstack *obs, int argc, token_data **argv) *p++ = '*'; if (*fmt == '*') { - width = ARG_INT (argc, argv); + width = ARG_INT (index, argc, argv); fmt++; } else @@ -195,7 +190,7 @@ format (struct obstack *obs, int argc, token_data **argv) ok['c'] = 0; if (*(++fmt) == '*') { - prec = ARG_INT (argc, argv); + prec = ARG_INT (index, argc, argv); ++fmt; } else @@ -280,27 +275,27 @@ format (struct obstack *obs, int argc, token_data **argv) switch (datatype) { case CHAR: - str = xasprintf (fstart, width, ARG_INT(argc, argv)); + str = xasprintf (fstart, width, ARG_INT (index, argc, argv)); break; case INT: - str = xasprintf (fstart, width, prec, ARG_INT(argc, argv)); + str = xasprintf (fstart, width, prec, ARG_INT (index, argc, argv)); break; case LONG: - str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv)); + str = xasprintf (fstart, width, prec, ARG_LONG (index, argc, argv)); break; case DOUBLE: - str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv)); + str = xasprintf (fstart, width, prec, ARG_DOUBLE (index, argc, argv)); break; case STR: - str = xasprintf (fstart, width, prec, ARG_STR(argc, argv)); + str = xasprintf (fstart, width, prec, ARG_STR (index, argc, argv)); break; default: - abort(); + abort (); } /* NULL was returned on failure, such as invalid format string. diff --git a/src/m4.h b/src/m4.h index 4f1fa1f..94276e9 100644 --- a/src/m4.h +++ b/src/m4.h @@ -89,7 +89,8 @@ typedef struct string STRING; /* Those must come first. */ typedef struct token_data token_data; -typedef void builtin_func (struct obstack *, int, token_data **); +typedef struct macro_arguments macro_arguments; +typedef void builtin_func (struct obstack *, int, macro_arguments *); /* Gnulib's stdbool doesn't work with bool bitfields. For nicer debugging, use bool when we know it works, but use the more @@ -103,14 +104,14 @@ typedef unsigned int bool_bitfield; /* Take advantage of GNU C compiler source level optimization hints, using portable macros. */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6) -# define M4_GNUC_ATTRIBUTE(args) __attribute__(args) +# define M4_GNUC_ATTRIBUTE(args) __attribute__ (args) #else # define M4_GNUC_ATTRIBUTE(args) #endif /* __GNUC__ */ -#define M4_GNUC_UNUSED M4_GNUC_ATTRIBUTE((__unused__)) +#define M4_GNUC_UNUSED M4_GNUC_ATTRIBUTE ((__unused__)) #define M4_GNUC_PRINTF(fmt, arg) \ - M4_GNUC_ATTRIBUTE((__format__ (__printf__, fmt, arg))) + M4_GNUC_ATTRIBUTE ((__format__ (__printf__, fmt, arg))) /* File: m4.c --- global definitions. */ @@ -132,12 +133,13 @@ extern const char *user_word_regexp; /* -W */ extern int retcode; extern const char *program_name; -void m4_error (int, int, const char *, const char *, ...) M4_GNUC_PRINTF(4, 5); +void m4_error (int, int, const char *, const char *, ...) + M4_GNUC_PRINTF (4, 5); void m4_error_at_line (int, int, const char *, int, const char *, - const char *, ...) M4_GNUC_PRINTF(6, 7); -void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF(3, 4); + const char *, ...) M4_GNUC_PRINTF (6, 7); +void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF (3, 4); void m4_warn_at_line (int, const char *, int, const char *, - const char *, ...) M4_GNUC_PRINTF(5, 6); + const char *, ...) M4_GNUC_PRINTF (5, 6); #ifdef USE_STACKOVF void setup_stackovf_trap (char *const *, char *const *, @@ -235,11 +237,13 @@ bool debug_set_output (const char *, const char *); void debug_message_prefix (void); void trace_prepre (const char *, int); -void trace_pre (const char *, int, int, token_data **); -void trace_post (const char *, int, int, token_data **, const char *); +void trace_pre (const char *, int, int, macro_arguments *); +void trace_post (const char *, int, int, macro_arguments *, const char *); /* File: input.c --- lexical definitions. */ +typedef struct token_chain token_chain; + /* Various different token types. */ enum token_type { @@ -256,9 +260,19 @@ enum token_type /* The data for a token, a macro argument, and a macro definition. */ enum token_data_type { - TOKEN_VOID, - TOKEN_TEXT, - TOKEN_FUNC + TOKEN_VOID, /* Token still being constructed, u is invalid. */ + TOKEN_TEXT, /* Straight text, u.u_t is valid. */ + TOKEN_FUNC, /* Builtin function definition, u.func is valid. */ + TOKEN_COMP /* Composite argument, u.chain is valid. */ +}; + +/* Composite tokens are built of a linked list of chains. */ +struct token_chain +{ + token_chain *next; /* Pointer to next link of chain. */ + char *str; /* NUL-terminated string if text, else NULL. */ + macro_arguments *argv; /* Reference to earlier $@. */ + unsigned int index; /* Index within argv to start reading from. */ }; struct token_data @@ -275,10 +289,31 @@ struct token_data } u_t; builtin_func *func; + + /* Composite text: a linked list of straight text and $@ + placeholders. */ + token_chain *chain; } u; }; +struct macro_arguments +{ + /* Number of arguments owned by this object, may be larger than + arraylen since the array can refer to multiple arguments via a + single $@ reference. */ + unsigned int argc; + /* False unless the macro expansion refers to $@, determines whether + this object can be freed at end of macro expansion or must wait + until next byte read from file. */ + bool inuse; + const char *argv0; /* The macro name being expanded. */ + size_t arraylen; /* True length of allocated elements in array. */ + /* Used as a variable-length array, storing information about each + argument. */ + token_data *array[FLEXIBLE_ARRAY_MEMBER]; +}; + #define TOKEN_DATA_TYPE(Td) ((Td)->type) #define TOKEN_DATA_TEXT(Td) ((Td)->u.u_t.text) #ifdef ENABLE_CHANGEWORD @@ -358,7 +393,7 @@ struct symbol int pending_expansions; char *name; - token_data data; + token_data data; /* Type should be only TOKEN_TEXT or TOKEN_FUNC. */ }; #define SYMBOL_NEXT(S) ((S)->next) @@ -391,7 +426,7 @@ void hack_all_symbols (hack_symbol *, void *); extern int expansion_level; void expand_input (void); -void call_macro (symbol *, int, token_data **, struct obstack *); +void call_macro (symbol *, int, macro_arguments *, struct obstack *); /* File: builtin.c --- builtins. */ @@ -427,8 +462,8 @@ void set_macro_sequence (const char *); void free_regex (void); void define_user_macro (const char *, const char *, symbol_lookup); void undivert_all (void); -void expand_user_macro (struct obstack *, symbol *, int, token_data **); -void m4_placeholder (struct obstack *, int, token_data **); +void expand_user_macro (struct obstack *, symbol *, int, macro_arguments *); +void m4_placeholder (struct obstack *, int, macro_arguments *); void init_pattern_buffer (struct re_pattern_buffer *, struct re_registers *); const char *ntoa (int32_t, int); @@ -448,7 +483,7 @@ bool evaluate (const char *, const char *, int32_t *); /* File: format.c --- printf like formatting. */ -void format (struct obstack *, int, token_data **); +void format (struct obstack *, int, macro_arguments *); /* File: freeze.c --- frozen state files. */ diff --git a/src/macro.c b/src/macro.c index 8a678d4..d2f2cb7 100644 --- a/src/macro.c +++ b/src/macro.c @@ -241,19 +241,22 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller) | on the obstack ARGPTR. | `-------------------------------------------------------------------------*/ -static void -collect_arguments (symbol *sym, struct obstack *argptr, +static macro_arguments * +collect_arguments (symbol *sym, struct obstack *argptr, unsigned argv_base, struct obstack *arguments) { token_data td; token_data *tdp; bool more_args; bool groks_macro_args = SYMBOL_MACRO_ARGS (sym); + macro_arguments args; + macro_arguments *argv; - TOKEN_DATA_TYPE (&td) = TOKEN_TEXT; - TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym); - tdp = (token_data *) obstack_copy (arguments, &td, sizeof td); - obstack_ptr_grow (argptr, tdp); + args.argc = 1; + args.inuse = false; + args.argv0 = SYMBOL_NAME (sym); + args.arraylen = 0; + obstack_grow (argptr, &args, offsetof (macro_arguments, array)); if (peek_token () == TOKEN_OPEN) { @@ -269,9 +272,15 @@ collect_arguments (symbol *sym, struct obstack *argptr, } tdp = (token_data *) obstack_copy (arguments, &td, sizeof td); obstack_ptr_grow (argptr, tdp); + args.arraylen++; + args.argc++; } while (more_args); } + argv = (macro_arguments *) ((char *) obstack_base (argptr) + argv_base); + argv->argc = args.argc; + argv->arraylen = args.arraylen; + return argv; } @@ -285,13 +294,13 @@ collect_arguments (symbol *sym, struct obstack *argptr, `------------------------------------------------------------------------*/ void -call_macro (symbol *sym, int argc, token_data **argv, - struct obstack *expansion) +call_macro (symbol *sym, int argc, macro_arguments *argv, + struct obstack *expansion) { switch (SYMBOL_TYPE (sym)) { case TOKEN_FUNC: - (*SYMBOL_FUNC (sym)) (expansion, argc, argv); + SYMBOL_FUNC (sym) (expansion, argc, argv); break; case TOKEN_TEXT: @@ -319,8 +328,8 @@ expand_macro (symbol *sym) { struct obstack arguments; /* Alternate obstack if argc_stack is busy. */ unsigned argv_base; /* Size of argv_stack on entry. */ - bool use_argc_stack = true; /* Whether argc_stack is safe. */ - token_data **argv; + void *argc_start; /* Start of argc_stack, else NULL if unsafe. */ + macro_arguments *argv; int argc; struct obstack *expansion; const char *expanded; @@ -357,18 +366,17 @@ expand_macro (symbol *sym) outer invocation has an unfinished argument being collected. */ obstack_init (&arguments); - use_argc_stack = false; + argc_start = NULL; } + else + argc_start = obstack_finish (&argc_stack); if (traced && (debug_level & DEBUG_TRACE_CALL)) trace_prepre (SYMBOL_NAME (sym), my_call_id); - collect_arguments (sym, &argv_stack, - use_argc_stack ? &argc_stack : &arguments); - - argc = ((obstack_object_size (&argv_stack) - argv_base) - / sizeof (token_data *)); - argv = (token_data **) ((char *) obstack_base (&argv_stack) + argv_base); + argv = collect_arguments (sym, &argv_stack, argv_base, + argc_start ? &argc_stack : &arguments); + argc = argv->argc; loc_close_file = current_file; loc_close_line = current_line; @@ -394,9 +402,10 @@ expand_macro (symbol *sym) if (SYMBOL_DELETED (sym)) free_symbol (sym); - if (use_argc_stack) - obstack_free (&argc_stack, argv[0]); + /* TODO pay attention to argv->inuse, in case someone is depending on $@. */ + if (argc_start) + obstack_free (&argc_stack, argc_start); else obstack_free (&arguments, NULL); - obstack_blank (&argv_stack, -argc * sizeof (token_data *)); + obstack_blank (&argv_stack, argv_base - obstack_object_size (&argv_stack)); } -- 1.5.3.5