summaryrefslogtreecommitdiff
path: root/m4
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2008-03-13 21:01:39 -0600
committerEric Blake <ebb9@byu.net>2008-03-13 21:09:33 -0600
commita2df6b461c098df5a505d79d119538b3a294e301 (patch)
treefdcd7642ec806c0690de278ddcb21d7228e601aa /m4
parent2f49d755e50a574e5a772893f3f5d683495084bc (diff)
downloadm4-a2df6b461c098df5a505d79d119538b3a294e301.tar.gz
Stage 19c: allow builtin tokens in more macros.
* m4/m4module.h (m4_symbol_value_lookup, m4_builtin_print): New prototypes. * m4/m4private.h (enum m4__symbol_chain_type): Add M4__CHAIN_FUNC. (struct m4__symbol_chain): Add builtin member. * m4/utility.c (m4_symbol_value_lookup): New method. * m4/builtin.c (m4_builtin_print): New function. * m4/symtab.c (m4_symbol_value_print): Use it. * m4/input.c (builtin_print): Likewise. (m4__push_symbol): Allow pushing builtin tokens. (composite_peek, composite_read, composite_unget, composite_clean) (composite_print): Handle builtin tokens. (init_builtin_token): Allow builtin tokens from composite input. (m4__next_token): Flatten builtins inside comment or string. * m4/macro.c (expand_argument): Strengthen assertion. (collect_arguments, m4_arg_equal, m4_arg_print, m4_push_args): Handle builtin tokens. (arg_symbol): Add parameter, and allow NULL level. (m4_arg_symbol, m4__push_arg_quote): Adjust callers. (m4_arg_text): Ensure all builtins have been flattened. * modules/m4.c (defn, dumpdef, popdef, traceoff, traceon) (undefine, m4_dump_symbols): Warn on invalid macro names. (ifdef, ifelse, shift): Handle builtin tokens. * modules/gnu.c (m4symbols): Likewise. * doc/m4.texinfo (Defn, Ifdef, Ifelse): Document and test the new behavior. (Debuglen): Likewise, and remove xfail. * NEWS: Mention the change. Signed-off-by: Eric Blake <ebb9@byu.net>
Diffstat (limited to 'm4')
-rw-r--r--m4/builtin.c32
-rw-r--r--m4/input.c201
-rw-r--r--m4/m4module.h6
-rw-r--r--m4/m4private.h3
-rw-r--r--m4/macro.c95
-rw-r--r--m4/symtab.c27
-rw-r--r--m4/utility.c21
7 files changed, 289 insertions, 96 deletions
diff --git a/m4/builtin.c b/m4/builtin.c
index 7f9d9578..5228abc7 100644
--- a/m4/builtin.c
+++ b/m4/builtin.c
@@ -85,3 +85,35 @@ m4_builtin_find_by_func (m4_module *module, m4_builtin_func *func)
return 0;
}
+
+/* Print a representation of FUNC to OBS, optionally including the
+ MODULE it came from. If FLATTEN, output QUOTES around an empty
+ string instead. */
+void
+m4_builtin_print (m4_obstack *obs, const m4_builtin *func, bool flatten,
+ const m4_string_pair *quotes, m4_module *module)
+{
+ assert (func);
+ if (flatten)
+ {
+ if (quotes)
+ {
+ obstack_grow (obs, quotes->str1, quotes->len1);
+ obstack_grow (obs, quotes->str2, quotes->len2);
+ }
+ module = NULL;
+ }
+ else
+ {
+ obstack_1grow (obs, '<');
+ obstack_grow (obs, func->name, strlen (func->name));
+ obstack_1grow (obs, '>');
+ }
+ if (module)
+ {
+ const char *text = m4_get_module_name (module);
+ obstack_1grow (obs, '{');
+ obstack_grow (obs, text, strlen (text));
+ obstack_1grow (obs, '}');
+ }
+}
diff --git a/m4/input.c b/m4/input.c
index c337ca8e..7d27dad8 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -409,20 +409,9 @@ builtin_unget (m4_input_block *me, int ch)
static void
builtin_print (m4_input_block *me, m4 *context, m4_obstack *obs)
{
- const m4__builtin *bp = me->u.builtin;
- const char *text = bp->builtin.name;
-
- assert (bp);
- obstack_1grow (obs, '<');
- obstack_grow (obs, text, strlen (text));
- obstack_1grow (obs, '>');
- if (m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE))
- {
- text = m4_get_module_name (bp->module);
- obstack_1grow (obs, '{');
- obstack_grow (obs, text, strlen (text));
- obstack_1grow (obs, '}');
- }
+ bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
+ m4_builtin_print (obs, &me->u.builtin->builtin, false, NULL,
+ module ? me->u.builtin->module : NULL);
}
/* m4_push_builtin () pushes TOKEN, which contains a builtin's
@@ -554,11 +543,7 @@ m4__push_symbol (m4 *context, m4_symbol_value *value, size_t level, bool inuse)
return false;
}
}
- else if (m4_is_symbol_value_func (value))
- {
- /* TODO - use the builtin, rather than flattening it. */
- }
- else
+ else if (!m4_is_symbol_value_func (value))
{
/* For composite values, if argv is already in use, creating
additional references for long text segments is more
@@ -605,8 +590,24 @@ m4__push_symbol (m4 *context, m4_symbol_value *value, size_t level, bool inuse)
m4__adjust_refcount (context, level, true);
inuse = true;
}
+ else if (m4_is_symbol_value_func (value))
+ {
+ chain = (m4__symbol_chain *) obstack_alloc (current_input,
+ sizeof *chain);
+ if (next->u.u_c.end)
+ next->u.u_c.end->next = chain;
+ else
+ next->u.u_c.chain = chain;
+ next->u.u_c.end = chain;
+ chain->next = NULL;
+ chain->type = M4__CHAIN_FUNC;
+ chain->quote_age = 0;
+ chain->u.builtin = value->u.builtin;
+ }
while (src_chain)
{
+ /* TODO - support func concatenation. */
+ assert (src_chain->type != M4__CHAIN_FUNC);
if (level == SIZE_MAX)
{
/* Nothing to copy, since link already lives on obstack. */
@@ -718,6 +719,10 @@ composite_peek (m4_input_block *me, m4 *context, bool allow_argv)
if (chain->u.u_s.len)
return to_uchar (chain->u.u_s.str[0]);
break;
+ case M4__CHAIN_FUNC:
+ if (chain->u.builtin)
+ return CHAR_BUILTIN;
+ break;
case M4__CHAIN_ARGV:
argc = m4_arg_argc (chain->u.u_a.argv);
if (chain->u.u_a.index == argc)
@@ -772,6 +777,10 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
if (chain->u.u_s.level < SIZE_MAX)
m4__adjust_refcount (context, chain->u.u_s.level, false);
break;
+ case M4__CHAIN_FUNC:
+ if (chain->u.builtin)
+ return CHAR_BUILTIN;
+ break;
case M4__CHAIN_ARGV:
if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
{
@@ -816,6 +825,9 @@ composite_unget (m4_input_block *me, int ch)
chain->u.u_s.str--;
chain->u.u_s.len++;
break;
+ case M4__CHAIN_FUNC:
+ assert (ch == CHAR_BUILTIN && chain->u.builtin);
+ break;
case M4__CHAIN_ARGV:
/* FIXME - support M4_SYNTAX_COMMA. */
assert (ch == ',' && !chain->u.u_a.comma);
@@ -845,6 +857,10 @@ composite_clean (m4_input_block *me, m4 *context, bool cleanup)
if (chain->u.u_s.level < SIZE_MAX)
m4__adjust_refcount (context, chain->u.u_s.level, false);
break;
+ case M4__CHAIN_FUNC:
+ if (chain->u.builtin)
+ return false;
+ break;
case M4__CHAIN_ARGV:
if (chain->u.u_a.index < m4_arg_argc (chain->u.u_a.argv))
{
@@ -883,6 +899,10 @@ composite_print (m4_input_block *me, m4 *context, m4_obstack *obs)
chain->u.u_s.len, NULL, &maxlen))
done = true;
break;
+ case M4__CHAIN_FUNC:
+ m4_builtin_print (obs, &chain->u.builtin->builtin, false, NULL,
+ module ? chain->u.builtin->module : NULL);
+ break;
case M4__CHAIN_ARGV:
assert (!chain->u.u_a.comma);
if (m4_arg_print (context, obs, chain->u.u_a.argv,
@@ -1060,17 +1080,32 @@ m4_pop_wrapup (m4 *context)
}
/* Populate TOKEN with the builtin token at the top of the input
- stack, then consume the input. */
+ stack, then consume the input. If TOKEN is NULL, discard the
+ builtin token instead. */
static void
init_builtin_token (m4 *context, m4_symbol_value *token)
{
int ch = next_char (context, false, true);
- m4_input_block *block = isp;
- assert (ch == CHAR_BUILTIN && block->funcs->read_func == builtin_read
- && block->u.builtin);
+ assert (ch == CHAR_BUILTIN);
- m4__set_symbol_value_builtin (token, block->u.builtin);
- block->u.builtin = NULL;
+ if (isp->funcs == &builtin_funcs)
+ {
+ assert (isp->u.builtin);
+ if (token)
+ m4__set_symbol_value_builtin (token, isp->u.builtin);
+ isp->u.builtin = NULL;
+ }
+ else
+ {
+ m4__symbol_chain *chain;
+ assert (isp->funcs == &composite_funcs);
+ chain = isp->u.u_c.chain;
+ assert (!chain->quote_age && chain->type == M4__CHAIN_FUNC
+ && chain->u.builtin);
+ if (token)
+ m4__set_symbol_value_builtin (token, chain->u.builtin);
+ chain->u.builtin = NULL;
+ }
}
/* When a QUOTE token is seen, convert VALUE to a composite (if it is
@@ -1526,12 +1561,41 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
if (obs)
obs_safe = obs;
quote_level = 1;
+ type = M4_TOKEN_STRING;
while (1)
{
ch = next_char (context, obs && m4__quote_age (M4SYNTAX), true);
if (ch == CHAR_EOF)
m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
_("end of file in string"));
+ if (ch == CHAR_BUILTIN)
+ {
+ /* TODO support concatenation of builtins. */
+ if (obstack_object_size (obs_safe) == 0
+ && token->type == M4_SYMBOL_VOID)
+ {
+ /* Strip quotes if they surround a lone builtin
+ token. */
+ assert (quote_level == 1);
+ init_builtin_token (context, token);
+ ch = peek_char (context, false);
+ if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_RQUOTE))
+ {
+ ch = next_char (context, false, true);
+#ifdef DEBUG_INPUT
+ m4_print_token (context, "next_token", M4_TOKEN_MACDEF,
+ token);
+#endif
+ return M4_TOKEN_MACDEF;
+ }
+ token->type = M4_SYMBOL_VOID;
+ }
+ else
+ init_builtin_token (context, NULL);
+ m4_warn_at_line (context, 0, file, *line, caller,
+ _("cannot quote builtin"));
+ continue;
+ }
if (ch == CHAR_QUOTE)
append_quote_token (context, obs, token);
else if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_RQUOTE))
@@ -1548,7 +1612,6 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
else
obstack_1grow (obs_safe, ch);
}
- type = M4_TOKEN_STRING;
}
else if (!m4_is_syntax_single_quotes (M4SYNTAX)
&& MATCH (context, ch, context->syntax->quote.str1, true))
@@ -1556,6 +1619,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
if (obs)
obs_safe = obs;
quote_level = 1;
+ type = M4_TOKEN_STRING;
assert (!m4__quote_age (M4SYNTAX));
while (1)
{
@@ -1563,6 +1627,36 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
if (ch == CHAR_EOF)
m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
_("end of file in string"));
+ if (ch == CHAR_BUILTIN)
+ {
+ /* TODO support concatenation of builtins. */
+ if (obstack_object_size (obs_safe) == 0
+ && token->type == M4_SYMBOL_VOID)
+ {
+ /* Strip quotes if they surround a lone builtin
+ token. */
+ assert (quote_level == 1);
+ init_builtin_token (context, token);
+ ch = peek_char (context, false);
+ if (MATCH (context, ch, context->syntax->quote.str2,
+ false))
+ {
+ ch = next_char (context, false, true);
+ MATCH (context, ch, context->syntax->quote.str2, true);
+#ifdef DEBUG_INPUT
+ m4_print_token (context, "next_token", M4_TOKEN_MACDEF,
+ token);
+#endif
+ return M4_TOKEN_MACDEF;
+ }
+ token->type = M4_SYMBOL_VOID;
+ }
+ else
+ init_builtin_token (context, NULL);
+ m4_warn_at_line (context, 0, file, *line, caller,
+ _("cannot quote builtin"));
+ continue;
+ }
if (MATCH (context, ch, context->syntax->quote.str2, true))
{
if (--quote_level == 0)
@@ -1579,24 +1673,34 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
else
obstack_1grow (obs_safe, ch);
}
- type = M4_TOKEN_STRING;
}
else if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_BCOMM))
{ /* COMMENT, SHORT DELIM */
if (obs && !m4_get_discard_comments_opt (context))
obs_safe = obs;
obstack_1grow (obs_safe, ch);
- while ((ch = next_char (context, false, true)) < CHAR_EOF
- && !m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ECOMM))
- obstack_1grow (obs_safe, ch);
- if (ch != CHAR_EOF)
+ while (1)
{
+ ch = next_char (context, false, true);
+ if (ch == CHAR_EOF)
+ m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
+ _("end of file in comment"));
+ if (ch == CHAR_BUILTIN)
+ {
+ /* TODO support concatenation of builtins. */
+ m4_warn_at_line (context, 0, file, *line, caller,
+ _("cannot comment builtin"));
+ init_builtin_token (context, NULL);
+ continue;
+ }
+ if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ECOMM))
+ {
+ obstack_1grow (obs_safe, ch);
+ break;
+ }
assert (ch < CHAR_EOF);
obstack_1grow (obs_safe, ch);
}
- else
- m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
- _("end of file in comment"));
type = (m4_get_discard_comments_opt (context)
? M4_TOKEN_NONE : M4_TOKEN_STRING);
}
@@ -1607,18 +1711,29 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
obs_safe = obs;
obstack_grow (obs_safe, context->syntax->comm.str1,
context->syntax->comm.len1);
- while ((ch = next_char (context, false, true)) < CHAR_EOF
- && !MATCH (context, ch, context->syntax->comm.str2, true))
- obstack_1grow (obs_safe, ch);
- if (ch != CHAR_EOF)
+ while (1)
{
+ ch = next_char (context, false, true);
+ if (ch == CHAR_EOF)
+ m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
+ _("end of file in comment"));
+ if (ch == CHAR_BUILTIN)
+ {
+ /* TODO support concatenation of builtins. */
+ m4_warn_at_line (context, 0, file, *line, caller,
+ _("cannot comment builtin"));
+ init_builtin_token (context, NULL);
+ continue;
+ }
+ if (MATCH (context, ch, context->syntax->comm.str2, true))
+ {
+ obstack_grow (obs_safe, context->syntax->comm.str2,
+ context->syntax->comm.len2);
+ break;
+ }
assert (ch < CHAR_EOF);
- obstack_grow (obs_safe, context->syntax->comm.str2,
- context->syntax->comm.len2);
+ obstack_1grow (obs_safe, ch);
}
- else
- m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
- _("end of file in comment"));
type = (m4_get_discard_comments_opt (context)
? M4_TOKEN_NONE : M4_TOKEN_STRING);
}
diff --git a/m4/m4module.h b/m4/m4module.h
index 0941d2be..6cbe185c 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -34,6 +34,7 @@ BEGIN_C_DECLS
typedef struct m4 m4;
typedef struct m4_builtin m4_builtin;
typedef struct m4_macro m4_macro;
+typedef struct m4_symbol m4_symbol;
typedef struct m4_symbol_value m4_symbol_value;
typedef struct m4_input_block m4_input_block;
typedef struct m4_module m4_module;
@@ -164,6 +165,8 @@ extern bool m4_bad_argc (m4 *, int, const char *, size_t, size_t,
bool);
extern bool m4_numeric_arg (m4 *, const char *, const char *, int *);
extern bool m4_parse_truth_arg (m4 *, const char *, const char *, bool);
+extern m4_symbol *m4_symbol_value_lookup (m4 *, const char *,
+ m4_symbol_value *, bool);
/* Error handling. */
extern void m4_error (m4 *, int, int, const char *, const char *, ...)
@@ -186,7 +189,6 @@ extern void m4_set_exit_failure (int);
typedef struct m4_syntax_table m4_syntax_table;
typedef struct m4_symbol_table m4_symbol_table;
-typedef struct m4_symbol m4_symbol;
extern m4 * m4_create (void);
extern void m4_delete (m4 *);
@@ -342,6 +344,8 @@ extern void m4_set_symbol_value_placeholder (m4_symbol_value *,
extern m4_symbol_value *m4_builtin_find_by_name (m4_module *, const char *);
extern m4_symbol_value *m4_builtin_find_by_func (m4_module *,
m4_builtin_func *);
+extern void m4_builtin_print (m4_obstack *, const m4_builtin *, bool,
+ const m4_string_pair *, m4_module *);
diff --git a/m4/m4private.h b/m4/m4private.h
index 65bcbe09..5ff7c950 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -211,7 +211,7 @@ struct m4_symbol
enum m4__symbol_chain_type
{
M4__CHAIN_STR, /* Link contains a string, u.u_s is valid. */
- /* TODO Add M4__CHAIN_FUNC. */
+ M4__CHAIN_FUNC, /* Link contains builtin token, u.builtin is valid. */
M4__CHAIN_ARGV /* Link contains a $@ reference, u.u_a is valid. */
};
@@ -229,6 +229,7 @@ struct m4__symbol_chain
size_t len; /* Remaining length of str. */
size_t level; /* Expansion level of content, or SIZE_MAX. */
} u_s; /* M4__CHAIN_STR. */
+ const m4__builtin *builtin; /* M4__CHAIN_FUNC. */
struct
{
m4_macro_args *argv; /* Reference to earlier $@. */
diff --git a/m4/macro.c b/m4/macro.c
index 583cb039..d03f5519 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -401,6 +401,7 @@ expand_argument (m4 *context, m4_obstack *obs, m4_symbol_value *argp,
assert (paren_level == 0 && argp->type == M4_SYMBOL_VOID
&& obstack_object_size (obs) == 0
&& token.u.u_c.chain == token.u.u_c.end
+ && token.u.u_c.chain->quote_age == age
&& token.u.u_c.chain->type == M4__CHAIN_ARGV);
argp->type = M4_SYMBOL_COMP;
argp->u.u_c.chain = argp->u.u_c.end = token.u.u_c.chain;
@@ -662,7 +663,8 @@ collect_arguments (m4 *context, const char *name, size_t len,
argv->wrapper = args.wrapper;
argv->has_ref = args.has_ref;
argv->has_func = args.has_func;
- if (args.quote_age != m4__quote_age (M4SYNTAX))
+ /* TODO allow funcs without crippling quote age. */
+ if (args.quote_age != m4__quote_age (M4SYNTAX) || args.has_func)
argv->quote_age = 0;
argv->arraylen = args.arraylen;
return argv;
@@ -1147,19 +1149,27 @@ make_argv_ref (m4 *context, m4_symbol_value *value, m4_obstack *obs,
/* Given ARGV, return the symbol value at the specified INDEX, which
must be non-zero. *LEVEL is set to the obstack level that contains
- the symbol (which is not necessarily the level of ARGV). */
+ the symbol (which is not necessarily the level of ARGV). If
+ FLATTEN, avoid returning a builtin token. */
static m4_symbol_value *
-arg_symbol (m4_macro_args *argv, size_t index, size_t *level)
+arg_symbol (m4_macro_args *argv, size_t index, size_t *level, bool flatten)
{
size_t i;
m4_symbol_value *value;
assert (index);
- *level = argv->level;
+ if (level)
+ *level = argv->level;
+ flatten |= argv->flatten;
if (argv->argc <= index)
return &empty_symbol;
if (!argv->wrapper)
- return argv->array[index - 1];
+ {
+ value = argv->array[index - 1];
+ if (flatten && m4_is_symbol_value_func (value))
+ value = &empty_symbol;
+ return value;
+ }
/* Must cycle through all array slots until we find index, since
wrappers can contain multiple arguments. */
@@ -1174,9 +1184,8 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t *level)
- chain->u.u_a.skip_last))
{
value = arg_symbol (chain->u.u_a.argv,
- chain->u.u_a.index - 1 + index, level);
- if (chain->u.u_a.flatten && m4_is_symbol_value_func (value))
- value = &empty_symbol;
+ chain->u.u_a.index - 1 + index, level,
+ flatten || chain->u.u_a.flatten);
break;
}
index -= (chain->u.u_a.argv->argc - chain->u.u_a.index
@@ -1193,8 +1202,7 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t *level)
m4_symbol_value *
m4_arg_symbol (m4_macro_args *argv, size_t index)
{
- size_t dummy;
- return arg_symbol (argv, index, &dummy);
+ return arg_symbol (argv, index, NULL, false);
}
/* Given ARGV, return true if argument INDEX is text. Index 0 is
@@ -1257,7 +1265,8 @@ m4_arg_text (m4 *context, m4_macro_args *argv, size_t index)
m4_arg_print (context, obs, chain->u.u_a.argv, chain->u.u_a.index,
m4__quote_cache (M4SYNTAX, NULL, chain->quote_age,
chain->u.u_a.quotes),
- chain->u.u_a.flatten, NULL, NULL, false, false);
+ argv->flatten || chain->u.u_a.flatten, NULL, NULL,
+ false, false);
break;
default:
assert (!"m4_arg_text");
@@ -1295,30 +1304,45 @@ m4_arg_equal (m4 *context, m4_macro_args *argv, size_t indexa, size_t indexb)
m4_get_symbol_value_len (sa)) == 0);
/* Convert both arguments to chains, if not one already. */
- /* TODO - allow builtin tokens in the comparison? */
- if (m4_is_symbol_value_text (sa))
+ switch (sa->type)
{
+ case M4_SYMBOL_TEXT:
tmpa.next = NULL;
tmpa.type = M4__CHAIN_STR;
tmpa.u.u_s.str = m4_get_symbol_value_text (sa);
tmpa.u.u_s.len = m4_get_symbol_value_len (sa);
- }
- else
- {
- assert (sa->type == M4_SYMBOL_COMP);
+ break;
+ case M4_SYMBOL_FUNC:
+ tmpa.next = NULL;
+ tmpa.type = M4__CHAIN_FUNC;
+ tmpa.u.builtin = sa->u.builtin;
+ break;
+ case M4_SYMBOL_COMP:
ca = sa->u.u_c.chain;
+ break;
+ default:
+ assert (!"m4_arg_equal");
+ abort ();
}
- if (m4_is_symbol_value_text (sb))
+ switch (sb->type)
{
+ case M4_SYMBOL_TEXT:
tmpb.next = NULL;
tmpb.type = M4__CHAIN_STR;
tmpb.u.u_s.str = m4_get_symbol_value_text (sb);
tmpb.u.u_s.len = m4_get_symbol_value_len (sb);
- }
- else
- {
- assert (sb->type == M4_SYMBOL_COMP);
+ break;
+ case M4_SYMBOL_FUNC:
+ tmpb.next = NULL;
+ tmpb.type = M4__CHAIN_FUNC;
+ tmpb.u.builtin = sb->u.builtin;
+ break;
+ case M4_SYMBOL_COMP:
cb = sb->u.u_c.chain;
+ break;
+ default:
+ assert (!"m4_arg_equal");
+ abort ();
}
/* Compare each link of the chain. */
@@ -1356,6 +1380,14 @@ m4_arg_equal (m4 *context, m4_macro_args *argv, size_t indexa, size_t indexb)
cb = &tmpb;
continue;
}
+ if (ca->type == M4__CHAIN_FUNC)
+ {
+ if (cb->type != M4__CHAIN_FUNC || ca->u.builtin != cb->u.builtin)
+ return false;
+ ca = ca->next;
+ cb = cb->next;
+ continue;
+ }
assert (ca->type == M4__CHAIN_STR && cb->type == M4__CHAIN_STR);
if (ca->u.u_s.len == cb->u.u_s.len)
{
@@ -1507,9 +1539,9 @@ m4_arg_print (m4 *context, m4_obstack *obs, m4_macro_args *argv, size_t index,
&& m4_shipout_string_trunc (obs, quotes->str1, quotes->len1, NULL,
plen))
return true;
- if (m4_symbol_value_print (context, m4_arg_symbol (argv, i), obs,
- quote_each ? quotes : NULL, flatten, &len,
- module))
+ if (m4_symbol_value_print (context, arg_symbol (argv, i, NULL, flatten),
+ obs, quote_each ? quotes : NULL, flatten,
+ &len, module))
return true;
if (quotes && !quote_each
&& m4_shipout_string_trunc (obs, quotes->str2, quotes->len2, NULL,
@@ -1591,18 +1623,16 @@ m4_push_arg (m4 *context, m4_obstack *obs, m4_macro_args *argv, size_t index)
m4__push_arg_quote (context, obs, argv, index, NULL);
}
-/* Push argument INDEX from ARGV, which must be a text token, onto the
- expansion stack OBS for rescanning. INDEX must be non-zero.
- QUOTES determines any quote delimiters that were in effect when the
- reference was created. */
+/* Push argument INDEX from ARGV onto the expansion stack OBS for
+ rescanning. INDEX must be non-zero. QUOTES determines any quote
+ delimiters that were in effect when the reference was created. */
void
m4__push_arg_quote (m4 *context, m4_obstack *obs, m4_macro_args *argv,
size_t index, const m4_string_pair *quotes)
{
size_t level;
- m4_symbol_value *value = arg_symbol (argv, index, &level);
+ m4_symbol_value *value = arg_symbol (argv, index, &level, false);
- /* TODO handle builtin tokens? */
if (quotes)
obstack_grow (obs, quotes->str1, quotes->len1);
if (value != &empty_symbol
@@ -1633,8 +1663,7 @@ m4_push_args (m4 *context, m4_obstack *obs, m4_macro_args *argv, bool skip,
return;
}
- /* TODO allow shift, $@, to push builtins without flatten. */
- value = make_argv_ref (context, &tmp, obs, -1, argv, i, true,
+ value = make_argv_ref (context, &tmp, obs, -1, argv, i, argv->flatten,
quote ? quotes : NULL);
assert (value == &tmp);
if (m4__push_symbol (context, value, -1, argv->inuse))
diff --git a/m4/symtab.c b/m4/symtab.c
index 995495f7..7fa7ccc6 100644
--- a/m4/symtab.c
+++ b/m4/symtab.c
@@ -555,7 +555,6 @@ m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
size_t *maxlen, bool module)
{
const char *text;
- const m4_builtin *bp;
m4__symbol_chain *chain;
size_t len = maxlen ? *maxlen : SIZE_MAX;
bool result = false;
@@ -569,22 +568,9 @@ m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
result = true;
break;
case M4_SYMBOL_FUNC:
- if (flatten)
- {
- if (quotes)
- {
- obstack_grow (obs, quotes->str1, quotes->len1);
- obstack_grow (obs, quotes->str2, quotes->len2);
- }
- module = false;
- }
- else
- {
- bp = m4_get_symbol_value_builtin (value);
- obstack_1grow (obs, '<');
- obstack_grow (obs, bp->name, strlen (bp->name));
- obstack_1grow (obs, '>');
- }
+ m4_builtin_print (obs, m4_get_symbol_value_builtin (value), flatten,
+ quotes, module ? VALUE_MODULE (value) : NULL);
+ module = false;
break;
case M4_SYMBOL_PLACEHOLDER:
if (flatten)
@@ -608,6 +594,7 @@ m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
break;
case M4_SYMBOL_COMP:
chain = value->u.u_c.chain;
+ assert (!module);
if (quotes)
obstack_grow (obs, quotes->str1, quotes->len1);
while (chain && !result)
@@ -619,6 +606,11 @@ m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
chain->u.u_s.len, NULL, &len))
result = true;
break;
+ case M4__CHAIN_FUNC:
+ m4_builtin_print (obs, &chain->u.builtin->builtin, flatten,
+ quotes,
+ module ? chain->u.builtin->module : NULL);
+ break;
case M4__CHAIN_ARGV:
if (m4_arg_print (context, obs, chain->u.u_a.argv,
chain->u.u_a.index,
@@ -637,7 +629,6 @@ m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
}
if (quotes)
obstack_grow (obs, quotes->str2, quotes->len2);
- assert (!module);
break;
default:
assert (!"m4_symbol_value_print");
diff --git a/m4/utility.c b/m4/utility.c
index 0a3296be..1e17d610 100644
--- a/m4/utility.c
+++ b/m4/utility.c
@@ -119,6 +119,27 @@ m4_parse_truth_arg (m4 *context, const char *arg, const char *me,
return previous;
}
+/* Helper method to look up a symbol table entry given an argument.
+ Warn on behalf of CALLER if VALUE is not a text argument, or if
+ MUST_EXIST and no macro exists by the name in VALUE. Return the
+ result of the lookup, or NULL. */
+m4_symbol *
+m4_symbol_value_lookup (m4 *context, const char *caller,
+ m4_symbol_value *value, bool must_exist)
+{
+ m4_symbol *result = NULL;
+ if (m4_is_symbol_value_text (value))
+ {
+ const char *name = m4_get_symbol_value_text (value);
+ result = m4_symbol_lookup (M4SYMTAB, name);
+ if (must_exist && !result)
+ m4_warn (context, 0, caller, _("undefined macro `%s'"), name);
+ }
+ else
+ m4_warn (context, 0, caller, _("invalid macro name ignored"));
+ return result;
+}
+
/* Helper for all error reporting. Report message based on FORMAT and
ARGS, on behalf of MACRO, at the optional location FILE and LINE.
If ERRNUM, decode the errno value as part of the message. If