ca32800f30a9dc5129d8b6f38f52a597da4398e5
[pspp] / src / language / lexer / macro.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2021 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/macro.h"
20
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdlib.h>
24
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"
35
36 #include "gl/c-ctype.h"
37 #include "gl/ftoastr.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 void
43 macro_token_copy (struct macro_token *dst, const struct macro_token *src)
44 {
45   token_copy (&dst->token, &src->token);
46   ss_alloc_substring (&dst->representation, src->representation);
47 }
48
49 void
50 macro_token_uninit (struct macro_token *mt)
51 {
52   token_uninit (&mt->token);
53   ss_dealloc (&mt->representation);
54 }
55
56 void
57 macro_token_to_representation (struct macro_token *mt, struct string *s)
58 {
59   ds_put_substring (s, mt->representation);
60 }
61
62 void
63 macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
64 {
65   *dst = (struct macro_tokens) {
66     .mts = xmalloc (src->n * sizeof *dst->mts),
67     .n = src->n,
68     .allocated = src->n,
69   };
70   for (size_t i = 0; i < src->n; i++)
71     macro_token_copy (&dst->mts[i], &src->mts[i]);
72 }
73
74 void
75 macro_tokens_uninit (struct macro_tokens *mts)
76 {
77   for (size_t i = 0; i < mts->n; i++)
78     macro_token_uninit (&mts->mts[i]);
79   free (mts->mts);
80 }
81
82 struct macro_token *
83 macro_tokens_add_uninit (struct macro_tokens *mts)
84 {
85   if (mts->n >= mts->allocated)
86     mts->mts = x2nrealloc (mts->mts, &mts->allocated, sizeof *mts->mts);
87   return &mts->mts[mts->n++];
88 }
89
90 void
91 macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt)
92 {
93   macro_token_copy (macro_tokens_add_uninit (mts), mt);
94 }
95
96 void
97 macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
98                           enum segmenter_mode mode)
99 {
100   struct state
101     {
102       struct segmenter segmenter;
103       struct substring body;
104     };
105
106   struct state state = {
107     .segmenter = segmenter_init (mode, true),
108     .body = src,
109   };
110   struct state saved = state;
111
112   while (state.body.length > 0)
113     {
114       struct macro_token mt = {
115         .token = { .type = T_STOP },
116         .representation = { .string = state.body.string },
117       };
118       struct token *token = &mt.token;
119
120       struct scanner scanner;
121       scanner_init (&scanner, token);
122
123       for (;;)
124         {
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);
129
130           struct substring segment = ss_head (state.body, seg_len);
131           ss_advance (&state.body, seg_len);
132
133           enum scan_result result = scanner_push (&scanner, type, segment, token);
134           if (result == SCAN_SAVE)
135             saved = state;
136           else if (result == SCAN_BACK)
137             {
138               state = saved;
139               break;
140             }
141           else if (result == SCAN_DONE)
142             break;
143         }
144
145       /* We have a token in 'token'. */
146       if (is_scan_type (token->type))
147         {
148           if (token->type != SCAN_SKIP)
149             {
150               printf ("error\n");
151               /* XXX report error */
152             }
153         }
154       else
155         {
156           mt.representation.length = state.body.string - mt.representation.string;
157           macro_tokens_add (mts, &mt);
158         }
159       token_uninit (token);
160     }
161 }
162
163 void
164 macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
165 {
166   for (size_t i = 0; i < mts->n; i++)
167     token_print (&mts->mts[i].token, stream);
168 }
169
170 enum token_class
171   {
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. */
177   };
178
179 static bool
180 needs_space (enum token_class prev, enum token_class next)
181 {
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)
185     return false;
186
187   /* Binary operators always have a space on both sides. */
188   if (prev == TC_BINOP || next == TC_BINOP)
189     return true;
190
191   /* A comma always has a space afterward. */
192   if (prev == TC_COMMA)
193     return true;
194
195   /* Otherwise, PREV is TC_ID or TC_PUNCT, which only need a space if there are
196      two or them in a row. */
197   return prev == next;
198 }
199
200 static enum token_class
201 classify_token (enum token_type type)
202 {
203   switch (type)
204     {
205     case T_ID:
206     case T_MACRO_ID:
207     case T_POS_NUM:
208     case T_NEG_NUM:
209     case T_STRING:
210       return TC_ID;
211
212     case T_STOP:
213       return TC_PUNCT;
214
215     case T_ENDCMD:
216       return TC_ENDCMD;
217
218     case T_LPAREN:
219     case T_RPAREN:
220     case T_LBRACK:
221     case T_RBRACK:
222       return TC_PUNCT;
223
224     case T_PLUS:
225     case T_DASH:
226     case T_ASTERISK:
227     case T_SLASH:
228     case T_EQUALS:
229     case T_AND:
230     case T_OR:
231     case T_NOT:
232     case T_EQ:
233     case T_GE:
234     case T_GT:
235     case T_LE:
236     case T_LT:
237     case T_NE:
238     case T_ALL:
239     case T_BY:
240     case T_TO:
241     case T_WITH:
242     case T_EXP:
243     case T_MACRO_PUNCT:
244       return TC_BINOP;
245
246     case T_COMMA:
247       return TC_COMMA;
248     }
249
250   NOT_REACHED ();
251 }
252
253 void
254 macro_tokens_to_representation (struct macro_tokens *mts, struct string *s)
255 {
256   if (!mts->n)
257     return;
258
259   macro_token_to_representation (&mts->mts[0], s);
260   for (size_t i = 1; i < mts->n; i++)
261     {
262       enum token_type prev = mts->mts[i - 1].token.type;
263       enum token_type next = mts->mts[i].token.type;
264
265       if (prev == T_ENDCMD)
266         ds_put_byte (s, '\n');
267       else
268         {
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, ' ');
273         }
274
275       macro_token_to_representation (&mts->mts[i], s);
276     }
277 }
278
279 void
280 macro_destroy (struct macro *m)
281 {
282   if (!m)
283     return;
284
285   free (m->name);
286   for (size_t i = 0; i < m->n_params; i++)
287     {
288       struct macro_param *p = &m->params[i];
289       free (p->name);
290
291       macro_tokens_uninit (&p->def);
292
293       switch (p->arg_type)
294         {
295         case ARG_N_TOKENS:
296           break;
297
298         case ARG_CHAREND:
299           token_uninit (&p->charend);
300           break;
301
302         case ARG_ENCLOSE:
303           token_uninit (&p->enclose[0]);
304           token_uninit (&p->enclose[1]);
305           break;
306
307         case ARG_CMDEND:
308           break;
309         }
310     }
311   free (m->params);
312   macro_tokens_uninit (&m->body);
313   free (m);
314 }
315 \f
316 struct macro_set *
317 macro_set_create (void)
318 {
319   struct macro_set *set = xmalloc (sizeof *set);
320   *set = (struct macro_set) {
321     .macros = HMAP_INITIALIZER (set->macros),
322   };
323   return set;
324 }
325
326 void
327 macro_set_destroy (struct macro_set *set)
328 {
329   if (!set)
330     return;
331
332   struct macro *macro, *next;
333   HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
334     {
335       hmap_delete (&set->macros, &macro->hmap_node);
336       macro_destroy (macro);
337     }
338   hmap_destroy (&set->macros);
339   free (set);
340 }
341
342 static unsigned int
343 hash_macro_name (const char *name)
344 {
345   return utf8_hash_case_string (name, 0);
346 }
347
348 static struct macro *
349 macro_set_find__ (struct macro_set *set, const char *name)
350 {
351   struct macro *macro;
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))
355       return macro;
356
357   return NULL;
358 }
359
360 const struct macro *
361 macro_set_find (const struct macro_set *set, const char *name)
362 {
363   return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
364 }
365
366 /* Adds M to SET.  M replaces any existing macro with the same name.  Takes
367    ownership of M. */
368 void
369 macro_set_add (struct macro_set *set, struct macro *m)
370 {
371   struct macro *victim = macro_set_find__ (set, m->name);
372   if (victim)
373     {
374       hmap_delete (&set->macros, &victim->hmap_node);
375       macro_destroy (victim);
376     }
377
378   hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
379 }
380 \f
381 enum me_state
382   {
383     /* Error state. */
384     ME_ERROR,
385
386     /* Accumulating tokens in me->params toward the end of any type of
387        argument. */
388     ME_ARG,
389
390     /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
391     ME_ENCLOSE,
392
393     /* Expecting a keyword for a keyword argument. */
394     ME_KEYWORD,
395
396     /* Expecting an equal sign for a keyword argument. */
397     ME_EQUALS,
398   };
399
400
401 struct macro_expander
402   {
403     const struct macro_set *macros;
404
405     enum me_state state;
406     size_t n_tokens;
407
408     const struct macro *macro;
409     struct macro_tokens **args;
410     const struct macro_param *param;
411   };
412
413 static int
414 me_finished (struct macro_expander *me)
415 {
416   for (size_t i = 0; i < me->macro->n_params; i++)
417     if (!me->args[i])
418       {
419         me->args[i] = xmalloc (sizeof *me->args[i]);
420         macro_tokens_copy (me->args[i], &me->macro->params[i].def);
421       }
422   return me->n_tokens;
423 }
424
425 static int
426 me_next_arg (struct macro_expander *me)
427 {
428   if (!me->param)
429     {
430       assert (!me->macro->n_params);
431       return me_finished (me);
432     }
433   else if (me->param->positional)
434     {
435       me->param++;
436       if (me->param >= &me->macro->params[me->macro->n_params])
437         return me_finished (me);
438       else
439         {
440           me->state = (!me->param->positional ? ME_KEYWORD
441                        : me->param->arg_type == ARG_ENCLOSE ? ME_ENCLOSE
442                        : ME_ARG);
443           return 0;
444         }
445     }
446   else
447     {
448       for (size_t i = 0; i < me->macro->n_params; i++)
449         if (!me->args[i])
450           {
451             me->state = ME_KEYWORD;
452             return 0;
453           }
454       return me_finished (me);
455     }
456 }
457
458 static int
459 me_error (struct macro_expander *me)
460 {
461   me->state = ME_ERROR;
462   return -1;
463 }
464
465 static int
466 me_add_arg (struct macro_expander *me, const struct macro_token *mt)
467 {
468   const struct macro_param *p = me->param;
469
470   const struct token *token = &mt->token;
471   if ((token->type == T_ENDCMD || token->type == T_STOP)
472       && p->arg_type != ARG_CMDEND)
473     {
474       msg (SE, _("Unexpected end of command reading argument %s "
475                  "to macro %s."), me->param->name, me->macro->name);
476
477       return me_error (me);
478     }
479
480   me->n_tokens++;
481
482   struct macro_tokens **argp = &me->args[p - me->macro->params];
483   if (!*argp)
484     *argp = xzalloc (sizeof **argp);
485   struct macro_tokens *arg = *argp;
486   if (p->arg_type == ARG_N_TOKENS)
487     {
488       macro_tokens_add (arg, mt);
489       if (arg->n >= p->n_tokens)
490         return me_next_arg (me);
491       return 0;
492     }
493   else if (p->arg_type == ARG_CMDEND)
494     {
495       if (token->type == T_ENDCMD || token->type == T_STOP)
496         return me_next_arg (me);
497       macro_tokens_add (arg, mt);
498       return 0;
499     }
500   else
501     {
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);
507       return 0;
508     }
509 }
510
511 static int
512 me_expected (struct macro_expander *me, const struct macro_token *actual,
513              const struct token *expected)
514 {
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 "
520              "to macro %s."),
521        (int) actual_s.length, actual_s.string, expected_s,
522        me->param->name, me->macro->name);
523   free (expected_s);
524
525   return me_error (me);
526 }
527
528 static int
529 me_enclose (struct macro_expander *me, const struct macro_token *mt)
530 {
531   const struct token *token = &mt->token;
532   me->n_tokens++;
533
534   if (token_equal (&me->param->enclose[0], token))
535     {
536       me->state = ME_ARG;
537       return 0;
538     }
539
540   return me_expected (me, mt, &me->param->enclose[0]);
541 }
542
543 static const struct macro_param *
544 macro_find_parameter_by_name (const struct macro *m, struct substring name)
545 {
546   if (ss_first (name) == '!')
547     ss_advance (&name, 1);
548
549   for (size_t i = 0; i < m->n_params; i++)
550     {
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))
555         return p;
556     }
557   return NULL;
558 }
559
560 static int
561 me_keyword (struct macro_expander *me, const struct macro_token *mt)
562 {
563   const struct token *token = &mt->token;
564   if (token->type != T_ID)
565     return me_finished (me);
566
567   const struct macro_param *p = macro_find_parameter_by_name (me->macro,
568                                                               token->string);
569   if (p)
570     {
571       size_t arg_index = p - me->macro->params;
572       me->param = p;
573       if (me->args[arg_index])
574         {
575           msg (SE,
576                _("Argument %s multiply specified in call to macro %s."),
577                p->name, me->macro->name);
578           return me_error (me);
579         }
580
581       me->n_tokens++;
582       me->state = ME_EQUALS;
583       return 0;
584     }
585
586   return me_finished (me);
587 }
588
589 static int
590 me_equals (struct macro_expander *me, const struct macro_token *mt)
591 {
592   const struct token *token = &mt->token;
593   me->n_tokens++;
594
595   if (token->type == T_EQUALS)
596     {
597       me->state = ME_ARG;
598       return 0;
599     }
600
601   return me_expected (me, mt, &(struct token) { .type = T_EQUALS });
602 }
603
604 int
605 macro_expander_create (const struct macro_set *macros,
606                        const struct token *token,
607                        struct macro_expander **mep)
608 {
609   *mep = NULL;
610   if (macro_set_is_empty (macros))
611     return -1;
612   if (token->type != T_ID && token->type != T_MACRO_ID)
613     return -1;
614
615   const struct macro *macro = macro_set_find (macros, token->string.string);
616   if (!macro)
617     return -1;
618
619   struct macro_expander *me = xmalloc (sizeof *me);
620   *me = (struct macro_expander) {
621     .macros = macros,
622     .n_tokens = 1,
623     .macro = macro,
624   };
625   *mep = me;
626
627   if (!macro->n_params)
628     return 1;
629   else
630     {
631       me->state = (!macro->params[0].positional ? ME_KEYWORD
632                    : macro->params[0].arg_type == ARG_ENCLOSE ? ME_ENCLOSE
633                    : ME_ARG);
634       me->args = xcalloc (macro->n_params, sizeof *me->args);
635       me->param = macro->params;
636       return 0;
637     }
638 }
639
640 void
641 macro_expander_destroy (struct macro_expander *me)
642 {
643   if (!me)
644     return;
645
646   for (size_t i = 0; i < me->macro->n_params; i++)
647     if (me->args[i])
648       {
649         macro_tokens_uninit (me->args[i]);
650         free (me->args[i]);
651       }
652   free (me->args);
653   free (me);
654 }
655
656 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
657    macro expanded.
658
659    Returns -1 if the tokens added do not actually invoke a macro.  The caller
660    should consume the first token without expanding it.
661
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.
665
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. */
671 int
672 macro_expander_add (struct macro_expander *me, const struct macro_token *mt)
673 {
674   switch (me->state)
675     {
676     case ME_ERROR:
677       return -1;
678
679     case ME_ARG:
680       return me_add_arg (me, mt);
681
682     case ME_ENCLOSE:
683       return me_enclose (me, mt);
684
685     case ME_KEYWORD:
686       return me_keyword (me, mt);
687
688     case ME_EQUALS:
689       return me_equals (me, mt);
690
691     default:
692       NOT_REACHED ();
693     }
694 }
695
696 /* Each argument to a macro function is one of:
697
698        - A quoted string or other single literal token.
699
700        - An argument to the macro being expanded, e.g. !1 or a named argument.
701
702        - !*.
703
704        - A function invocation.
705
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.
709 */
710 struct parse_macro_function_ctx
711   {
712     const struct macro_token *input;
713     size_t n_input;
714     int nesting_countdown;
715     const struct macro_set *macros;
716     const struct macro_expander *me;
717     struct string_map *vars;
718     bool *expand;
719   };
720
721 static void
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);
726
727 static bool
728 expand_macro_function (struct parse_macro_function_ctx *ctx,
729                        struct string *output, size_t *input_consumed);
730
731 /* Returns true if the pair of tokens starting at offset OFS within MTS are !*,
732    false otherwise. */
733 static bool
734 is_bang_star (const struct macro_token *mts, size_t n, size_t ofs)
735 {
736   return (ofs + 1 < n
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);
740 }
741
742 static size_t
743 parse_function_arg (struct parse_macro_function_ctx *ctx,
744                     size_t i, struct string *farg)
745 {
746   const struct macro_token *tokens = ctx->input;
747   const struct token *token = &tokens[i].token;
748   if (token->type == T_MACRO_ID)
749     {
750       const struct macro_param *param = macro_find_parameter_by_name (
751         ctx->me->macro, token->string);
752       if (param)
753         {
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++)
757             {
758               if (i)
759                 ds_put_byte (farg, ' ');
760               ds_put_substring (farg, marg->mts[i].representation);
761             }
762           return 1;
763         }
764
765       if (is_bang_star (ctx->input, ctx->n_input, i))
766         {
767           for (size_t i = 0; i < ctx->me->macro->n_params; i++)
768             {
769               if (!ctx->me->macro->params[i].positional)
770                 break;
771
772               const struct macro_tokens *marg = ctx->me->args[i];
773               for (size_t j = 0; j < marg->n; j++)
774                 {
775                   if (i || j)
776                     ds_put_byte (farg, ' ');
777                   ds_put_substring (farg, marg->mts[j].representation);
778                 }
779             }
780           return 2;
781         }
782
783       if (ctx->vars)
784         {
785           const char *value = string_map_find__ (ctx->vars,
786                                                  token->string.string,
787                                                  token->string.length);
788           if (value)
789             {
790               ds_put_cstr (farg, value);
791               return 1;
792             }
793         }
794
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,
800         .me = ctx->me,
801         .vars = ctx->vars,
802         .expand = ctx->expand,
803       };
804       size_t subinput_consumed;
805       if (expand_macro_function (&subctx, farg, &subinput_consumed))
806         return subinput_consumed;
807     }
808
809   ds_put_substring (farg, tokens[i].representation);
810   return 1;
811 }
812
813 static bool
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)
819 {
820   const struct macro_token *tokens = ctx->input;
821   size_t n_tokens = ctx->n_input;
822
823   if (!n_tokens
824       || tokens[0].token.type != T_MACRO_ID
825       || !ss_equals_case (tokens[0].token.string, function)) /* XXX abbrevs allowed */
826     return false;
827
828   if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
829     {
830       printf ("`(' expected following %s'\n", function.string);
831       return false;
832     }
833
834   string_array_init (args);
835
836   for (size_t i = 2;; )
837     {
838       if (i >= n_tokens)
839         goto unexpected_end;
840       if (tokens[i].token.type == T_RPAREN)
841         {
842           *input_consumed = i + 1;
843           if (args->n < min_args || args->n > max_args)
844             {
845               printf ("Wrong number of arguments to %s.\n", function.string);
846               goto error;
847             }
848           return true;
849         }
850
851       struct string s = DS_EMPTY_INITIALIZER;
852       i += parse_function_arg (ctx, i, &s);
853       if (i >= n_tokens)
854         {
855           ds_destroy (&s);
856           goto unexpected_end;
857         }
858       string_array_append_nocopy (args, ds_steal_cstr (&s));
859
860       if (tokens[i].token.type == T_COMMA)
861         i++;
862       else if (tokens[i].token.type != T_RPAREN)
863         {
864           printf ("Expecting `,' or `)' in %s invocation.", function.string);
865           goto error;
866         }
867     }
868
869 unexpected_end:
870   printf ("Missing closing parenthesis in arguments to %s.\n",
871           function.string);
872   /* Fall through. */
873 error:
874   string_array_destroy (args);
875   return false;
876 }
877
878 static bool
879 unquote_string (const char *s, struct string *content)
880 {
881   struct string_lexer slex;
882   string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */);
883
884   struct token token1;
885   if (!string_lexer_next (&slex, &token1))
886     return false;
887
888   if (token1.type != T_STRING)
889     {
890       token_uninit (&token1);
891       return false;
892     }
893
894   struct token token2;
895   if (string_lexer_next (&slex, &token2))
896     {
897       token_uninit (&token1);
898       token_uninit (&token2);
899       return false;
900     }
901
902   ds_put_substring (content, token1.string);
903   token_uninit (&token1);
904   return true;
905 }
906
907 static const char *
908 unquote_string_in_place (const char *s, struct string *tmp)
909 {
910   ds_init_empty (tmp);
911   return unquote_string (s, tmp) ? ds_cstr (tmp) : s;
912 }
913
914 static bool
915 parse_integer (const char *s, int *np)
916 {
917   errno = 0;
918
919   char *tail;
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;
924 }
925
926 static bool
927 expand_macro_function (struct parse_macro_function_ctx *ctx,
928                        struct string *output,
929                        size_t *input_consumed)
930 {
931   struct string_array args;
932
933   if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1,
934                             input_consumed))
935     ds_put_format (output, "%zu", strlen (args.strings[0]));
936   else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
937                                  input_consumed))
938     {
939       int n;
940       if (!parse_integer (args.strings[0], &n))
941         {
942           printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]);
943           string_array_destroy (&args);
944           return false;
945         }
946
947       ds_put_byte_multiple (output, ' ', n);
948     }
949   else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
950                                  input_consumed))
951     {
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]);
955     }
956   else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
957                                  input_consumed))
958     {
959       struct string tmp;
960       const char *s = unquote_string_in_place (args.strings[0], &tmp);
961
962       struct macro_tokens mts = { .n = 0 };
963       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
964       if (mts.n > 0)
965         ds_put_substring (output, mts.mts[0].representation);
966       macro_tokens_uninit (&mts);
967       ds_destroy (&tmp);
968     }
969   else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
970                                  input_consumed))
971     {
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);
975     }
976   else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
977                                  input_consumed))
978     {
979       if (unquote_string (args.strings[0], NULL))
980         ds_put_cstr (output, args.strings[0]);
981       else
982         {
983           ds_extend (output, strlen (args.strings[0]) + 2);
984           ds_put_byte (output, '\'');
985           for (const char *p = args.strings[0]; *p; p++)
986             {
987               if (*p == '\'')
988                 ds_put_byte (output, '\'');
989               ds_put_byte (output, *p);
990             }
991           ds_put_byte (output, '\'');
992         }
993     }
994   else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3,
995                                  input_consumed))
996     {
997       int start;
998       if (!parse_integer (args.strings[1], &start) || start < 1)
999         {
1000           printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]);
1001           string_array_destroy (&args);
1002           return false;
1003         }
1004
1005       int count = INT_MAX;
1006       if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
1007         {
1008           printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]);
1009           string_array_destroy (&args);
1010           return false;
1011         }
1012
1013       struct substring s = ss_cstr (args.strings[0]);
1014       ds_put_substring (output, ss_substr (s, start - 1, count));
1015     }
1016   else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1,
1017                                  input_consumed))
1018     {
1019       struct string tmp;
1020       const char *s = unquote_string_in_place (args.strings[0], &tmp);
1021
1022       struct macro_tokens mts = { .n = 0 };
1023       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
1024       if (mts.n > 1)
1025         {
1026           struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
1027           macro_tokens_to_representation (&tail, output);
1028         }
1029       macro_tokens_uninit (&mts);
1030       ds_destroy (&tmp);
1031     }
1032   else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
1033                                  input_consumed))
1034     {
1035       if (!unquote_string (args.strings[0], output))
1036         ds_put_cstr (output, args.strings[0]);
1037     }
1038   else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
1039                                  input_consumed))
1040     {
1041       struct string tmp;
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);
1045       free (upper);
1046       ds_destroy (&tmp);
1047     }
1048   else if (parse_macro_function (ctx, &args, ss_cstr ("!eval"), 1, 1,
1049                                  input_consumed))
1050     {
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);
1060     }
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")))
1064     {
1065       *input_consumed = 1;
1066       return true;
1067     }
1068   else
1069     return false;
1070
1071   string_array_destroy (&args);
1072   return true;
1073 }
1074
1075 struct expr_context
1076   {
1077     int nesting_countdown;
1078     const struct macro_set *macros;
1079     const struct macro_expander *me;
1080     struct string_map *vars;
1081     bool *expand;
1082   };
1083
1084 static char *macro_evaluate_or (const struct expr_context *ctx,
1085                                 const struct macro_token **tokens,
1086                                 const struct macro_token *end);
1087
1088 static char *
1089 macro_evaluate_literal (const struct expr_context *ctx,
1090                         const struct macro_token **tokens,
1091                         const struct macro_token *end)
1092 {
1093   const struct macro_token *p = *tokens;
1094   if (p >= end)
1095     return NULL;
1096   if (p->token.type == T_LPAREN)
1097     {
1098       p++;
1099       char *value = macro_evaluate_or (ctx, &p, end);
1100       if (!value)
1101         return NULL;
1102       if (p >= end || p->token.type != T_RPAREN)
1103         {
1104           free (value);
1105           printf ("expecting ')' in macro expression\n");
1106           return NULL;
1107         }
1108       p++;
1109       *tokens = p;
1110       return value;
1111     }
1112
1113   struct parse_macro_function_ctx fctx = {
1114     .input = p,
1115     .n_input = end - p,
1116     .nesting_countdown = ctx->nesting_countdown,
1117     .macros = ctx->macros,
1118     .me = ctx->me,
1119     .vars = ctx->vars,
1120     .expand = ctx->expand,
1121   };
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))
1126     {
1127       ds_swap (&function_output, &unquoted);
1128       ds_destroy (&unquoted);
1129     }
1130   *tokens = p + function_consumed;
1131   return ds_steal_cstr (&function_output);
1132 }
1133
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). */
1137 static bool
1138 is_macro_operator (const struct macro_token *mt)
1139 {
1140   return (mt->representation.length > 0
1141           && !c_isalpha (mt->representation.string[0]));
1142 }
1143
1144 static enum token_type
1145 parse_relational_op (const struct macro_token *mt)
1146 {
1147   switch (mt->token.type)
1148     {
1149     case T_EQUALS:
1150       return T_EQ;
1151
1152     case T_NE:
1153     case T_LT:
1154     case T_GT:
1155     case T_LE:
1156     case T_GE:
1157       return is_macro_operator (mt) ? mt->token.type : T_STOP;
1158
1159     case T_MACRO_ID:
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
1166               : T_STOP);
1167
1168     default:
1169       return T_STOP;
1170     }
1171 }
1172
1173 static char *
1174 macro_evaluate_relational (const struct expr_context *ctx,
1175                            const struct macro_token **tokens,
1176                            const struct macro_token *end)
1177 {
1178   const struct macro_token *p = *tokens;
1179   char *lhs = macro_evaluate_literal (ctx, &p, end);
1180   if (!lhs)
1181     return NULL;
1182
1183   enum token_type op = p >= end ? T_STOP : parse_relational_op (p);
1184   if (op == T_STOP)
1185     {
1186       *tokens = p;
1187       return lhs;
1188     }
1189   p++;
1190
1191   char *rhs = macro_evaluate_literal (ctx, &p, end);
1192   if (!rhs)
1193     {
1194       free (lhs);
1195       return NULL;
1196     }
1197
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);
1203
1204   free (lhs);
1205   free (rhs);
1206
1207   bool b = (op == T_EQUALS || op == T_EQ ? !cmp
1208             : op == T_NE ? 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);
1213
1214   *tokens = p;
1215   return xstrdup (b ? "1" : "0");
1216 }
1217
1218 static char *
1219 macro_evaluate_not (const struct expr_context *ctx,
1220                     const struct macro_token **tokens,
1221                     const struct macro_token *end)
1222 {
1223   const struct macro_token *p = *tokens;
1224
1225   unsigned int negations = 0;
1226   while (p < end
1227          && (ss_equals_case (p->representation, ss_cstr ("!NOT"))
1228              || ss_equals (p->representation, ss_cstr ("~"))))
1229     {
1230       p++;
1231       negations++;
1232     }
1233
1234   char *operand = macro_evaluate_relational (ctx, &p, end);
1235   if (!operand || !negations)
1236     {
1237       *tokens = p;
1238       return operand;
1239     }
1240
1241   bool b = strcmp (operand, "0") ^ (negations & 1);
1242   free (operand);
1243   *tokens = p;
1244   return xstrdup (b ? "1" : "0");
1245 }
1246
1247 static char *
1248 macro_evaluate_and (const struct expr_context *ctx,
1249                     const struct macro_token **tokens,
1250                     const struct macro_token *end)
1251 {
1252   const struct macro_token *p = *tokens;
1253   char *lhs = macro_evaluate_not (ctx, &p, end);
1254   if (!lhs)
1255     return NULL;
1256
1257   while (p < end
1258          && (ss_equals_case (p->representation, ss_cstr ("!AND"))
1259              || ss_equals (p->representation, ss_cstr ("&"))))
1260     {
1261       p++;
1262       char *rhs = macro_evaluate_not (ctx, &p, end);
1263       if (!rhs)
1264         {
1265           free (lhs);
1266           return NULL;
1267         }
1268
1269       bool b = strcmp (lhs, "0") && strcmp (rhs, "0");
1270       free (lhs);
1271       free (rhs);
1272       lhs = xstrdup (b ? "1" : "0");
1273     }
1274   *tokens = p;
1275   return lhs;
1276 }
1277
1278 static char *
1279 macro_evaluate_or (const struct expr_context *ctx,
1280                    const struct macro_token **tokens,
1281                    const struct macro_token *end)
1282 {
1283   const struct macro_token *p = *tokens;
1284   char *lhs = macro_evaluate_and (ctx, &p, end);
1285   if (!lhs)
1286     return NULL;
1287
1288   while (p < end
1289          && (ss_equals_case (p->representation, ss_cstr ("!OR"))
1290              || ss_equals (p->representation, ss_cstr ("|"))))
1291     {
1292       p++;
1293       char *rhs = macro_evaluate_and (ctx, &p, end);
1294       if (!rhs)
1295         {
1296           free (lhs);
1297           return NULL;
1298         }
1299
1300       bool b = strcmp (lhs, "0") || strcmp (rhs, "0");
1301       free (lhs);
1302       free (rhs);
1303       lhs = xstrdup (b ? "1" : "0");
1304     }
1305   *tokens = p;
1306   return lhs;
1307 }
1308
1309 static char *
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,
1313                            bool *expand)
1314 {
1315   const struct expr_context ctx = {
1316     .nesting_countdown = nesting_countdown,
1317     .macros = macros,
1318     .me = me,
1319     .vars = vars,
1320     .expand = expand,
1321   };
1322   return macro_evaluate_or (&ctx, tokens, *tokens + n_tokens);
1323 }
1324
1325 static bool
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)
1330 {
1331   char *s = macro_evaluate_expression (tokens, n_tokens, nesting_countdown,
1332                                        macros, me, vars, expand);
1333   if (!s)
1334     return false;
1335
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))
1339     {
1340       macro_tokens_print (&mts, stdout);
1341       printf ("expression must evaluate to a number (not %s)\n", s);
1342       free (s);
1343       macro_tokens_uninit (&mts);
1344       return false;
1345     }
1346
1347   *number = token_number (&mts.mts[0].token);
1348   free (s);
1349   macro_tokens_uninit (&mts);
1350   return true;
1351 }
1352
1353 static const struct macro_token *
1354 find_ifend_clause (const struct macro_token *p, const struct macro_token *end)
1355 {
1356   size_t nesting = 0;
1357   for (; p < end; p++)
1358     {
1359       if (p->token.type != T_MACRO_ID)
1360         continue;
1361
1362       if (ss_equals_case (p->token.string, ss_cstr ("!IF")))
1363         nesting++;
1364       else if (ss_equals_case (p->token.string, ss_cstr ("!IFEND")))
1365         {
1366           if (!nesting)
1367             return p;
1368           nesting--;
1369         }
1370       else if (ss_equals_case (p->token.string, ss_cstr ("!ELSE")) && !nesting)
1371         return p;
1372     }
1373   return NULL;
1374 }
1375
1376 static size_t
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)
1381 {
1382   const struct macro_token *p = tokens;
1383   const struct macro_token *end = tokens + n_tokens;
1384
1385   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!IF")))
1386     return 0;
1387
1388   p++;
1389   char *result = macro_evaluate_expression (&p, end - p,
1390                                             nesting_countdown, macros, me, vars,
1391                                             expand);
1392   if (!result)
1393     return 0;
1394   bool b = strcmp (result, "0");
1395   free (result);
1396
1397   if (p >= end
1398       || p->token.type != T_MACRO_ID
1399       || !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
1400     {
1401       printf ("!THEN expected\n");
1402       return 0;
1403     }
1404
1405   const struct macro_token *start_then = p + 1;
1406   const struct macro_token *end_then = find_ifend_clause (start_then, end);
1407   if (!end_then)
1408     {
1409       printf ("!ELSE or !IFEND expected\n");
1410       return 0;
1411     }
1412
1413   const struct macro_token *start_else, *end_if;
1414   if (ss_equals_case (end_then->token.string, ss_cstr ("!ELSE")))
1415     {
1416       start_else = end_then + 1;
1417       end_if = find_ifend_clause (start_else, end);
1418       if (!end_if
1419           || !ss_equals_case (end_if->token.string, ss_cstr ("!IFEND")))
1420         {
1421           printf ("!IFEND expected\n");
1422           return 0;
1423         }
1424     }
1425   else
1426     {
1427       start_else = NULL;
1428       end_if = end_then;
1429     }
1430
1431   const struct macro_token *start;
1432   size_t n;
1433   if (b)
1434     {
1435       start = start_then;
1436       n = end_then - start_then;
1437     }
1438   else if (start_else)
1439     {
1440       start = start_else;
1441       n = end_if - start_else;
1442     }
1443   else
1444     {
1445       start = NULL;
1446       n = 0;
1447     }
1448
1449   if (n)
1450     {
1451       struct macro_tokens mts = {
1452         .mts = CONST_CAST (struct macro_token *, start),
1453         .n = n,
1454       };
1455       macro_expand (&mts, nesting_countdown, macros, me, vars, expand, exp);
1456     }
1457   return (end_if + 1) - tokens;
1458 }
1459
1460 static size_t
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,
1464                  bool *expand)
1465 {
1466   const struct macro_token *p = tokens;
1467   const struct macro_token *end = tokens + n_tokens;
1468
1469   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!LET")))
1470     return 0;
1471   p++;
1472
1473   if (p >= end || p->token.type != T_MACRO_ID)
1474     {
1475       printf ("expected macro variable name following !LET\n");
1476       return 0;
1477     }
1478   const struct substring var_name = p->token.string;
1479   p++;
1480
1481   if (p >= end || p->token.type != T_EQUALS)
1482     {
1483       printf ("expected = following !LET\n");
1484       return 0;
1485     }
1486   p++;
1487
1488   char *value = macro_evaluate_expression (&p, end - p,
1489                                            nesting_countdown, macros, me, vars,
1490                                            expand);
1491   if (!value)
1492     return 0;
1493
1494   string_map_replace_nocopy (vars, ss_xstrdup (var_name), value);
1495   return p - tokens;
1496 }
1497
1498 static const struct macro_token *
1499 find_doend (const struct macro_token *p, const struct macro_token *end)
1500 {
1501   size_t nesting = 0;
1502   for (; p < end; p++)
1503     {
1504       if (p->token.type != T_MACRO_ID)
1505         continue;
1506
1507       if (ss_equals_case (p->token.string, ss_cstr ("!DO")))
1508         nesting++;
1509       else if (ss_equals_case (p->token.string, ss_cstr ("!DOEND")))
1510         {
1511           if (!nesting)
1512             return p;
1513           nesting--;
1514         }
1515     }
1516   printf ("missing !DOEND\n");
1517   return NULL;
1518 }
1519
1520 static size_t
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)
1525 {
1526   const struct macro_token *p = tokens;
1527   const struct macro_token *end = tokens + n_tokens;
1528
1529   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!DO")))
1530     return 0;
1531   p++;
1532
1533   if (p >= end || p->token.type != T_MACRO_ID)
1534     {
1535       printf ("expected macro variable name following !DO\n");
1536       return 0;
1537     }
1538   const struct substring var_name = p->token.string;
1539   p++;
1540
1541   if (p < end && p->token.type == T_MACRO_ID
1542       && ss_equals_case (p->token.string, ss_cstr ("!IN")))
1543     {
1544       p++;
1545       char *list = macro_evaluate_expression (&p, end - p,
1546                                               nesting_countdown, macros, me, vars,
1547                                               expand);
1548       if (!list)
1549         return 0;
1550
1551       struct macro_tokens items = { .n = 0 };
1552       macro_tokens_from_string (&items, ss_cstr (list),
1553                                 SEG_MODE_INTERACTIVE /* XXX */);
1554       free (list);
1555
1556       const struct macro_token *do_end = find_doend (p, end);
1557       if (!do_end)
1558         {
1559           macro_tokens_uninit (&items);
1560           return 0;
1561         }
1562
1563       const struct macro_tokens inner = {
1564         .mts = CONST_CAST (struct macro_token *, p),
1565         .n = do_end - p
1566       };
1567       for (size_t i = 0; i < items.n; i++)
1568         {
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);
1573         }
1574       return do_end - tokens + 1;
1575     }
1576   else if (p < end && p->token.type == T_EQUALS)
1577     {
1578       p++;
1579       double first;
1580       if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1581                                   vars, expand, &first))
1582         return 0;
1583
1584       if (p >= end || p->token.type != T_MACRO_ID
1585           || !ss_equals_case (p->token.string, ss_cstr ("!TO")))
1586         {
1587           printf ("expecting !TO\n");
1588           return 0;
1589         }
1590       p++;
1591
1592       double last;
1593       if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1594                                   vars, expand, &last))
1595         return 0;
1596
1597       double by = 1.0;
1598       if (p < end && p->token.type == T_MACRO_ID
1599           && ss_equals_case (p->token.string, ss_cstr ("!BY")))
1600         {
1601           p++;
1602           if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1603                                       vars, expand, &by))
1604             return 0;
1605
1606           if (by == 0.0)
1607             {
1608               printf ("!BY value cannot be zero\n");
1609               return 0;
1610             }
1611         }
1612
1613       const struct macro_token *do_end = find_doend (p, end);
1614       if (!do_end)
1615         return 0;
1616       const struct macro_tokens inner = {
1617         .mts = CONST_CAST (struct macro_token *, p),
1618         .n = do_end - p
1619       };
1620
1621       if ((by > 0 && first <= last) || (by < 0 && first >= last))
1622         for (double index = first;
1623              by > 0 ? (index <= last) : (index >= last);
1624              index += by)
1625           {
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),
1629                                        xstrdup (index_s));
1630             macro_expand (&inner, nesting_countdown, macros,
1631                           me, vars, expand, exp);
1632           }
1633
1634       return do_end - tokens + 1;
1635     }
1636   else
1637     {
1638       printf ("expecting = or !IN in !DO loop\n");
1639       return 0;
1640     }
1641 }
1642
1643 static void
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)
1648 {
1649   if (nesting_countdown <= 0)
1650     {
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]);
1654       return;
1655     }
1656
1657   struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
1658   if (!vars)
1659     vars = &own_vars;
1660   for (size_t i = 0; i < mts->n; i++)
1661     {
1662       const struct macro_token *mt = &mts->mts[i];
1663       const struct token *token = &mt->token;
1664       if (token->type == T_MACRO_ID && me)
1665         {
1666           const struct macro_param *param = macro_find_parameter_by_name (
1667             me->macro, token->string);
1668           if (param)
1669             {
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,
1674                               expand, exp);
1675               else
1676                 for (size_t i = 0; i < arg->n; i++)
1677                   macro_tokens_add (exp, &arg->mts[i]);
1678               continue;
1679             }
1680
1681           if (is_bang_star (mts->mts, mts->n, i))
1682             {
1683               for (size_t j = 0; j < me->macro->n_params; j++)
1684                 {
1685                   const struct macro_param *param = &me->macro->params[j];
1686                   if (!param->positional)
1687                     break;
1688
1689                   const struct macro_tokens *arg = me->args[j];
1690                   if (*expand && param->expand_arg)
1691                     macro_expand (arg, nesting_countdown, macros, NULL, NULL,
1692                                   expand, exp);
1693                   else
1694                     for (size_t k = 0; k < arg->n; k++)
1695                       macro_tokens_add (exp, &arg->mts[k]);
1696                 }
1697               i++;
1698               continue;
1699             }
1700
1701           size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
1702                                       nesting_countdown, macros, me, vars,
1703                                       expand, exp);
1704           if (n > 0)
1705             {
1706               i += n - 1;
1707               continue;
1708             }
1709         }
1710
1711       if (token->type == T_MACRO_ID && vars)
1712         {
1713           const char *value = string_map_find__ (vars, token->string.string,
1714                                                  token->string.length);
1715           if (value)
1716             {
1717               macro_tokens_from_string (exp, ss_cstr (value),
1718                                         SEG_MODE_INTERACTIVE /* XXX */);
1719               continue;
1720             }
1721         }
1722
1723       if (*expand)
1724         {
1725           struct macro_expander *subme;
1726           int retval = macro_expander_create (macros, token, &subme);
1727           for (size_t j = 1; !retval; j++)
1728             {
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);
1732             }
1733           if (retval > 0)
1734             {
1735               i += retval - 1;
1736               macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
1737                             subme, NULL, expand, exp);
1738               macro_expander_destroy (subme);
1739               continue;
1740             }
1741
1742           macro_expander_destroy (subme);
1743         }
1744
1745       if (token->type != T_MACRO_ID)
1746         {
1747           macro_tokens_add (exp, mt);
1748           continue;
1749         }
1750
1751       struct parse_macro_function_ctx ctx = {
1752         .input = &mts->mts[i],
1753         .n_input = mts->n - i,
1754         .nesting_countdown = nesting_countdown,
1755         .macros = macros,
1756         .me = me,
1757         .vars = vars,
1758         .expand = expand,
1759       };
1760       struct string function_output = DS_EMPTY_INITIALIZER;
1761       size_t function_consumed;
1762       if (expand_macro_function (&ctx, &function_output, &function_consumed))
1763         {
1764           i += function_consumed - 1;
1765
1766           macro_tokens_from_string (exp, function_output.ss,
1767                                     SEG_MODE_INTERACTIVE /* XXX */);
1768           ds_destroy (&function_output);
1769
1770           continue;
1771         }
1772
1773       size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
1774                                   nesting_countdown, macros, me, vars,
1775                                   expand);
1776       if (n > 0)
1777         {
1778           i += n - 1;
1779           continue;
1780         }
1781
1782       n = macro_expand_do (&mts->mts[i], mts->n - i,
1783                            nesting_countdown, macros, me, vars,
1784                            expand, exp);
1785       if (n > 0)
1786         {
1787           i += n - 1;
1788           continue;
1789         }
1790
1791       if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
1792         *expand = true;
1793       else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
1794         *expand = false;
1795       else
1796         macro_tokens_add (exp, mt);
1797     }
1798   if (vars == &own_vars)
1799     string_map_destroy (&own_vars);
1800 }
1801
1802 void
1803 macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
1804 {
1805 #if 0
1806   for (size_t i = 0; i < me->macro->n_params; i++)
1807     {
1808       printf ("%s:\n", me->macro->params[i].name);
1809       macro_tokens_print (me->args[i], stdout);
1810     }
1811 #endif
1812
1813   bool expand = true;
1814   macro_expand (&me->macro->body, settings_get_mnest (),
1815                 me->macros, me, NULL, &expand, exp);
1816
1817 #if 0
1818   printf ("expansion:\n");
1819   macro_tokens_print (exp, stdout);
1820 #endif
1821 }
1822