struct macro_expander
{
- const struct macro_set *macros;
+ /* Always available. */
+ const struct macro_set *macros; /* Macros to expand recursively. */
+ enum segmenter_mode segmenter_mode; /* Mode for tokenization. */
+ int nesting_countdown; /* Remaining nesting levels. */
+ const struct macro_expansion_stack *stack; /* Stack for error reporting. */
+ bool *expand; /* May macro calls be expanded? */
+ struct stringi_map *vars; /* Variables from !DO and !LET. */
+
+ /* Only nonnull if inside a !DO loop. */
+ bool *break_; /* Set to true to break out of loop. */
+
+ /* Only nonnull if expanding a macro (and not, say, a macro argument). */
const struct macro *macro;
struct macro_tokens **args;
- enum segmenter_mode segmenter_mode;
- struct stringi_map *vars;
- bool *expand;
- bool *break_;
- int nesting_countdown;
- const struct macro_expansion_stack *stack;
};
/* Each argument to a macro function is one of:
sequence of tokens. The case where that character sequence is a single
quoted string is an important special case.
*/
-struct parse_macro_function_ctx
- {
- const struct macro_token *input;
- size_t n_input;
- const struct macro_expander *me;
- };
static void
macro_expand (const struct macro_tokens *, const struct macro_expander *,
struct macro_tokens *);
static bool
-expand_macro_function (struct parse_macro_function_ctx *ctx,
+expand_macro_function (const struct macro_expander *me,
+ const struct macro_token *input, size_t n_input,
struct string *output, size_t *input_consumed);
/* Returns true if the pair of tokens starting at offset OFS within MTS are !*,
}
static size_t
-parse_function_arg (struct parse_macro_function_ctx *ctx,
+parse_function_arg (const struct macro_expander *me,
+ const struct macro_token *input, size_t n_input,
size_t i, struct string *farg)
{
- const struct macro_token *tokens = ctx->input;
- const struct token *token = &tokens[i].token;
- if (token->type == T_MACRO_ID && ctx->me->macro)
+ const struct token *token = &input[i].token;
+ if (token->type == T_MACRO_ID && me->macro)
{
const struct macro_param *param = macro_find_parameter_by_name (
- ctx->me->macro, token->string);
+ me->macro, token->string);
if (param)
{
- size_t param_idx = param - ctx->me->macro->params;
- const struct macro_tokens *marg = ctx->me->args[param_idx];
+ size_t param_idx = param - me->macro->params;
+ const struct macro_tokens *marg = me->args[param_idx];
for (size_t i = 0; i < marg->n; i++)
{
if (i)
return 1;
}
- if (is_bang_star (ctx->input, ctx->n_input, i))
+ if (is_bang_star (input, n_input, i))
{
- for (size_t i = 0; i < ctx->me->macro->n_params; i++)
+ for (size_t i = 0; i < me->macro->n_params; i++)
{
- if (!ctx->me->macro->params[i].positional)
+ if (!me->macro->params[i].positional)
break;
- const struct macro_tokens *marg = ctx->me->args[i];
+ const struct macro_tokens *marg = me->args[i];
for (size_t j = 0; j < marg->n; j++)
{
if (i || j)
return 2;
}
- const char *value = stringi_map_find__ (ctx->me->vars,
+ const char *value = stringi_map_find__ (me->vars,
token->string.string,
token->string.length);
if (value)
return 1;
}
- struct parse_macro_function_ctx subctx = {
- .input = &ctx->input[i],
- .n_input = ctx->n_input - i,
- .me = ctx->me,
- };
size_t subinput_consumed;
- if (expand_macro_function (&subctx, farg, &subinput_consumed))
+ if (expand_macro_function (me, &input[i], n_input - i,
+ farg, &subinput_consumed))
return subinput_consumed;
}
- ds_put_substring (farg, tokens[i].representation);
+ ds_put_substring (farg, input[i].representation);
return 1;
}
static bool
-parse_macro_function (struct parse_macro_function_ctx *ctx,
+parse_macro_function (const struct macro_expander *me,
+ const struct macro_token *tokens, size_t n_tokens,
struct string_array *args,
struct substring function,
int min_args, int max_args,
size_t *input_consumed)
{
- const struct macro_token *tokens = ctx->input;
- size_t n_tokens = ctx->n_input;
-
if (!n_tokens
|| tokens[0].token.type != T_MACRO_ID
|| !ss_equals_case (tokens[0].token.string, function)) /* XXX abbrevs allowed */
if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
{
- macro_error (ctx->me->stack, n_tokens > 1 ? &tokens[1] : NULL,
+ macro_error (me->stack, n_tokens > 1 ? &tokens[1] : NULL,
_("`(' expected following %s."), function.string);
return false;
}
*input_consumed = i + 1;
if (args->n < min_args || args->n > max_args)
{
- macro_error (ctx->me->stack, &tokens[i],
+ macro_error (me->stack, &tokens[i],
_("Wrong number of arguments to macro function %s."),
function.string);
goto error;
}
struct string s = DS_EMPTY_INITIALIZER;
- i += parse_function_arg (ctx, i, &s);
+ i += parse_function_arg (me, tokens, n_tokens, i, &s);
if (i >= n_tokens)
{
ds_destroy (&s);
i++;
else if (tokens[i].token.type != T_RPAREN)
{
- macro_error (ctx->me->stack, &tokens[i],
+ macro_error (me->stack, &tokens[i],
_("`,' or `)' expected in call to macro function %s."),
function.string);
goto error;
}
unexpected_end:
- macro_error (ctx->me->stack, NULL, _("Missing `)' in call to macro function %s."),
+ macro_error (me->stack, NULL, _("Missing `)' in call to macro function %s."),
function.string);
/* Fall through. */
error:
}
static bool
-expand_macro_function (struct parse_macro_function_ctx *ctx,
- struct string *output,
- size_t *input_consumed)
+expand_macro_function (const struct macro_expander *me,
+ const struct macro_token *input, size_t n_input,
+ struct string *output, size_t *input_consumed)
{
struct string_array args;
-
- if (parse_macro_function (ctx, &args, ss_cstr ("!LENGTH"), 1, 1,
+ if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!LENGTH"), 1, 1,
input_consumed))
ds_put_format (output, "%zu", strlen (args.strings[0]));
- else if (parse_macro_function (ctx, &args, ss_cstr ("!BLANKS"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!BLANKS"), 1, 1,
input_consumed))
{
int n;
if (!parse_integer (args.strings[0], &n))
{
- macro_error (ctx->me->stack, NULL,
+ macro_error (me->stack, NULL,
_("Argument to !BLANKS must be non-negative integer "
"(not \"%s\")."), args.strings[0]);
string_array_destroy (&args);
ds_put_byte_multiple (output, ' ', n);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!CONCAT"), 1, INT_MAX,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!CONCAT"), 1, INT_MAX,
input_consumed))
{
for (size_t i = 0; i < args.n; i++)
- if (!unquote_string (args.strings[i], ctx->me->segmenter_mode, output))
+ if (!unquote_string (args.strings[i], me->segmenter_mode, output))
ds_put_cstr (output, args.strings[i]);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!HEAD"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!HEAD"), 1, 1,
input_consumed))
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->me->segmenter_mode, &tmp);
+ me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
- ctx->me->stack);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
+ me->stack);
if (mts.n > 0)
ds_put_substring (output, mts.mts[0].representation);
macro_tokens_uninit (&mts);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!INDEX"), 2, 2,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!INDEX"), 2, 2,
input_consumed))
{
const char *haystack = args.strings[0];
const char *needle = strstr (haystack, args.strings[1]);
ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!QUOTE"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!QUOTE"), 1, 1,
input_consumed))
{
- if (unquote_string (args.strings[0], ctx->me->segmenter_mode, NULL))
+ if (unquote_string (args.strings[0], me->segmenter_mode, NULL))
ds_put_cstr (output, args.strings[0]);
else
{
ds_put_byte (output, '\'');
}
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!SUBSTR"), 2, 3,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!SUBSTR"), 2, 3,
input_consumed))
{
int start;
if (!parse_integer (args.strings[1], &start) || start < 1)
{
- macro_error (ctx->me->stack, NULL,
+ macro_error (me->stack, NULL,
_("Second argument of !SUBSTR must be "
"positive integer (not \"%s\")."),
args.strings[1]);
int count = INT_MAX;
if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
{
- macro_error (ctx->me->stack, NULL,
+ macro_error (me->stack, NULL,
_("Third argument of !SUBSTR must be "
"non-negative integer (not \"%s\")."),
args.strings[2]);
struct substring s = ss_cstr (args.strings[0]);
ds_put_substring (output, ss_substr (s, start - 1, count));
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!TAIL"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!TAIL"), 1, 1,
input_consumed))
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->me->segmenter_mode, &tmp);
+ me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
- ctx->me->stack);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
+ me->stack);
if (mts.n > 1)
{
struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
macro_tokens_uninit (&mts);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!UNQUOTE"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!UNQUOTE"), 1, 1,
input_consumed))
{
- if (!unquote_string (args.strings[0], ctx->me->segmenter_mode, output))
+ if (!unquote_string (args.strings[0], me->segmenter_mode, output))
ds_put_cstr (output, args.strings[0]);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!UPCASE"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!UPCASE"), 1, 1,
input_consumed))
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->me->segmenter_mode, &tmp);
+ me->segmenter_mode, &tmp);
char *upper = utf8_to_upper (s);
ds_put_cstr (output, upper);
free (upper);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!EVAL"), 1, 1,
+ else if (parse_macro_function (me, input, n_input, &args, ss_cstr ("!EVAL"), 1, 1,
input_consumed))
{
struct macro_tokens mts = { .n = 0 };
macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
- ctx->me->segmenter_mode, ctx->me->stack);
+ me->segmenter_mode, me->stack);
struct macro_tokens exp = { .n = 0 };
struct macro_expansion_stack stack = {
.name = "!EVAL",
- .next = ctx->me->stack
+ .next = me->stack
};
- struct macro_expander subme = *ctx->me;
+ struct macro_expander subme = *me;
subme.break_ = NULL;
subme.stack = &stack;
macro_tokens_uninit (&exp);
macro_tokens_uninit (&mts);
}
- else if (ctx->n_input > 0
- && ctx->input[0].token.type == T_MACRO_ID
- && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!NULL")))
+ else if (n_input > 0
+ && input[0].token.type == T_MACRO_ID
+ && ss_equals_case (input[0].token.string, ss_cstr ("!NULL")))
{
*input_consumed = 1;
return true;
return NULL;
}
- struct parse_macro_function_ctx fctx = {
- .input = p,
- .n_input = end - p,
- .me = me,
- };
struct string function_output = DS_EMPTY_INITIALIZER;
- size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
+ size_t function_consumed = parse_function_arg (me, p, end - p,
+ 0, &function_output);
struct string unquoted = DS_EMPTY_INITIALIZER;
if (unquote_string (ds_cstr (&function_output), me->segmenter_mode,
&unquoted))
}
}
- struct parse_macro_function_ctx ctx = {
- .input = &mts->mts[i],
- .n_input = mts->n - i,
- .me = me,
- };
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed;
- if (expand_macro_function (&ctx, &function_output, &function_consumed))
+ if (expand_macro_function (me, &mts->mts[i], mts->n - i,
+ &function_output, &function_consumed))
{
i += function_consumed - 1;