#include "gettext.h"
#define _(msgid) gettext (msgid)
+void
+macro_token_copy (struct macro_token *dst, const struct macro_token *src)
+{
+ token_copy (&dst->token, &src->token);
+ ss_alloc_substring (&dst->representation, src->representation);
+}
+
+void
+macro_token_uninit (struct macro_token *mt)
+{
+ token_uninit (&mt->token);
+ ss_dealloc (&mt->representation);
+}
+
+void
+macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
+{
+ *dst = (struct macro_tokens) {
+ .mts = xmalloc (src->n * sizeof *dst->mts),
+ .n = src->n,
+ .allocated = src->n,
+ };
+ for (size_t i = 0; i < src->n; i++)
+ macro_token_copy (&dst->mts[i], &src->mts[i]);
+}
+
+void
+macro_tokens_uninit (struct macro_tokens *mts)
+{
+ for (size_t i = 0; i < mts->n; i++)
+ macro_token_uninit (&mts->mts[i]);
+ free (mts->mts);
+}
+
+void
+macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt)
+{
+ if (mts->n >= mts->allocated)
+ mts->mts = x2nrealloc (mts->mts, &mts->allocated, sizeof *mts->mts);
+ macro_token_copy (&mts->mts[mts->n++], mt);
+}
+
+void
+macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
+{
+ for (size_t i = 0; i < mts->n; i++)
+ token_print (&mts->mts[i].token, stream);
+}
+
void
macro_destroy (struct macro *m)
{
struct macro_param *p = &m->params[i];
free (p->name);
- tokens_uninit (&p->def);
+ macro_tokens_uninit (&p->def);
switch (p->arg_type)
{
break;
case ARG_CHAREND:
- token_destroy (&p->charend);
+ token_uninit (&p->charend);
break;
case ARG_ENCLOSE:
- token_destroy (&p->enclose[0]);
- token_destroy (&p->enclose[1]);
+ token_uninit (&p->enclose[0]);
+ token_uninit (&p->enclose[1]);
break;
case ARG_CMDEND:
}
}
free (m->params);
- ss_dealloc (&m->body);
- tokens_uninit (&m->body_tokens);
+ macro_tokens_uninit (&m->body);
free (m);
}
\f
size_t n_tokens;
const struct macro *macro;
- struct tokens **args;
+ struct macro_tokens **args;
const struct macro_param *param;
};
if (!me->args[i])
{
me->args[i] = xmalloc (sizeof *me->args[i]);
- tokens_copy (me->args[i], &me->macro->params[i].def);
+ macro_tokens_copy (me->args[i], &me->macro->params[i].def);
}
return me->n_tokens;
}
}
static int
-me_add_arg (struct macro_expander *me, const struct token *token)
+me_add_arg (struct macro_expander *me, const struct macro_token *mt)
{
+ const struct token *token = &mt->token;
if (token->type == T_STOP)
{
msg (SE, _("Unexpected end of file reading argument %s "
me->n_tokens++;
const struct macro_param *p = me->param;
- struct tokens **argp = &me->args[p - me->macro->params];
+ struct macro_tokens **argp = &me->args[p - me->macro->params];
if (!*argp)
*argp = xzalloc (sizeof **argp);
- struct tokens *arg = *argp;
+ struct macro_tokens *arg = *argp;
if (p->arg_type == ARG_N_TOKENS)
{
- tokens_add (arg, token);
+ macro_tokens_add (arg, mt);
if (arg->n >= p->n_tokens)
return me_next_arg (me);
return 0;
{
if (token->type == T_ENDCMD || token->type == T_STOP)
return me_next_arg (me);
- tokens_add (arg, token);
+ macro_tokens_add (arg, mt);
return 0;
}
else
= p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
if (token_equal (token, end))
return me_next_arg (me);
- tokens_add (arg, token);
+ macro_tokens_add (arg, mt);
return 0;
}
}
static int
-me_expected (struct macro_expander *me, const struct token *token,
- const struct token *wanted)
+me_expected (struct macro_expander *me, const struct macro_token *actual,
+ const struct token *expected)
{
- char *actual = token_to_string (token);
- if (!actual)
- actual = xstrdup ("<eof>");
- char *expected = token_to_string (wanted);
- msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
+ const struct substring actual_s
+ = (actual->representation.length ? actual->representation
+ : ss_cstr (_("<end of input>")));
+ char *expected_s = token_to_string (expected);
+ msg (SE, _("Found `%.*s' while expecting `%s' reading argument %s "
"to macro %s."),
- actual, expected, me->param->name, me->macro->name);
- free (expected);
- free (actual);
+ (int) actual_s.length, actual_s.string, expected_s,
+ me->param->name, me->macro->name);
+ free (expected_s);
return me_error (me);
}
static int
-me_enclose (struct macro_expander *me, const struct token *token)
+me_enclose (struct macro_expander *me, const struct macro_token *mt)
{
+ const struct token *token = &mt->token;
me->n_tokens++;
if (token_equal (&me->param->enclose[0], token))
return 0;
}
- return me_expected (me, token, &me->param->enclose[0]);
+ return me_expected (me, mt, &me->param->enclose[0]);
}
static const struct macro_param *
}
static int
-me_keyword (struct macro_expander *me, const struct token *token)
+me_keyword (struct macro_expander *me, const struct macro_token *mt)
{
+ const struct token *token = &mt->token;
if (token->type != T_ID)
return me_finished (me);
}
static int
-me_equals (struct macro_expander *me, const struct token *token)
+me_equals (struct macro_expander *me, const struct macro_token *mt)
{
+ const struct token *token = &mt->token;
me->n_tokens++;
if (token->type == T_EQUALS)
return 0;
}
- const struct token equals = { .type = T_EQUALS };
- return me_expected (me, token, &equals);
+ return me_expected (me, mt, &(struct token) { .type = T_EQUALS });
}
int
for (size_t i = 0; i < me->macro->n_params; i++)
if (me->args[i])
{
- tokens_uninit (me->args[i]);
+ macro_tokens_uninit (me->args[i]);
free (me->args[i]);
}
free (me->args);
macro invocation is finished. The caller should call
macro_expander_get_expansion() to obtain the expansion. */
int
-macro_expander_add (struct macro_expander *me, const struct token *token)
+macro_expander_add (struct macro_expander *me, const struct macro_token *mt)
{
switch (me->state)
{
return -1;
case ME_ARG:
- return me_add_arg (me, token);
+ return me_add_arg (me, mt);
case ME_ENCLOSE:
- return me_enclose (me, token);
+ return me_enclose (me, mt);
case ME_KEYWORD:
- return me_keyword (me, token);
+ return me_keyword (me, mt);
case ME_EQUALS:
- return me_equals (me, token);
+ return me_equals (me, mt);
default:
NOT_REACHED ();
struct parse_macro_function_ctx
{
- const struct tokens *tokens;
+ const struct macro_tokens *mts;
size_t *idx;
- struct tokens *args;
+ struct macro_tokens *args;
int nesting_countdown;
const struct macro_set *macros;
const struct macro_expander *me;
};
static void
-macro_expand (const struct tokens *tokens, int nesting_countdown,
- const struct macro_set *macros, const struct macro_expander *me,
- bool *expand, struct tokens *exp);
+macro_expand (const struct macro_tokens *,
+ int nesting_countdown, const struct macro_set *,
+ const struct macro_expander *, bool *expand, struct macro_tokens *exp);
static bool
parse_macro_function (struct parse_macro_function_ctx *ctx,
struct substring function,
int min_args, int max_args)
{
- const struct token *tokens = ctx->tokens->tokens;
- size_t n_tokens = ctx->tokens->n;
+ struct macro_token *tokens = ctx->mts->mts;
+ size_t n_tokens = ctx->mts->n;
- if (!ss_equals_case (tokens[0].string, function))
+ if (!ss_equals_case (tokens[0].token.string, function))
return false;
size_t lparen_idx = *ctx->idx + 1;
- if (lparen_idx >= n_tokens || tokens[lparen_idx].type != T_LPAREN)
+ if (lparen_idx >= n_tokens || tokens[lparen_idx].token.type != T_LPAREN)
{
printf ("`(' expected following %s'\n", function.string);
return false;
}
- *ctx->args = (struct tokens) { .n = 0 };
+ *ctx->args = (struct macro_tokens) { .n = 0 };
size_t i = lparen_idx + 1;
for (size_t j = i; ; j++)
goto error;
}
- int type = tokens[j].type;
+ int type = tokens[j].token.type;
if (type == T_LPAREN)
{
int paren_nesting_level = 1;
ctx->args->n + 1, function.string);
goto error;
}
- if (tokens[j].type == T_LPAREN)
+ if (tokens[j].token.type == T_LPAREN)
paren_nesting_level++;
- else if (tokens[j].type == T_RPAREN)
+ else if (tokens[j].token.type == T_RPAREN)
paren_nesting_level--;
}
while (paren_nesting_level != 0);
}
else if (type == T_RPAREN || type == T_COMMA)
{
- const struct tokens unexpanded_arg = {
- .tokens = CONST_CAST (struct token *, &tokens[i]),
- .n = j - i,
- };
- struct tokens expanded_arg = { .n = 0 };
- macro_expand (&unexpanded_arg, ctx->nesting_countdown, ctx->macros,
+ struct macro_tokens expanded_arg = { .n = 0 };
+ macro_expand (&(const struct macro_tokens) { .mts = &tokens[i], .n = j - i },
+ ctx->nesting_countdown, ctx->macros,
ctx->me, ctx->expand, &expanded_arg);
if (expanded_arg.n != 1)
printf ("argument %zu to %s must be a single token "
"(not %zu tokens)\n", ctx->args->n + 1, function.string,
expanded_arg.n);
- tokens_uninit (&expanded_arg);
+ macro_tokens_uninit (&expanded_arg);
goto error;
}
- tokens_add (ctx->args, &expanded_arg.tokens[0]);
- tokens_uninit (&expanded_arg);
+ macro_tokens_add (ctx->args, &expanded_arg.mts[0]);
+ macro_tokens_uninit (&expanded_arg);
i = j + 1;
if (type == T_RPAREN)
return true;
error:
- tokens_uninit (ctx->args);
+ macro_tokens_uninit (ctx->args);
return false;
}
static void
-macro_expand (const struct tokens *tokens, int nesting_countdown,
- const struct macro_set *macros, const struct macro_expander *me,
- bool *expand, struct tokens *exp)
+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)
{
if (nesting_countdown <= 0)
{
printf ("maximum nesting level exceeded\n");
- for (size_t i = 0; i < tokens->n; i++)
- tokens_add (exp, &tokens->tokens[i]);
+ for (size_t i = 0; i < mts->n; i++)
+ macro_tokens_add (exp, &mts->mts[i]);
return;
}
- for (size_t i = 0; i < tokens->n; i++)
+ for (size_t i = 0; i < mts->n; i++)
{
- const struct token *token = &tokens->tokens[i];
+ const struct macro_token *mt = &mts->mts[i];
+ const struct token *token = &mt->token;
if (token->type == T_MACRO_ID && me)
{
const struct macro_param *param = macro_find_parameter_by_name (
if (param)
{
printf ("expand %s to:\n", param->name);
- const struct tokens *arg = me->args[param - me->macro->params];
- tokens_print (arg, stdout);
+ 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);
else
for (size_t i = 0; i < arg->n; i++)
- tokens_add (exp, &arg->tokens[i]);
+ macro_tokens_add (exp, &arg->mts[i]);
continue;
}
}
int retval = macro_expander_create (macros, token, &subme);
for (size_t j = 1; !retval; j++)
{
- static const struct token stop = { .type = T_STOP };
+ const struct macro_token stop = { .token = { .type = T_STOP } };
retval = macro_expander_add (
- subme, i + j < tokens->n ? &tokens->tokens[i + j] : &stop);
+ subme, i + j < mts->n ? &mts->mts[i + j] : &stop);
}
if (retval > 0)
{
i += retval - 1;
- macro_expand (&subme->macro->body_tokens, nesting_countdown - 1,
- macros, subme, expand, exp);
+ macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
+ subme, expand, exp);
macro_expander_destroy (subme);
continue;
}
if (token->type != T_MACRO_ID)
{
- tokens_add (exp, token);
+ macro_tokens_add (exp, mt);
continue;
}
{ "!eval", 1, 1 },
};
#endif
- struct tokens args;
+ /* Maybe each arg should just be a string, either a quoted string or a
+ non-quoted string containing tokens. */
+ struct macro_tokens args;
struct parse_macro_function_ctx ctx = {
- .tokens = tokens,
+ .mts = mts,
.idx = &i,
.args = &args,
.nesting_countdown = nesting_countdown,
};
if (parse_macro_function (&ctx, ss_cstr ("!length"), 1, 1))
{
- char *s = token_to_string (&args.tokens[0]);
- struct token t = { .type = T_POS_NUM, .number = strlen (s) };
- tokens_add (exp, &t);
- free (s);
+ size_t length = args.mts[0].representation.length;
+ struct macro_token mt = {
+ .token = { .type = T_POS_NUM, .number = length },
+ .representation = ss_cstr (xasprintf ("%zu", length)),
+ };
+ macro_tokens_add (exp, &mt);
+ macro_token_uninit (&mt);
- tokens_uninit (&args);
+ macro_tokens_uninit (&args);
}
else if (parse_macro_function (&ctx, ss_cstr ("!blanks"), 1, 1))
{
- if (args.tokens[0].type != T_POS_NUM)
+ /* XXX this isn't right, it might be a character string containing a
+ positive integer, e.g. via !CONCAT. */
+ if (args.mts[0].token.type != T_POS_NUM)
printf ("argument to !BLANKS must be positive integer\n");
else
{
struct string s = DS_EMPTY_INITIALIZER;
- ds_put_byte_multiple (&s, ' ', args.tokens[0].number);
- struct token t = { .type = T_ID, .string = s.ss };
- tokens_add (exp, &t);
+ ds_put_byte_multiple (&s, ' ', args.mts[0].token.number);
+
+ struct macro_token mt = {
+ .token = { .type = T_ID, .string = s.ss },
+ .representation = s.ss
+ };
+ macro_tokens_add (exp, &mt);
+
ds_destroy (&s);
}
- tokens_uninit (&args);
+ macro_tokens_uninit (&args);
}
else if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
*expand = true;
else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
*expand = false;
else
- tokens_add (exp, token);
+ macro_tokens_add (exp, mt);
}
}
-
void
-macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
+macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
{
for (size_t i = 0; i < me->macro->n_params; i++)
{
printf ("%s:\n", me->macro->params[i].name);
- tokens_print (me->args[i], stdout);
+ macro_tokens_print (me->args[i], stdout);
}
bool expand = true;
- macro_expand (&me->macro->body_tokens, settings_get_mnest (),
+ macro_expand (&me->macro->body, settings_get_mnest (),
me->macros, me, &expand, exp);
printf ("expansion:\n");
- tokens_print (exp, stdout);
+ macro_tokens_print (exp, stdout);
}