#include <stdlib.h>
#include "data/settings.h"
+#include "language/lexer/lexer.h"
#include "language/lexer/segment.h"
#include "language/lexer/scan.h"
#include "libpspp/assertion.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
+struct macro_expansion_stack
+ {
+ const struct macro_expansion_stack *next;
+ const char *name;
+ const char *file_name;
+ int first_line;
+ int last_line;
+ };
+
+static void PRINTF_FORMAT (3, 4)
+macro_error (const struct macro_expansion_stack *stack,
+ const struct macro_token *mt,
+ const char *format, ...)
+{
+ struct msg_stack **ms = NULL;
+ size_t allocated_ms = 0;
+ size_t n_ms = 0;
+
+ for (const struct macro_expansion_stack *p = stack; p; p = p->next)
+ {
+ if (n_ms >= allocated_ms)
+ ms = x2nrealloc (ms, &allocated_ms, sizeof *ms);
+
+ /* TRANSLATORS: These strings are used for explaining the context of an
+ error. The "While expanding" message appears first, followed by zero
+ or more of the "inside expansion" messages. `innermost',
+ `next_inner`, etc., are names of macros, and `foobar' is a piece of
+ PSPP syntax:
+
+ foo.sps:12: At `foobar' in the expansion of 'innermost',
+ foo.sps:23: inside the expansion of 'next_inner',
+ foo.sps:34: inside the expansion of 'next_inner2',
+ foo.sps:45: inside the expansion of 'outermost',
+ foo.sps:76: This is the actual error message. */
+ char *description;
+ if (p == stack)
+ {
+ if (mt && mt->representation.length)
+ {
+ char syntax[64];
+ lex_ellipsize (mt->representation, syntax, sizeof syntax);
+ description = xasprintf (_("At `%s' in the expansion of `%s',"),
+ syntax, p->name);
+ }
+ else
+ description = xasprintf (_("In the expansion of `%s',"), p->name);
+ }
+ else
+ description = xasprintf (_("inside the expansion of `%s',"), p->name);
+
+ ms[n_ms] = xmalloc (sizeof *ms[n_ms]);
+ *ms[n_ms] = (struct msg_stack) {
+ .location = {
+ .file_name = xstrdup_if_nonnull (p->file_name),
+ .first_line = p->first_line,
+ .last_line = p->last_line,
+ },
+ .description = description,
+ };
+ n_ms++;
+ }
+
+ va_list args;
+ va_start (args, format);
+ char *s = xvasprintf (format, args);
+ va_end (args);
+
+ struct msg *m = xmalloc (sizeof *m);
+ *m = (struct msg) {
+ .category = MSG_C_SYNTAX,
+ .severity = MSG_S_ERROR,
+ .stack = ms,
+ .n_stack = n_ms,
+ .text = s,
+ };
+ msg_emit (m);
+}
+
void
macro_token_copy (struct macro_token *dst, const struct macro_token *src)
{
macro_token_copy (macro_tokens_add_uninit (mts), mt);
}
-void
-macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
- enum segmenter_mode mode)
+static void
+macro_tokens_from_string__ (struct macro_tokens *mts, const struct substring src,
+ enum segmenter_mode mode,
+ const struct macro_expansion_stack *stack)
{
struct state
{
}
/* We have a token in 'token'. */
+ mt.representation.length = state.body.string - mt.representation.string;
if (is_scan_type (token->type))
{
if (token->type != SCAN_SKIP)
{
- printf ("error\n");
- /* XXX report error */
+ char *s = scan_token_to_error (token);
+ if (stack)
+ {
+ mt.token.type = T_STRING;
+ macro_error (stack, &mt, "%s", s);
+ }
+ else
+ msg (SE, "%s", s);
+ free (s);
}
}
else
- {
- mt.representation.length = state.body.string - mt.representation.string;
- macro_tokens_add (mts, &mt);
- }
+ macro_tokens_add (mts, &mt);
token_uninit (token);
}
}
+void
+macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
+ enum segmenter_mode mode)
+{
+ macro_tokens_from_string__ (mts, src, mode, NULL);
+}
+
void
macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
{
return;
free (m->name);
+ free (m->file_name);
for (size_t i = 0; i < m->n_params; i++)
{
struct macro_param *p = &m->params[i];
const struct macro_token *input;
size_t n_input;
int nesting_countdown;
+ enum segmenter_mode segmenter_mode;
const struct macro_set *macros;
const struct macro_expander *me;
+ const struct macro_expansion_stack *stack;
struct string_map *vars;
bool *expand;
};
static void
-macro_expand (const struct macro_tokens *,
- int nesting_countdown, const struct macro_set *,
+macro_expand (const struct macro_tokens *, int nesting_countdown,
+ enum segmenter_mode segmenter_mode, const struct macro_set *,
const struct macro_expander *, struct string_map *vars,
- bool *expand, bool *break_, struct macro_tokens *exp);
+ const struct macro_expansion_stack *stack,
+ bool *expand, bool *break_,
+ struct macro_tokens *exp);
static bool
expand_macro_function (struct parse_macro_function_ctx *ctx,
.input = &ctx->input[i],
.n_input = ctx->n_input - i,
.nesting_countdown = ctx->nesting_countdown,
+ .segmenter_mode = ctx->segmenter_mode,
.macros = ctx->macros,
.me = ctx->me,
+ .stack = ctx->stack,
.vars = ctx->vars,
.expand = ctx->expand,
};
if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
{
- printf ("`(' expected following %s'\n", function.string);
+ macro_error (ctx->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)
{
- printf ("Wrong number of arguments to %s.\n", function.string);
+ macro_error (ctx->stack, &tokens[i],
+ _("Wrong number of arguments to macro function %s."),
+ function.string);
goto error;
}
return true;
i++;
else if (tokens[i].token.type != T_RPAREN)
{
- printf ("Expecting `,' or `)' in %s invocation.", function.string);
+ macro_error (ctx->stack, &tokens[i],
+ _("`,' or `)' expected in call to macro function %s."),
+ function.string);
goto error;
}
}
unexpected_end:
- printf ("Missing closing parenthesis in arguments to %s.\n",
- function.string);
+ macro_error (ctx->stack, NULL, _("Missing `)' in call to macro function %s."),
+ function.string);
/* Fall through. */
error:
string_array_destroy (args);
}
static bool
-unquote_string (const char *s, struct string *content)
+unquote_string (const char *s, enum segmenter_mode segmenter_mode,
+ struct string *content)
{
struct string_lexer slex;
- string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */,
- true);
+ string_lexer_init (&slex, s, strlen (s), segmenter_mode, true);
struct token token1;
if (!string_lexer_next (&slex, &token1))
}
static const char *
-unquote_string_in_place (const char *s, struct string *tmp)
+unquote_string_in_place (const char *s, enum segmenter_mode segmenter_mode,
+ struct string *tmp)
{
ds_init_empty (tmp);
- return unquote_string (s, tmp) ? ds_cstr (tmp) : s;
+ return unquote_string (s, segmenter_mode, tmp) ? ds_cstr (tmp) : s;
}
static bool
int n;
if (!parse_integer (args.strings[0], &n))
{
- printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]);
+ macro_error (ctx->stack, NULL,
+ _("Argument to !BLANKS must be non-negative integer "
+ "(not \"%s\")."), args.strings[0]);
string_array_destroy (&args);
return false;
}
input_consumed))
{
for (size_t i = 0; i < args.n; i++)
- if (!unquote_string (args.strings[i], output))
+ if (!unquote_string (args.strings[i], ctx->segmenter_mode, output))
ds_put_cstr (output, args.strings[i]);
}
else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
input_consumed))
{
struct string tmp;
- const char *s = unquote_string_in_place (args.strings[0], &tmp);
+ const char *s = unquote_string_in_place (args.strings[0],
+ ctx->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->segmenter_mode,
+ ctx->stack);
if (mts.n > 0)
ds_put_substring (output, mts.mts[0].representation);
macro_tokens_uninit (&mts);
else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
input_consumed))
{
- if (unquote_string (args.strings[0], NULL))
+ if (unquote_string (args.strings[0], ctx->segmenter_mode, NULL))
ds_put_cstr (output, args.strings[0]);
else
{
int start;
if (!parse_integer (args.strings[1], &start) || start < 1)
{
- printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]);
+ macro_error (ctx->stack, NULL,
+ _("Second argument of !SUBSTR must be "
+ "positive integer (not \"%s\")."),
+ args.strings[1]);
string_array_destroy (&args);
return false;
}
int count = INT_MAX;
if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
{
- printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]);
+ macro_error (ctx->stack, NULL,
+ _("Third argument of !SUBSTR must be "
+ "non-negative integer (not \"%s\")."),
+ args.strings[1]);
string_array_destroy (&args);
return false;
}
input_consumed))
{
struct string tmp;
- const char *s = unquote_string_in_place (args.strings[0], &tmp);
+ const char *s = unquote_string_in_place (args.strings[0],
+ ctx->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->segmenter_mode,
+ ctx->stack);
if (mts.n > 1)
{
struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
input_consumed))
{
- if (!unquote_string (args.strings[0], output))
+ if (!unquote_string (args.strings[0], ctx->segmenter_mode, output))
ds_put_cstr (output, args.strings[0]);
}
else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
input_consumed))
{
struct string tmp;
- const char *s = unquote_string_in_place (args.strings[0], &tmp);
+ const char *s = unquote_string_in_place (args.strings[0],
+ ctx->segmenter_mode, &tmp);
char *upper = utf8_to_upper (s);
ds_put_cstr (output, upper);
free (upper);
input_consumed))
{
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string (&mts, ss_cstr (args.strings[0]),
- SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
+ ctx->segmenter_mode, ctx->stack);
struct macro_tokens exp = { .n = 0 };
- macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros, ctx->me,
- ctx->vars, ctx->expand, NULL, &exp);
+ macro_expand (&mts, ctx->nesting_countdown - 1, ctx->segmenter_mode,
+ ctx->macros, ctx->me, ctx->vars,
+ &(struct macro_expansion_stack) {
+ .name = "!EVAL",
+ .next = ctx->stack,
+ }, ctx->expand, NULL, &exp);
macro_tokens_to_representation (&exp, output, NULL, NULL);
macro_tokens_uninit (&exp);
macro_tokens_uninit (&mts);
struct expr_context
{
int nesting_countdown;
+ enum segmenter_mode segmenter_mode;
const struct macro_set *macros;
const struct macro_expander *me;
+ const struct macro_expansion_stack *stack;
struct string_map *vars;
bool *expand;
};
if (p >= end || p->token.type != T_RPAREN)
{
free (value);
- printf ("expecting ')' in macro expression\n");
+ macro_error (ctx->stack, p < end ? p : NULL,
+ _("Expecting ')' in macro expression."));
return NULL;
}
p++;
.input = p,
.n_input = end - p,
.nesting_countdown = ctx->nesting_countdown,
+ .segmenter_mode = ctx->segmenter_mode,
.macros = ctx->macros,
.me = ctx->me,
+ .stack = ctx->stack,
.vars = ctx->vars,
.expand = ctx->expand,
};
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
struct string unquoted = DS_EMPTY_INITIALIZER;
- if (unquote_string (ds_cstr (&function_output), &unquoted))
+ if (unquote_string (ds_cstr (&function_output), ctx->segmenter_mode,
+ &unquoted))
{
ds_swap (&function_output, &unquoted);
ds_destroy (&unquoted);
}
struct string lhs_tmp, rhs_tmp;
- int cmp = strcmp/*XXX*/ (unquote_string_in_place (lhs, &lhs_tmp),
- unquote_string_in_place (rhs, &rhs_tmp));
+ int cmp = strcmp (unquote_string_in_place (lhs, ctx->segmenter_mode,
+ &lhs_tmp),
+ unquote_string_in_place (rhs, ctx->segmenter_mode,
+ &rhs_tmp));
ds_destroy (&lhs_tmp);
ds_destroy (&rhs_tmp);
: op == T_LT ? cmp < 0
: op == T_GT ? cmp > 0
: op == T_LE ? cmp <= 0
- :/*op == T_GE*/cmp >= 0);
+ : /* T_GE */ cmp >= 0);
*tokens = p;
return xstrdup (b ? "1" : "0");
static char *
macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, struct string_map *vars,
- bool *expand)
+ int nesting_countdown,
+ enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
+ struct string_map *vars, bool *expand)
{
const struct expr_context ctx = {
.nesting_countdown = nesting_countdown,
+ .segmenter_mode = segmenter_mode,
.macros = macros,
.me = me,
+ .stack = stack,
.vars = vars,
.expand = expand,
};
static bool
macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, struct string_map *vars,
+ int nesting_countdown,
+ enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
+ struct string_map *vars,
bool *expand, double *number)
{
char *s = macro_evaluate_expression (tokens, n_tokens, nesting_countdown,
- macros, me, vars, expand);
+ segmenter_mode, macros, me, stack, vars,
+ expand);
if (!s)
return false;
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), segmenter_mode, stack);
if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
{
macro_tokens_print (&mts, stdout);
- printf ("expression must evaluate to a number (not %s)\n", s);
+ macro_error (stack, mts.n > 0 ? &mts.mts[0] : NULL,
+ _("Macro expression must evaluate to "
+ "a number (not \"%s\")."), s);
free (s);
macro_tokens_uninit (&mts);
return false;
static size_t
macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, struct string_map *vars,
+ int nesting_countdown, enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
+ struct string_map *vars,
bool *expand, bool *break_, struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
p++;
char *result = macro_evaluate_expression (&p, end - p,
- nesting_countdown, macros, me, vars,
- expand);
+ nesting_countdown, segmenter_mode,
+ macros, me,
+ stack, vars, expand);
if (!result)
return 0;
bool b = strcmp (result, "0");
|| p->token.type != T_MACRO_ID
|| !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
{
- printf ("!THEN expected\n");
+ macro_error (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)
{
- printf ("!ELSE or !IFEND expected\n");
+ macro_error (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")))
{
- printf ("!IFEND expected\n");
+ macro_error (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, nesting_countdown, macros, me, vars, expand,
- break_, exp);
+ macro_expand (&mts, nesting_countdown, segmenter_mode, macros, me, vars,
+ &(struct macro_expansion_stack) {
+ .name = "!IF",
+ .next = stack,
+ },
+ expand, break_, exp);
}
return (end_if + 1) - tokens;
}
static size_t
macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, struct string_map *vars,
- bool *expand)
+ int nesting_countdown, enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
+ struct string_map *vars, bool *expand)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
if (p >= end || p->token.type != T_MACRO_ID)
{
- printf ("expected macro variable name following !LET\n");
+ macro_error (stack, p < end ? p : NULL,
+ _("Expected macro variable name following !LET."));
return 0;
}
const struct substring var_name = p->token.string;
if (is_macro_keyword (var_name)
|| macro_find_parameter_by_name (me->macro, var_name))
{
- printf ("cannot use argument name or macro keyword %.*s as !LET variable\n", (int) var_name.length, var_name.string);
+ macro_error (stack, p < end ? p : NULL,
+ _("Cannot use argument name or macro keyword "
+ "\"%.*s\" as !LET variable."),
+ (int) var_name.length, var_name.string);
return 0;
}
p++;
if (p >= end || p->token.type != T_EQUALS)
{
- printf ("expected = following !LET\n");
+ macro_error (stack, p < end ? p : NULL,
+ _("Expected `=' following !LET."));
return 0;
}
p++;
- char *value = macro_evaluate_expression (&p, end - p,
- nesting_countdown, macros, me, vars,
- expand);
+ char *value = macro_evaluate_expression (&p, end - p, nesting_countdown,
+ segmenter_mode, macros, me, stack,
+ vars, expand);
if (!value)
return 0;
}
static const struct macro_token *
-find_doend (const struct macro_token *p, const struct macro_token *end)
+find_doend (const struct macro_expansion_stack *stack,
+ const struct macro_token *p, const struct macro_token *end)
{
size_t nesting = 0;
for (; p < end; p++)
nesting--;
}
}
- printf ("missing !DOEND\n");
+ macro_error (stack, NULL, _("Missing !DOEND."));
return NULL;
}
static size_t
macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, struct string_map *vars,
+ int nesting_countdown, enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
+ struct string_map *vars,
bool *expand, struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
if (p >= end || p->token.type != T_MACRO_ID)
{
- printf ("expected macro variable name following !DO\n");
+ macro_error (stack, p < end ? p : NULL,
+ _("Expected macro variable name following !DO."));
return 0;
}
const struct substring var_name = p->token.string;
if (is_macro_keyword (var_name)
|| macro_find_parameter_by_name (me->macro, var_name))
{
- printf ("cannot use argument name or macro keyword %.*s as !DO variable\n", (int) var_name.length, var_name.string);
+ macro_error (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,
+ };
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,
- nesting_countdown, macros, me, vars,
- expand);
+ char *list = macro_evaluate_expression (&p, end - p, nesting_countdown,
+ segmenter_mode, macros, me,
+ &next_stack, vars, expand);
if (!list)
return 0;
struct macro_tokens items = { .n = 0 };
- macro_tokens_from_string (&items, ss_cstr (list),
- SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (&items, ss_cstr (list), segmenter_mode,
+ stack);
free (list);
- const struct macro_token *do_end = find_doend (p, end);
+ const struct macro_token *do_end = find_doend (stack, p, end);
if (!do_end)
{
macro_tokens_uninit (&items);
{
if (i >= miterate)
{
- printf ("exceeded maximum number of iterations %d\n", miterate);
+ macro_error (stack, NULL,
+ _("!DO loop over list exceeded "
+ "maximum number of iterations %d. "
+ "(Use SET MITERATE to change the limit.)"),
+ miterate);
break;
}
string_map_replace_nocopy (vars, ss_xstrdup (var_name),
ss_xstrdup (items.mts[i].representation));
bool break_ = false;
- macro_expand (&inner, nesting_countdown, macros,
- me, vars, expand, &break_, exp);
+ macro_expand (&inner, nesting_countdown, segmenter_mode, macros,
+ me, vars, &next_stack, expand, &break_, exp);
if (break_)
break;
}
{
p++;
double first;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
+ if (!macro_evaluate_number (&p, end - p, nesting_countdown,
+ segmenter_mode, macros, me, &next_stack,
vars, expand, &first))
return 0;
if (p >= end || p->token.type != T_MACRO_ID
|| !ss_equals_case (p->token.string, ss_cstr ("!TO")))
{
- printf ("expecting !TO\n");
+ macro_error (stack, p < end ? p : NULL,
+ _("Expected !TO in numerical !DO loop."));
return 0;
}
p++;
double last;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
+ if (!macro_evaluate_number (&p, end - p, nesting_countdown,
+ segmenter_mode, macros, me, &next_stack,
vars, expand, &last))
return 0;
&& ss_equals_case (p->token.string, ss_cstr ("!BY")))
{
p++;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
+ if (!macro_evaluate_number (&p, end - p, nesting_countdown,
+ segmenter_mode, macros, me, &next_stack,
vars, expand, &by))
return 0;
if (by == 0.0)
{
- printf ("!BY value cannot be zero\n");
+ macro_error (stack, NULL, _("!BY value cannot be zero."));
return 0;
}
}
- const struct macro_token *do_end = find_doend (p, end);
+ const struct macro_token *do_end = find_doend (stack, p, end);
if (!do_end)
return 0;
const struct macro_tokens inner = {
{
if (i++ > miterate)
{
- printf ("exceeded maximum number of iterations %d\n",
- miterate);
+ macro_error (stack, NULL,
+ _("Numerical !DO loop exceeded "
+ "maximum number of iterations %d. "
+ "(Use SET MITERATE to change the limit.)"),
+ miterate);
break;
}
xstrdup (index_s));
bool break_ = false;
- macro_expand (&inner, nesting_countdown, macros,
- me, vars, expand, &break_, exp);
+ macro_expand (&inner, nesting_countdown, segmenter_mode, macros,
+ me, vars, &next_stack, expand, &break_, exp);
if (break_)
break;
}
}
else
{
- printf ("expecting = or !IN in !DO loop\n");
+ macro_error (stack, p < end ? p : NULL,
+ _("Expected `=' or !IN in !DO loop."));
return 0;
}
}
static void
-macro_expand (const struct macro_tokens *mts,
- int nesting_countdown, const struct macro_set *macros,
+macro_expand (const struct macro_tokens *mts, int nesting_countdown,
+ enum segmenter_mode segmenter_mode,
+ const struct macro_set *macros,
const struct macro_expander *me, struct string_map *vars,
+ const struct macro_expansion_stack *stack,
bool *expand, bool *break_, struct macro_tokens *exp)
{
if (nesting_countdown <= 0)
{
- printf ("maximum nesting level exceeded\n");
+ macro_error (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]);
return;
if (param)
{
const struct macro_tokens *arg = me->args[param - me->macro->params];
- //macro_tokens_print (arg, stdout);
if (*expand && param->expand_arg)
- macro_expand (arg, nesting_countdown, macros, NULL, NULL,
- expand, break_, exp);
+ macro_expand (arg, nesting_countdown, segmenter_mode,
+ macros, NULL, NULL,
+ &(struct macro_expansion_stack) {
+ .name = param->name,
+ .next = stack,
+ }, expand, break_, exp);
else
for (size_t i = 0; i < arg->n; i++)
macro_tokens_add (exp, &arg->mts[i]);
const struct macro_tokens *arg = me->args[j];
if (*expand && param->expand_arg)
- macro_expand (arg, nesting_countdown, macros, NULL, NULL,
- expand, break_, exp);
+ macro_expand (arg, nesting_countdown, segmenter_mode,
+ macros, NULL, NULL,
+ &(struct macro_expansion_stack) {
+ .name = "!*",
+ .next = stack,
+ }, expand, break_, exp);
else
for (size_t k = 0; k < arg->n; k++)
macro_tokens_add (exp, &arg->mts[k]);
}
size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
- nesting_countdown, macros, me, vars,
- expand, break_, exp);
+ nesting_countdown, segmenter_mode,
+ macros, me, stack,
+ vars, expand, break_, exp);
if (n > 0)
{
i += n - 1;
token->string.length);
if (value)
{
- macro_tokens_from_string (exp, ss_cstr (value),
- SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (exp, ss_cstr (value), segmenter_mode,
+ stack);
continue;
}
}
if (retval > 0)
{
i += retval - 1;
- macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
- subme, NULL, expand, break_, exp);
+ macro_expand (&subme->macro->body, nesting_countdown - 1,
+ segmenter_mode, macros, subme, NULL,
+ &(struct macro_expansion_stack) {
+ .name = subme->macro->name,
+ .file_name = subme->macro->file_name,
+ .first_line = subme->macro->first_line,
+ .last_line = subme->macro->last_line,
+ .next = stack,
+ }, expand, break_, exp);
macro_expander_destroy (subme);
continue;
}
if (ss_equals_case (token->string, ss_cstr ("!break")))
{
if (!break_)
- printf ("!BREAK outside !DO\n");
+ macro_error (stack, mt, _("!BREAK outside !DO."));
else
{
*break_ = true;
.input = &mts->mts[i],
.n_input = mts->n - i,
.nesting_countdown = nesting_countdown,
+ .segmenter_mode = segmenter_mode,
.macros = macros,
.me = me,
+ .stack = stack,
.vars = vars,
.expand = expand,
};
{
i += function_consumed - 1;
- macro_tokens_from_string (exp, function_output.ss,
- SEG_MODE_INTERACTIVE /* XXX */);
+ macro_tokens_from_string__ (exp, function_output.ss, segmenter_mode,
+ stack);
ds_destroy (&function_output);
continue;
}
size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
- nesting_countdown, macros, me, vars,
- expand);
+ nesting_countdown, segmenter_mode,
+ macros, me, stack, vars, expand);
if (n > 0)
{
i += n - 1;
}
n = macro_expand_do (&mts->mts[i], mts->n - i,
- nesting_countdown, macros, me, vars,
- expand, exp);
+ nesting_countdown, segmenter_mode,
+ macros, me, stack, vars, expand, exp);
if (n > 0)
{
i += n - 1;
}
void
-macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
+macro_expander_get_expansion (struct macro_expander *me,
+ enum segmenter_mode segmenter_mode,
+ struct macro_tokens *exp)
{
-#if 0
- for (size_t i = 0; i < me->macro->n_params; i++)
- {
- printf ("%s:\n", me->macro->params[i].name);
- macro_tokens_print (me->args[i], stdout);
- }
-#endif
-
bool expand = true;
- macro_expand (&me->macro->body, settings_get_mnest (),
- me->macros, me, NULL, &expand, NULL, exp);
-
-#if 0
- printf ("expansion:\n");
- macro_tokens_print (exp, stdout);
-#endif
+ struct macro_expansion_stack stack = {
+ .name = me->macro->name,
+ .file_name = me->macro->file_name,
+ .first_line = me->macro->first_line,
+ .last_line = me->macro->last_line,
+ };
+ macro_expand (&me->macro->body, settings_get_mnest (), segmenter_mode,
+ me->macros, me, NULL, &stack, &expand, NULL, exp);
}