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 "language/lexer/segment.h"
24 #include "language/lexer/scan.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "libpspp/str.h"
31 #define _(msgid) gettext (msgid)
34 macro_destroy (struct macro *m)
40 for (size_t i = 0; i < m->n_params; i++)
42 struct macro_param *p = &m->params[i];
45 tokens_uninit (&p->def);
53 token_destroy (&p->charend);
57 token_destroy (&p->enclose[0]);
58 token_destroy (&p->enclose[1]);
66 ss_dealloc (&m->body);
71 macro_set_create (void)
73 struct macro_set *set = xmalloc (sizeof *set);
74 *set = (struct macro_set) {
75 .macros = HMAP_INITIALIZER (set->macros),
81 macro_set_destroy (struct macro_set *set)
86 struct macro *macro, *next;
87 HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
89 hmap_delete (&set->macros, ¯o->hmap_node);
90 macro_destroy (macro);
92 hmap_destroy (&set->macros);
97 hash_macro_name (const char *name)
99 return utf8_hash_case_string (name, 0);
102 static struct macro *
103 macro_set_find__ (struct macro_set *set, const char *name)
106 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
107 hash_macro_name (name), &set->macros)
108 if (!utf8_strcasecmp (macro->name, name))
115 macro_set_find (const struct macro_set *set, const char *name)
117 return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
120 /* Adds M to SET. M replaces any existing macro with the same name. Takes
123 macro_set_add (struct macro_set *set, struct macro *m)
125 struct macro *victim = macro_set_find__ (set, m->name);
128 hmap_delete (&set->macros, &victim->hmap_node);
129 macro_destroy (victim);
132 hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
139 /* Accumulating tokens in me->params toward the end of any type of
143 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
146 /* Expecting a keyword for a keyword argument. */
149 /* Expecting an equal sign for a keyword argument. */
154 struct macro_expander
156 const struct macro_set *macros;
161 const struct macro *macro;
162 struct tokens **args;
167 me_finished (struct macro_expander *me)
169 for (size_t i = 0; i < me->macro->n_params; i++)
172 me->args[i] = xmalloc (sizeof *me->args[i]);
173 tokens_copy (me->args[i], &me->macro->params[i].def);
179 me_next_arg (struct macro_expander *me)
181 if (me->arg_index >= me->macro->n_params)
183 assert (!me->macro->n_params);
184 return me_finished (me);
186 else if (!me->macro->params[me->arg_index].name)
189 if (me->arg_index >= me->macro->n_params)
190 return me_finished (me);
193 if (!me->macro->params[me->arg_index].name)
196 me->state = 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_add_start (struct macro_expander *me, const struct token *token)
215 if (token->type != T_ID && token->type != T_MACRO_ID)
218 me->macro = macro_set_find (me->macros, token->string.string);
223 me->args = xcalloc (me->macro->n_params, sizeof *me->args);
225 return me_next_arg (me);
229 me_error (struct macro_expander *me)
231 me->state = ME_START;
236 me_add_arg (struct macro_expander *me, const struct token *token)
238 const struct macro_param *p = &me->macro->params[me->arg_index];
239 if (token->type == T_STOP)
241 char *param_name = (p->name
243 : xasprintf ("%zu", me->arg_index));
244 msg (SE, _("Unexpected end of file reading argument %s "
245 "to macro %s."), param_name, me->macro->name);
248 return me_error (me);
253 struct tokens **argp = &me->args[me->arg_index];
255 *argp = xzalloc (sizeof **argp);
256 struct tokens *arg = *argp;
257 if (p->arg_type == ARG_N_TOKENS)
259 tokens_add (arg, token);
260 if (arg->n >= p->n_tokens)
261 return me_next_arg (me);
264 else if (p->arg_type == ARG_CMDEND)
266 if (token->type == T_ENDCMD || token->type == T_STOP)
267 return me_next_arg (me);
268 tokens_add (arg, token);
273 const struct token *end
274 = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
275 if (token_equal (token, end))
276 return me_next_arg (me);
277 tokens_add (arg, token);
283 me_expected (struct macro_expander *me, const struct token *token,
284 const struct token *wanted)
286 const struct macro_param *p = &me->macro->params[me->arg_index];
287 char *param_name = (p->name
289 : xasprintf ("%zu", me->arg_index));
290 char *actual = token_to_string (token);
292 actual = xstrdup ("<eof>");
293 char *expected = token_to_string (wanted);
294 msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
296 actual, expected, param_name, me->macro->name);
301 return me_error (me);
305 me_enclose (struct macro_expander *me, const struct token *token)
309 const struct macro_param *p = &me->macro->params[me->arg_index];
310 if (token_equal (&p->enclose[0], token))
316 return me_expected (me, token, &p->enclose[0]);
320 me_keyword (struct macro_expander *me, const struct token *token)
322 if (token->type != T_ID)
323 return me_finished (me);
325 for (size_t i = 0; i < me->macro->n_params; i++)
327 const struct macro_param *p = &me->macro->params[i];
328 if (p->name && ss_equals_case (ss_cstr (p->name), token->string))
334 _("Argument %s multiply specified in call to macro %s."),
335 p->name, me->macro->name);
336 return me_error (me);
340 me->state = ME_EQUALS;
345 return me_finished (me);
349 me_equals (struct macro_expander *me, const struct token *token)
353 if (token->type == T_EQUALS)
359 const struct token equals = { .type = T_EQUALS };
360 return me_expected (me, token, &equals);
364 macro_expander_create (const struct macro_set *macros,
365 const struct token *token,
366 struct macro_expander **mep)
369 if (macro_set_is_empty (macros))
371 if (token->type != T_ID && token->type != T_MACRO_ID)
374 const struct macro *macro = macro_set_find (macros, token->string.string);
378 struct macro_expander *me = xmalloc (sizeof *me);
379 *me = (struct macro_expander) {
386 .args = xcalloc (macro->n_params, sizeof *me->args),
390 return me_next_arg (me);
394 macro_expander_destroy (struct macro_expander *me)
399 for (size_t i = 0; i < me->macro->n_params; i++)
402 tokens_uninit (me->args[i]);
409 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
412 Returns -1 if the tokens added do not actually invoke a macro. The caller
413 should consume the first token without expanding it.
415 Returns 0 if the macro expander needs more tokens, for macro arguments or to
416 decide whether this is actually a macro invocation. The caller should call
417 macro_expander_add() again with the next token.
419 Returns a positive number to indicate that the returned number of tokens
420 invoke a macro. The number returned might be less than the number of tokens
421 added because it can take a few tokens of lookahead to determine whether the
422 macro invocation is finished. The caller should call
423 macro_expander_get_expansion() to obtain the expansion. */
425 macro_expander_add (struct macro_expander *me, const struct token *token)
430 return me_add_start (me, token);
433 return me_add_arg (me, token);
436 return me_enclose (me, token);
439 return me_keyword (me, token);
442 return me_equals (me, token);
450 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
454 struct segmenter segmenter;
455 struct substring body;
459 segmenter_init (&state.segmenter, SEG_MODE_INTERACTIVE /*XXX*/);
460 state.body = me->macro->body;
462 struct state saved = state;
464 struct token token = { .type = T_STOP };
466 while (state.body.length > 0)
468 struct scanner scanner;
469 scanner_init (&scanner, &token);
473 enum segment_type type;
474 int seg_len = segmenter_push (&state.segmenter, state.body.string,
475 state.body.length, true, &type);
476 assert (seg_len >= 0);
478 struct substring segment = ss_head (state.body, seg_len);
479 ss_advance (&state.body, seg_len);
480 printf ("segment \"%.*s\" %s token.type=%d\n", (int) segment.length, segment.string, segment_type_to_string (type), token.type);
482 enum scan_result result = scanner_push (&scanner, type, segment, &token);
483 if (result == SCAN_SAVE)
485 else if (result == SCAN_BACK)
491 else if (result == SCAN_DONE)
498 /* We have a token in 'token'. */
499 printf ("add token %d %s\n", token.type, token_type_to_name (token.type));
500 if (is_scan_type (token.type))
502 /* XXX report error if it's not SCAN_SKIP */
505 tokens_add (exp, &token);
506 token_destroy (&token);