!*
[pspp] / src / language / lexer / macro.c
index e900a5e7d1a542f0ec1faedaa813b0bd9ac883dc..b120b35d725e432fecbb96f5f503ee9031cc0b2f 100644 (file)
@@ -721,6 +721,17 @@ static bool
 expand_macro_function (struct parse_macro_function_ctx *ctx,
                        struct string *output, size_t *input_consumed);
 
+/* Returns true if the pair of tokens starting at offset OFS within MTS are !*,
+   false otherwise. */
+static bool
+is_bang_star (const struct macro_token *mts, size_t n, size_t ofs)
+{
+  return (ofs + 1 < n
+          && mts[ofs].token.type == T_MACRO_ID
+          && ss_equals (mts[ofs].token.string, ss_cstr ("!"))
+          && mts[ofs + 1].token.type == T_ASTERISK);
+}
+
 static size_t
 parse_function_arg (struct parse_macro_function_ctx *ctx,
                     size_t i, struct string *farg)
@@ -744,6 +755,24 @@ parse_function_arg (struct parse_macro_function_ctx *ctx,
           return 1;
         }
 
+      if (is_bang_star (ctx->input, ctx->n_input, i))
+        {
+          for (size_t i = 0; i < ctx->me->macro->n_params; i++)
+            {
+              if (!ctx->me->macro->params[i].positional)
+                break;
+
+              const struct macro_tokens *marg = ctx->me->args[i];
+              for (size_t j = 0; j < marg->n; j++)
+                {
+                  if (i || j)
+                    ds_put_byte (farg, ' ');
+                  ds_put_substring (farg, marg->mts[j].representation);
+                }
+            }
+          return 2;
+        }
+
       struct parse_macro_function_ctx subctx = {
         .input = &ctx->input[i],
         .n_input = ctx->n_input - i,
@@ -1056,6 +1085,25 @@ macro_expand (const struct macro_tokens *mts,
                   macro_tokens_add (exp, &arg->mts[i]);
               continue;
             }
+
+          if (is_bang_star (mts->mts, mts->n, i))
+            {
+              for (size_t j = 0; j < me->macro->n_params; j++)
+                {
+                  const struct macro_param *param = &me->macro->params[j];
+                  if (!param->positional)
+                    break;
+
+                  const struct macro_tokens *arg = me->args[j];
+                  if (*expand && param->expand_arg)
+                    macro_expand (arg, nesting_countdown, macros, NULL, expand, exp);
+                  else
+                    for (size_t k = 0; k < arg->n; k++)
+                      macro_tokens_add (exp, &arg->mts[k]);
+                }
+              i++;
+              continue;
+            }
         }
 
       if (*expand)