}
}
+static bool
+parse_macro_body (struct lexer *lexer, struct macro_tokens *mts)
+{
+ *mts = (struct macro_tokens) { .n = 0 };
+ struct string body = DS_EMPTY_INITIALIZER;
+ struct msg_point start = lex_ofs_start_point (lexer, lex_ofs (lexer));
+ while (!match_macro_id (lexer, "!ENDDEFINE"))
+ {
+ if (lex_token (lexer) != T_STRING)
+ {
+ lex_error (lexer,
+ _("Syntax error expecting macro body or !ENDDEFINE."));
+ ds_destroy (&body);
+ return false;
+ }
+
+ ds_put_substring (&body, lex_tokss (lexer));
+ ds_put_byte (&body, '\n');
+ lex_get (lexer);
+ }
+
+ struct segmenter segmenter = segmenter_init (lex_get_syntax_mode (lexer),
+ true);
+ struct substring p = body.ss;
+ bool ok = true;
+ while (p.length > 0)
+ {
+ enum segment_type type;
+ int seg_len = segmenter_push (&segmenter, p.string,
+ p.length, true, &type);
+ assert (seg_len >= 0);
+
+ struct macro_token mt = {
+ .token = { .type = T_STOP },
+ .syntax = ss_head (p, seg_len),
+ };
+ enum tokenize_result result
+ = token_from_segment (type, mt.syntax, &mt.token);
+ ss_advance (&p, seg_len);
+
+ switch (result)
+ {
+ case TOKENIZE_EMPTY:
+ break;
+
+ case TOKENIZE_TOKEN:
+ macro_tokens_add (mts, &mt);
+ break;
+
+ case TOKENIZE_ERROR:
+ size_t start_offset = mt.syntax.string - body.ss.string;
+ size_t end_offset = start_offset + (mt.syntax.length ? mt.syntax.length - 1 : 0);
+
+ const struct msg_location loc = {
+ .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)),
+ .start = msg_point_advance (start, ss_buffer (body.ss.string, start_offset)),
+ .end = msg_point_advance (start, ss_buffer (body.ss.string, end_offset)),
+ .src = CONST_CAST (struct lex_source *, lex_source (lexer)),
+ };
+ msg_at (SE, &loc, "%s", mt.token.string.string);
+ intern_unref (loc.file_name);
+
+ ok = false;
+ break;
+ }
+
+ token_uninit (&mt.token);
+ }
+ ds_destroy (&body);
+ return ok;
+}
+
int
cmd_define (struct lexer *lexer, struct dataset *ds UNUSED)
{
goto error;
}
- struct string body = DS_EMPTY_INITIALIZER;
- while (!match_macro_id (lexer, "!ENDDEFINE"))
- {
- if (lex_token (lexer) != T_STRING)
- {
- lex_error (lexer,
- _("Syntax error expecting macro body or !ENDDEFINE."));
- ds_destroy (&body);
- goto error;
- }
-
- ds_put_substring (&body, lex_tokss (lexer));
- ds_put_byte (&body, '\n');
- lex_get (lexer);
- }
+ if (!parse_macro_body (lexer, &m->body))
+ goto error;
struct msg_point macro_end = lex_ofs_end_point (lexer, lex_ofs (lexer) - 1);
m->location = xmalloc (sizeof *m->location);
.end = { .line = macro_end.line },
};
- macro_tokens_from_string (&m->body, body.ss, lex_get_syntax_mode (lexer));
- ds_destroy (&body);
-
lex_define_macro (lexer, m);
return CMD_SUCCESS;
: ll_data (ll_head (&lexer->sources), struct lex_source, ll));
}
+const struct lex_source *
+lex_source (const struct lexer *lexer)
+{
+ return lex_source__ (lexer);
+}
+
/* Returns the text of the syntax in SRC for tokens with offsets OFS0 through
OFS1 in the current command, inclusive. (For example, if OFS0 and OFS1 are
both zero, this requests the syntax for the first token in the current
const char *lex_get_file_name (const struct lexer *);
struct msg_location *lex_get_location (const struct lexer *, int n0, int n1);
const char *lex_get_encoding (const struct lexer *);
+const struct lex_source *lex_source (const struct lexer *);
/* Issuing errors and warnings. */
void lex_error (struct lexer *, const char *, ...) PRINTF_FORMAT (2, 3);
macro_token_copy (macro_tokens_add_uninit (mts), mt);
}
-/* Tokenizes SRC according to MODE and appends the tokens to MTS. Uses STACK,
- if nonull, for error reporting. */
+/* Tokenizes SRC according to MODE and appends the tokens to MTS, using STACK
+ for error reporting. */
static void
-macro_tokens_from_string__ (struct macro_tokens *mts, const struct substring src,
- enum segmenter_mode mode,
- const struct macro_expansion_stack *stack)
+macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
+ enum segmenter_mode mode,
+ const struct macro_expansion_stack *stack)
{
struct segmenter segmenter = segmenter_init (mode, true);
struct substring body = src;
}
}
-/* Tokenizes SRC according to MODE and appends the tokens to MTS. */
-void
-macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
- enum segmenter_mode mode)
-{
- macro_tokens_from_string__ (mts, src, mode, NULL);
-}
-
void
macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
{
me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
- me->stack);
+ macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode,
+ me->stack);
if (mts.n > 0)
ds_put_substring (output, mts.mts[0].syntax);
macro_tokens_uninit (&mts);
me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
- me->stack);
+ macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode,
+ me->stack);
if (mts.n > 1)
{
struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
case MF_EVAL:
{
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
- me->segmenter_mode, me->stack);
+ macro_tokens_from_string (&mts, ss_cstr (args.strings[0]),
+ me->segmenter_mode, me->stack);
struct macro_tokens exp = { .n = 0 };
struct macro_expansion_stack stack = {
.name = "!EVAL",
return false;
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, me->stack);
+ macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode, me->stack);
if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
{
macro_error (me->stack, mts.n > 0 ? &mts.mts[0] : NULL,
return 0;
struct macro_tokens items = { .n = 0 };
- macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode,
- me->stack);
+ macro_tokens_from_string (&items, ss_cstr (list), me->segmenter_mode,
+ me->stack);
free (list);
const struct macro_token *do_end = find_doend (subme.stack, p, end);
token->string.length);
if (var)
{
- macro_tokens_from_string__ (exp, ss_cstr (var),
- me->segmenter_mode, me->stack);
+ macro_tokens_from_string (exp, ss_cstr (var),
+ me->segmenter_mode, me->stack);
return true;
}
size_t n_function = expand_macro_function (me, mts, n, &function_output);
if (n_function)
{
- macro_tokens_from_string__ (exp, function_output.ss,
- me->segmenter_mode, me->stack);
+ macro_tokens_from_string (exp, function_output.ss,
+ me->segmenter_mode, me->stack);
ds_destroy (&function_output);
return n_function;
struct macro_token *macro_tokens_add_uninit (struct macro_tokens *);
void macro_tokens_add (struct macro_tokens *, const struct macro_token *);
-void macro_tokens_from_string (struct macro_tokens *, const struct substring,
- enum segmenter_mode);
-
void macro_tokens_to_syntax (struct macro_tokens *, struct string *,
size_t *ofs, size_t *len);
msg_handler = *handler;
}
\f
+/* msg_point. */
+
+/* Takes POINT, adds to it the syntax in SYNTAX, incrementing the line number
+ for each new-line in SYNTAX and the column number for each column, and
+ returns the result. */
+struct msg_point
+msg_point_advance (struct msg_point point, struct substring syntax)
+{
+ for (;;)
+ {
+ size_t newline = ss_find_byte (syntax, '\n');
+ if (newline == SIZE_MAX)
+ break;
+ point.line++;
+ point.column = 1;
+ ss_advance (&syntax, newline + 1);
+ }
+
+ point.column += ss_utf8_count_columns (syntax);
+ return point;
+}
+\f
/* msg_location. */
void
#include "libpspp/compiler.h"
struct string;
+struct substring;
/* What kind of message is this? */
enum msg_category
int column;
};
+struct msg_point msg_point_advance (struct msg_point, struct substring);
+
/* Location of the cause of an error. */
struct msg_location
{
!ENDDEFINE.
])
AT_CHECK([pspp define.sps], [1], [dnl
-define.sps:3: error: DEFINE: String of hex digits has 3 characters, which is
-not a multiple of 2.
+define.sps:2.1-2.6: error: DEFINE: String of hex digits has 3 characters, which
+is not a multiple of 2.
+ 2 | x'123'
+ | ^~~~~~
])
AT_CLEANUP