bool *expand;
bool *break_;
int nesting_countdown;
+ const struct macro_expansion_stack *stack;
};
/* Each argument to a macro function is one of:
const struct macro_token *input;
size_t n_input;
const struct macro_expander *me;
- const struct macro_expansion_stack *stack;
};
static void
macro_expand (const struct macro_tokens *, const struct macro_expander *,
- const struct macro_expansion_stack *,
struct macro_tokens *);
static bool
.input = &ctx->input[i],
.n_input = ctx->n_input - i,
.me = ctx->me,
- .stack = ctx->stack,
};
size_t subinput_consumed;
if (expand_macro_function (&subctx, farg, &subinput_consumed))
if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
{
- macro_error (ctx->stack, n_tokens > 1 ? &tokens[1] : NULL,
+ macro_error (ctx->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->stack, &tokens[i],
+ macro_error (ctx->me->stack, &tokens[i],
_("Wrong number of arguments to macro function %s."),
function.string);
goto error;
i++;
else if (tokens[i].token.type != T_RPAREN)
{
- macro_error (ctx->stack, &tokens[i],
+ macro_error (ctx->me->stack, &tokens[i],
_("`,' or `)' expected in call to macro function %s."),
function.string);
goto error;
}
unexpected_end:
- macro_error (ctx->stack, NULL, _("Missing `)' in call to macro function %s."),
+ macro_error (ctx->me->stack, NULL, _("Missing `)' in call to macro function %s."),
function.string);
/* Fall through. */
error:
int n;
if (!parse_integer (args.strings[0], &n))
{
- macro_error (ctx->stack, NULL,
+ macro_error (ctx->me->stack, NULL,
_("Argument to !BLANKS must be non-negative integer "
"(not \"%s\")."), args.strings[0]);
string_array_destroy (&args);
struct macro_tokens mts = { .n = 0 };
macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
- ctx->stack);
+ ctx->me->stack);
if (mts.n > 0)
ds_put_substring (output, mts.mts[0].representation);
macro_tokens_uninit (&mts);
int start;
if (!parse_integer (args.strings[1], &start) || start < 1)
{
- macro_error (ctx->stack, NULL,
+ macro_error (ctx->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->stack, NULL,
+ macro_error (ctx->me->stack, NULL,
_("Third argument of !SUBSTR must be "
"non-negative integer (not \"%s\")."),
args.strings[2]);
struct macro_tokens mts = { .n = 0 };
macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
- ctx->stack);
+ ctx->me->stack);
if (mts.n > 1)
{
struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
{
struct macro_tokens mts = { .n = 0 };
macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
- ctx->me->segmenter_mode, ctx->stack);
+ ctx->me->segmenter_mode, ctx->me->stack);
struct macro_tokens exp = { .n = 0 };
+ struct macro_expansion_stack stack = {
+ .name = "!EVAL",
+ .next = ctx->me->stack
+ };
struct macro_expander subme = *ctx->me;
subme.break_ = NULL;
- macro_expand (&mts, &subme,
- &(struct macro_expansion_stack) {
- .name = "!EVAL",
- .next = ctx->stack,
- }, &exp);
+ subme.stack = &stack;
+
+ macro_expand (&mts, &subme, &exp);
macro_tokens_to_representation (&exp, output, NULL, NULL);
macro_tokens_uninit (&exp);
macro_tokens_uninit (&mts);
}
static char *macro_evaluate_or (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end);
static char *
macro_evaluate_literal (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
if (p->token.type == T_LPAREN)
{
p++;
- char *value = macro_evaluate_or (me, stack, &p, end);
+ char *value = macro_evaluate_or (me, &p, end);
if (!value)
return NULL;
if (p >= end || p->token.type != T_RPAREN)
{
free (value);
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Expecting ')' in macro expression."));
return NULL;
}
}
else if (p->token.type == T_RPAREN)
{
- macro_error (stack, p, _("Expecting literal or function invocation "
- "in macro expression."));
+ macro_error (me->stack, p, _("Expecting literal or function invocation "
+ "in macro expression."));
return NULL;
}
.input = p,
.n_input = end - p,
.me = me,
- .stack = stack,
};
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
static char *
macro_evaluate_relational (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_literal (me, stack, &p, end);
+ char *lhs = macro_evaluate_literal (me, &p, end);
if (!lhs)
return NULL;
}
p++;
- char *rhs = macro_evaluate_literal (me, stack, &p, end);
+ char *rhs = macro_evaluate_literal (me, &p, end);
if (!rhs)
{
free (lhs);
static char *
macro_evaluate_not (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
negations++;
}
- char *operand = macro_evaluate_relational (me, stack, &p, end);
+ char *operand = macro_evaluate_relational (me, &p, end);
if (!operand || !negations)
{
*tokens = p;
static char *
macro_evaluate_and (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_not (me, stack, &p, end);
+ char *lhs = macro_evaluate_not (me, &p, end);
if (!lhs)
return NULL;
|| ss_equals (p->representation, ss_cstr ("&"))))
{
p++;
- char *rhs = macro_evaluate_not (me, stack, &p, end);
+ char *rhs = macro_evaluate_not (me, &p, end);
if (!rhs)
{
free (lhs);
static char *
macro_evaluate_or (const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_and (me, stack, &p, end);
+ char *lhs = macro_evaluate_and (me, &p, end);
if (!lhs)
return NULL;
|| ss_equals (p->representation, ss_cstr ("|"))))
{
p++;
- char *rhs = macro_evaluate_and (me, stack, &p, end);
+ char *rhs = macro_evaluate_and (me, &p, end);
if (!rhs)
{
free (lhs);
static char *
macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
- const struct macro_expander *me,
- const struct macro_expansion_stack *stack)
+ const struct macro_expander *me)
{
- return macro_evaluate_or (me, stack, tokens, *tokens + n_tokens);
+ return macro_evaluate_or (me, tokens, *tokens + n_tokens);
}
static bool
macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
double *number)
{
- char *s = macro_evaluate_expression (tokens, n_tokens, me, stack);
+ char *s = macro_evaluate_expression (tokens, n_tokens, me);
if (!s)
return false;
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, stack);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, me->stack);
if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
{
- macro_error (stack, mts.n > 0 ? &mts.mts[0] : NULL,
+ macro_error (me->stack, mts.n > 0 ? &mts.mts[0] : NULL,
_("Macro expression must evaluate to "
"a number (not \"%s\")."), s);
free (s);
static size_t
macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
return 0;
p++;
- char *result = macro_evaluate_expression (&p, end - p, me, stack);
+ char *result = macro_evaluate_expression (&p, end - p, me);
if (!result)
return 0;
bool b = strcmp (result, "0");
|| p->token.type != T_MACRO_ID
|| !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("!THEN expected in macro !IF construct."));
return 0;
}
const struct macro_token *end_then = find_ifend_clause (start_then, end);
if (!end_then)
{
- macro_error (stack, NULL,
+ macro_error (me->stack, NULL,
_("!ELSE or !IFEND expected in macro !IF construct."));
return 0;
}
if (!end_if
|| !ss_equals_case (end_if->token.string, ss_cstr ("!IFEND")))
{
- macro_error (stack, end_if ? end_if : NULL,
+ macro_error (me->stack, end_if ? end_if : NULL,
_("!IFEND expected in macro !IF construct."));
return 0;
}
.mts = CONST_CAST (struct macro_token *, start),
.n = n,
};
- macro_expand (&mts, me, &(struct macro_expansion_stack) {
- .name = "!IF",
- .next = stack,
- },
- exp);
+ struct macro_expansion_stack stack = {
+ .name = "!IF",
+ .next = me->stack,
+ };
+ struct macro_expander subme = *me;
+ subme.stack = &stack;
+ macro_expand (&mts, &subme, exp);
}
return (end_if + 1) - tokens;
}
static size_t
macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
- const struct macro_expander *me,
- const struct macro_expansion_stack *stack)
+ const struct macro_expander *me)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
if (p >= end || p->token.type != T_MACRO_ID)
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Expected macro variable name following !LET."));
return 0;
}
if (is_macro_keyword (var_name)
|| (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Cannot use argument name or macro keyword "
"\"%.*s\" as !LET variable."),
(int) var_name.length, var_name.string);
if (p >= end || p->token.type != T_EQUALS)
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Expected `=' following !LET."));
return 0;
}
p++;
- char *value = macro_evaluate_expression (&p, end - p, me, stack);
+ char *value = macro_evaluate_expression (&p, end - p, me);
if (!value)
return 0;
static size_t
macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
if (p >= end || p->token.type != T_MACRO_ID)
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Expected macro variable name following !DO."));
return 0;
}
if (is_macro_keyword (var_name)
|| (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
{
- macro_error (stack, p, _("Cannot use argument name or macro "
+ macro_error (me->stack, p, _("Cannot use argument name or macro "
"keyword as !DO variable."));
return 0;
}
p++;
- struct macro_expansion_stack next_stack = {
- .name = "!DO", .next = stack,
+ struct macro_expansion_stack substack = {
+ .name = "!DO",
+ .next = me->stack,
};
+ bool break_ = false;
+ struct macro_expander subme = *me;
+ subme.break_ = &break_;
+ subme.stack = &substack;
+
int miterate = settings_get_miterate ();
if (p < end && p->token.type == T_MACRO_ID
&& ss_equals_case (p->token.string, ss_cstr ("!IN")))
{
p++;
- char *list = macro_evaluate_expression (&p, end - p, me, &next_stack);
+ char *list = macro_evaluate_expression (&p, end - p, &subme);
if (!list)
return 0;
struct macro_tokens items = { .n = 0 };
macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode,
- stack);
+ me->stack);
free (list);
- const struct macro_token *do_end = find_doend (stack, p, end);
+ const struct macro_token *do_end = find_doend (subme.stack, p, end);
if (!do_end)
{
macro_tokens_uninit (&items);
.n = do_end - p
};
- bool break_ = false;
- struct macro_expander subme = *me;
- subme.break_ = &break_;
-
for (size_t i = 0; i < items.n && !break_; i++)
{
if (i >= miterate)
{
- macro_error (stack, NULL,
+ macro_error (&substack, NULL,
_("!DO loop over list exceeded "
"maximum number of iterations %d. "
"(Use SET MITERATE to change the limit.)"),
stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
ss_xstrdup (items.mts[i].representation));
- macro_expand (&inner, &subme, &next_stack, exp);
+ macro_expand (&inner, &subme, exp);
}
return do_end - tokens + 1;
}
{
p++;
double first;
- if (!macro_evaluate_number (&p, end - p, me, &next_stack, &first))
+ if (!macro_evaluate_number (&p, end - p, &subme, &first))
return 0;
if (p >= end || p->token.type != T_MACRO_ID
|| !ss_equals_case (p->token.string, ss_cstr ("!TO")))
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (subme.stack, p < end ? p : NULL,
_("Expected !TO in numerical !DO loop."));
return 0;
}
p++;
double last;
- if (!macro_evaluate_number (&p, end - p, me, &next_stack, &last))
+ if (!macro_evaluate_number (&p, end - p, &subme, &last))
return 0;
double by = 1.0;
&& ss_equals_case (p->token.string, ss_cstr ("!BY")))
{
p++;
- if (!macro_evaluate_number (&p, end - p, me, &next_stack, &by))
+ if (!macro_evaluate_number (&p, end - p, &subme, &by))
return 0;
if (by == 0.0)
{
- macro_error (stack, NULL, _("!BY value cannot be zero."));
+ macro_error (subme.stack, NULL, _("!BY value cannot be zero."));
return 0;
}
}
- const struct macro_token *do_end = find_doend (stack, p, end);
+ const struct macro_token *do_end = find_doend (subme.stack, p, end);
if (!do_end)
return 0;
const struct macro_tokens inner = {
.n = do_end - p
};
- bool break_ = false;
- struct macro_expander subme = *me;
- subme.break_ = &break_;
-
if ((by > 0 && first <= last) || (by < 0 && first >= last))
{
int i = 0;
{
if (i++ > miterate)
{
- macro_error (stack, NULL,
+ macro_error (subme.stack, NULL,
_("Numerical !DO loop exceeded "
"maximum number of iterations %d. "
"(Use SET MITERATE to change the limit.)"),
stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
xstrdup (index_s));
- macro_expand (&inner, &subme, &next_stack, exp);
+ macro_expand (&inner, &subme, exp);
}
}
}
else
{
- macro_error (stack, p < end ? p : NULL,
+ macro_error (me->stack, p < end ? p : NULL,
_("Expected `=' or !IN in !DO loop."));
return 0;
}
static void
macro_expand (const struct macro_tokens *mts,
const struct macro_expander *me,
- const struct macro_expansion_stack *stack,
struct macro_tokens *exp)
{
if (me->nesting_countdown <= 0)
{
- macro_error (stack, NULL, _("Maximum nesting level %d exceeded. "
- "(Use SET MNEST to change the limit.)"),
+ macro_error (me->stack, NULL, _("Maximum nesting level %d exceeded. "
+ "(Use SET MNEST to change the limit.)"),
settings_get_mnest ());
for (size_t i = 0; i < mts->n; i++)
macro_tokens_add (exp, &mts->mts[i]);
if (*me->expand && param->expand_arg)
{
struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expansion_stack stack = {
+ .name = param->name,
+ .next = me->stack,
+ };
struct macro_expander subme = {
.macros = me->macros,
.macro = NULL,
.break_ = NULL,
.vars = &vars,
.nesting_countdown = me->nesting_countdown,
+ .stack = &stack,
};
- macro_expand (arg, &subme, &(struct macro_expansion_stack) {
- .name = param->name,
- .next = stack,
- }, exp);
+ macro_expand (arg, &subme, exp);
stringi_map_destroy (&vars);
}
else
if (*me->expand && param->expand_arg)
{
struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expansion_stack stack = {
+ .name = "!*",
+ .next = me->stack,
+ };
struct macro_expander subme = {
.macros = me->macros,
.macro = NULL,
.break_ = NULL,
.vars = &vars,
.nesting_countdown = me->nesting_countdown,
+ .stack = &stack,
};
- macro_expand (arg, &subme,
- &(struct macro_expansion_stack) {
- .name = "!*",
- .next = stack,
- }, exp);
+ macro_expand (arg, &subme, exp);
stringi_map_destroy (&vars);
}
else
continue;
}
- size_t n = macro_expand_if (&mts->mts[i], mts->n - i, me, stack,
- exp);
+ size_t n = macro_expand_if (&mts->mts[i], mts->n - i, me, exp);
if (n > 0)
{
i += n - 1;
if (value)
{
macro_tokens_from_string__ (exp, ss_cstr (value),
- me->segmenter_mode, stack);
+ me->segmenter_mode, me->stack);
continue;
}
}
{
i += retval - 1;
struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expansion_stack stack = {
+ .name = submc->macro->name,
+ .file_name = submc->macro->file_name,
+ .first_line = submc->macro->first_line,
+ .last_line = submc->macro->last_line,
+ .next = me->stack,
+ };
struct macro_expander subme = {
.macros = submc->macros,
.macro = submc->macro,
.break_ = NULL,
.vars = &vars,
.nesting_countdown = me->nesting_countdown - 1,
+ .stack = &stack,
};
- macro_expand (&submc->macro->body, &subme,
- &(struct macro_expansion_stack) {
- .name = submc->macro->name,
- .file_name = submc->macro->file_name,
- .first_line = submc->macro->first_line,
- .last_line = submc->macro->last_line,
- .next = stack,
- }, exp);
+ macro_expand (&submc->macro->body, &subme, exp);
macro_call_destroy (submc);
stringi_map_destroy (&vars);
continue;
if (ss_equals_case (token->string, ss_cstr ("!break")))
{
if (!me->break_)
- macro_error (stack, mt, _("!BREAK outside !DO."));
+ macro_error (me->stack, mt, _("!BREAK outside !DO."));
else
{
*me->break_ = true;
.input = &mts->mts[i],
.n_input = mts->n - i,
.me = me,
- .stack = stack,
};
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed;
i += function_consumed - 1;
macro_tokens_from_string__ (exp, function_output.ss,
- me->segmenter_mode, stack);
+ me->segmenter_mode, me->stack);
ds_destroy (&function_output);
continue;
}
- size_t n = macro_parse_let (&mts->mts[i], mts->n - i, me, stack);
+ size_t n = macro_parse_let (&mts->mts[i], mts->n - i, me);
if (n > 0)
{
i += n - 1;
continue;
}
- n = macro_expand_do (&mts->mts[i], mts->n - i, me, stack, exp);
+ n = macro_expand_do (&mts->mts[i], mts->n - i, me, exp);
if (n > 0)
{
i += n - 1;
bool expand = true;
struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expansion_stack stack = {
+ .name = mc->macro->name,
+ .file_name = mc->macro->file_name,
+ .first_line = mc->macro->first_line,
+ .last_line = mc->macro->last_line,
+ };
struct macro_expander me = {
.macros = mc->macros,
.macro = mc->macro,
.break_ = NULL,
.vars = &vars,
.nesting_countdown = settings_get_mnest (),
+ .stack = &stack,
};
- struct macro_expansion_stack stack = {
- .name = mc->macro->name,
- .file_name = mc->macro->file_name,
- .first_line = mc->macro->first_line,
- .last_line = mc->macro->last_line,
- };
- macro_expand (&mc->macro->body, &me, &stack, exp);
+ macro_expand (&mc->macro->body, &me, exp);
stringi_map_destroy (&vars);
}