1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2021 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "language/lexer/macro.h"
23 #include "data/settings.h"
24 #include "language/lexer/segment.h"
25 #include "language/lexer/scan.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/i18n.h"
28 #include "libpspp/message.h"
29 #include "libpspp/str.h"
32 #define _(msgid) gettext (msgid)
35 macro_destroy (struct macro *m)
41 for (size_t i = 0; i < m->n_params; i++)
43 struct macro_param *p = &m->params[i];
46 tokens_uninit (&p->def);
54 token_destroy (&p->charend);
58 token_destroy (&p->enclose[0]);
59 token_destroy (&p->enclose[1]);
67 ss_dealloc (&m->body);
68 tokens_uninit (&m->body_tokens);
73 macro_set_create (void)
75 struct macro_set *set = xmalloc (sizeof *set);
76 *set = (struct macro_set) {
77 .macros = HMAP_INITIALIZER (set->macros),
83 macro_set_destroy (struct macro_set *set)
88 struct macro *macro, *next;
89 HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
91 hmap_delete (&set->macros, ¯o->hmap_node);
92 macro_destroy (macro);
94 hmap_destroy (&set->macros);
99 hash_macro_name (const char *name)
101 return utf8_hash_case_string (name, 0);
104 static struct macro *
105 macro_set_find__ (struct macro_set *set, const char *name)
108 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
109 hash_macro_name (name), &set->macros)
110 if (!utf8_strcasecmp (macro->name, name))
117 macro_set_find (const struct macro_set *set, const char *name)
119 return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
122 /* Adds M to SET. M replaces any existing macro with the same name. Takes
125 macro_set_add (struct macro_set *set, struct macro *m)
127 struct macro *victim = macro_set_find__ (set, m->name);
130 hmap_delete (&set->macros, &victim->hmap_node);
131 macro_destroy (victim);
134 hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
142 /* Accumulating tokens in me->params toward the end of any type of
146 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
149 /* Expecting a keyword for a keyword argument. */
152 /* Expecting an equal sign for a keyword argument. */
157 struct macro_expander
159 const struct macro_set *macros;
164 const struct macro *macro;
165 struct tokens **args;
166 const struct macro_param *param;
170 me_finished (struct macro_expander *me)
172 for (size_t i = 0; i < me->macro->n_params; i++)
175 me->args[i] = xmalloc (sizeof *me->args[i]);
176 tokens_copy (me->args[i], &me->macro->params[i].def);
182 me_next_arg (struct macro_expander *me)
186 assert (!me->macro->n_params);
187 return me_finished (me);
189 else if (me->param->positional)
192 if (me->param >= &me->macro->params[me->macro->n_params])
193 return me_finished (me);
196 me->state = me->param->positional ? ME_ARG : ME_KEYWORD;
202 for (size_t i = 0; i < me->macro->n_params; i++)
205 me->state = ME_KEYWORD;
208 return me_finished (me);
213 me_error (struct macro_expander *me)
215 me->state = ME_ERROR;
220 me_add_arg (struct macro_expander *me, const struct token *token)
222 if (token->type == T_STOP)
224 msg (SE, _("Unexpected end of file reading argument %s "
225 "to macro %s."), me->param->name, me->macro->name);
227 return me_error (me);
232 const struct macro_param *p = me->param;
233 struct tokens **argp = &me->args[p - me->macro->params];
235 *argp = xzalloc (sizeof **argp);
236 struct tokens *arg = *argp;
237 if (p->arg_type == ARG_N_TOKENS)
239 tokens_add (arg, token);
240 if (arg->n >= p->n_tokens)
241 return me_next_arg (me);
244 else if (p->arg_type == ARG_CMDEND)
246 if (token->type == T_ENDCMD || token->type == T_STOP)
247 return me_next_arg (me);
248 tokens_add (arg, token);
253 const struct token *end
254 = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
255 if (token_equal (token, end))
256 return me_next_arg (me);
257 tokens_add (arg, token);
263 me_expected (struct macro_expander *me, const struct token *token,
264 const struct token *wanted)
266 char *actual = token_to_string (token);
268 actual = xstrdup ("<eof>");
269 char *expected = token_to_string (wanted);
270 msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
272 actual, expected, me->param->name, me->macro->name);
276 return me_error (me);
280 me_enclose (struct macro_expander *me, const struct token *token)
284 if (token_equal (&me->param->enclose[0], token))
290 return me_expected (me, token, &me->param->enclose[0]);
293 static const struct macro_param *
294 macro_find_parameter_by_name (const struct macro *m, struct substring name)
296 for (size_t i = 0; i < m->n_params; i++)
298 const struct macro_param *p = &m->params[i];
299 struct substring p_name = ss_cstr (p->name);
300 if (!utf8_strncasecmp (p_name.string, p_name.length,
301 name.string, name.length))
308 me_keyword (struct macro_expander *me, const struct token *token)
310 if (token->type != T_ID)
311 return me_finished (me);
313 const struct macro_param *p = macro_find_parameter_by_name (me->macro,
317 size_t arg_index = p - me->macro->params;
319 if (me->args[arg_index])
322 _("Argument %s multiply specified in call to macro %s."),
323 p->name, me->macro->name);
324 return me_error (me);
328 me->state = ME_EQUALS;
332 return me_finished (me);
336 me_equals (struct macro_expander *me, const struct token *token)
340 if (token->type == T_EQUALS)
346 const struct token equals = { .type = T_EQUALS };
347 return me_expected (me, token, &equals);
351 macro_expander_create (const struct macro_set *macros,
352 const struct token *token,
353 struct macro_expander **mep)
356 if (macro_set_is_empty (macros))
358 if (token->type != T_ID && token->type != T_MACRO_ID)
361 const struct macro *macro = macro_set_find (macros, token->string.string);
365 struct macro_expander *me = xmalloc (sizeof *me);
366 *me = (struct macro_expander) {
373 if (!macro->n_params)
377 me->state = macro->params[0].positional ? ME_ARG : ME_KEYWORD;
378 me->args = xcalloc (macro->n_params, sizeof *me->args);
379 me->param = macro->params;
385 macro_expander_destroy (struct macro_expander *me)
390 for (size_t i = 0; i < me->macro->n_params; i++)
393 tokens_uninit (me->args[i]);
400 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
403 Returns -1 if the tokens added do not actually invoke a macro. The caller
404 should consume the first token without expanding it.
406 Returns 0 if the macro expander needs more tokens, for macro arguments or to
407 decide whether this is actually a macro invocation. The caller should call
408 macro_expander_add() again with the next token.
410 Returns a positive number to indicate that the returned number of tokens
411 invoke a macro. The number returned might be less than the number of tokens
412 added because it can take a few tokens of lookahead to determine whether the
413 macro invocation is finished. The caller should call
414 macro_expander_get_expansion() to obtain the expansion. */
416 macro_expander_add (struct macro_expander *me, const struct token *token)
424 return me_add_arg (me, token);
427 return me_enclose (me, token);
430 return me_keyword (me, token);
433 return me_equals (me, token);
441 macro_expand (const struct tokens *tokens, int nesting_countdown,
442 const struct macro_set *macros, const struct macro_expander *me,
443 bool *expand, struct tokens *exp)
445 if (nesting_countdown <= 0)
447 printf ("maximum nesting level exceeded\n");
448 for (size_t i = 0; i < tokens->n; i++)
449 tokens_add (exp, &tokens->tokens[i]);
453 for (size_t i = 0; i < tokens->n; i++)
455 const struct token *token = &tokens->tokens[i];
456 if (token->type == T_MACRO_ID && me)
458 const struct macro_param *param = macro_find_parameter_by_name (
459 me->macro, token->string);
462 printf ("expand %s to:\n", param->name);
463 const struct tokens *arg = me->args[param - me->macro->params];
464 tokens_print (arg, stdout);
465 if (*expand && param->expand_arg)
466 macro_expand (arg, nesting_countdown, macros, NULL, expand, exp);
468 for (size_t i = 0; i < arg->n; i++)
469 tokens_add (exp, &arg->tokens[i]);
476 struct macro_expander *subme;
477 int retval = macro_expander_create (macros, token, &subme);
478 for (size_t j = 1; !retval; j++)
480 static const struct token stop = { .type = T_STOP };
481 retval = macro_expander_add (
482 subme, i + j < tokens->n ? &tokens->tokens[i + j] : &stop);
487 macro_expand (&subme->macro->body_tokens, nesting_countdown - 1,
488 macros, subme, expand, exp);
489 macro_expander_destroy (subme);
493 macro_expander_destroy (subme);
496 if (token->type != T_MACRO_ID)
498 tokens_add (exp, token);
502 if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
504 else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
506 else if (ss_equals_case (token->string, ss_cstr ("!length")))
508 if (i + 1 >= tokens->n || tokens->tokens[i + 1].type != T_LPAREN)
510 printf ("`(' expected following !LENGTH'\n");
516 for (j = i + 2; n_parens && j < tokens->n; j++)
517 if (tokens->tokens[j].type == T_LPAREN)
519 else if (tokens->tokens[j].type == T_RPAREN)
523 printf ("Unbalanced parentheses in !LENGTH argument.\n");
527 size_t lparen_idx = i + 1;
528 size_t rparen_idx = j - 1;
529 const struct tokens unexpanded_args = {
530 .tokens = &tokens->tokens[lparen_idx + 1],
531 .n = rparen_idx - (lparen_idx + 1),
533 struct tokens args = { .n = 0 };
534 macro_expand (&unexpanded_args, nesting_countdown, macros,
539 tokens_uninit (&args);
540 printf ("!LENGTH argument must be a single token (not %zu)\n", args.n);
544 char *s = token_to_string (&args.tokens[0]);
545 struct token t = { .type = T_POS_NUM, .number = strlen (s) };
546 tokens_add (exp, &t);
549 tokens_uninit (&args);
554 tokens_add (exp, token);
560 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
562 for (size_t i = 0; i < me->macro->n_params; i++)
564 printf ("%s:\n", me->macro->params[i].name);
565 tokens_print (me->args[i], stdout);
569 macro_expand (&me->macro->body_tokens, settings_get_mnest (),
570 me->macros, me, &expand, exp);
572 printf ("expansion:\n");
573 tokens_print (exp, stdout);