1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2021 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "language/lexer/macro.h"
25 #include "data/settings.h"
26 #include "language/lexer/segment.h"
27 #include "language/lexer/scan.h"
28 #include "libpspp/assertion.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/i18n.h"
31 #include "libpspp/message.h"
32 #include "libpspp/str.h"
33 #include "libpspp/string-array.h"
34 #include "libpspp/string-map.h"
36 #include "gl/c-ctype.h"
37 #include "gl/ftoastr.h"
40 #define _(msgid) gettext (msgid)
43 macro_token_copy (struct macro_token *dst, const struct macro_token *src)
45 token_copy (&dst->token, &src->token);
46 ss_alloc_substring (&dst->representation, src->representation);
50 macro_token_uninit (struct macro_token *mt)
52 token_uninit (&mt->token);
53 ss_dealloc (&mt->representation);
57 macro_token_to_representation (struct macro_token *mt, struct string *s)
59 ds_put_substring (s, mt->representation);
63 macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
65 *dst = (struct macro_tokens) {
66 .mts = xmalloc (src->n * sizeof *dst->mts),
70 for (size_t i = 0; i < src->n; i++)
71 macro_token_copy (&dst->mts[i], &src->mts[i]);
75 macro_tokens_uninit (struct macro_tokens *mts)
77 for (size_t i = 0; i < mts->n; i++)
78 macro_token_uninit (&mts->mts[i]);
83 macro_tokens_add_uninit (struct macro_tokens *mts)
85 if (mts->n >= mts->allocated)
86 mts->mts = x2nrealloc (mts->mts, &mts->allocated, sizeof *mts->mts);
87 return &mts->mts[mts->n++];
91 macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt)
93 macro_token_copy (macro_tokens_add_uninit (mts), mt);
97 macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
98 enum segmenter_mode mode)
102 struct segmenter segmenter;
103 struct substring body;
106 struct state state = {
107 .segmenter = segmenter_init (mode, true),
110 struct state saved = state;
112 while (state.body.length > 0)
114 struct macro_token mt = {
115 .token = { .type = T_STOP },
116 .representation = { .string = state.body.string },
118 struct token *token = &mt.token;
120 struct scanner scanner;
121 scanner_init (&scanner, token);
125 enum segment_type type;
126 int seg_len = segmenter_push (&state.segmenter, state.body.string,
127 state.body.length, true, &type);
128 assert (seg_len >= 0);
130 struct substring segment = ss_head (state.body, seg_len);
131 ss_advance (&state.body, seg_len);
133 enum scan_result result = scanner_push (&scanner, type, segment, token);
134 if (result == SCAN_SAVE)
136 else if (result == SCAN_BACK)
141 else if (result == SCAN_DONE)
145 /* We have a token in 'token'. */
146 if (is_scan_type (token->type))
148 if (token->type != SCAN_SKIP)
151 /* XXX report error */
156 mt.representation.length = state.body.string - mt.representation.string;
157 macro_tokens_add (mts, &mt);
159 token_uninit (token);
164 macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
166 for (size_t i = 0; i < mts->n; i++)
167 token_print (&mts->mts[i].token, stream);
172 TC_ENDCMD, /* No space before or after (new-line after). */
173 TC_BINOP, /* Space on both sides. */
174 TC_COMMA, /* Space afterward. */
175 TC_ID, /* Don't need spaces except sequentially. */
176 TC_PUNCT, /* Don't need spaces except sequentially. */
180 needs_space (enum token_class prev, enum token_class next)
182 /* Don't need a space before or after the end of a command.
183 (A new-line is needed afterward as a special case.) */
184 if (prev == TC_ENDCMD || next == TC_ENDCMD)
187 /* Binary operators always have a space on both sides. */
188 if (prev == TC_BINOP || next == TC_BINOP)
191 /* A comma always has a space afterward. */
192 if (prev == TC_COMMA)
195 /* Otherwise, PREV is TC_ID or TC_PUNCT, which only need a space if there are
196 two or them in a row. */
200 static enum token_class
201 classify_token (enum token_type type)
254 macro_tokens_to_representation (struct macro_tokens *mts, struct string *s)
259 macro_token_to_representation (&mts->mts[0], s);
260 for (size_t i = 1; i < mts->n; i++)
262 enum token_type prev = mts->mts[i - 1].token.type;
263 enum token_type next = mts->mts[i].token.type;
265 if (prev == T_ENDCMD)
266 ds_put_byte (s, '\n');
269 enum token_class pc = classify_token (prev);
270 enum token_class nc = classify_token (next);
271 if (needs_space (pc, nc))
272 ds_put_byte (s, ' ');
275 macro_token_to_representation (&mts->mts[i], s);
280 macro_destroy (struct macro *m)
286 for (size_t i = 0; i < m->n_params; i++)
288 struct macro_param *p = &m->params[i];
291 macro_tokens_uninit (&p->def);
299 token_uninit (&p->charend);
303 token_uninit (&p->enclose[0]);
304 token_uninit (&p->enclose[1]);
312 macro_tokens_uninit (&m->body);
317 macro_set_create (void)
319 struct macro_set *set = xmalloc (sizeof *set);
320 *set = (struct macro_set) {
321 .macros = HMAP_INITIALIZER (set->macros),
327 macro_set_destroy (struct macro_set *set)
332 struct macro *macro, *next;
333 HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
335 hmap_delete (&set->macros, ¯o->hmap_node);
336 macro_destroy (macro);
338 hmap_destroy (&set->macros);
343 hash_macro_name (const char *name)
345 return utf8_hash_case_string (name, 0);
348 static struct macro *
349 macro_set_find__ (struct macro_set *set, const char *name)
352 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
353 hash_macro_name (name), &set->macros)
354 if (!utf8_strcasecmp (macro->name, name))
361 macro_set_find (const struct macro_set *set, const char *name)
363 return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
366 /* Adds M to SET. M replaces any existing macro with the same name. Takes
369 macro_set_add (struct macro_set *set, struct macro *m)
371 struct macro *victim = macro_set_find__ (set, m->name);
374 hmap_delete (&set->macros, &victim->hmap_node);
375 macro_destroy (victim);
378 hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
386 /* Accumulating tokens in me->params toward the end of any type of
390 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
393 /* Expecting a keyword for a keyword argument. */
396 /* Expecting an equal sign for a keyword argument. */
401 struct macro_expander
403 const struct macro_set *macros;
408 const struct macro *macro;
409 struct macro_tokens **args;
410 const struct macro_param *param;
414 me_finished (struct macro_expander *me)
416 for (size_t i = 0; i < me->macro->n_params; i++)
419 me->args[i] = xmalloc (sizeof *me->args[i]);
420 macro_tokens_copy (me->args[i], &me->macro->params[i].def);
426 me_next_arg (struct macro_expander *me)
430 assert (!me->macro->n_params);
431 return me_finished (me);
433 else if (me->param->positional)
436 if (me->param >= &me->macro->params[me->macro->n_params])
437 return me_finished (me);
440 me->state = (!me->param->positional ? ME_KEYWORD
441 : me->param->arg_type == ARG_ENCLOSE ? ME_ENCLOSE
448 for (size_t i = 0; i < me->macro->n_params; i++)
451 me->state = ME_KEYWORD;
454 return me_finished (me);
459 me_error (struct macro_expander *me)
461 me->state = ME_ERROR;
466 me_add_arg (struct macro_expander *me, const struct macro_token *mt)
468 const struct macro_param *p = me->param;
470 const struct token *token = &mt->token;
471 if ((token->type == T_ENDCMD || token->type == T_STOP)
472 && p->arg_type != ARG_CMDEND)
474 msg (SE, _("Unexpected end of command reading argument %s "
475 "to macro %s."), me->param->name, me->macro->name);
477 return me_error (me);
482 struct macro_tokens **argp = &me->args[p - me->macro->params];
484 *argp = xzalloc (sizeof **argp);
485 struct macro_tokens *arg = *argp;
486 if (p->arg_type == ARG_N_TOKENS)
488 macro_tokens_add (arg, mt);
489 if (arg->n >= p->n_tokens)
490 return me_next_arg (me);
493 else if (p->arg_type == ARG_CMDEND)
495 if (token->type == T_ENDCMD || token->type == T_STOP)
496 return me_next_arg (me);
497 macro_tokens_add (arg, mt);
502 const struct token *end
503 = p->arg_type == ARG_CHAREND ? &p->charend : &p->enclose[1];
504 if (token_equal (token, end))
505 return me_next_arg (me);
506 macro_tokens_add (arg, mt);
512 me_expected (struct macro_expander *me, const struct macro_token *actual,
513 const struct token *expected)
515 const struct substring actual_s
516 = (actual->representation.length ? actual->representation
517 : ss_cstr (_("<end of input>")));
518 char *expected_s = token_to_string (expected);
519 msg (SE, _("Found `%.*s' while expecting `%s' reading argument %s "
521 (int) actual_s.length, actual_s.string, expected_s,
522 me->param->name, me->macro->name);
525 return me_error (me);
529 me_enclose (struct macro_expander *me, const struct macro_token *mt)
531 const struct token *token = &mt->token;
534 if (token_equal (&me->param->enclose[0], token))
540 return me_expected (me, mt, &me->param->enclose[0]);
543 static const struct macro_param *
544 macro_find_parameter_by_name (const struct macro *m, struct substring name)
546 if (ss_first (name) == '!')
547 ss_advance (&name, 1);
549 for (size_t i = 0; i < m->n_params; i++)
551 const struct macro_param *p = &m->params[i];
552 struct substring p_name = ss_cstr (p->name + 1);
553 if (!utf8_strncasecmp (p_name.string, p_name.length,
554 name.string, name.length))
561 me_keyword (struct macro_expander *me, const struct macro_token *mt)
563 const struct token *token = &mt->token;
564 if (token->type != T_ID)
565 return me_finished (me);
567 const struct macro_param *p = macro_find_parameter_by_name (me->macro,
571 size_t arg_index = p - me->macro->params;
573 if (me->args[arg_index])
576 _("Argument %s multiply specified in call to macro %s."),
577 p->name, me->macro->name);
578 return me_error (me);
582 me->state = ME_EQUALS;
586 return me_finished (me);
590 me_equals (struct macro_expander *me, const struct macro_token *mt)
592 const struct token *token = &mt->token;
595 if (token->type == T_EQUALS)
601 return me_expected (me, mt, &(struct token) { .type = T_EQUALS });
605 macro_expander_create (const struct macro_set *macros,
606 const struct token *token,
607 struct macro_expander **mep)
610 if (macro_set_is_empty (macros))
612 if (token->type != T_ID && token->type != T_MACRO_ID)
615 const struct macro *macro = macro_set_find (macros, token->string.string);
619 struct macro_expander *me = xmalloc (sizeof *me);
620 *me = (struct macro_expander) {
627 if (!macro->n_params)
631 me->state = (!macro->params[0].positional ? ME_KEYWORD
632 : macro->params[0].arg_type == ARG_ENCLOSE ? ME_ENCLOSE
634 me->args = xcalloc (macro->n_params, sizeof *me->args);
635 me->param = macro->params;
641 macro_expander_destroy (struct macro_expander *me)
646 for (size_t i = 0; i < me->macro->n_params; i++)
649 macro_tokens_uninit (me->args[i]);
656 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
659 Returns -1 if the tokens added do not actually invoke a macro. The caller
660 should consume the first token without expanding it.
662 Returns 0 if the macro expander needs more tokens, for macro arguments or to
663 decide whether this is actually a macro invocation. The caller should call
664 macro_expander_add() again with the next token.
666 Returns a positive number to indicate that the returned number of tokens
667 invoke a macro. The number returned might be less than the number of tokens
668 added because it can take a few tokens of lookahead to determine whether the
669 macro invocation is finished. The caller should call
670 macro_expander_get_expansion() to obtain the expansion. */
672 macro_expander_add (struct macro_expander *me, const struct macro_token *mt)
680 return me_add_arg (me, mt);
683 return me_enclose (me, mt);
686 return me_keyword (me, mt);
689 return me_equals (me, mt);
696 /* Each argument to a macro function is one of:
698 - A quoted string or other single literal token.
700 - An argument to the macro being expanded, e.g. !1 or a named argument.
704 - A function invocation.
706 Each function invocation yields a character sequence to be turned into a
707 sequence of tokens. The case where that character sequence is a single
708 quoted string is an important special case.
710 struct parse_macro_function_ctx
712 const struct macro_token *input;
714 int nesting_countdown;
715 const struct macro_set *macros;
716 const struct macro_expander *me;
717 struct string_map *vars;
722 macro_expand (const struct macro_tokens *,
723 int nesting_countdown, const struct macro_set *,
724 const struct macro_expander *, struct string_map *vars,
725 bool *expand, struct macro_tokens *exp);
728 expand_macro_function (struct parse_macro_function_ctx *ctx,
729 struct string *output, size_t *input_consumed);
731 /* Returns true if the pair of tokens starting at offset OFS within MTS are !*,
734 is_bang_star (const struct macro_token *mts, size_t n, size_t ofs)
737 && mts[ofs].token.type == T_MACRO_ID
738 && ss_equals (mts[ofs].token.string, ss_cstr ("!"))
739 && mts[ofs + 1].token.type == T_ASTERISK);
743 parse_function_arg (struct parse_macro_function_ctx *ctx,
744 size_t i, struct string *farg)
746 const struct macro_token *tokens = ctx->input;
747 const struct token *token = &tokens[i].token;
748 if (token->type == T_MACRO_ID)
750 const struct macro_param *param = macro_find_parameter_by_name (
751 ctx->me->macro, token->string);
754 size_t param_idx = param - ctx->me->macro->params;
755 const struct macro_tokens *marg = ctx->me->args[param_idx];
756 for (size_t i = 0; i < marg->n; i++)
759 ds_put_byte (farg, ' ');
760 ds_put_substring (farg, marg->mts[i].representation);
765 if (is_bang_star (ctx->input, ctx->n_input, i))
767 for (size_t i = 0; i < ctx->me->macro->n_params; i++)
769 if (!ctx->me->macro->params[i].positional)
772 const struct macro_tokens *marg = ctx->me->args[i];
773 for (size_t j = 0; j < marg->n; j++)
776 ds_put_byte (farg, ' ');
777 ds_put_substring (farg, marg->mts[j].representation);
785 const char *value = string_map_find__ (ctx->vars,
786 token->string.string,
787 token->string.length);
790 ds_put_cstr (farg, value);
795 struct parse_macro_function_ctx subctx = {
796 .input = &ctx->input[i],
797 .n_input = ctx->n_input - i,
798 .nesting_countdown = ctx->nesting_countdown,
799 .macros = ctx->macros,
802 .expand = ctx->expand,
804 size_t subinput_consumed;
805 if (expand_macro_function (&subctx, farg, &subinput_consumed))
806 return subinput_consumed;
809 ds_put_substring (farg, tokens[i].representation);
814 parse_macro_function (struct parse_macro_function_ctx *ctx,
815 struct string_array *args,
816 struct substring function,
817 int min_args, int max_args,
818 size_t *input_consumed)
820 const struct macro_token *tokens = ctx->input;
821 size_t n_tokens = ctx->n_input;
824 || tokens[0].token.type != T_MACRO_ID
825 || !ss_equals_case (tokens[0].token.string, function)) /* XXX abbrevs allowed */
828 if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
830 printf ("`(' expected following %s'\n", function.string);
834 string_array_init (args);
836 for (size_t i = 2;; )
840 if (tokens[i].token.type == T_RPAREN)
842 *input_consumed = i + 1;
843 if (args->n < min_args || args->n > max_args)
845 printf ("Wrong number of arguments to %s.\n", function.string);
851 struct string s = DS_EMPTY_INITIALIZER;
852 i += parse_function_arg (ctx, i, &s);
858 string_array_append_nocopy (args, ds_steal_cstr (&s));
860 if (tokens[i].token.type == T_COMMA)
862 else if (tokens[i].token.type != T_RPAREN)
864 printf ("Expecting `,' or `)' in %s invocation.", function.string);
870 printf ("Missing closing parenthesis in arguments to %s.\n",
874 string_array_destroy (args);
879 unquote_string (const char *s, struct string *content)
881 struct string_lexer slex;
882 string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */);
885 if (!string_lexer_next (&slex, &token1))
888 if (token1.type != T_STRING)
890 token_uninit (&token1);
895 if (string_lexer_next (&slex, &token2))
897 token_uninit (&token1);
898 token_uninit (&token2);
902 ds_put_substring (content, token1.string);
903 token_uninit (&token1);
908 unquote_string_in_place (const char *s, struct string *tmp)
911 return unquote_string (s, tmp) ? ds_cstr (tmp) : s;
915 parse_integer (const char *s, int *np)
920 long int n = strtol (s, &tail, 10);
921 *np = n < INT_MIN ? INT_MIN : n > INT_MAX ? INT_MAX : n;
922 tail += strspn (tail, CC_SPACES);
923 return *tail == '\0' && errno != ERANGE && n == *np;
927 expand_macro_function (struct parse_macro_function_ctx *ctx,
928 struct string *output,
929 size_t *input_consumed)
931 struct string_array args;
933 if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1,
935 ds_put_format (output, "%zu", strlen (args.strings[0]));
936 else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
940 if (!parse_integer (args.strings[0], &n))
942 printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]);
943 string_array_destroy (&args);
947 ds_put_byte_multiple (output, ' ', n);
949 else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
952 for (size_t i = 0; i < args.n; i++)
953 if (!unquote_string (args.strings[i], output))
954 ds_put_cstr (output, args.strings[i]);
956 else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
960 const char *s = unquote_string_in_place (args.strings[0], &tmp);
962 struct macro_tokens mts = { .n = 0 };
963 macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
965 ds_put_substring (output, mts.mts[0].representation);
966 macro_tokens_uninit (&mts);
969 else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
972 const char *haystack = args.strings[0];
973 const char *needle = strstr (haystack, args.strings[1]);
974 ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
976 else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
979 if (unquote_string (args.strings[0], NULL))
980 ds_put_cstr (output, args.strings[0]);
983 ds_extend (output, strlen (args.strings[0]) + 2);
984 ds_put_byte (output, '\'');
985 for (const char *p = args.strings[0]; *p; p++)
988 ds_put_byte (output, '\'');
989 ds_put_byte (output, *p);
991 ds_put_byte (output, '\'');
994 else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3,
998 if (!parse_integer (args.strings[1], &start) || start < 1)
1000 printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]);
1001 string_array_destroy (&args);
1005 int count = INT_MAX;
1006 if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
1008 printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]);
1009 string_array_destroy (&args);
1013 struct substring s = ss_cstr (args.strings[0]);
1014 ds_put_substring (output, ss_substr (s, start - 1, count));
1016 else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1,
1020 const char *s = unquote_string_in_place (args.strings[0], &tmp);
1022 struct macro_tokens mts = { .n = 0 };
1023 macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
1026 struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
1027 macro_tokens_to_representation (&tail, output);
1029 macro_tokens_uninit (&mts);
1032 else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
1035 if (!unquote_string (args.strings[0], output))
1036 ds_put_cstr (output, args.strings[0]);
1038 else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
1042 const char *s = unquote_string_in_place (args.strings[0], &tmp);
1043 char *upper = utf8_to_upper (s);
1044 ds_put_cstr (output, upper);
1048 else if (parse_macro_function (ctx, &args, ss_cstr ("!eval"), 1, 1,
1051 struct macro_tokens mts = { .n = 0 };
1052 macro_tokens_from_string (&mts, ss_cstr (args.strings[0]),
1053 SEG_MODE_INTERACTIVE /* XXX */);
1054 struct macro_tokens exp = { .n = 0 };
1055 macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros, ctx->me,
1056 ctx->vars, ctx->expand, &exp);
1057 macro_tokens_to_representation (&exp, output);
1058 macro_tokens_uninit (&exp);
1059 macro_tokens_uninit (&mts);
1061 else if (ctx->n_input > 0
1062 && ctx->input[0].token.type == T_MACRO_ID
1063 && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null")))
1065 *input_consumed = 1;
1071 string_array_destroy (&args);
1077 int nesting_countdown;
1078 const struct macro_set *macros;
1079 const struct macro_expander *me;
1080 struct string_map *vars;
1084 static char *macro_evaluate_or (const struct expr_context *ctx,
1085 const struct macro_token **tokens,
1086 const struct macro_token *end);
1089 macro_evaluate_literal (const struct expr_context *ctx,
1090 const struct macro_token **tokens,
1091 const struct macro_token *end)
1093 const struct macro_token *p = *tokens;
1096 if (p->token.type == T_LPAREN)
1099 char *value = macro_evaluate_or (ctx, &p, end);
1102 if (p >= end || p->token.type != T_RPAREN)
1105 printf ("expecting ')' in macro expression\n");
1113 struct parse_macro_function_ctx fctx = {
1116 .nesting_countdown = ctx->nesting_countdown,
1117 .macros = ctx->macros,
1120 .expand = ctx->expand,
1122 struct string function_output = DS_EMPTY_INITIALIZER;
1123 size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
1124 struct string unquoted = DS_EMPTY_INITIALIZER;
1125 if (unquote_string (ds_cstr (&function_output), &unquoted))
1127 ds_swap (&function_output, &unquoted);
1128 ds_destroy (&unquoted);
1130 *tokens = p + function_consumed;
1131 return ds_steal_cstr (&function_output);
1134 /* Returns true if MT is valid as a macro operator. Only operators written as
1135 symbols (e.g. <>) are usable in macro expressions, not operator written as
1136 letters (e.g. EQ). */
1138 is_macro_operator (const struct macro_token *mt)
1140 return (mt->representation.length > 0
1141 && !c_isalpha (mt->representation.string[0]));
1144 static enum token_type
1145 parse_relational_op (const struct macro_token *mt)
1147 switch (mt->token.type)
1157 return is_macro_operator (mt) ? mt->token.type : T_STOP;
1160 return (ss_equals_case (mt->token.string, ss_cstr ("!EQ")) ? T_EQ
1161 : ss_equals_case (mt->token.string, ss_cstr ("!NE")) ? T_NE
1162 : ss_equals_case (mt->token.string, ss_cstr ("!LT")) ? T_LT
1163 : ss_equals_case (mt->token.string, ss_cstr ("!GT")) ? T_GT
1164 : ss_equals_case (mt->token.string, ss_cstr ("!LE")) ? T_LE
1165 : ss_equals_case (mt->token.string, ss_cstr ("!GE")) ? T_GE
1174 macro_evaluate_relational (const struct expr_context *ctx,
1175 const struct macro_token **tokens,
1176 const struct macro_token *end)
1178 const struct macro_token *p = *tokens;
1179 char *lhs = macro_evaluate_literal (ctx, &p, end);
1183 enum token_type op = p >= end ? T_STOP : parse_relational_op (p);
1191 char *rhs = macro_evaluate_literal (ctx, &p, end);
1198 struct string lhs_tmp, rhs_tmp;
1199 int cmp = strcmp/*XXX*/ (unquote_string_in_place (lhs, &lhs_tmp),
1200 unquote_string_in_place (rhs, &rhs_tmp));
1201 ds_destroy (&lhs_tmp);
1202 ds_destroy (&rhs_tmp);
1207 bool b = (op == T_EQUALS || op == T_EQ ? !cmp
1209 : op == T_LT ? cmp < 0
1210 : op == T_GT ? cmp > 0
1211 : op == T_LE ? cmp <= 0
1212 :/*op == T_GE*/cmp >= 0);
1215 return xstrdup (b ? "1" : "0");
1219 macro_evaluate_not (const struct expr_context *ctx,
1220 const struct macro_token **tokens,
1221 const struct macro_token *end)
1223 const struct macro_token *p = *tokens;
1225 unsigned int negations = 0;
1227 && (ss_equals_case (p->representation, ss_cstr ("!NOT"))
1228 || ss_equals (p->representation, ss_cstr ("~"))))
1234 char *operand = macro_evaluate_relational (ctx, &p, end);
1235 if (!operand || !negations)
1241 bool b = strcmp (operand, "0") ^ (negations & 1);
1244 return xstrdup (b ? "1" : "0");
1248 macro_evaluate_and (const struct expr_context *ctx,
1249 const struct macro_token **tokens,
1250 const struct macro_token *end)
1252 const struct macro_token *p = *tokens;
1253 char *lhs = macro_evaluate_not (ctx, &p, end);
1258 && (ss_equals_case (p->representation, ss_cstr ("!AND"))
1259 || ss_equals (p->representation, ss_cstr ("&"))))
1262 char *rhs = macro_evaluate_not (ctx, &p, end);
1269 bool b = strcmp (lhs, "0") && strcmp (rhs, "0");
1272 lhs = xstrdup (b ? "1" : "0");
1279 macro_evaluate_or (const struct expr_context *ctx,
1280 const struct macro_token **tokens,
1281 const struct macro_token *end)
1283 const struct macro_token *p = *tokens;
1284 char *lhs = macro_evaluate_and (ctx, &p, end);
1289 && (ss_equals_case (p->representation, ss_cstr ("!OR"))
1290 || ss_equals (p->representation, ss_cstr ("|"))))
1293 char *rhs = macro_evaluate_and (ctx, &p, end);
1300 bool b = strcmp (lhs, "0") || strcmp (rhs, "0");
1303 lhs = xstrdup (b ? "1" : "0");
1310 macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
1311 int nesting_countdown, const struct macro_set *macros,
1312 const struct macro_expander *me, struct string_map *vars,
1315 const struct expr_context ctx = {
1316 .nesting_countdown = nesting_countdown,
1322 return macro_evaluate_or (&ctx, tokens, *tokens + n_tokens);
1326 macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
1327 int nesting_countdown, const struct macro_set *macros,
1328 const struct macro_expander *me, struct string_map *vars,
1329 bool *expand, double *number)
1331 char *s = macro_evaluate_expression (tokens, n_tokens, nesting_countdown,
1332 macros, me, vars, expand);
1336 struct macro_tokens mts = { .n = 0 };
1337 macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
1338 if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
1340 macro_tokens_print (&mts, stdout);
1341 printf ("expression must evaluate to a number (not %s)\n", s);
1343 macro_tokens_uninit (&mts);
1347 *number = token_number (&mts.mts[0].token);
1349 macro_tokens_uninit (&mts);
1353 static const struct macro_token *
1354 find_ifend_clause (const struct macro_token *p, const struct macro_token *end)
1357 for (; p < end; p++)
1359 if (p->token.type != T_MACRO_ID)
1362 if (ss_equals_case (p->token.string, ss_cstr ("!IF")))
1364 else if (ss_equals_case (p->token.string, ss_cstr ("!IFEND")))
1370 else if (ss_equals_case (p->token.string, ss_cstr ("!ELSE")) && !nesting)
1377 macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
1378 int nesting_countdown, const struct macro_set *macros,
1379 const struct macro_expander *me, struct string_map *vars,
1380 bool *expand, struct macro_tokens *exp)
1382 const struct macro_token *p = tokens;
1383 const struct macro_token *end = tokens + n_tokens;
1385 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!IF")))
1389 char *result = macro_evaluate_expression (&p, end - p,
1390 nesting_countdown, macros, me, vars,
1394 bool b = strcmp (result, "0");
1398 || p->token.type != T_MACRO_ID
1399 || !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
1401 printf ("!THEN expected\n");
1405 const struct macro_token *start_then = p + 1;
1406 const struct macro_token *end_then = find_ifend_clause (start_then, end);
1409 printf ("!ELSE or !IFEND expected\n");
1413 const struct macro_token *start_else, *end_if;
1414 if (ss_equals_case (end_then->token.string, ss_cstr ("!ELSE")))
1416 start_else = end_then + 1;
1417 end_if = find_ifend_clause (start_else, end);
1419 || !ss_equals_case (end_if->token.string, ss_cstr ("!IFEND")))
1421 printf ("!IFEND expected\n");
1431 const struct macro_token *start;
1436 n = end_then - start_then;
1438 else if (start_else)
1441 n = end_if - start_else;
1451 struct macro_tokens mts = {
1452 .mts = CONST_CAST (struct macro_token *, start),
1455 macro_expand (&mts, nesting_countdown, macros, me, vars, expand, exp);
1457 return (end_if + 1) - tokens;
1461 macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
1462 int nesting_countdown, const struct macro_set *macros,
1463 const struct macro_expander *me, struct string_map *vars,
1466 const struct macro_token *p = tokens;
1467 const struct macro_token *end = tokens + n_tokens;
1469 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!LET")))
1473 if (p >= end || p->token.type != T_MACRO_ID)
1475 printf ("expected macro variable name following !LET\n");
1478 const struct substring var_name = p->token.string;
1481 if (p >= end || p->token.type != T_EQUALS)
1483 printf ("expected = following !LET\n");
1488 char *value = macro_evaluate_expression (&p, end - p,
1489 nesting_countdown, macros, me, vars,
1494 string_map_replace_nocopy (vars, ss_xstrdup (var_name), value);
1498 static const struct macro_token *
1499 find_doend (const struct macro_token *p, const struct macro_token *end)
1502 for (; p < end; p++)
1504 if (p->token.type != T_MACRO_ID)
1507 if (ss_equals_case (p->token.string, ss_cstr ("!DO")))
1509 else if (ss_equals_case (p->token.string, ss_cstr ("!DOEND")))
1516 printf ("missing !DOEND\n");
1521 macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
1522 int nesting_countdown, const struct macro_set *macros,
1523 const struct macro_expander *me, struct string_map *vars,
1524 bool *expand, struct macro_tokens *exp)
1526 const struct macro_token *p = tokens;
1527 const struct macro_token *end = tokens + n_tokens;
1529 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!DO")))
1533 if (p >= end || p->token.type != T_MACRO_ID)
1535 printf ("expected macro variable name following !DO\n");
1538 const struct substring var_name = p->token.string;
1541 if (p < end && p->token.type == T_MACRO_ID
1542 && ss_equals_case (p->token.string, ss_cstr ("!IN")))
1545 char *list = macro_evaluate_expression (&p, end - p,
1546 nesting_countdown, macros, me, vars,
1551 struct macro_tokens items = { .n = 0 };
1552 macro_tokens_from_string (&items, ss_cstr (list),
1553 SEG_MODE_INTERACTIVE /* XXX */);
1556 const struct macro_token *do_end = find_doend (p, end);
1559 macro_tokens_uninit (&items);
1563 const struct macro_tokens inner = {
1564 .mts = CONST_CAST (struct macro_token *, p),
1567 for (size_t i = 0; i < items.n; i++)
1569 string_map_replace_nocopy (vars, ss_xstrdup (var_name),
1570 ss_xstrdup (items.mts[i].representation));
1571 macro_expand (&inner, nesting_countdown, macros,
1572 me, vars, expand, exp);
1574 return do_end - tokens + 1;
1576 else if (p < end && p->token.type == T_EQUALS)
1580 if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1581 vars, expand, &first))
1584 if (p >= end || p->token.type != T_MACRO_ID
1585 || !ss_equals_case (p->token.string, ss_cstr ("!TO")))
1587 printf ("expecting !TO\n");
1593 if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1594 vars, expand, &last))
1598 if (p < end && p->token.type == T_MACRO_ID
1599 && ss_equals_case (p->token.string, ss_cstr ("!BY")))
1602 if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1608 printf ("!BY value cannot be zero\n");
1613 const struct macro_token *do_end = find_doend (p, end);
1616 const struct macro_tokens inner = {
1617 .mts = CONST_CAST (struct macro_token *, p),
1621 if ((by > 0 && first <= last) || (by < 0 && first >= last))
1622 for (double index = first;
1623 by > 0 ? (index <= last) : (index >= last);
1626 char index_s[DBL_BUFSIZE_BOUND];
1627 c_dtoastr (index_s, sizeof index_s, 0, 0, index);
1628 string_map_replace_nocopy (vars, ss_xstrdup (var_name),
1630 macro_expand (&inner, nesting_countdown, macros,
1631 me, vars, expand, exp);
1634 return do_end - tokens + 1;
1638 printf ("expecting = or !IN in !DO loop\n");
1644 macro_expand (const struct macro_tokens *mts,
1645 int nesting_countdown, const struct macro_set *macros,
1646 const struct macro_expander *me, struct string_map *vars,
1647 bool *expand, struct macro_tokens *exp)
1649 if (nesting_countdown <= 0)
1651 printf ("maximum nesting level exceeded\n");
1652 for (size_t i = 0; i < mts->n; i++)
1653 macro_tokens_add (exp, &mts->mts[i]);
1657 struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
1660 for (size_t i = 0; i < mts->n; i++)
1662 const struct macro_token *mt = &mts->mts[i];
1663 const struct token *token = &mt->token;
1664 if (token->type == T_MACRO_ID && me)
1666 const struct macro_param *param = macro_find_parameter_by_name (
1667 me->macro, token->string);
1670 const struct macro_tokens *arg = me->args[param - me->macro->params];
1671 //macro_tokens_print (arg, stdout);
1672 if (*expand && param->expand_arg)
1673 macro_expand (arg, nesting_countdown, macros, NULL, NULL,
1676 for (size_t i = 0; i < arg->n; i++)
1677 macro_tokens_add (exp, &arg->mts[i]);
1681 if (is_bang_star (mts->mts, mts->n, i))
1683 for (size_t j = 0; j < me->macro->n_params; j++)
1685 const struct macro_param *param = &me->macro->params[j];
1686 if (!param->positional)
1689 const struct macro_tokens *arg = me->args[j];
1690 if (*expand && param->expand_arg)
1691 macro_expand (arg, nesting_countdown, macros, NULL, NULL,
1694 for (size_t k = 0; k < arg->n; k++)
1695 macro_tokens_add (exp, &arg->mts[k]);
1701 size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
1702 nesting_countdown, macros, me, vars,
1711 if (token->type == T_MACRO_ID && vars)
1713 const char *value = string_map_find__ (vars, token->string.string,
1714 token->string.length);
1717 macro_tokens_from_string (exp, ss_cstr (value),
1718 SEG_MODE_INTERACTIVE /* XXX */);
1725 struct macro_expander *subme;
1726 int retval = macro_expander_create (macros, token, &subme);
1727 for (size_t j = 1; !retval; j++)
1729 const struct macro_token endcmd = { .token = { .type = T_ENDCMD } };
1730 retval = macro_expander_add (
1731 subme, i + j < mts->n ? &mts->mts[i + j] : &endcmd);
1736 macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
1737 subme, NULL, expand, exp);
1738 macro_expander_destroy (subme);
1742 macro_expander_destroy (subme);
1745 if (token->type != T_MACRO_ID)
1747 macro_tokens_add (exp, mt);
1751 struct parse_macro_function_ctx ctx = {
1752 .input = &mts->mts[i],
1753 .n_input = mts->n - i,
1754 .nesting_countdown = nesting_countdown,
1760 struct string function_output = DS_EMPTY_INITIALIZER;
1761 size_t function_consumed;
1762 if (expand_macro_function (&ctx, &function_output, &function_consumed))
1764 i += function_consumed - 1;
1766 macro_tokens_from_string (exp, function_output.ss,
1767 SEG_MODE_INTERACTIVE /* XXX */);
1768 ds_destroy (&function_output);
1773 size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
1774 nesting_countdown, macros, me, vars,
1782 n = macro_expand_do (&mts->mts[i], mts->n - i,
1783 nesting_countdown, macros, me, vars,
1791 if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
1793 else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
1796 macro_tokens_add (exp, mt);
1798 if (vars == &own_vars)
1799 string_map_destroy (&own_vars);
1803 macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
1806 for (size_t i = 0; i < me->macro->n_params; i++)
1808 printf ("%s:\n", me->macro->params[i].name);
1809 macro_tokens_print (me->args[i], stdout);
1814 macro_expand (&me->macro->body, settings_get_mnest (),
1815 me->macros, me, NULL, &expand, exp);
1818 printf ("expansion:\n");
1819 macro_tokens_print (exp, stdout);