#include <uniwidth.h>
#include "language/command.h"
+#include "language/lexer/macro.h"
#include "language/lexer/scan.h"
#include "language/lexer/segment.h"
#include "language/lexer/token.h"
#include "libpspp/i18n.h"
#include "libpspp/ll.h"
#include "libpspp/message.h"
-#include "libpspp/macro.h"
#include "libpspp/misc.h"
#include "libpspp/str.h"
#include "libpspp/u8-istream.h"
size_t token_len; /* Length of source for token in bytes. */
size_t line_pos; /* Start of line containing token_pos. */
int first_line; /* Line number at token_pos. */
+ bool from_macro;
};
/* A source of tokens, corresponding to a syntax file.
struct lex_token *tokens; /* Lookahead tokens for parser. */
};
-static struct lex_source *lex_source_create (struct lex_reader *);
+static struct lex_source *lex_source_create (struct lexer *,
+ struct lex_reader *);
static void lex_source_destroy (struct lex_source *);
/* Lexer. */
struct lexer
{
struct ll_list sources; /* Contains "struct lex_source"s. */
+ struct macro_set *macros;
};
static struct lex_source *lex_source__ (const struct lexer *);
struct lexer *
lex_create (void)
{
- struct lexer *lexer = xzalloc (sizeof *lexer);
- ll_init (&lexer->sources);
+ struct lexer *lexer = xmalloc (sizeof *lexer);
+ *lexer = (struct lexer) {
+ .sources = LL_INITIALIZER (lexer->sources),
+ .macros = macro_set_create (),
+ };
return lexer;
}
ll_for_each_safe (source, next, struct lex_source, ll, &lexer->sources)
lex_source_destroy (source);
+ macro_set_destroy (lexer->macros);
free (lexer);
}
}
+/* Adds M to LEXER's set of macros. M replaces any existing macro with the
+ same name. Takes ownership of M. */
+void
+lex_define_macro (struct lexer *lexer, struct macro *m)
+{
+ macro_set_add (lexer->macros, m);
+}
+
/* Inserts READER into LEXER so that the next token read by LEXER comes from
READER. Before the caller, LEXER must either be empty or at a T_ENDCMD
token. */
}
}
-static const struct token *
+static const struct lex_token *
lex_source_front (const struct lex_source *src)
{
- return &src->tokens[deque_front (&src->deque, 0)].token;
+ return &src->tokens[deque_front (&src->deque, 0)];
}
static const struct lex_token *
{
if (!deque_is_empty (&src->deque))
{
- const struct token *front = lex_source_front (src);
- if (front->type == T_STOP || front->type == T_ENDCMD)
+ const struct lex_token *front = lex_source_front (src);
+ if (front->token.type == T_STOP || front->token.type == T_ENDCMD)
return front;
}
token = lex_source_next__ (src, n0);
if (token->token.type == T_ENDCMD)
ds_put_cstr (&s, _("Syntax error at end of command"));
+ else if (token->from_macro)
+ {
+ /* XXX this isn't ideal, we should get the actual syntax */
+ char *syntax = token_to_string (&token->token);
+ if (syntax)
+ ds_put_format (&s, _("Syntax error at `%s'"), syntax);
+ else
+ ds_put_cstr (&s, _("Syntax error"));
+ free (syntax);
+ }
else
{
struct substring syntax = lex_source_get_syntax__ (src, n0, n1);
static bool
lex_source_get__ (struct lex_source *src)
{
- for (;;) (
- if (src->eof)
- return false;
- else if (lex_source_try_get (src))
- return true;
+ for (;;)
+ {
+ if (src->eof)
+ return false;
+ else if (lex_source_try_get (src))
+ return true;
}
}
{
struct lex_source *src = CONST_CAST (struct lex_source *, src_);
- if (!lex_source_get (src))
+ size_t old_count = deque_count (&src->deque);
+ if (!lex_source_get__ (src))
return false;
- struct macro_expander *me = macro_expander_create (src->lexer,
- lex_source_front (src));
- if (!me)
- return true;
-
- for (;;)
+ struct macro_expander *me;
+ int retval = macro_expander_create (src->lexer->macros,
+ &lex_source_front (src)->token, &me);
+ while (!retval)
{
- if (!lex_source_get (src))
+ if (!lex_source_get__ (src))
{
/* This should not be reachable because we always get a T_STOP at the
end of input and the macro_expander should always terminate
NOT_REACHED ();
}
- int retval = macro_expander_add (me, lex_source_front (src));
-
+ retval = macro_expander_add (me, &lex_source_front (src)->token);
+ }
+ if (retval < 0)
+ {
+ /* XXX handle case where there's a macro invocation starting from some
+ later token we've already obtained */
+ macro_expander_destroy (me);
+ return true;
+ }
+
+ /* XXX handle case where the macro invocation doesn't use all the tokens */
+ while (deque_count (&src->deque) > old_count)
+ lex_source_pop_front (src);
+ struct tokens expansion = { .tokens = NULL };
+ macro_expander_get_expansion (me, &expansion);
+ macro_expander_destroy (me);
+
+ for (size_t i = 0; i < expansion.n; i++)
+ {
+ *lex_push_token__ (src) = (struct lex_token) {
+ .token = expansion.tokens[i],
+ .from_macro = true,
+ /* XXX the rest */
+ };
}
-
+ free (expansion.tokens);
+ return true;
}
\f
static void