#include "libpspp/message.h"
#include "libpspp/str.h"
#include "libpspp/string-array.h"
+#include "libpspp/string-map.h"
#include "gl/c-ctype.h"
int nesting_countdown;
const struct macro_set *macros;
const struct macro_expander *me;
+ struct string_map *vars;
bool *expand;
};
static void
macro_expand (const struct macro_tokens *,
int nesting_countdown, const struct macro_set *,
- const struct macro_expander *, bool *expand, struct macro_tokens *exp);
+ const struct macro_expander *, struct string_map *vars,
+ bool *expand, struct macro_tokens *exp);
static bool
expand_macro_function (struct parse_macro_function_ctx *ctx,
return 2;
}
+ if (ctx->vars)
+ {
+ const char *value = string_map_find__ (ctx->vars,
+ token->string.string,
+ token->string.length);
+ if (value)
+ {
+ ds_put_cstr (farg, value);
+ return 1;
+ }
+ }
+
struct parse_macro_function_ctx subctx = {
.input = &ctx->input[i],
.n_input = ctx->n_input - i,
.nesting_countdown = ctx->nesting_countdown,
.macros = ctx->macros,
.me = ctx->me,
+ .vars = ctx->vars,
.expand = ctx->expand,
};
size_t subinput_consumed;
macro_tokens_from_string (&mts, ss_cstr (args.strings[0]),
SEG_MODE_INTERACTIVE /* XXX */);
struct macro_tokens exp = { .n = 0 };
- macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros,
- ctx->me, ctx->expand, &exp);
+ macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros, ctx->me,
+ ctx->vars, ctx->expand, &exp);
macro_tokens_to_representation (&exp, output);
macro_tokens_uninit (&exp);
macro_tokens_uninit (&mts);
int nesting_countdown;
const struct macro_set *macros;
const struct macro_expander *me;
+ struct string_map *vars;
bool *expand;
};
.nesting_countdown = ctx->nesting_countdown,
.macros = ctx->macros,
.me = ctx->me,
+ .vars = ctx->vars,
.expand = ctx->expand,
};
struct string function_output = DS_EMPTY_INITIALIZER;
static char *
macro_evaluate_relational (const struct expr_context *ctx,
- const struct macro_token **tokens,
- const struct macro_token *end)
+ const struct macro_token **tokens,
+ const struct macro_token *end)
{
const struct macro_token *p = *tokens;
char *lhs = macro_evaluate_literal (ctx, &p, end);
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, bool *expand)
+ const struct macro_expander *me, struct string_map *vars,
+ bool *expand)
{
const struct expr_context ctx = {
.nesting_countdown = nesting_countdown,
.macros = macros,
.me = me,
+ .vars = vars,
.expand = expand,
};
return macro_evaluate_or (&ctx, tokens, *tokens + n_tokens);
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, bool *expand,
- struct macro_tokens *exp)
+ const struct macro_expander *me, struct string_map *vars,
+ bool *expand, struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
p++;
char *result = macro_evaluate_expression (&p, end - p,
- nesting_countdown, macros, me, expand);
+ nesting_countdown, macros, me, vars,
+ expand);
if (!result)
return 0;
bool b = strcmp (result, "0");
.mts = CONST_CAST (struct macro_token *, start),
.n = n,
};
- macro_expand (&mts, nesting_countdown, macros, me, expand, exp);
+ macro_expand (&mts, nesting_countdown, macros, me, vars, expand, 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)
+{
+ const struct macro_token *p = tokens;
+ const struct macro_token *end = tokens + n_tokens;
+
+ if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!LET")))
+ return 0;
+ p++;
+
+ if (p >= end || p->token.type != T_MACRO_ID)
+ {
+ printf ("expected macro variable name following !LET\n");
+ return 0;
+ }
+ const struct substring var_name = p->token.string;
+ p++;
+
+ if (p >= end || p->token.type != T_EQUALS)
+ {
+ printf ("expected = following !LET\n");
+ return 0;
+ }
+ p++;
+
+ char *value = macro_evaluate_expression (&p, end - p,
+ nesting_countdown, macros, me, vars,
+ expand);
+ if (!value)
+ return 0;
+
+ string_map_replace_nocopy (vars, ss_xstrdup (var_name), value);
+ return p - tokens;
+}
+
static void
macro_expand (const struct macro_tokens *mts,
int nesting_countdown, const struct macro_set *macros,
- const struct macro_expander *me, bool *expand,
- struct macro_tokens *exp)
+ const struct macro_expander *me, struct string_map *vars,
+ bool *expand, struct macro_tokens *exp)
{
if (nesting_countdown <= 0)
{
return;
}
+ struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
+ if (!vars)
+ vars = &own_vars;
for (size_t i = 0; i < mts->n; i++)
{
const struct macro_token *mt = &mts->mts[i];
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, expand, exp);
+ macro_expand (arg, nesting_countdown, macros, NULL, NULL,
+ expand, 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, expand, exp);
+ macro_expand (arg, nesting_countdown, macros, NULL, NULL,
+ expand, 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, expand,
- exp);
+ nesting_countdown, macros, me, vars,
+ expand, exp);
if (n > 0)
{
i += n - 1;
}
}
+ if (token->type == T_MACRO_ID && vars)
+ {
+ const char *value = string_map_find__ (vars, token->string.string,
+ token->string.length);
+ if (value)
+ {
+ macro_tokens_from_string (exp, ss_cstr (value),
+ SEG_MODE_INTERACTIVE /* XXX */);
+ continue;
+ }
+ }
+
if (*expand)
{
struct macro_expander *subme;
{
i += retval - 1;
macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
- subme, expand, exp);
+ subme, NULL, expand, exp);
macro_expander_destroy (subme);
continue;
}
.nesting_countdown = nesting_countdown,
.macros = macros,
.me = me,
+ .vars = vars,
.expand = expand,
};
struct string function_output = DS_EMPTY_INITIALIZER;
continue;
}
+ size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
+ nesting_countdown, macros, me, vars,
+ expand);
+ if (n > 0)
+ {
+ i += n - 1;
+ continue;
+ }
+
if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
*expand = true;
else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
else
macro_tokens_add (exp, mt);
}
+ if (vars == &own_vars)
+ string_map_destroy (&own_vars);
}
void
bool expand = true;
macro_expand (&me->macro->body, settings_get_mnest (),
- me->macros, me, &expand, exp);
+ me->macros, me, NULL, &expand, exp);
#if 0
printf ("expansion:\n");