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_find (const struct macro_set *set, const char *name)
75 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
76 utf8_hash_case_string (name, 0), &set->macros)
78 if (!utf8_strcasecmp (macro->name, name))
89 /* Accumulating tokens in me->params toward the end of any type of
93 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
96 /* Expecting a keyword for a keyword argument. */
99 /* Expecting an equal sign for a keyword argument. */
104 struct macro_expander
106 const struct macro_set *macros;
111 const struct macro *macro;
112 struct tokens **args;
117 me_finished (struct macro_expander *me)
119 for (size_t i = 0; i < me->macro->n_params; i++)
122 me->args[i] = xmalloc (sizeof *me->args[i]);
123 tokens_copy (me->args[i], &me->macro->params[i].def);
129 me_next_arg (struct macro_expander *me)
131 if (me->arg_index >= me->macro->n_params)
133 assert (!me->macro->n_params);
134 return me_finished (me);
136 else if (!me->macro->params[me->arg_index].name)
139 if (me->arg_index >= me->macro->n_params)
140 return me_finished (me);
143 if (!me->macro->params[me->arg_index].name)
146 me->state = ME_KEYWORD;
152 for (size_t i = 0; i < me->macro->n_params; i++)
155 me->state = ME_KEYWORD;
158 return me_finished (me);
163 me_add_start (struct macro_expander *me, const struct token *token)
165 if (token->type != T_ID && token->type != T_MACRO_ID)
168 me->macro = macro_set_find (me->macros, token->string.string);
173 me->args = xcalloc (me->macro->n_params, sizeof *me->args);
175 return me_next_arg (me);
179 me_error (struct macro_expander *me)
181 me->state = ME_START;
186 me_add_arg (struct macro_expander *me, const struct token *token)
188 const struct macro_param *p = &me->macro->params[me->arg_index];
189 if (token->type == T_STOP)
191 char *param_name = (p->name
193 : xasprintf ("%zu", me->arg_index));
194 msg (SE, _("Unexpected end of file reading argument %s "
195 "to macro %s."), param_name, me->macro->name);
198 return me_error (me);
203 struct tokens **argp = &me->args[me->arg_index];
205 *argp = xzalloc (sizeof **argp);
206 struct tokens *arg = *argp;
207 if (p->arg_type == ARG_N_TOKENS)
209 tokens_add (arg, token);
210 if (arg->n >= p->n_tokens)
211 return me_next_arg (me);
214 else if (p->arg_type == ARG_CMDEND)
216 if (token->type == T_ENDCMD || token->type == T_STOP)
217 return me_next_arg (me);
218 tokens_add (arg, token);
223 const struct token *end
224 = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
225 if (token_equal (token, end))
226 return me_next_arg (me);
227 tokens_add (arg, token);
233 me_expected (struct macro_expander *me, const struct token *token,
234 const struct token *wanted)
236 const struct macro_param *p = &me->macro->params[me->arg_index];
237 char *param_name = (p->name
239 : xasprintf ("%zu", me->arg_index));
240 char *actual = token_to_string (token);
242 actual = xstrdup ("<eof>");
243 char *expected = token_to_string (wanted);
244 msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
246 actual, expected, param_name, me->macro->name);
251 return me_error (me);
255 me_enclose (struct macro_expander *me, const struct token *token)
259 const struct macro_param *p = &me->macro->params[me->arg_index];
260 if (token_equal (&p->enclose[0], token))
266 return me_expected (me, token, &p->enclose[0]);
270 me_keyword (struct macro_expander *me, const struct token *token)
272 if (token->type != T_ID)
273 return me_finished (me);
275 for (size_t i = 0; i < me->macro->n_params; i++)
277 const struct macro_param *p = &me->macro->params[i];
278 if (p->name && ss_equals_case (ss_cstr (p->name), token->string))
284 _("Argument %s multiply specified in call to macro %s."),
285 p->name, me->macro->name);
286 return me_error (me);
290 me->state = ME_EQUALS;
295 return me_finished (me);
299 me_equals (struct macro_expander *me, const struct token *token)
303 if (token->type == T_EQUALS)
309 const struct token equals = { .type = T_EQUALS };
310 return me_expected (me, token, &equals);
313 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
318 * -1: The tokens added do not actually invoke a macro. The caller should
319 consume the first token without expanding it.
321 * 0: The macro expander needs more tokens, for macro arguments or to decide
322 whether this is actually a macro invocation. The caller should call
323 macro_expander_add() again with the next token.
325 * >0: Expand the given number of tokens. */
327 macro_expander_add (struct macro_expander *me, const struct token *token)
332 return me_add_start (me, token);
335 return me_add_arg (me, token);
338 return me_enclose (me, token);
341 return me_keyword (me, token);
344 return me_equals (me, token);
352 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
356 struct segmenter segmenter;
357 struct substring body;
361 segmenter_init (&state.segmenter, SEG_MODE_INTERACTIVE /*XXX*/);
362 state.body = me->macro->body;
364 struct state saved = state;
366 struct token token = { .type = T_STOP };
368 while (state.body.length > 0)
370 struct scanner scanner;
371 scanner_init (&scanner, &token);
375 enum segment_type type;
376 int seg_len = segmenter_push (&state.segmenter, state.body.string,
377 state.body.length, true, &type);
378 assert (seg_len >= 0);
380 struct substring segment = ss_head (state.body, seg_len);
381 ss_advance (&state.body, seg_len);
383 enum scan_result result = scanner_push (&scanner, type, segment, &token);
384 if (result == SCAN_SAVE)
386 else if (result == SCAN_BACK)
391 else if (result == SCAN_DONE)
395 /* We have a token in 'token'. */
396 tokens_add (exp, &token);
397 token_destroy (&token);