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 "libpspp/assertion.h"
24 #include "libpspp/i18n.h"
25 #include "libpspp/message.h"
28 #define _(msgid) gettext (msgid)
31 macro_destroy (struct macro *m)
37 for (size_t i = 0; i < m->n_params; i++)
39 struct macro_param *p = &m->params[i];
42 tokens_uninit (&p->def);
50 token_destroy (&p->charend);
54 token_destroy (&p->enclose[0]);
55 token_destroy (&p->enclose[1]);
63 for (size_t i = 0; i < m->n_body; i++)
70 macro_set_find (const struct macro_set *set, const char *name)
74 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
75 utf8_hash_case_string (name, 0), &set->macros)
77 if (!utf8_strcasecmp (macro->name, name))
88 /* Accumulating tokens in me->params toward the end of any type of
92 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
95 /* Expecting a keyword for a keyword argument. */
98 /* Expecting an equal sign for a keyword argument. */
103 struct macro_expander
105 const struct macro_set *macros;
110 const struct macro *macro;
111 struct tokens **args;
116 me_finished (struct macro_expander *me)
118 for (size_t i = 0; i < me->macro->n_params; i++)
121 me->args[i] = xmalloc (sizeof *me->args[i]);
122 tokens_copy (me->args[i], &me->macro->params[i].def);
128 me_next_arg (struct macro_expander *me)
130 if (me->arg_index >= me->macro->n_params)
132 assert (!me->macro->n_params);
133 return me_finished (me);
135 else if (!me->macro->params[me->arg_index].name)
138 if (me->arg_index >= me->macro->n_params)
139 return me_finished (me);
142 if (!me->macro->params[me->arg_index].name)
145 me->state = ME_KEYWORD;
151 for (size_t i = 0; i < me->macro->n_params; i++)
154 me->state = ME_KEYWORD;
157 return me_finished (me);
162 me_add_start (struct macro_expander *me, const struct token *token)
164 if (token->type != T_ID && token->type != T_MACRO_ID)
167 me->macro = macro_set_find (me->macros, token->string.string);
172 me->args = xcalloc (me->macro->n_params, sizeof *me->args);
174 return me_next_arg (me);
178 me_add_arg (struct macro_expander *me, const struct token *token)
182 struct tokens **ap = &me->args[me->arg_index];
184 *ap = xzalloc (sizeof **ap);
185 struct tokens *a = *ap;
186 const struct macro_param *p = &me->macro->params[me->arg_index];
187 if (p->arg_type == ARG_N_TOKENS)
189 tokens_add (a, token);
190 if (a->n >= p->n_tokens)
191 return me_next_arg (me);
194 else if (p->arg_type == ARG_CMDEND)
196 if (token->type == T_ENDCMD || token->type == T_STOP)
197 return me_next_arg (me);
198 tokens_add (a, token);
203 const struct token *end
204 = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
205 if (token_equal (token, end))
206 return me_next_arg (me);
207 tokens_add (a, token);
213 me_error (struct macro_expander *me)
215 me->state = ME_START;
220 me_expected (struct macro_expander *me, const struct token *token,
221 const struct token *wanted)
223 const struct macro_param *p = &me->macro->params[me->arg_index];
224 char *param_name = (p->name
226 : xasprintf ("%zu", me->arg_index));
227 char *actual = token_to_string (token);
229 actual = xstrdup ("<eof>");
230 char *expected = token_to_string (wanted);
231 msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
232 "in call to macro %s."),
233 actual, expected, param_name, me->macro->name);
238 return me_error (me);
242 me_enclose (struct macro_expander *me, const struct token *token)
246 const struct macro_param *p = &me->macro->params[me->arg_index];
247 if (token_equal (&p->enclose[0], token))
253 return me_expected (me, token, &p->enclose[0]);
257 me_keyword (struct macro_expander *me, const struct token *token)
259 if (token->type != T_ID)
260 return me_finished (me);
262 for (size_t i = 0; i < me->macro->n_params; i++)
264 const struct macro_param *p = &me->macro->params[i];
265 if (p->name && ss_equals_case (ss_cstr (p->name), token->string))
271 _("Argument %s multiply specified in call to macro %s."),
272 p->name, me->macro->name);
273 return me_error (me);
277 me->state = ME_EQUALS;
282 return me_finished (me);
286 me_equals (struct macro_expander *me, const struct token *token)
290 if (token->type == T_EQUALS)
296 const struct token equals = { .type = T_EQUALS };
297 return me_expected (me, token, &equals);
301 macro_expander_add (struct macro_expander *me, const struct token *token)
306 return me_add_start (me, token);
309 return me_add_arg (me, token);
312 return me_enclose (me, token);
315 return me_keyword (me, token);
318 return me_equals (me, token);