}
if (loop->last_expr == NULL)
{
- lex_sbc_missing ("TO");
+ lex_sbc_missing (lexer, "TO");
return false;
}
{
if (command == COMB_UPDATE)
{
- lex_sbc_missing ("BY");
+ lex_sbc_missing (lexer, "BY");
goto error;
}
if (n_tables)
struct fh_properties properties = *fh_default_properties ();
if (file_name == NULL)
{
- lex_sbc_missing ("NAME");
+ lex_sbc_missing (lexer, "NAME");
goto exit;
}
if (fh == NULL)
{
- lex_sbc_missing ("FILE");
+ lex_sbc_missing (lexer, "FILE");
goto error;
}
if (type == 0)
{
- lex_sbc_missing ("TYPE");
+ lex_sbc_missing (lexer, "TYPE");
goto error;
}
else if (handle == NULL)
{
- lex_sbc_missing ("OUTFILE");
+ lex_sbc_missing (lexer, "OUTFILE");
goto error;
}
else if (!replace && fn_exists (handle))
if (h == NULL)
{
- lex_sbc_missing ("FILE");
+ lex_sbc_missing (lexer, "FILE");
goto error;
}
command has been parsed, and so lex_error() would always report "Syntax
error at end of command", which does not help the user find the error. */
void
-lex_sbc_missing (const char *sbc)
+lex_sbc_missing (struct lexer *lexer, const char *sbc)
{
- msg (SE, _("Required subcommand %s was not specified."), sbc);
+ lex_ofs_error (lexer, 0, lex_max_ofs (lexer),
+ _("Required subcommand %s was not specified."), sbc);
}
/* Reports an error to the effect that specification SPEC may only be specified
return src ? src->parse_ofs : 0;
}
+/* Returns the offset of the last token in the current command. */
+int
+lex_max_ofs (const struct lexer *lexer)
+{
+ struct lex_source *src = lex_source__ (lexer);
+ if (!src)
+ return 0;
+
+ int ofs = MAX (1, src->n_parse) - 1;
+ for (;;)
+ {
+ enum token_type type = lex_source_ofs__ (src, ofs)->token.type;
+ if (type == T_ENDCMD || type == T_STOP)
+ return ofs;
+
+ ofs++;
+ }
+}
+
/* Returns the token within LEXER's current command with offset OFS. Use
lex_ofs() to find out the offset of the current token. */
const struct token *
/* Looking at the current command, including lookahead and lookbehind. */
int lex_ofs (const struct lexer *);
+int lex_max_ofs (const struct lexer *);
const struct token *lex_ofs_token (const struct lexer *, int ofs);
struct msg_location *lex_ofs_location (const struct lexer *, int ofs0, int ofs1);
struct msg_point lex_ofs_start_point (const struct lexer *, int ofs);
void lex_error_expecting_array (struct lexer *, const char **, size_t n);
void lex_sbc_only_once (struct lexer *, const char *);
-void lex_sbc_missing (const char *);
+void lex_sbc_missing (struct lexer *, const char *);
void lex_spec_only_once (struct lexer *, const char *subcommand,
const char *specification);
fh = fh_ref (s->prev_save_file);
else
{
- lex_sbc_missing ("OUTFILE");
+ lex_sbc_missing (s->lexer, "OUTFILE");
goto error;
}
}
if (!read->c1)
{
- lex_sbc_missing ("FIELD");
+ lex_sbc_missing (s->lexer, "FIELD");
goto error;
}
fh = fh_ref (s->prev_read_file);
else
{
- lex_sbc_missing ("FILE");
+ lex_sbc_missing (s->lexer, "FILE");
goto error;
}
}
if (!write->c1)
{
- lex_sbc_missing ("FIELD");
+ lex_sbc_missing (s->lexer, "FIELD");
goto error;
}
fh = fh_ref (s->prev_write_file);
else
{
- lex_sbc_missing ("OUTFILE");
+ lex_sbc_missing (s->lexer, "OUTFILE");
goto error;
}
}
}
if (!msave->rowtype)
{
- lex_sbc_missing ("TYPE");
+ lex_sbc_missing (s->lexer, "TYPE");
goto error;
}
}
if (!common->outfile)
{
- lex_sbc_missing ("OUTFILE");
+ lex_sbc_missing (s->lexer, "OUTFILE");
goto error;
}
common->location = lex_ofs_location (s->lexer, start_ofs,
if (tt.n_vars == 0 && tt.mode != MODE_PAIRED)
{
- lex_sbc_missing ("VARIABLES");
+ lex_sbc_missing (lexer, "VARIABLES");
goto exit;
}
19 | LOOP A=1 BY 5 TO 10 BY !.
| ^~
-loop.sps:21: error: LOOP: Required subcommand TO was not specified.
+loop.sps:21.1-21.9: error: LOOP: Required subcommand TO was not specified.
+ 21 | LOOP A=1.
+ | ^~~~~~~~~
loop.sps:23.6: error: LOOP: Syntax error.
23 | LOOP !.
17 | READ x/!.
| ^
-matrix.sps:18: error: READ: Required subcommand FIELD was not specified.
+matrix.sps:18.1-18.7: error: READ: Required subcommand FIELD was not specified.
+ 18 | READ x.
+ | ^~~~~~~
matrix.sps:19: error: READ: SIZE is required for reading data into a full
matrix (as opposed to a submatrix).
19 | READ x/FIELD=1 TO 10.
| ^
-matrix.sps:20: error: READ: Required subcommand FILE was not specified.
+matrix.sps:20.1-20.32: error: READ: Required subcommand FILE was not specified.
+ 20 | READ x/FIELD=1 TO 10/SIZE={1,2}.
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
matrix.sps:21: error: READ: 15 repetitions cannot fit in record width 10.
14 | WRITE 1/!.
| ^
-matrix.sps:15: error: WRITE: Required subcommand FIELD was not specified.
+matrix.sps:15.1-15.8: error: WRITE: Required subcommand FIELD was not
+specified.
+ 15 | WRITE 1.
+ | ^~~~~~~~
-matrix.sps:16: error: WRITE: Required subcommand OUTFILE was not specified.
+matrix.sps:16.1-16.22: error: WRITE: Required subcommand OUTFILE was not
+specified.
+ 16 | WRITE 1/FIELD=1 TO 10.
+ | ^~~~~~~~~~~~~~~~~~~~~~
matrix.sps:17.51-17.55: note: WRITE: This syntax designates the number of
repetitions.
6 | SAVE 1/!.
| ^
-matrix.sps:7: error: SAVE: Required subcommand OUTFILE was not specified.
+matrix.sps:7.1-7.7: error: SAVE: Required subcommand OUTFILE was not specified.
+ 7 | SAVE 1.
+ | ^~~~~~~
matrix.sps:8: warning: SAVE: VARIABLES and NAMES both specified; ignoring
NAMES.
10 | MSAVE 1/!.
| ^
-matrix.sps:11: error: MSAVE: Required subcommand TYPE was not specified.
+matrix.sps:11.1-11.8: error: MSAVE: Required subcommand TYPE was not specified.
+ 11 | MSAVE 1.
+ | ^~~~~~~~
matrix.sps:12.25: error: MSAVE: FNAMES requires FACTOR.
12 | MSAVE 1/TYPE=COV/FNAMES=x.
13 | MSAVE 1/TYPE=COV/SNAMES=x.
| ^
-matrix.sps:14: error: MSAVE: Required subcommand OUTFILE was not specified.
+matrix.sps:14.1-14.17: error: MSAVE: Required subcommand OUTFILE was not
+specified.
+ 14 | MSAVE 1/TYPE=COV.
+ | ^~~~~~~~~~~~~~~~~
matrix.sps:20: error: MSAVE: OUTFILE must name the same file on each MSAVE
within a single MATRIX command.
T-TEST /groups=id(3) .
])
AT_CHECK([pspp -O format=csv t-test.sps], [1], [dnl
-t-test.sps:11: error: T-TEST: Required subcommand VARIABLES was not specified.
+"t-test.sps:11.1-11.21: error: T-TEST: Required subcommand VARIABLES was not specified.
+ 11 | T-TEST /testval=2.0 .
+ | ^~~~~~~~~~~~~~~~~~~~~"
-t-test.sps:12: error: T-TEST: Required subcommand VARIABLES was not specified.
+"t-test.sps:12.1-12.22: error: T-TEST: Required subcommand VARIABLES was not specified.
+ 12 | T-TEST /groups=id(3) .
+ | ^~~~~~~~~~~~~~~~~~~~~~"
])
AT_CLEANUP