Move stack into macro_expander.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 4 Jul 2021 22:56:34 +0000 (15:56 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 4 Jul 2021 22:56:34 +0000 (15:56 -0700)
src/language/lexer/macro.c
tests/language/control/define.at

index 3b17d90f38a977220d77492ec83321e4c1c5ec91..c35144dc3a984bb28a3cd798d633a7afa1ab779e 100644 (file)
@@ -874,6 +874,7 @@ struct macro_expander
     bool *expand;
     bool *break_;
     int nesting_countdown;
+    const struct macro_expansion_stack *stack;
   };
 
 /* Each argument to a macro function is one of:
@@ -895,12 +896,10 @@ struct parse_macro_function_ctx
     const struct macro_token *input;
     size_t n_input;
     const struct macro_expander *me;
-    const struct macro_expansion_stack *stack;
   };
 
 static void
 macro_expand (const struct macro_tokens *, const struct macro_expander *,
-              const struct macro_expansion_stack *,
               struct macro_tokens *);
 
 static bool
@@ -972,7 +971,6 @@ parse_function_arg (struct parse_macro_function_ctx *ctx,
         .input = &ctx->input[i],
         .n_input = ctx->n_input - i,
         .me = ctx->me,
-        .stack = ctx->stack,
       };
       size_t subinput_consumed;
       if (expand_macro_function (&subctx, farg, &subinput_consumed))
@@ -1000,7 +998,7 @@ parse_macro_function (struct parse_macro_function_ctx *ctx,
 
   if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
     {
-      macro_error (ctx->stack, n_tokens > 1 ? &tokens[1] : NULL,
+      macro_error (ctx->me->stack, n_tokens > 1 ? &tokens[1] : NULL,
                    _("`(' expected following %s."), function.string);
       return false;
     }
@@ -1016,7 +1014,7 @@ parse_macro_function (struct parse_macro_function_ctx *ctx,
           *input_consumed = i + 1;
           if (args->n < min_args || args->n > max_args)
             {
-              macro_error (ctx->stack, &tokens[i],
+              macro_error (ctx->me->stack, &tokens[i],
                            _("Wrong number of arguments to macro function %s."),
                            function.string);
               goto error;
@@ -1037,7 +1035,7 @@ parse_macro_function (struct parse_macro_function_ctx *ctx,
         i++;
       else if (tokens[i].token.type != T_RPAREN)
         {
-          macro_error (ctx->stack, &tokens[i],
+          macro_error (ctx->me->stack, &tokens[i],
                        _("`,' or `)' expected in call to macro function %s."),
                        function.string);
           goto error;
@@ -1045,7 +1043,7 @@ parse_macro_function (struct parse_macro_function_ctx *ctx,
     }
 
 unexpected_end:
-  macro_error (ctx->stack, NULL, _("Missing `)' in call to macro function %s."),
+  macro_error (ctx->me->stack, NULL, _("Missing `)' in call to macro function %s."),
                function.string);
   /* Fall through. */
 error:
@@ -1119,7 +1117,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
       int n;
       if (!parse_integer (args.strings[0], &n))
         {
-          macro_error (ctx->stack, NULL,
+          macro_error (ctx->me->stack, NULL,
                        _("Argument to !BLANKS must be non-negative integer "
                          "(not \"%s\")."), args.strings[0]);
           string_array_destroy (&args);
@@ -1144,7 +1142,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
 
       struct macro_tokens mts = { .n = 0 };
       macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
-                                  ctx->stack);
+                                  ctx->me->stack);
       if (mts.n > 0)
         ds_put_substring (output, mts.mts[0].representation);
       macro_tokens_uninit (&mts);
@@ -1181,7 +1179,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
       int start;
       if (!parse_integer (args.strings[1], &start) || start < 1)
         {
-          macro_error (ctx->stack, NULL,
+          macro_error (ctx->me->stack, NULL,
                        _("Second argument of !SUBSTR must be "
                          "positive integer (not \"%s\")."),
                        args.strings[1]);
@@ -1192,7 +1190,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
       int count = INT_MAX;
       if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
         {
-          macro_error (ctx->stack, NULL,
+          macro_error (ctx->me->stack, NULL,
                        _("Third argument of !SUBSTR must be "
                          "non-negative integer (not \"%s\")."),
                        args.strings[2]);
@@ -1212,7 +1210,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
 
       struct macro_tokens mts = { .n = 0 };
       macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
-                                  ctx->stack);
+                                  ctx->me->stack);
       if (mts.n > 1)
         {
           struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
@@ -1243,15 +1241,17 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
     {
       struct macro_tokens mts = { .n = 0 };
       macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
-                                  ctx->me->segmenter_mode, ctx->stack);
+                                  ctx->me->segmenter_mode, ctx->me->stack);
       struct macro_tokens exp = { .n = 0 };
+      struct macro_expansion_stack stack = {
+        .name = "!EVAL",
+        .next = ctx->me->stack
+      };
       struct macro_expander subme = *ctx->me;
       subme.break_ = NULL;
-      macro_expand (&mts, &subme,
-                    &(struct macro_expansion_stack) {
-                      .name = "!EVAL",
-                      .next = ctx->stack,
-                    }, &exp);
+      subme.stack = &stack;
+      
+      macro_expand (&mts, &subme, &exp);
       macro_tokens_to_representation (&exp, output, NULL, NULL);
       macro_tokens_uninit (&exp);
       macro_tokens_uninit (&mts);
@@ -1271,13 +1271,11 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
 }
 
 static char *macro_evaluate_or (const struct macro_expander *me,
-                                const struct macro_expansion_stack *stack,
                                 const struct macro_token **tokens,
                                 const struct macro_token *end);
 
 static char *
 macro_evaluate_literal (const struct macro_expander *me,
-                        const struct macro_expansion_stack *stack,
                         const struct macro_token **tokens,
                         const struct macro_token *end)
 {
@@ -1287,13 +1285,13 @@ macro_evaluate_literal (const struct macro_expander *me,
   if (p->token.type == T_LPAREN)
     {
       p++;
-      char *value = macro_evaluate_or (me, stack, &p, end);
+      char *value = macro_evaluate_or (me, &p, end);
       if (!value)
         return NULL;
       if (p >= end || p->token.type != T_RPAREN)
         {
           free (value);
-          macro_error (stack, p < end ? p : NULL,
+          macro_error (me->stack, p < end ? p : NULL,
                        _("Expecting ')' in macro expression."));
           return NULL;
         }
@@ -1303,8 +1301,8 @@ macro_evaluate_literal (const struct macro_expander *me,
     }
   else if (p->token.type == T_RPAREN)
     {
-      macro_error (stack, p, _("Expecting literal or function invocation "
-                               "in macro expression."));
+      macro_error (me->stack, p, _("Expecting literal or function invocation "
+                                   "in macro expression."));
       return NULL;
     }
 
@@ -1312,7 +1310,6 @@ macro_evaluate_literal (const struct macro_expander *me,
     .input = p,
     .n_input = end - p,
     .me = me,
-    .stack = stack,
   };
   struct string function_output = DS_EMPTY_INITIALIZER;
   size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
@@ -1368,12 +1365,11 @@ parse_relational_op (const struct macro_token *mt)
 
 static char *
 macro_evaluate_relational (const struct macro_expander *me,
-                           const struct macro_expansion_stack *stack,
                            const struct macro_token **tokens,
                            const struct macro_token *end)
 {
   const struct macro_token *p = *tokens;
-  char *lhs = macro_evaluate_literal (me, stack, &p, end);
+  char *lhs = macro_evaluate_literal (me, &p, end);
   if (!lhs)
     return NULL;
 
@@ -1385,7 +1381,7 @@ macro_evaluate_relational (const struct macro_expander *me,
     }
   p++;
 
-  char *rhs = macro_evaluate_literal (me, stack, &p, end);
+  char *rhs = macro_evaluate_literal (me, &p, end);
   if (!rhs)
     {
       free (lhs);
@@ -1416,7 +1412,6 @@ macro_evaluate_relational (const struct macro_expander *me,
 
 static char *
 macro_evaluate_not (const struct macro_expander *me,
-                    const struct macro_expansion_stack *stack,
                     const struct macro_token **tokens,
                     const struct macro_token *end)
 {
@@ -1431,7 +1426,7 @@ macro_evaluate_not (const struct macro_expander *me,
       negations++;
     }
 
-  char *operand = macro_evaluate_relational (me, stack, &p, end);
+  char *operand = macro_evaluate_relational (me, &p, end);
   if (!operand || !negations)
     {
       *tokens = p;
@@ -1446,12 +1441,11 @@ macro_evaluate_not (const struct macro_expander *me,
 
 static char *
 macro_evaluate_and (const struct macro_expander *me,
-                    const struct macro_expansion_stack *stack,
                     const struct macro_token **tokens,
                     const struct macro_token *end)
 {
   const struct macro_token *p = *tokens;
-  char *lhs = macro_evaluate_not (me, stack, &p, end);
+  char *lhs = macro_evaluate_not (me, &p, end);
   if (!lhs)
     return NULL;
 
@@ -1460,7 +1454,7 @@ macro_evaluate_and (const struct macro_expander *me,
              || ss_equals (p->representation, ss_cstr ("&"))))
     {
       p++;
-      char *rhs = macro_evaluate_not (me, stack, &p, end);
+      char *rhs = macro_evaluate_not (me, &p, end);
       if (!rhs)
         {
           free (lhs);
@@ -1478,12 +1472,11 @@ macro_evaluate_and (const struct macro_expander *me,
 
 static char *
 macro_evaluate_or (const struct macro_expander *me,
-                   const struct macro_expansion_stack *stack,
                    const struct macro_token **tokens,
                    const struct macro_token *end)
 {
   const struct macro_token *p = *tokens;
-  char *lhs = macro_evaluate_and (me, stack, &p, end);
+  char *lhs = macro_evaluate_and (me, &p, end);
   if (!lhs)
     return NULL;
 
@@ -1492,7 +1485,7 @@ macro_evaluate_or (const struct macro_expander *me,
              || ss_equals (p->representation, ss_cstr ("|"))))
     {
       p++;
-      char *rhs = macro_evaluate_and (me, stack, &p, end);
+      char *rhs = macro_evaluate_and (me, &p, end);
       if (!rhs)
         {
           free (lhs);
@@ -1510,27 +1503,25 @@ macro_evaluate_or (const struct macro_expander *me,
 
 static char *
 macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
-                           const struct macro_expander *me,
-                           const struct macro_expansion_stack *stack)
+                           const struct macro_expander *me)
 {
-  return macro_evaluate_or (me, stack, tokens, *tokens + n_tokens);
+  return macro_evaluate_or (me, tokens, *tokens + n_tokens);
 }
 
 static bool
 macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
                        const struct macro_expander *me,
-                       const struct macro_expansion_stack *stack,
                        double *number)
 {
-  char *s = macro_evaluate_expression (tokens, n_tokens, me, stack);
+  char *s = macro_evaluate_expression (tokens, n_tokens, me);
   if (!s)
     return false;
 
   struct macro_tokens mts = { .n = 0 };
-  macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, stack);
+  macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, me->stack);
   if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
     {
-      macro_error (stack, mts.n > 0 ? &mts.mts[0] : NULL,
+      macro_error (me->stack, mts.n > 0 ? &mts.mts[0] : NULL,
                    _("Macro expression must evaluate to "
                      "a number (not \"%s\")."), s);
       free (s);
@@ -1570,7 +1561,6 @@ find_ifend_clause (const struct macro_token *p, const struct macro_token *end)
 static size_t
 macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
                  const struct macro_expander *me,
-                 const struct macro_expansion_stack *stack,
                  struct macro_tokens *exp)
 {
   const struct macro_token *p = tokens;
@@ -1580,7 +1570,7 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
     return 0;
 
   p++;
-  char *result = macro_evaluate_expression (&p, end - p, me, stack);
+  char *result = macro_evaluate_expression (&p, end - p, me);
   if (!result)
     return 0;
   bool b = strcmp (result, "0");
@@ -1590,7 +1580,7 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
       || p->token.type != T_MACRO_ID
       || !ss_equals_case (p->token.string, ss_cstr ("!THEN")))
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("!THEN expected in macro !IF construct."));
       return 0;
     }
@@ -1599,7 +1589,7 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
   const struct macro_token *end_then = find_ifend_clause (start_then, end);
   if (!end_then)
     {
-      macro_error (stack, NULL,
+      macro_error (me->stack, NULL,
                    _("!ELSE or !IFEND expected in macro !IF construct."));
       return 0;
     }
@@ -1612,7 +1602,7 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
       if (!end_if
           || !ss_equals_case (end_if->token.string, ss_cstr ("!IFEND")))
         {
-          macro_error (stack, end_if ? end_if : NULL,
+          macro_error (me->stack, end_if ? end_if : NULL,
                        _("!IFEND expected in macro !IF construct."));
           return 0;
         }
@@ -1647,19 +1637,20 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
         .mts = CONST_CAST (struct macro_token *, start),
         .n = n,
       };
-      macro_expand (&mts, me, &(struct macro_expansion_stack) {
-                      .name = "!IF",
-                      .next = stack,
-                    },
-                    exp);
+      struct macro_expansion_stack stack = {
+        .name = "!IF",
+        .next = me->stack,
+      };
+      struct macro_expander subme = *me;
+      subme.stack = &stack;
+      macro_expand (&mts, &subme, exp);
     }
   return (end_if + 1) - tokens;
 }
 
 static size_t
 macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
-                 const struct macro_expander *me,
-                 const struct macro_expansion_stack *stack)
+                 const struct macro_expander *me)
 {
   const struct macro_token *p = tokens;
   const struct macro_token *end = tokens + n_tokens;
@@ -1670,7 +1661,7 @@ macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
 
   if (p >= end || p->token.type != T_MACRO_ID)
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("Expected macro variable name following !LET."));
       return 0;
     }
@@ -1678,7 +1669,7 @@ macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
   if (is_macro_keyword (var_name)
       || (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("Cannot use argument name or macro keyword "
                      "\"%.*s\" as !LET variable."),
                    (int) var_name.length, var_name.string);
@@ -1688,13 +1679,13 @@ macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
 
   if (p >= end || p->token.type != T_EQUALS)
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("Expected `=' following !LET."));
       return 0;
     }
   p++;
 
-  char *value = macro_evaluate_expression (&p, end - p, me, stack);
+  char *value = macro_evaluate_expression (&p, end - p, me);
   if (!value)
     return 0;
 
@@ -1728,7 +1719,6 @@ find_doend (const struct macro_expansion_stack *stack,
 static size_t
 macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
                  const struct macro_expander *me,
-                 const struct macro_expansion_stack *stack,
                  struct macro_tokens *exp)
 {
   const struct macro_token *p = tokens;
@@ -1740,7 +1730,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
 
   if (p >= end || p->token.type != T_MACRO_ID)
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("Expected macro variable name following !DO."));
       return 0;
     }
@@ -1748,30 +1738,36 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
   if (is_macro_keyword (var_name)
       || (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
     {
-      macro_error (stack, p, _("Cannot use argument name or macro "
+      macro_error (me->stack, p, _("Cannot use argument name or macro "
                                "keyword as !DO variable."));
       return 0;
     }
   p++;
 
-  struct macro_expansion_stack next_stack = {
-    .name = "!DO", .next = stack,
+  struct macro_expansion_stack substack = {
+    .name = "!DO",
+    .next = me->stack,
   };
+  bool break_ = false;
+  struct macro_expander subme = *me;
+  subme.break_ = &break_;
+  subme.stack = &substack;
+
   int miterate = settings_get_miterate ();
   if (p < end && p->token.type == T_MACRO_ID
       && ss_equals_case (p->token.string, ss_cstr ("!IN")))
     {
       p++;
-      char *list = macro_evaluate_expression (&p, end - p, me, &next_stack);
+      char *list = macro_evaluate_expression (&p, end - p, &subme);
       if (!list)
         return 0;
 
       struct macro_tokens items = { .n = 0 };
       macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode,
-                                  stack);
+                                  me->stack);
       free (list);
 
-      const struct macro_token *do_end = find_doend (stack, p, end);
+      const struct macro_token *do_end = find_doend (subme.stack, p, end);
       if (!do_end)
         {
           macro_tokens_uninit (&items);
@@ -1783,15 +1779,11 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
         .n = do_end - p
       };
 
-      bool break_ = false;
-      struct macro_expander subme = *me;
-      subme.break_ = &break_;
-
       for (size_t i = 0; i < items.n && !break_; i++)
         {
           if (i >= miterate)
             {
-              macro_error (stack, NULL,
+              macro_error (&substack, NULL,
                            _("!DO loop over list exceeded "
                              "maximum number of iterations %d.  "
                              "(Use SET MITERATE to change the limit.)"),
@@ -1801,7 +1793,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
           stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
                                       ss_xstrdup (items.mts[i].representation));
 
-          macro_expand (&inner, &subme, &next_stack, exp);
+          macro_expand (&inner, &subme, exp);
         }
       return do_end - tokens + 1;
     }
@@ -1809,20 +1801,20 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
     {
       p++;
       double first;
-      if (!macro_evaluate_number (&p, end - p, me, &next_stack, &first))
+      if (!macro_evaluate_number (&p, end - p, &subme, &first))
         return 0;
 
       if (p >= end || p->token.type != T_MACRO_ID
           || !ss_equals_case (p->token.string, ss_cstr ("!TO")))
         {
-          macro_error (stack, p < end ? p : NULL,
+          macro_error (subme.stack, p < end ? p : NULL,
                        _("Expected !TO in numerical !DO loop."));
           return 0;
         }
       p++;
 
       double last;
-      if (!macro_evaluate_number (&p, end - p, me, &next_stack, &last))
+      if (!macro_evaluate_number (&p, end - p, &subme, &last))
         return 0;
 
       double by = 1.0;
@@ -1830,17 +1822,17 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
           && ss_equals_case (p->token.string, ss_cstr ("!BY")))
         {
           p++;
-          if (!macro_evaluate_number (&p, end - p, me, &next_stack, &by))
+          if (!macro_evaluate_number (&p, end - p, &subme, &by))
             return 0;
 
           if (by == 0.0)
             {
-              macro_error (stack, NULL, _("!BY value cannot be zero."));
+              macro_error (subme.stack, NULL, _("!BY value cannot be zero."));
               return 0;
             }
         }
 
-      const struct macro_token *do_end = find_doend (stack, p, end);
+      const struct macro_token *do_end = find_doend (subme.stack, p, end);
       if (!do_end)
         return 0;
       const struct macro_tokens inner = {
@@ -1848,10 +1840,6 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
         .n = do_end - p
       };
 
-      bool break_ = false;
-      struct macro_expander subme = *me;
-      subme.break_ = &break_;
-
       if ((by > 0 && first <= last) || (by < 0 && first >= last))
         {
           int i = 0;
@@ -1861,7 +1849,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
             {
               if (i++ > miterate)
                 {
-                  macro_error (stack, NULL,
+                  macro_error (subme.stack, NULL,
                                _("Numerical !DO loop exceeded "
                                  "maximum number of iterations %d.  "
                                  "(Use SET MITERATE to change the limit.)"),
@@ -1874,7 +1862,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
               stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
                                           xstrdup (index_s));
 
-              macro_expand (&inner, &subme, &next_stack, exp);
+              macro_expand (&inner, &subme, exp);
             }
         }
 
@@ -1882,7 +1870,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
     }
   else
     {
-      macro_error (stack, p < end ? p : NULL,
+      macro_error (me->stack, p < end ? p : NULL,
                    _("Expected `=' or !IN in !DO loop."));
       return 0;
     }
@@ -1891,13 +1879,12 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
 static void
 macro_expand (const struct macro_tokens *mts,
               const struct macro_expander *me,
-              const struct macro_expansion_stack *stack,
               struct macro_tokens *exp)
 {
   if (me->nesting_countdown <= 0)
     {
-      macro_error (stack, NULL, _("Maximum nesting level %d exceeded.  "
-                                  "(Use SET MNEST to change the limit.)"),
+      macro_error (me->stack, NULL, _("Maximum nesting level %d exceeded.  "
+                                      "(Use SET MNEST to change the limit.)"),
                    settings_get_mnest ());
       for (size_t i = 0; i < mts->n; i++)
         macro_tokens_add (exp, &mts->mts[i]);
@@ -1919,6 +1906,10 @@ macro_expand (const struct macro_tokens *mts,
               if (*me->expand && param->expand_arg)
                 {
                   struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+                  struct macro_expansion_stack stack = {
+                    .name = param->name,
+                    .next = me->stack,
+                  };
                   struct macro_expander subme = {
                     .macros = me->macros,
                     .macro = NULL,
@@ -1928,11 +1919,9 @@ macro_expand (const struct macro_tokens *mts,
                     .break_ = NULL,
                     .vars = &vars,
                     .nesting_countdown = me->nesting_countdown,
+                    .stack = &stack,
                   };
-                  macro_expand (arg, &subme, &(struct macro_expansion_stack) {
-                                  .name = param->name,
-                                  .next = stack,
-                                }, exp);
+                  macro_expand (arg, &subme, exp);
                   stringi_map_destroy (&vars);
                 }
               else
@@ -1953,6 +1942,10 @@ macro_expand (const struct macro_tokens *mts,
                   if (*me->expand && param->expand_arg)
                     {
                       struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+                      struct macro_expansion_stack stack = {
+                        .name = "!*",
+                        .next = me->stack,
+                      };
                       struct macro_expander subme = {
                         .macros = me->macros,
                         .macro = NULL,
@@ -1962,12 +1955,9 @@ macro_expand (const struct macro_tokens *mts,
                         .break_ = NULL,
                         .vars = &vars,
                         .nesting_countdown = me->nesting_countdown,
+                        .stack = &stack,
                       };
-                      macro_expand (arg, &subme,
-                                    &(struct macro_expansion_stack) {
-                                      .name = "!*",
-                                      .next = stack,
-                                    }, exp);
+                      macro_expand (arg, &subme, exp);
                       stringi_map_destroy (&vars);
                     }
                   else
@@ -1978,8 +1968,7 @@ macro_expand (const struct macro_tokens *mts,
               continue;
             }
 
-          size_t n = macro_expand_if (&mts->mts[i], mts->n - i, me, stack,
-                                      exp);
+          size_t n = macro_expand_if (&mts->mts[i], mts->n - i, me, exp);
           if (n > 0)
             {
               i += n - 1;
@@ -1995,7 +1984,7 @@ macro_expand (const struct macro_tokens *mts,
           if (value)
             {
               macro_tokens_from_string__ (exp, ss_cstr (value),
-                                          me->segmenter_mode, stack);
+                                          me->segmenter_mode, me->stack);
               continue;
             }
         }
@@ -2015,6 +2004,13 @@ macro_expand (const struct macro_tokens *mts,
             {
               i += retval - 1;
               struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+              struct macro_expansion_stack stack = {
+                .name = submc->macro->name,
+                .file_name = submc->macro->file_name,
+                .first_line = submc->macro->first_line,
+                .last_line = submc->macro->last_line,
+                .next = me->stack,
+              };
               struct macro_expander subme = {
                 .macros = submc->macros,
                 .macro = submc->macro,
@@ -2024,15 +2020,9 @@ macro_expand (const struct macro_tokens *mts,
                 .break_ = NULL,
                 .vars = &vars,
                 .nesting_countdown = me->nesting_countdown - 1,
+                .stack = &stack,
               };
-              macro_expand (&submc->macro->body, &subme,
-                            &(struct macro_expansion_stack) {
-                              .name = submc->macro->name,
-                              .file_name = submc->macro->file_name,
-                              .first_line = submc->macro->first_line,
-                              .last_line = submc->macro->last_line,
-                              .next = stack,
-                            }, exp);
+              macro_expand (&submc->macro->body, &subme, exp);
               macro_call_destroy (submc);
               stringi_map_destroy (&vars);
               continue;
@@ -2050,7 +2040,7 @@ macro_expand (const struct macro_tokens *mts,
       if (ss_equals_case (token->string, ss_cstr ("!break")))
         {
           if (!me->break_)
-            macro_error (stack, mt, _("!BREAK outside !DO."));
+            macro_error (me->stack, mt, _("!BREAK outside !DO."));
           else
             {
               *me->break_ = true;
@@ -2062,7 +2052,6 @@ macro_expand (const struct macro_tokens *mts,
         .input = &mts->mts[i],
         .n_input = mts->n - i,
         .me = me,
-        .stack = stack,
       };
       struct string function_output = DS_EMPTY_INITIALIZER;
       size_t function_consumed;
@@ -2071,20 +2060,20 @@ macro_expand (const struct macro_tokens *mts,
           i += function_consumed - 1;
 
           macro_tokens_from_string__ (exp, function_output.ss,
-                                      me->segmenter_mode, stack);
+                                      me->segmenter_mode, me->stack);
           ds_destroy (&function_output);
 
           continue;
         }
 
-      size_t n = macro_parse_let (&mts->mts[i], mts->n - i, me, stack);
+      size_t n = macro_parse_let (&mts->mts[i], mts->n - i, me);
       if (n > 0)
         {
           i += n - 1;
           continue;
         }
 
-      n = macro_expand_do (&mts->mts[i], mts->n - i, me, stack, exp);
+      n = macro_expand_do (&mts->mts[i], mts->n - i, me, exp);
       if (n > 0)
         {
           i += n - 1;
@@ -2108,6 +2097,12 @@ macro_call_expand (struct macro_call *mc, enum segmenter_mode segmenter_mode,
 
   bool expand = true;
   struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+  struct macro_expansion_stack stack = {
+    .name = mc->macro->name,
+    .file_name = mc->macro->file_name,
+    .first_line = mc->macro->first_line,
+    .last_line = mc->macro->last_line,
+  };
   struct macro_expander me = {
     .macros = mc->macros,
     .macro = mc->macro,
@@ -2117,15 +2112,10 @@ macro_call_expand (struct macro_call *mc, enum segmenter_mode segmenter_mode,
     .break_ = NULL,
     .vars = &vars,
     .nesting_countdown = settings_get_mnest (),
+    .stack = &stack,
   };
 
-  struct macro_expansion_stack stack = {
-    .name = mc->macro->name,
-    .file_name = mc->macro->file_name,
-    .first_line = mc->macro->first_line,
-    .last_line = mc->macro->last_line,
-  };
-  macro_expand (&mc->macro->body, &me, &stack, exp);
+  macro_expand (&mc->macro->body, &me, exp);
 
   stringi_map_destroy (&vars);
 }
index 44061836d3da54c88268bc15a756c984fae20a89..1e18b81bd716e89cdfc5bfb0625bdaab488ca4ea 100644 (file)
@@ -956,13 +956,15 @@ DEBUG EXPAND.
 AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
 "increasing".
 
-define.sps:3-5: In the expansion of `!for',
+In the expansion of `!DO',
+define.sps:3-5: inside the expansion of `!for',
 define.sps:14: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number
 of iterations 3.  (Use SET MITERATE to change the limit.)
 
 1 2 3 4.
 
-define.sps:7-9: In the expansion of `!forby',
+In the expansion of `!DO',
+define.sps:7-9: inside the expansion of `!forby',
 define.sps:15: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number
 of iterations 3.  (Use SET MITERATE to change the limit.)
 
@@ -980,7 +982,8 @@ of iterations 3.  (Use SET MITERATE to change the limit.)
 
 .
 
-define.sps:7-9: In the expansion of `!forby',
+In the expansion of `!DO',
+define.sps:7-9: inside the expansion of `!forby',
 define.sps:23: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number
 of iterations 3.  (Use SET MITERATE to change the limit.)
 
@@ -1058,13 +1061,15 @@ DEBUG EXPAND.
 !for.
 ])
 AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
-define.sps:1-3: In the expansion of `!for',
+In the expansion of `!DO',
+define.sps:1-3: inside the expansion of `!for',
 define.sps:7: error: DEBUG EXPAND: !DO loop over list exceeded maximum number
 of iterations 2.  (Use SET MITERATE to change the limit.)
 
 ( (a) (b) ).
 
-define.sps:1-3: In the expansion of `!for',
+In the expansion of `!DO',
+define.sps:1-3: inside the expansion of `!for',
 define.sps:8: error: DEBUG EXPAND: !DO loop over list exceeded maximum number
 of iterations 2.  (Use SET MITERATE to change the limit.)
 
@@ -1461,7 +1466,8 @@ define.sps:14: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop.
 
 !DO !x
 
-define.sps:4: In the expansion of `!d',
+In the expansion of `!DO',
+define.sps:4: inside the expansion of `!d',
 define.sps:15: error: DEBUG EXPAND: Missing !DOEND.
 
 !DO !x !in(x)
@@ -1473,12 +1479,14 @@ define.sps:16: error: DEBUG EXPAND: Macro expression must evaluate to a number
 
 !DO !x = x.
 
-define.sps:6: At `x' in the expansion of `!f',
+At `x' in the expansion of `!DO',
+define.sps:6: inside the expansion of `!f',
 define.sps:17: error: DEBUG EXPAND: Expected !TO in numerical !DO loop.
 
 !DO !x = 5 x
 
-define.sps:7: In the expansion of `!g',
+In the expansion of `!DO',
+define.sps:7: inside the expansion of `!g',
 define.sps:18: error: DEBUG EXPAND: !BY value cannot be zero.
 
 !DO !x = 5 !TO 6 !BY 0