[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-63-
From: |
Eric Blake |
Subject: |
[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-63-g5d083e4 |
Date: |
Sat, 16 Feb 2008 13:55:46 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".
http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=5d083e4726ed578b093aaf82e2a5a542f5815dcd
The branch, master has been updated
via 5d083e4726ed578b093aaf82e2a5a542f5815dcd (commit)
from 7f0b47b96e8872513aae3a4e3819aef6d799e6bd (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 5d083e4726ed578b093aaf82e2a5a542f5815dcd
Author: Eric Blake <address@hidden>
Date: Fri Feb 15 22:12:03 2008 -0700
Stage 15: return argv refs back to collect_arguments.
* m4/m4private.h (CHAR_ARGV): New input engine sentinel.
(enum m4__token_type): Add M4_TOKEN_ARGV.
(struct m4__symbol_chain): Add skip_last member to argv link.
(m4__next_token): Add parameter.
* m4/input.c (peek_char, file_peek, builtin_peek, string_peek)
(composite_peek, m4__next_token): Add new parameter.
(composite_read, append_quote_token): Support argv in quotes.
(init_argv_symbol): New function.
(m4__push_symbol, match_input, consume_syntax)
(m4__next_token_is_open, m4_print_token): Adjust callers.
* m4/macro.c (m4_macro_expand_input, m4__arg_adjust_refcount)
(arg_mark, m4_arg_text, make_argv_ref): Likewise.
(expand_argument, collect_arguments): Handle new token.
(arg_symbol): Drill through $@ reference.
* m4/syntax.c (set_quote_age): Detect disabled comments.
* m4/symtab.c (dump_symbol_CB) [DEBUG_SYM]: Fix debug code.
Signed-off-by: Eric Blake <address@hidden>
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 26 +++++++
m4/input.c | 207 +++++++++++++++++++++++++++++++++++++++++---------------
m4/m4private.h | 9 ++-
m4/macro.c | 114 ++++++++++++++++++++++++-------
m4/symtab.c | 2 +-
m4/syntax.c | 8 ++-
6 files changed, 277 insertions(+), 89 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0e3c93e..d0ba987 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2008-02-16 Eric Blake <address@hidden>
+
+ Stage 15: return argv refs back to collect_arguments.
+ Collect an entire $@ reference at once rather than one argument at
+ a time, outside of quotes (but inside quotes, $@ is still
+ flattened for now). The skip_last field allows concatenation of
+ $@ with other text when collecting arguments.
+ Memory impact: noticeable improvement, due to better reuse of
address@hidden
+ Speed impact: noticeable improvement, due to less parsing.
+ * m4/m4private.h (CHAR_ARGV): New input engine sentinel.
+ (enum m4__token_type): Add M4_TOKEN_ARGV.
+ (struct m4__symbol_chain): Add skip_last member to argv link.
+ (m4__next_token): Add parameter.
+ * m4/input.c (peek_char, file_peek, builtin_peek, string_peek)
+ (composite_peek, m4__next_token): Add new parameter.
+ (composite_read, append_quote_token): Support argv in quotes.
+ (init_argv_symbol): New function.
+ (m4__push_symbol, match_input, consume_syntax)
+ (m4__next_token_is_open, m4_print_token): Adjust callers.
+ * m4/macro.c (m4_macro_expand_input, m4__arg_adjust_refcount)
+ (arg_mark, m4_arg_text, make_argv_ref): Likewise.
+ (expand_argument, collect_arguments): Handle new token.
+ (arg_symbol): Drill through $@ reference.
+ * m4/syntax.c (set_quote_age): Detect disabled comments.
+ * m4/symtab.c (dump_symbol_CB) [DEBUG_SYM]: Fix debug code.
+
2008-02-15 Eric Blake <address@hidden>
* modules/gnu.c (regexp_compile): Use a fastmap for regex speed.
diff --git a/m4/input.c b/m4/input.c
index 025ae0d..b5d50a1 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -92,20 +92,20 @@
maintains its own notion of the current file and line, so swapping
between input blocks must update the context accordingly. */
-static int file_peek (m4_input_block *, m4 *);
+static int file_peek (m4_input_block *, m4 *, bool);
static int file_read (m4_input_block *, m4 *, bool, bool);
static void file_unget (m4_input_block *, int);
static bool file_clean (m4_input_block *, m4 *, bool);
static void file_print (m4_input_block *, m4 *, m4_obstack *);
-static int builtin_peek (m4_input_block *, m4 *);
+static int builtin_peek (m4_input_block *, m4 *, bool);
static int builtin_read (m4_input_block *, m4 *, bool, bool);
static void builtin_unget (m4_input_block *, int);
static void builtin_print (m4_input_block *, m4 *, m4_obstack *);
-static int string_peek (m4_input_block *, m4 *);
+static int string_peek (m4_input_block *, m4 *, bool);
static int string_read (m4_input_block *, m4 *, bool, bool);
static void string_unget (m4_input_block *, int);
static void string_print (m4_input_block *, m4 *, m4_obstack *);
-static int composite_peek (m4_input_block *, m4 *);
+static int composite_peek (m4_input_block *, m4 *, bool);
static int composite_read (m4_input_block *, m4 *, bool, bool);
static void composite_unget (m4_input_block *, int);
static bool composite_clean (m4_input_block *, m4 *, bool);
@@ -116,12 +116,14 @@ static void append_quote_token (m4 *,
m4_obstack *,
m4_symbol_value *);
static bool match_input (m4 *, const char *, bool);
static int next_char (m4 *, bool, bool);
-static int peek_char (m4 *);
+static int peek_char (m4 *, bool);
static bool pop_input (m4 *, bool);
static void unget_input (int);
static bool consume_syntax (m4 *, m4_obstack *, unsigned int);
#ifdef DEBUG_INPUT
+# include "quotearg.h"
+
static int m4_print_token (const char *, m4__token_type, m4_symbol_value *);
#endif
@@ -129,8 +131,9 @@ static int m4_print_token (const char *, m4__token_type,
m4_symbol_value *);
struct input_funcs
{
/* Peek at input, return an unsigned char, CHAR_BUILTIN if it is a
- builtin, or CHAR_RETRY if none available. */
- int (*peek_func) (m4_input_block *, m4 *);
+ builtin, or CHAR_RETRY if none available. If ALLOW_ARGV, then
+ CHAR_ARGV may be returned. */
+ int (*peek_func) (m4_input_block *, m4 *, bool);
/* Read input, return an unsigned char, CHAR_BUILTIN if it is a
builtin, or CHAR_RETRY if none available. If ALLOW_QUOTE, then
@@ -254,7 +257,8 @@ static struct input_funcs composite_funcs = {
/* Input files, from command line or [s]include. */
static int
-file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+ bool allow_argv M4_GNUC_UNUSED)
{
int ch;
@@ -389,7 +393,8 @@ m4_push_file (m4 *context, FILE *fp, const char *title,
bool close_file)
/* Handle a builtin macro token. */
static int
-builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+ bool allow_argv M4_GNUC_UNUSED)
{
if (me->u.u_b.read)
return CHAR_RETRY;
@@ -474,7 +479,8 @@ m4_push_builtin (m4 *context, m4_symbol_value *token)
/* Handle string expansion text. */
static int
-string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+ bool allow_argv M4_GNUC_UNUSED)
{
return me->u.u_s.len ? to_uchar (*me->u.u_s.str) : CHAR_RETRY;
}
@@ -662,7 +668,7 @@ m4__push_symbol (m4 *context, m4_symbol_value *value,
size_t level, bool inuse)
next->u.u_c.end = chain;
if (chain->type == M4__CHAIN_ARGV)
{
- assert (!chain->u.u_a.comma);
+ assert (!chain->u.u_a.comma && !chain->u.u_a.skip_last);
inuse |= m4__arg_adjust_refcount (context, chain->u.u_a.argv, true);
}
else if (chain->type == M4__CHAIN_STR && chain->u.u_s.level < SIZE_MAX)
@@ -718,9 +724,11 @@ m4_push_string_finish (void)
in FIFO order, even though the obstack allocates memory in LIFO
order. */
static int
-composite_peek (m4_input_block *me, m4 *context)
+composite_peek (m4_input_block *me, m4 *context, bool allow_argv)
{
m4__symbol_chain *chain = me->u.u_c.chain;
+ size_t argc;
+
while (chain)
{
switch (chain->type)
@@ -730,12 +738,16 @@ composite_peek (m4_input_block *me, m4 *context)
return to_uchar (chain->u.u_s.str[0]);
break;
case M4__CHAIN_ARGV:
- /* TODO - figure out how to pass multiple arguments to
- macro.c at once. */
- if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
+ argc = m4_arg_argc (chain->u.u_a.argv);
+ if (chain->u.u_a.index == argc)
break;
if (chain->u.u_a.comma)
return ','; /* FIXME - support M4_SYNTAX_COMMA. */
+ /* Only return a reference in the quoting is correct and the
+ reference has more than one argument left. */
+ if (allow_argv && chain->quote_age == m4__quote_age (M4SYNTAX)
+ && chain->u.u_a.quotes && chain->u.u_a.index + 1 < argc)
+ return CHAR_ARGV;
/* Rather than directly parse argv here, we push another
input block containing the next unparsed argument from
argv. */
@@ -745,7 +757,7 @@ composite_peek (m4_input_block *me, m4 *context)
chain->u.u_a.index++;
chain->u.u_a.comma = true;
m4_push_string_finish ();
- return peek_char (context);
+ return peek_char (context, allow_argv);
default:
assert (!"composite_peek");
abort ();
@@ -761,9 +773,7 @@ composite_read (m4_input_block *me, m4 *context, bool
allow_quote, bool safe)
m4__symbol_chain *chain = me->u.u_c.chain;
while (chain)
{
- /* TODO also support returning $@ as CHAR_QUOTE. */
- if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX)
- && chain->type == M4__CHAIN_STR)
+ if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX))
return CHAR_QUOTE;
switch (chain->type)
{
@@ -779,8 +789,6 @@ composite_read (m4_input_block *me, m4 *context, bool
allow_quote, bool safe)
m4__adjust_refcount (context, chain->u.u_s.level, false);
break;
case M4__CHAIN_ARGV:
- /* TODO - figure out how to pass multiple arguments to
- macro.c at once. */
if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
{
m4__arg_adjust_refcount (context, chain->u.u_a.argv, false);
@@ -996,7 +1004,7 @@ pop_input (m4 *context, bool cleanup)
assert (isp);
if (isp->funcs->clean_func
? !isp->funcs->clean_func (isp, context, cleanup)
- : (isp->funcs->peek_func (isp, context) != CHAR_RETRY))
+ : (isp->funcs->peek_func (isp, context, true) != CHAR_RETRY))
return false;
if (tmp != NULL)
@@ -1073,18 +1081,28 @@ append_quote_token (m4 *context, m4_obstack *obs,
m4_symbol_value *value)
{
m4__symbol_chain *src_chain = isp->u.u_c.chain;
m4__symbol_chain *chain;
- assert (isp->funcs == &composite_funcs && obs && m4__quote_age (M4SYNTAX)
- && src_chain->type == M4__CHAIN_STR
- && src_chain->u.u_s.level <= SIZE_MAX);
+ assert (isp->funcs == &composite_funcs && obs && m4__quote_age (M4SYNTAX));
isp->u.u_c.chain = src_chain->next;
/* Speed consideration - for short enough symbols, the speed and
memory overhead of parsing another INPUT_CHAIN link outweighs the
time to inline the symbol text. */
- if (src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
+ if (src_chain->type == M4__CHAIN_STR
+ && src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
{
+ assert (src_chain->u.u_s.level <= SIZE_MAX);
obstack_grow (obs, src_chain->u.u_s.str, src_chain->u.u_s.len);
m4__adjust_refcount (context, src_chain->u.u_s.level, false);
+ return;
+ }
+
+ /* TODO preserve $@ through quotes. */
+ if (src_chain->type == M4__CHAIN_ARGV)
+ {
+ m4_arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
+ src_chain->u.u_a.quotes, NULL, false);
+ m4__arg_adjust_refcount (context, src_chain->u.u_a.argv, false);
+ return;
}
if (value->type == M4_SYMBOL_VOID)
@@ -1103,6 +1121,65 @@ append_quote_token (m4 *context, m4_obstack *obs,
m4_symbol_value *value)
chain->next = NULL;
}
+/* When an ARGV token is seen, convert VALUE to point to it via a
+ composite chain. Use OBS for any additional allocations
+ needed. */
+static void
+init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value)
+{
+ m4__symbol_chain *src_chain;
+ m4__symbol_chain *chain;
+ int ch = next_char (context, true, true);
+ const m4_string_pair *comments = m4_get_syntax_comments (M4SYNTAX);
+
+ assert (ch == CHAR_QUOTE && value->type == M4_SYMBOL_VOID
+ && isp->funcs == &composite_funcs
+ && isp->u.u_c.chain->type == M4__CHAIN_ARGV
+ && obs && obstack_object_size (obs) == 0);
+
+ src_chain = isp->u.u_c.chain;
+ isp->u.u_c.chain = src_chain->next;
+ value->type = M4_SYMBOL_COMP;
+ /* Clone the link, since the input will be discarded soon. */
+ chain = (m4__symbol_chain *) obstack_copy (obs, src_chain, sizeof *chain);
+ value->u.u_c.chain = value->u.u_c.end = chain;
+ chain->next = NULL;
+
+ /* If the next character is not ',' or ')', then unlink the last
+ argument from argv and schedule it for reparsing. This way,
+ expand_argument never has to deal with concatenation of argv with
+ arbitrary text. Note that the implementation of safe_quotes
+ ensures peek_input won't return CHAR_ARGV if the user is perverse
+ enough to mix comment delimiters with argument separators:
+
+ define(n,`$#')define(echo,$*)changecom(`,,',`)')n(echo(a,`,b`)'',c))
+ => 2 (not 3)
+
+ Therefore, we do not have to worry about calling MATCH, and thus
+ do not have to worry about pop_input being called and
+ invalidating the argv reference.
+
+ When the $@ ref is used unchanged, we completely bypass the
+ decrement of the argv refcount in next_char, since the ref is
+ still live via the current collect_arguments. However, when the
+ last element of the $@ ref is reparsed, we must increase the argv
+ refcount here, to compensate for the fact that it will be
+ decreased once the final element is parsed. */
+ assert (!comments->len1
+ || (!m4_has_syntax (M4SYNTAX, *comments->str1,
+ M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)
+ && *comments->str1 != *src_chain->u.u_a.quotes->str1));
+ ch = peek_char (context, false);
+ if (!m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE))
+ {
+ isp->u.u_c.chain = src_chain;
+ src_chain->u.u_a.index = m4_arg_argc (chain->u.u_a.argv) - 1;
+ src_chain->u.u_a.comma = true;
+ chain->u.u_a.skip_last = true;
+ m4__arg_adjust_refcount (context, chain->u.u_a.argv, true);
+ }
+}
+
/* Low level input is done a character at a time. The function
next_char () is used to read and advance the input to the next
@@ -1146,9 +1223,10 @@ next_char (m4 *context, bool allow_quote, bool retry)
/* The function peek_char () is used to look at the next character in
the input stream. At any given time, it reads from the input_block
- on the top of the current input stack. */
+ on the top of the current input stack. If ALLOW_ARGV, then return
+ CHAR_ARGV if an entire $@ reference is available for use. */
static int
-peek_char (m4 *context)
+peek_char (m4 *context, bool allow_argv)
{
int ch;
m4_input_block *block = isp;
@@ -1159,7 +1237,8 @@ peek_char (m4 *context)
return CHAR_EOF;
assert (block->funcs->peek_func);
- if ((ch = block->funcs->peek_func (block, context)) != CHAR_RETRY)
+ ch = block->funcs->peek_func (block, context, allow_argv);
+ if (ch != CHAR_RETRY)
{
/* if (IS_IGNORE (ch)) */
/* return next_char (context, false, true); */
@@ -1228,7 +1307,7 @@ match_input (m4 *context, const char *s, bool consume)
m4_obstack *st;
bool result = false;
- ch = peek_char (context);
+ ch = peek_char (context, false);
if (ch != to_uchar (*s))
return false; /* fail */
@@ -1240,7 +1319,7 @@ match_input (m4 *context, const char *s, bool consume)
}
next_char (context, false, true);
- for (n = 1, t = s++; (ch = peek_char (context)) == to_uchar (*s++); )
+ for (n = 1, t = s++; (ch = peek_char (context, false)) == to_uchar (*s++); )
{
next_char (context, false, true);
n++;
@@ -1297,7 +1376,7 @@ consume_syntax (m4 *context, m4_obstack *obs, unsigned
int syntax)
}
if (ch == CHAR_RETRY || ch == CHAR_QUOTE)
{
- ch = peek_char (context);
+ ch = peek_char (context, false);
if (m4_has_syntax (M4SYNTAX, ch, syntax))
{
assert (ch < CHAR_EOF);
@@ -1355,8 +1434,10 @@ m4_input_exit (void)
with a description of what TOKEN will contain. If LINE is not
NULL, set *LINE to the line number where the token starts. If OBS,
expand safe tokens (strings and comments) directly into OBS rather
- than in a temporary staging area. Report errors (unterminated
- comments or strings) on behalf of CALLER, if non-NULL.
+ than in a temporary staging area. If ALLOW_ARGV, OBS must be
+ non-NULL, and an entire series of arguments can be returned if a $@
+ reference is encountered. Report errors (unterminated comments or
+ strings) on behalf of CALLER, if non-NULL.
If OBS is NULL or the token expansion is unknown, the token text is
collected on the obstack token_stack, which never contains more
@@ -1365,7 +1446,7 @@ m4_input_exit (void)
m4__next_token () is called. */
m4__token_type
m4__next_token (m4 *context, m4_symbol_value *token, int *line,
- m4_obstack *obs, const char *caller)
+ m4_obstack *obs, bool allow_argv, const char *caller)
{
int ch;
int quote_level;
@@ -1388,7 +1469,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int
*line,
/* Must consume an input character, but not until CHAR_BUILTIN is
handled. */
- ch = peek_char (context);
+ ch = peek_char (context, allow_argv && m4__quote_age (M4SYNTAX));
if (ch == CHAR_EOF) /* EOF */
{
#ifdef DEBUG_INPUT
@@ -1407,6 +1488,14 @@ m4__next_token (m4 *context, m4_symbol_value *token, int
*line,
#endif
return M4_TOKEN_MACDEF;
}
+ if (ch == CHAR_ARGV)
+ {
+ init_argv_symbol (context, obs, token);
+#ifdef DEBUG_INPUT
+ m4_print_token ("next_token", M4_TOKEN_ARGV, token);
+#endif
+ return M4_TOKEN_ARGV;
+ }
/* Consume character we already peeked at. */
next_char (context, false, true);
@@ -1644,7 +1733,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int
*line,
bool
m4__next_token_is_open (m4 *context)
{
- int ch = peek_char (context);
+ int ch = peek_char (context, false);
if (ch == CHAR_EOF || ch == CHAR_BUILTIN
|| m4_has_syntax (M4SYNTAX, ch, (M4_SYNTAX_BCOMM | M4_SYNTAX_ESCAPE
@@ -1667,55 +1756,61 @@ m4_print_token (const char *s, m4__token_type type,
m4_symbol_value *token)
m4_obstack obs;
size_t len;
- obstack_init (&obs);
if (!s)
s = "m4input";
- obstack_grow (&obs, s, strlen (s));
- obstack_1grow (&obs, ':');
- obstack_1grow (&obs, ' ');
+ xfprintf (stderr, "%s: ", s);
switch (type)
{ /* TOKSW */
case M4_TOKEN_EOF:
- obstack_grow (&obs, "eof", strlen ("eof"));
+ fputs ("eof", stderr);
token = NULL;
break;
case M4_TOKEN_NONE:
- obstack_grow (&obs, "none", strlen ("none"));
+ fputs ("none", stderr);
token = NULL;
break;
case M4_TOKEN_STRING:
- obstack_grow (&obs, "string\t", strlen ("string\t"));
+ fputs ("string\t", stderr);
break;
case M4_TOKEN_SPACE:
- obstack_grow (&obs, "space\t", strlen ("space\t"));
+ fputs ("space\t", stderr);
break;
case M4_TOKEN_WORD:
- obstack_grow (&obs, "word\t", strlen ("word\t"));
+ fputs ("word\t", stderr);
break;
case M4_TOKEN_OPEN:
- obstack_grow (&obs, "open\t", strlen ("open\t"));
+ fputs ("open\t", stderr);
break;
case M4_TOKEN_COMMA:
- obstack_grow (&obs, "comma\t", strlen ("comma\t"));
+ fputs ("comma\t", stderr);
break;
case M4_TOKEN_CLOSE:
- obstack_grow (&obs, "close\t", strlen ("close\t"));
+ fputs ("close\t", stderr);
break;
case M4_TOKEN_SIMPLE:
- obstack_grow (&obs, "simple\t", strlen ("simple\t"));
+ fputs ("simple\t", stderr);
break;
case M4_TOKEN_MACDEF:
- obstack_grow (&obs, "builtin\t", strlen ("builtin\t"));
+ fputs ("builtin\t", stderr);
+ break;
+ case M4_TOKEN_ARGV:
+ fputs ("argv\t", stderr);
break;
default:
abort ();
}
if (token)
- m4_symbol_value_print (token, &obs, true, "\"", "\"", SIZE_MAX, NULL);
- obstack_1grow (&obs, '\n');
- len = obstack_object_size (&obs);
- fwrite (obstack_finish (&obs), 1, len, stderr);
- obstack_free (&obs, NULL);
+ {
+ obstack_init (&obs);
+ m4_symbol_value_print (token, &obs, NULL, NULL, true);
+ len = obstack_object_size (&obs);
+ xfprintf (stderr, "%s\n", quotearg_style_mem (c_maybe_quoting_style,
+ obstack_finish (&obs),
+ len));
+ obstack_free (&obs, NULL);
+ }
+ else
+ fputc ('\n', stderr);
return 0;
}
#endif /* DEBUG_INPUT */
diff --git a/m4/m4private.h b/m4/m4private.h
index 77590f3..a2b78b8 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -221,6 +221,7 @@ struct m4__symbol_chain
size_t index; /* Argument index within argv. */
bool_bitfield flatten : 1; /* True to treat builtins as text. */
bool_bitfield comma : 1; /* True when `,' is next input. */
+ bool_bitfield skip_last : 1; /* True if last argument omitted. */
const m4_string_pair *quotes; /* NULL for $*, quotes for
address@hidden */
} u_a; /* M4__CHAIN_ARGV. */
} u;
@@ -397,7 +398,8 @@ extern void m4__symtab_remove_module_references
(m4_symbol_table*,
#define CHAR_EOF 256 /* Character return on EOF. */
#define CHAR_BUILTIN 257 /* Character return for BUILTIN token. */
#define CHAR_QUOTE 258 /* Character return for quoted string. */
-#define CHAR_RETRY 259 /* Character return for end of input block. */
+#define CHAR_ARGV 259 /* Character return for $@ reference. */
+#define CHAR_RETRY 260 /* Character return for end of input block. */
#define DEF_LQUOTE "`" /* Default left quote delimiter. */
#define DEF_RQUOTE "\'" /* Default right quote delimiter. */
@@ -475,7 +477,8 @@ typedef enum {
M4_TOKEN_COMMA, /* Argument separator, M4_SYMBOL_TEXT. */
M4_TOKEN_CLOSE, /* Argument list end, M4_SYMBOL_TEXT. */
M4_TOKEN_SIMPLE, /* Single character, M4_SYMBOL_TEXT. */
- M4_TOKEN_MACDEF /* Macro's definition (see "defn"), M4_SYMBOL_FUNC. */
+ M4_TOKEN_MACDEF, /* Macro's definition (see "defn"), M4_SYMBOL_FUNC. */
+ M4_TOKEN_ARGV /* A series of parameters, M4_SYMBOL_COMP. */
} m4__token_type;
extern void m4__make_text_link (m4_obstack *, m4__symbol_chain **,
@@ -483,7 +486,7 @@ extern void m4__make_text_link (m4_obstack
*, m4__symbol_chain **,
extern bool m4__push_symbol (m4 *, m4_symbol_value *, size_t,
bool);
extern m4__token_type m4__next_token (m4 *, m4_symbol_value *, int *,
- m4_obstack *, const char *);
+ m4_obstack *, bool, const char *);
extern bool m4__next_token_is_open (m4 *);
/* Fast macro versions of macro argv accessor functions,
diff --git a/m4/macro.c b/m4/macro.c
index 708be58..d6f81d8 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -183,7 +183,7 @@ m4_macro_expand_input (m4 *context)
m4_set_symbol_value_text (&empty_symbol, "", 0, 0);
VALUE_MAX_ARGS (&empty_symbol) = -1;
- while ((type = m4__next_token (context, &token, &line, NULL, NULL))
+ while ((type = m4__next_token (context, &token, &line, NULL, false, NULL))
!= M4_TOKEN_EOF)
expand_token (context, NULL, type, &token, line, true);
}
@@ -311,7 +311,7 @@ expand_argument (m4 *context, m4_obstack *obs,
m4_symbol_value *argp,
/* Skip leading white space. */
do
{
- type = m4__next_token (context, &token, NULL, obs, caller);
+ type = m4__next_token (context, &token, NULL, obs, true, caller);
}
while (type == M4_TOKEN_SPACE);
@@ -389,6 +389,20 @@ expand_argument (m4 *context, m4_obstack *obs,
m4_symbol_value *argp,
argp->type = M4_SYMBOL_TEXT;
break;
+ case M4_TOKEN_ARGV:
+ 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->type == M4__CHAIN_ARGV);
+ argp->type = M4_SYMBOL_COMP;
+ argp->u.u_c.chain = argp->u.u_c.end = token.u.u_c.chain;
+ type = m4__next_token (context, &token, NULL, NULL, false, caller);
+ if (argp->u.u_c.chain->u.u_a.skip_last)
+ assert (type == M4_TOKEN_COMMA);
+ else
+ assert (type == M4_TOKEN_COMMA || type == M4_TOKEN_CLOSE);
+ return type == M4_TOKEN_COMMA;
+
default:
assert (!"expand_argument");
abort ();
@@ -396,7 +410,7 @@ expand_argument (m4 *context, m4_obstack *obs,
m4_symbol_value *argp,
if (argp->type != M4_SYMBOL_VOID || obstack_object_size (obs))
first = false;
- type = m4__next_token (context, &token, NULL, obs, caller);
+ type = m4__next_token (context, &token, NULL, obs, first, caller);
}
}
@@ -583,7 +597,7 @@ collect_arguments (m4 *context, const char *name, size_t
len,
if (m4__next_token_is_open (context))
{
/* Gobble parenthesis, then collect arguments. */
- m4__next_token (context, &token, NULL, NULL, name);
+ m4__next_token (context, &token, NULL, NULL, false, name);
do
{
tokenp = (m4_symbol_value *) obstack_alloc (arguments,
@@ -608,12 +622,22 @@ collect_arguments (m4 *context, const char *name, size_t
len,
&& m4_get_symbol_value_quote_age (tokenp) != args.quote_age)
args.quote_age = 0;
else if (tokenp->type == M4_SYMBOL_COMP)
- args.has_ref = true;
+ {
+ args.has_ref = true;
+ if (tokenp->u.u_c.chain->type == M4__CHAIN_ARGV)
+ {
+ args.argc += (tokenp->u.u_c.chain->u.u_a.argv->argc
+ - tokenp->u.u_c.chain->u.u_a.index
+ - tokenp->u.u_c.chain->u.u_a.skip_last - 1);
+ args.wrapper = true;
+ }
+ }
}
while (more_args);
}
argv = (m4_macro_args *) obstack_finish (argv_stack);
argv->argc = args.argc;
+ argv->wrapper = args.wrapper;
argv->has_ref = args.has_ref;
if (args.quote_age != m4__quote_age (M4SYNTAX))
argv->quote_age = 0;
@@ -981,9 +1005,22 @@ m4__arg_adjust_refcount (m4 *context, m4_macro_args
*argv, bool increase)
chain = argv->array[i]->u.u_c.chain;
while (chain)
{
- assert (chain->type == M4__CHAIN_STR);
- if (chain->u.u_s.level < SIZE_MAX)
- m4__adjust_refcount (context, chain->u.u_s.level, increase);
+ switch (chain->type)
+ {
+ case M4__CHAIN_STR:
+ if (chain->u.u_s.level < SIZE_MAX)
+ m4__adjust_refcount (context, chain->u.u_s.level,
+ increase);
+ break;
+ case M4__CHAIN_ARGV:
+ assert (chain->u.u_a.argv->inuse);
+ m4__arg_adjust_refcount (context, chain->u.u_a.argv,
+ increase);
+ break;
+ default:
+ assert (!"m4__arg_adjust_refcount");
+ abort ();
+ }
chain = chain->next;
}
}
@@ -996,15 +1033,25 @@ m4__arg_adjust_refcount (m4 *context, m4_macro_args
*argv, bool increase)
static void
arg_mark (m4_macro_args *argv)
{
+ size_t i;
+ m4__symbol_chain *chain;
+
+ if (argv->inuse)
+ return;
argv->inuse = true;
if (argv->wrapper)
{
- /* TODO for now we support only a single-length $@ chain. */
- assert (argv->arraylen == 1
- && argv->array[0]->type == M4_SYMBOL_COMP
- && !argv->array[0]->u.u_c.chain->next
- && argv->array[0]->u.u_c.chain->type == M4__CHAIN_ARGV);
- argv->array[0]->u.u_c.chain->u.u_a.argv->inuse = true;
+ for (i = 0; i < argv->arraylen; i++)
+ if (argv->array[i]->type == M4_SYMBOL_COMP)
+ {
+ chain = argv->array[i]->u.u_c.chain;
+ while (chain)
+ {
+ if (chain->type == M4__CHAIN_ARGV && !chain->u.u_a.argv->inuse)
+ arg_mark (chain->u.u_a.argv);
+ chain = chain->next;
+ }
+ }
}
}
@@ -1022,12 +1069,13 @@ make_argv_ref (m4_symbol_value *value, m4_obstack *obs,
size_t level,
m4__symbol_chain *chain;
assert (obstack_object_size (obs) == 0);
- if (argv->wrapper)
+ if (argv->wrapper && argv->arraylen == 1)
{
- /* TODO support concatenation with $@ refs. */
- assert (argv->arraylen == 1 && argv->array[0]->type == M4_SYMBOL_COMP);
+ /* TODO support $@ ref alongside other arguments. */
+ assert (argv->array[0]->type == M4_SYMBOL_COMP);
chain= argv->array[0]->u.u_c.chain;
- assert (!chain->next && chain->type == M4__CHAIN_ARGV);
+ assert (!chain->next && chain->type == M4__CHAIN_ARGV
+ && !chain->u.u_a.skip_last);
argv = chain->u.u_a.argv;
index += chain->u.u_a.index - 1;
}
@@ -1044,6 +1092,7 @@ make_argv_ref (m4_symbol_value *value, m4_obstack *obs,
size_t level,
chain->u.u_a.index = index;
chain->u.u_a.flatten = flatten;
chain->u.u_a.comma = false;
+ chain->u.u_a.skip_last = false;
if (quotes)
{
/* Clone the quotes into the obstack, since changequote can
@@ -1081,12 +1130,14 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t
*level)
for (i = 0; i < argv->arraylen; i++)
{
value = argv->array[i];
- if (value->type == M4_SYMBOL_COMP)
+ if (value->type == M4_SYMBOL_COMP
+ && value->u.u_c.chain->type == M4__CHAIN_ARGV)
{
m4__symbol_chain *chain = value->u.u_c.chain;
/* TODO - for now we support only a single $@ chain. */
- assert (!chain->next && chain->type == M4__CHAIN_ARGV);
- if (index < chain->u.u_a.argv->argc - (chain->u.u_a.index - 1))
+ assert (!chain->next);
+ if (index <= (chain->u.u_a.argv->argc - chain->u.u_a.index
+ - chain->u.u_a.skip_last))
{
value = arg_symbol (chain->u.u_a.argv,
chain->u.u_a.index - 1 + index, level);
@@ -1094,7 +1145,8 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t
*level)
value = &empty_symbol;
break;
}
- index -= chain->u.u_a.argv->argc - chain->u.u_a.index;
+ index -= (chain->u.u_a.argv->argc - chain->u.u_a.index
+ - chain->u.u_a.skip_last);
}
else if (--index == 0)
break;
@@ -1154,15 +1206,25 @@ m4_arg_text (m4 *context, m4_macro_args *argv, size_t
index)
value = m4_arg_symbol (argv, index);
if (m4_is_symbol_value_text (value))
return m4_get_symbol_value_text (value);
- /* TODO - concatenate argv refs and functions? For now, we assume
- all chain elements are text. */
+ /* TODO - concatenate functions. */
assert (value->type == M4_SYMBOL_COMP);
chain = value->u.u_c.chain;
obs = m4_arg_scratch (context);
while (chain)
{
- assert (chain->type == M4__CHAIN_STR);
- obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+ switch (chain->type)
+ {
+ case M4__CHAIN_STR:
+ obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+ break;
+ case M4__CHAIN_ARGV:
+ m4_arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
+ chain->u.u_a.quotes, NULL, false);
+ break;
+ default:
+ assert (!"m4_arg_text");
+ abort ();
+ }
chain = chain->next;
}
obstack_1grow (obs, '\0');
diff --git a/m4/symtab.c b/m4/symtab.c
index f302fe8..9636f9d 100644
--- a/m4/symtab.c
+++ b/m4/symtab.c
@@ -845,7 +845,7 @@ dump_symbol_CB (m4_symbol_table *symtab, const char *name,
{
m4_obstack obs;
obstack_init (&obs);
- m4_symbol_value_print (value, &obs, false, NULL, NULL, SIZE_MAX, true);
+ m4_symbol_value_print (value, &obs, NULL, NULL, true);
xfprintf (stderr, "%s", (char *) obstack_finish (&obs));
obstack_free (&obs, NULL);
}
diff --git a/m4/syntax.c b/m4/syntax.c
index aff6444..8a7b0d1 100644
--- a/m4/syntax.c
+++ b/m4/syntax.c
@@ -743,9 +743,11 @@ set_quote_age (m4_syntax_table *syntax, bool reset, bool
change)
| M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE
| M4_SYNTAX_SPACE))
&& *syntax->quote.str1 != *syntax->quote.str2
- && *syntax->comm.str1 != *syntax->quote.str2
- && !m4_has_syntax (syntax, *syntax->comm.str1,
- M4_SYNTAX_OPEN | M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)
+ && (!syntax->comm.len1
+ || (*syntax->comm.str1 != *syntax->quote.str2
+ && !m4_has_syntax (syntax, *syntax->comm.str1,
+ (M4_SYNTAX_OPEN | M4_SYNTAX_COMMA
+ | M4_SYNTAX_CLOSE))))
&& m4_has_syntax (syntax, ',', M4_SYNTAX_COMMA))
{
syntax->quote_age = ((local_syntax_age << 16)
hooks/post-receive
--
GNU M4 source repository
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-63-g5d083e4,
Eric Blake <=