fix string lexer
[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                      true);
884
885   struct token token1;
886   if (!string_lexer_next (&slex, &token1))
887     return false;
888
889   if (token1.type != T_STRING)
890     {
891       token_uninit (&token1);
892       return false;
893     }
894
895   struct token token2;
896   if (string_lexer_next (&slex, &token2))
897     {
898       token_uninit (&token1);
899       token_uninit (&token2);
900       return false;
901     }
902
903   ds_put_substring (content, token1.string);
904   token_uninit (&token1);
905   return true;
906 }
907
908 static const char *
909 unquote_string_in_place (const char *s, struct string *tmp)
910 {
911   ds_init_empty (tmp);
912   return unquote_string (s, tmp) ? ds_cstr (tmp) : s;
913 }
914
915 static bool
916 parse_integer (const char *s, int *np)
917 {
918   errno = 0;
919
920   char *tail;
921   long int n = strtol (s, &tail, 10);
922   *np = n < INT_MIN ? INT_MIN : n > INT_MAX ? INT_MAX : n;
923   tail += strspn (tail, CC_SPACES);
924   return *tail == '\0' && errno != ERANGE && n == *np;
925 }
926
927 static bool
928 expand_macro_function (struct parse_macro_function_ctx *ctx,
929                        struct string *output,
930                        size_t *input_consumed)
931 {
932   struct string_array args;
933
934   if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1,
935                             input_consumed))
936     ds_put_format (output, "%zu", strlen (args.strings[0]));
937   else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
938                                  input_consumed))
939     {
940       int n;
941       if (!parse_integer (args.strings[0], &n))
942         {
943           printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]);
944           string_array_destroy (&args);
945           return false;
946         }
947
948       ds_put_byte_multiple (output, ' ', n);
949     }
950   else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
951                                  input_consumed))
952     {
953       for (size_t i = 0; i < args.n; i++)
954         if (!unquote_string (args.strings[i], output))
955           ds_put_cstr (output, args.strings[i]);
956     }
957   else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
958                                  input_consumed))
959     {
960       struct string tmp;
961       const char *s = unquote_string_in_place (args.strings[0], &tmp);
962
963       struct macro_tokens mts = { .n = 0 };
964       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
965       if (mts.n > 0)
966         ds_put_substring (output, mts.mts[0].representation);
967       macro_tokens_uninit (&mts);
968       ds_destroy (&tmp);
969     }
970   else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
971                                  input_consumed))
972     {
973       const char *haystack = args.strings[0];
974       const char *needle = strstr (haystack, args.strings[1]);
975       ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
976     }
977   else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
978                                  input_consumed))
979     {
980       if (unquote_string (args.strings[0], NULL))
981         ds_put_cstr (output, args.strings[0]);
982       else
983         {
984           ds_extend (output, strlen (args.strings[0]) + 2);
985           ds_put_byte (output, '\'');
986           for (const char *p = args.strings[0]; *p; p++)
987             {
988               if (*p == '\'')
989                 ds_put_byte (output, '\'');
990               ds_put_byte (output, *p);
991             }
992           ds_put_byte (output, '\'');
993         }
994     }
995   else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3,
996                                  input_consumed))
997     {
998       int start;
999       if (!parse_integer (args.strings[1], &start) || start < 1)
1000         {
1001           printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]);
1002           string_array_destroy (&args);
1003           return false;
1004         }
1005
1006       int count = INT_MAX;
1007       if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
1008         {
1009           printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]);
1010           string_array_destroy (&args);
1011           return false;
1012         }
1013
1014       struct substring s = ss_cstr (args.strings[0]);
1015       ds_put_substring (output, ss_substr (s, start - 1, count));
1016     }
1017   else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1,
1018                                  input_consumed))
1019     {
1020       struct string tmp;
1021       const char *s = unquote_string_in_place (args.strings[0], &tmp);
1022
1023       struct macro_tokens mts = { .n = 0 };
1024       macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
1025       if (mts.n > 1)
1026         {
1027           struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
1028           macro_tokens_to_representation (&tail, output);
1029         }
1030       macro_tokens_uninit (&mts);
1031       ds_destroy (&tmp);
1032     }
1033   else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
1034                                  input_consumed))
1035     {
1036       if (!unquote_string (args.strings[0], output))
1037         ds_put_cstr (output, args.strings[0]);
1038     }
1039   else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
1040                                  input_consumed))
1041     {
1042       struct string tmp;
1043       const char *s = unquote_string_in_place (args.strings[0], &tmp);
1044       char *upper = utf8_to_upper (s);
1045       ds_put_cstr (output, upper);
1046       free (upper);
1047       ds_destroy (&tmp);
1048     }
1049   else if (parse_macro_function (ctx, &args, ss_cstr ("!eval"), 1, 1,
1050                                  input_consumed))
1051     {
1052       struct macro_tokens mts = { .n = 0 };
1053       macro_tokens_from_string (&mts, ss_cstr (args.strings[0]),
1054                                 SEG_MODE_INTERACTIVE /* XXX */);
1055       struct macro_tokens exp = { .n = 0 };
1056       macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros, ctx->me,
1057                     ctx->vars, ctx->expand, &exp);
1058       macro_tokens_to_representation (&exp, output);
1059       macro_tokens_uninit (&exp);
1060       macro_tokens_uninit (&mts);
1061     }
1062   else if (ctx->n_input > 0
1063            && ctx->input[0].token.type == T_MACRO_ID
1064            && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null")))
1065     {
1066       *input_consumed = 1;
1067       return true;
1068     }
1069   else
1070     return false;
1071
1072   string_array_destroy (&args);
1073   return true;
1074 }
1075
1076 struct expr_context
1077   {
1078     int nesting_countdown;
1079     const struct macro_set *macros;
1080     const struct macro_expander *me;
1081     struct string_map *vars;
1082     bool *expand;
1083   };
1084
1085 static char *macro_evaluate_or (const struct expr_context *ctx,
1086                                 const struct macro_token **tokens,
1087                                 const struct macro_token *end);
1088
1089 static char *
1090 macro_evaluate_literal (const struct expr_context *ctx,
1091                         const struct macro_token **tokens,
1092                         const struct macro_token *end)
1093 {
1094   const struct macro_token *p = *tokens;
1095   if (p >= end)
1096     return NULL;
1097   if (p->token.type == T_LPAREN)
1098     {
1099       p++;
1100       char *value = macro_evaluate_or (ctx, &p, end);
1101       if (!value)
1102         return NULL;
1103       if (p >= end || p->token.type != T_RPAREN)
1104         {
1105           free (value);
1106           printf ("expecting ')' in macro expression\n");
1107           return NULL;
1108         }
1109       p++;
1110       *tokens = p;
1111       return value;
1112     }
1113
1114   struct parse_macro_function_ctx fctx = {
1115     .input = p,
1116     .n_input = end - p,
1117     .nesting_countdown = ctx->nesting_countdown,
1118     .macros = ctx->macros,
1119     .me = ctx->me,
1120     .vars = ctx->vars,
1121     .expand = ctx->expand,
1122   };
1123   struct string function_output = DS_EMPTY_INITIALIZER;
1124   size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
1125   struct string unquoted = DS_EMPTY_INITIALIZER;
1126   if (unquote_string (ds_cstr (&function_output), &unquoted))
1127     {
1128       ds_swap (&function_output, &unquoted);
1129       ds_destroy (&unquoted);
1130     }
1131   *tokens = p + function_consumed;
1132   return ds_steal_cstr (&function_output);
1133 }
1134
1135 /* Returns true if MT is valid as a macro operator.  Only operators written as
1136    symbols (e.g. <>) are usable in macro expressions, not operator written as
1137    letters (e.g. EQ). */
1138 static bool
1139 is_macro_operator (const struct macro_token *mt)
1140 {
1141   return (mt->representation.length > 0
1142           && !c_isalpha (mt->representation.string[0]));
1143 }
1144
1145 static enum token_type
1146 parse_relational_op (const struct macro_token *mt)
1147 {
1148   switch (mt->token.type)
1149     {
1150     case T_EQUALS:
1151       return T_EQ;
1152
1153     case T_NE:
1154     case T_LT:
1155     case T_GT:
1156     case T_LE:
1157     case T_GE:
1158       return is_macro_operator (mt) ? mt->token.type : T_STOP;
1159
1160     case T_MACRO_ID:
1161       return (ss_equals_case (mt->token.string, ss_cstr ("!EQ")) ? T_EQ
1162               : ss_equals_case (mt->token.string, ss_cstr ("!NE")) ? T_NE
1163               : ss_equals_case (mt->token.string, ss_cstr ("!LT")) ? T_LT
1164               : ss_equals_case (mt->token.string, ss_cstr ("!GT")) ? T_GT
1165               : ss_equals_case (mt->token.string, ss_cstr ("!LE")) ? T_LE
1166               : ss_equals_case (mt->token.string, ss_cstr ("!GE")) ? T_GE
1167               : T_STOP);
1168
1169     default:
1170       return T_STOP;
1171     }
1172 }
1173
1174 static char *
1175 macro_evaluate_relational (const struct expr_context *ctx,
1176                            const struct macro_token **tokens,
1177                            const struct macro_token *end)
1178 {
1179   const struct macro_token *p = *tokens;
1180   char *lhs = macro_evaluate_literal (ctx, &p, end);
1181   if (!lhs)
1182     return NULL;
1183
1184   enum token_type op = p >= end ? T_STOP : parse_relational_op (p);
1185   if (op == T_STOP)
1186     {
1187       *tokens = p;
1188       return lhs;
1189     }
1190   p++;
1191
1192   char *rhs = macro_evaluate_literal (ctx, &p, end);
1193   if (!rhs)
1194     {
1195       free (lhs);
1196       return NULL;
1197     }
1198
1199   struct string lhs_tmp, rhs_tmp;
1200   int cmp = strcmp/*XXX*/ (unquote_string_in_place (lhs, &lhs_tmp),
1201                            unquote_string_in_place (rhs, &rhs_tmp));
1202   ds_destroy (&lhs_tmp);
1203   ds_destroy (&rhs_tmp);
1204
1205   free (lhs);
1206   free (rhs);
1207
1208   bool b = (op == T_EQUALS || op == T_EQ ? !cmp
1209             : op == T_NE ? cmp
1210             : op == T_LT ? cmp < 0
1211             : op == T_GT ? cmp > 0
1212             : op == T_LE ? cmp <= 0
1213             :/*op == T_GE*/cmp >= 0);
1214
1215   *tokens = p;
1216   return xstrdup (b ? "1" : "0");
1217 }
1218
1219 static char *
1220 macro_evaluate_not (const struct expr_context *ctx,
1221                     const struct macro_token **tokens,
1222                     const struct macro_token *end)
1223 {
1224   const struct macro_token *p = *tokens;
1225
1226   unsigned int negations = 0;
1227   while (p < end
1228          && (ss_equals_case (p->representation, ss_cstr ("!NOT"))
1229              || ss_equals (p->representation, ss_cstr ("~"))))
1230     {
1231       p++;
1232       negations++;
1233     }
1234
1235   char *operand = macro_evaluate_relational (ctx, &p, end);
1236   if (!operand || !negations)
1237     {
1238       *tokens = p;
1239       return operand;
1240     }
1241
1242   bool b = strcmp (operand, "0") ^ (negations & 1);
1243   free (operand);
1244   *tokens = p;
1245   return xstrdup (b ? "1" : "0");
1246 }
1247
1248 static char *
1249 macro_evaluate_and (const struct expr_context *ctx,
1250                     const struct macro_token **tokens,
1251                     const struct macro_token *end)
1252 {
1253   const struct macro_token *p = *tokens;
1254   char *lhs = macro_evaluate_not (ctx, &p, end);
1255   if (!lhs)
1256     return NULL;
1257
1258   while (p < end
1259          && (ss_equals_case (p->representation, ss_cstr ("!AND"))
1260              || ss_equals (p->representation, ss_cstr ("&"))))
1261     {
1262       p++;
1263       char *rhs = macro_evaluate_not (ctx, &p, end);
1264       if (!rhs)
1265         {
1266           free (lhs);
1267           return NULL;
1268         }
1269
1270       bool b = strcmp (lhs, "0") && strcmp (rhs, "0");
1271       free (lhs);
1272       free (rhs);
1273       lhs = xstrdup (b ? "1" : "0");
1274     }
1275   *tokens = p;
1276   return lhs;
1277 }
1278
1279 static char *
1280 macro_evaluate_or (const struct expr_context *ctx,
1281                    const struct macro_token **tokens,
1282                    const struct macro_token *end)
1283 {
1284   const struct macro_token *p = *tokens;
1285   char *lhs = macro_evaluate_and (ctx, &p, end);
1286   if (!lhs)
1287     return NULL;
1288
1289   while (p < end
1290          && (ss_equals_case (p->representation, ss_cstr ("!OR"))
1291              || ss_equals (p->representation, ss_cstr ("|"))))
1292     {
1293       p++;
1294       char *rhs = macro_evaluate_and (ctx, &p, end);
1295       if (!rhs)
1296         {
1297           free (lhs);
1298           return NULL;
1299         }
1300
1301       bool b = strcmp (lhs, "0") || strcmp (rhs, "0");
1302       free (lhs);
1303       free (rhs);
1304       lhs = xstrdup (b ? "1" : "0");
1305     }
1306   *tokens = p;
1307   return lhs;
1308 }
1309
1310 static char *
1311 macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
1312                            int nesting_countdown, const struct macro_set *macros,
1313                            const struct macro_expander *me, struct string_map *vars,
1314                            bool *expand)
1315 {
1316   const struct expr_context ctx = {
1317     .nesting_countdown = nesting_countdown,
1318     .macros = macros,
1319     .me = me,
1320     .vars = vars,
1321     .expand = expand,
1322   };
1323   return macro_evaluate_or (&ctx, tokens, *tokens + n_tokens);
1324 }
1325
1326 static bool
1327 macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
1328                        int nesting_countdown, const struct macro_set *macros,
1329                        const struct macro_expander *me, struct string_map *vars,
1330                        bool *expand, double *number)
1331 {
1332   char *s = macro_evaluate_expression (tokens, n_tokens, nesting_countdown,
1333                                        macros, me, vars, expand);
1334   if (!s)
1335     return false;
1336
1337   struct macro_tokens mts = { .n = 0 };
1338   macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */);
1339   if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
1340     {
1341       macro_tokens_print (&mts, stdout);
1342       printf ("expression must evaluate to a number (not %s)\n", s);
1343       free (s);
1344       macro_tokens_uninit (&mts);
1345       return false;
1346     }
1347
1348   *number = token_number (&mts.mts[0].token);
1349   free (s);
1350   macro_tokens_uninit (&mts);
1351   return true;
1352 }
1353
1354 static const struct macro_token *
1355 find_ifend_clause (const struct macro_token *p, const struct macro_token *end)
1356 {
1357   size_t nesting = 0;
1358   for (; p < end; p++)
1359     {
1360       if (p->token.type != T_MACRO_ID)
1361         continue;
1362
1363       if (ss_equals_case (p->token.string, ss_cstr ("!IF")))
1364         nesting++;
1365       else if (ss_equals_case (p->token.string, ss_cstr ("!IFEND")))
1366         {
1367           if (!nesting)
1368             return p;
1369           nesting--;
1370         }
1371       else if (ss_equals_case (p->token.string, ss_cstr ("!ELSE")) && !nesting)
1372         return p;
1373     }
1374   return NULL;
1375 }
1376
1377 static size_t
1378 macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
1379                  int nesting_countdown, const struct macro_set *macros,
1380                  const struct macro_expander *me, struct string_map *vars,
1381                  bool *expand, struct macro_tokens *exp)
1382 {
1383   const struct macro_token *p = tokens;
1384   const struct macro_token *end = tokens + n_tokens;
1385
1386   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!IF")))
1387     return 0;
1388
1389   p++;
1390   char *result = macro_evaluate_expression (&p, end - p,
1391                                             nesting_countdown, macros, me, vars,
1392                                             expand);
1393   if (!result)
1394     return 0;
1395   bool b = strcmp (result, "0");
1396   free (result);
1397
1398   if (p >= end
1399       || p->token.type != T_MACRO_ID
1400       || !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
1401     {
1402       printf ("!THEN expected\n");
1403       return 0;
1404     }
1405
1406   const struct macro_token *start_then = p + 1;
1407   const struct macro_token *end_then = find_ifend_clause (start_then, end);
1408   if (!end_then)
1409     {
1410       printf ("!ELSE or !IFEND expected\n");
1411       return 0;
1412     }
1413
1414   const struct macro_token *start_else, *end_if;
1415   if (ss_equals_case (end_then->token.string, ss_cstr ("!ELSE")))
1416     {
1417       start_else = end_then + 1;
1418       end_if = find_ifend_clause (start_else, end);
1419       if (!end_if
1420           || !ss_equals_case (end_if->token.string, ss_cstr ("!IFEND")))
1421         {
1422           printf ("!IFEND expected\n");
1423           return 0;
1424         }
1425     }
1426   else
1427     {
1428       start_else = NULL;
1429       end_if = end_then;
1430     }
1431
1432   const struct macro_token *start;
1433   size_t n;
1434   if (b)
1435     {
1436       start = start_then;
1437       n = end_then - start_then;
1438     }
1439   else if (start_else)
1440     {
1441       start = start_else;
1442       n = end_if - start_else;
1443     }
1444   else
1445     {
1446       start = NULL;
1447       n = 0;
1448     }
1449
1450   if (n)
1451     {
1452       struct macro_tokens mts = {
1453         .mts = CONST_CAST (struct macro_token *, start),
1454         .n = n,
1455       };
1456       macro_expand (&mts, nesting_countdown, macros, me, vars, expand, exp);
1457     }
1458   return (end_if + 1) - tokens;
1459 }
1460
1461 static size_t
1462 macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
1463                  int nesting_countdown, const struct macro_set *macros,
1464                  const struct macro_expander *me, struct string_map *vars,
1465                  bool *expand)
1466 {
1467   const struct macro_token *p = tokens;
1468   const struct macro_token *end = tokens + n_tokens;
1469
1470   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!LET")))
1471     return 0;
1472   p++;
1473
1474   if (p >= end || p->token.type != T_MACRO_ID)
1475     {
1476       printf ("expected macro variable name following !LET\n");
1477       return 0;
1478     }
1479   const struct substring var_name = p->token.string;
1480   p++;
1481
1482   if (p >= end || p->token.type != T_EQUALS)
1483     {
1484       printf ("expected = following !LET\n");
1485       return 0;
1486     }
1487   p++;
1488
1489   char *value = macro_evaluate_expression (&p, end - p,
1490                                            nesting_countdown, macros, me, vars,
1491                                            expand);
1492   if (!value)
1493     return 0;
1494
1495   string_map_replace_nocopy (vars, ss_xstrdup (var_name), value);
1496   return p - tokens;
1497 }
1498
1499 static const struct macro_token *
1500 find_doend (const struct macro_token *p, const struct macro_token *end)
1501 {
1502   size_t nesting = 0;
1503   for (; p < end; p++)
1504     {
1505       if (p->token.type != T_MACRO_ID)
1506         continue;
1507
1508       if (ss_equals_case (p->token.string, ss_cstr ("!DO")))
1509         nesting++;
1510       else if (ss_equals_case (p->token.string, ss_cstr ("!DOEND")))
1511         {
1512           if (!nesting)
1513             return p;
1514           nesting--;
1515         }
1516     }
1517   printf ("missing !DOEND\n");
1518   return NULL;
1519 }
1520
1521 static size_t
1522 macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
1523                  int nesting_countdown, const struct macro_set *macros,
1524                  const struct macro_expander *me, struct string_map *vars,
1525                  bool *expand, struct macro_tokens *exp)
1526 {
1527   const struct macro_token *p = tokens;
1528   const struct macro_token *end = tokens + n_tokens;
1529
1530   if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!DO")))
1531     return 0;
1532   p++;
1533
1534   if (p >= end || p->token.type != T_MACRO_ID)
1535     {
1536       printf ("expected macro variable name following !DO\n");
1537       return 0;
1538     }
1539   const struct substring var_name = p->token.string;
1540   p++;
1541
1542   if (p < end && p->token.type == T_MACRO_ID
1543       && ss_equals_case (p->token.string, ss_cstr ("!IN")))
1544     {
1545       p++;
1546       char *list = macro_evaluate_expression (&p, end - p,
1547                                               nesting_countdown, macros, me, vars,
1548                                               expand);
1549       if (!list)
1550         return 0;
1551
1552       struct macro_tokens items = { .n = 0 };
1553       macro_tokens_from_string (&items, ss_cstr (list),
1554                                 SEG_MODE_INTERACTIVE /* XXX */);
1555       free (list);
1556
1557       const struct macro_token *do_end = find_doend (p, end);
1558       if (!do_end)
1559         {
1560           macro_tokens_uninit (&items);
1561           return 0;
1562         }
1563
1564       const struct macro_tokens inner = {
1565         .mts = CONST_CAST (struct macro_token *, p),
1566         .n = do_end - p
1567       };
1568       for (size_t i = 0; i < items.n; i++)
1569         {
1570           string_map_replace_nocopy (vars, ss_xstrdup (var_name),
1571                                      ss_xstrdup (items.mts[i].representation));
1572           macro_expand (&inner, nesting_countdown, macros,
1573                         me, vars, expand, exp);
1574         }
1575       return do_end - tokens + 1;
1576     }
1577   else if (p < end && p->token.type == T_EQUALS)
1578     {
1579       p++;
1580       double first;
1581       if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1582                                   vars, expand, &first))
1583         return 0;
1584
1585       if (p >= end || p->token.type != T_MACRO_ID
1586           || !ss_equals_case (p->token.string, ss_cstr ("!TO")))
1587         {
1588           printf ("expecting !TO\n");
1589           return 0;
1590         }
1591       p++;
1592
1593       double last;
1594       if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1595                                   vars, expand, &last))
1596         return 0;
1597
1598       double by = 1.0;
1599       if (p < end && p->token.type == T_MACRO_ID
1600           && ss_equals_case (p->token.string, ss_cstr ("!BY")))
1601         {
1602           p++;
1603           if (!macro_evaluate_number (&p, end - p, nesting_countdown, macros, me,
1604                                       vars, expand, &by))
1605             return 0;
1606
1607           if (by == 0.0)
1608             {
1609               printf ("!BY value cannot be zero\n");
1610               return 0;
1611             }
1612         }
1613
1614       const struct macro_token *do_end = find_doend (p, end);
1615       if (!do_end)
1616         return 0;
1617       const struct macro_tokens inner = {
1618         .mts = CONST_CAST (struct macro_token *, p),
1619         .n = do_end - p
1620       };
1621
1622       if ((by > 0 && first <= last) || (by < 0 && first >= last))
1623         for (double index = first;
1624              by > 0 ? (index <= last) : (index >= last);
1625              index += by)
1626           {
1627             char index_s[DBL_BUFSIZE_BOUND];
1628             c_dtoastr (index_s, sizeof index_s, 0, 0, index);
1629             string_map_replace_nocopy (vars, ss_xstrdup (var_name),
1630                                        xstrdup (index_s));
1631             macro_expand (&inner, nesting_countdown, macros,
1632                           me, vars, expand, exp);
1633           }
1634
1635       return do_end - tokens + 1;
1636     }
1637   else
1638     {
1639       printf ("expecting = or !IN in !DO loop\n");
1640       return 0;
1641     }
1642 }
1643
1644 static void
1645 macro_expand (const struct macro_tokens *mts,
1646               int nesting_countdown, const struct macro_set *macros,
1647               const struct macro_expander *me, struct string_map *vars,
1648               bool *expand, struct macro_tokens *exp)
1649 {
1650   if (nesting_countdown <= 0)
1651     {
1652       printf ("maximum nesting level exceeded\n");
1653       for (size_t i = 0; i < mts->n; i++)
1654         macro_tokens_add (exp, &mts->mts[i]);
1655       return;
1656     }
1657
1658   struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
1659   if (!vars)
1660     vars = &own_vars;
1661   for (size_t i = 0; i < mts->n; i++)
1662     {
1663       const struct macro_token *mt = &mts->mts[i];
1664       const struct token *token = &mt->token;
1665       if (token->type == T_MACRO_ID && me)
1666         {
1667           const struct macro_param *param = macro_find_parameter_by_name (
1668             me->macro, token->string);
1669           if (param)
1670             {
1671               const struct macro_tokens *arg = me->args[param - me->macro->params];
1672               //macro_tokens_print (arg, stdout);
1673               if (*expand && param->expand_arg)
1674                 macro_expand (arg, nesting_countdown, macros, NULL, NULL,
1675                               expand, exp);
1676               else
1677                 for (size_t i = 0; i < arg->n; i++)
1678                   macro_tokens_add (exp, &arg->mts[i]);
1679               continue;
1680             }
1681
1682           if (is_bang_star (mts->mts, mts->n, i))
1683             {
1684               for (size_t j = 0; j < me->macro->n_params; j++)
1685                 {
1686                   const struct macro_param *param = &me->macro->params[j];
1687                   if (!param->positional)
1688                     break;
1689
1690                   const struct macro_tokens *arg = me->args[j];
1691                   if (*expand && param->expand_arg)
1692                     macro_expand (arg, nesting_countdown, macros, NULL, NULL,
1693                                   expand, exp);
1694                   else
1695                     for (size_t k = 0; k < arg->n; k++)
1696                       macro_tokens_add (exp, &arg->mts[k]);
1697                 }
1698               i++;
1699               continue;
1700             }
1701
1702           size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
1703                                       nesting_countdown, macros, me, vars,
1704                                       expand, exp);
1705           if (n > 0)
1706             {
1707               i += n - 1;
1708               continue;
1709             }
1710         }
1711
1712       if (token->type == T_MACRO_ID && vars)
1713         {
1714           const char *value = string_map_find__ (vars, token->string.string,
1715                                                  token->string.length);
1716           if (value)
1717             {
1718               macro_tokens_from_string (exp, ss_cstr (value),
1719                                         SEG_MODE_INTERACTIVE /* XXX */);
1720               continue;
1721             }
1722         }
1723
1724       if (*expand)
1725         {
1726           struct macro_expander *subme;
1727           int retval = macro_expander_create (macros, token, &subme);
1728           for (size_t j = 1; !retval; j++)
1729             {
1730               const struct macro_token endcmd = { .token = { .type = T_ENDCMD } };
1731               retval = macro_expander_add (
1732                 subme, i + j < mts->n ? &mts->mts[i + j] : &endcmd);
1733             }
1734           if (retval > 0)
1735             {
1736               i += retval - 1;
1737               macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
1738                             subme, NULL, expand, exp);
1739               macro_expander_destroy (subme);
1740               continue;
1741             }
1742
1743           macro_expander_destroy (subme);
1744         }
1745
1746       if (token->type != T_MACRO_ID)
1747         {
1748           macro_tokens_add (exp, mt);
1749           continue;
1750         }
1751
1752       struct parse_macro_function_ctx ctx = {
1753         .input = &mts->mts[i],
1754         .n_input = mts->n - i,
1755         .nesting_countdown = nesting_countdown,
1756         .macros = macros,
1757         .me = me,
1758         .vars = vars,
1759         .expand = expand,
1760       };
1761       struct string function_output = DS_EMPTY_INITIALIZER;
1762       size_t function_consumed;
1763       if (expand_macro_function (&ctx, &function_output, &function_consumed))
1764         {
1765           i += function_consumed - 1;
1766
1767           macro_tokens_from_string (exp, function_output.ss,
1768                                     SEG_MODE_INTERACTIVE /* XXX */);
1769           ds_destroy (&function_output);
1770
1771           continue;
1772         }
1773
1774       size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
1775                                   nesting_countdown, macros, me, vars,
1776                                   expand);
1777       if (n > 0)
1778         {
1779           i += n - 1;
1780           continue;
1781         }
1782
1783       n = macro_expand_do (&mts->mts[i], mts->n - i,
1784                            nesting_countdown, macros, me, vars,
1785                            expand, exp);
1786       if (n > 0)
1787         {
1788           i += n - 1;
1789           continue;
1790         }
1791
1792       if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
1793         *expand = true;
1794       else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
1795         *expand = false;
1796       else
1797         macro_tokens_add (exp, mt);
1798     }
1799   if (vars == &own_vars)
1800     string_map_destroy (&own_vars);
1801 }
1802
1803 void
1804 macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
1805 {
1806 #if 0
1807   for (size_t i = 0; i < me->macro->n_params; i++)
1808     {
1809       printf ("%s:\n", me->macro->params[i].name);
1810       macro_tokens_print (me->args[i], stdout);
1811     }
1812 #endif
1813
1814   bool expand = true;
1815   macro_expand (&me->macro->body, settings_get_mnest (),
1816                 me->macros, me, NULL, &expand, exp);
1817
1818 #if 0
1819   printf ("expansion:\n");
1820   macro_tokens_print (exp, stdout);
1821 #endif
1822 }
1823