From 72c9c6a2f92e94779b2e55d0726568090411871c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 29 Aug 2022 10:02:48 -0700 Subject: [PATCH] Improve error messages by citing syntax in more of them. A while back, PSPP gained the ability to cite particular tokens in diagnostics, but few of the existing messages were enhanced to do so. This commit adds this to several more of them, in particular all of the messages that used lex_error() and variations. --- doc/matrices.texi | 2 +- src/data/dict-class.h | 8 +- src/data/por-file-reader.c | 2 +- src/language/command.c | 113 +-- src/language/control/define.c | 27 +- src/language/control/do-if.c | 8 +- src/language/control/loop.c | 4 +- src/language/control/repeat.c | 8 +- src/language/control/temporary.c | 7 +- src/language/data-io/combine-files.c | 30 +- src/language/data-io/data-list.c | 16 +- src/language/data-io/data-reader.c | 5 +- src/language/data-io/dataset.c | 2 +- src/language/data-io/file-handle.c | 32 +- src/language/data-io/get-data.c | 29 +- src/language/data-io/inpt-pgm.c | 2 +- src/language/data-io/list.c | 1 - src/language/data-io/matrix-data.c | 13 +- src/language/data-io/placement-parser.c | 46 +- src/language/data-io/print-space.c | 2 +- src/language/data-io/print.c | 3 +- src/language/data-io/save-translate.c | 12 +- src/language/data-io/save.c | 4 +- src/language/data-io/trim.c | 2 +- src/language/dictionary/delete-variables.c | 8 +- src/language/dictionary/missing-values.c | 6 +- src/language/dictionary/modify-variables.c | 34 +- src/language/dictionary/mrsets.c | 6 +- src/language/dictionary/numeric.c | 10 +- src/language/dictionary/rename-variables.c | 6 +- src/language/dictionary/sys-file-info.c | 2 +- src/language/dictionary/value-labels.c | 4 +- src/language/dictionary/vector.c | 16 +- src/language/dictionary/weight.c | 6 +- src/language/expressions/evaluate.c | 6 +- src/language/expressions/parse.c | 7 +- src/language/lexer/format-parser.c | 12 +- src/language/lexer/lexer.c | 383 +++++----- src/language/lexer/lexer.h | 25 +- src/language/lexer/macro.c | 6 +- src/language/lexer/value-parser.c | 19 +- src/language/lexer/variable-parser.c | 201 +++-- src/language/lexer/variable-parser.h | 11 +- src/language/stats/aggregate.c | 65 +- src/language/stats/autorecode.c | 2 +- src/language/stats/crosstabs.c | 10 +- src/language/stats/ctables.c | 160 ++-- src/language/stats/descriptives.c | 22 +- src/language/stats/examine.c | 2 +- src/language/stats/flip.c | 6 +- src/language/stats/graph.c | 3 +- src/language/stats/matrix.c | 249 +++++-- src/language/stats/npar.c | 9 +- src/language/stats/oneway.c | 5 +- src/language/stats/quick-cluster.c | 3 +- src/language/stats/rank.c | 6 +- src/language/stats/regression.c | 20 +- src/language/stats/reliability.c | 8 +- src/language/stats/t-test-parser.c | 15 +- src/language/tests/float-format.c | 2 +- src/language/tests/moments-test.c | 2 +- src/language/utilities/cd.c | 4 +- src/language/utilities/date.c | 2 +- src/language/utilities/host.c | 22 +- src/language/utilities/permissions.c | 14 +- src/language/utilities/set.c | 84 +-- src/language/xforms/compute.c | 3 +- src/language/xforms/count.c | 2 +- src/language/xforms/recode.c | 21 +- src/language/xforms/sample.c | 8 +- src/language/xforms/select-if.c | 26 +- src/libpspp/message.h | 2 +- tests/language/command.at | 36 +- tests/language/control/define.at | 366 +++++++-- tests/language/control/do-if.at | 14 +- tests/language/control/do-repeat.at | 2 +- tests/language/control/loop.at | 50 +- tests/language/data-io/data-list.at | 8 +- tests/language/data-io/dataset.at | 8 +- tests/language/data-io/get-data-txt.at | 20 +- tests/language/data-io/inpt-pgm.at | 10 +- tests/language/data-io/matrix-data.at | 56 +- tests/language/data-io/mconvert.at | 4 +- tests/language/data-io/print.at | 4 +- tests/language/dictionary/formats.at | 8 +- tests/language/dictionary/missing-values.at | 16 +- tests/language/dictionary/mrsets.at | 38 +- tests/language/dictionary/rename-variables.at | 4 +- tests/language/dictionary/value-labels.at | 4 +- tests/language/expressions/evaluate.at | 36 +- tests/language/expressions/parse.at | 37 +- tests/language/lexer/lexer.at | 62 +- tests/language/stats/aggregate.at | 206 ++--- tests/language/stats/ctables.at | 705 +++++++++++------- tests/language/stats/descriptives.at | 13 +- tests/language/stats/flip.at | 4 +- tests/language/stats/matrix.at | 523 +++++++++---- tests/language/stats/quick-cluster.at | 4 +- tests/language/stats/rank.at | 16 +- tests/language/stats/regression.at | 4 +- tests/language/stats/reliability.at | 10 +- tests/language/stats/t-test.at | 4 +- tests/language/utilities/host.at | 4 +- tests/language/utilities/insert.at | 36 +- tests/language/utilities/permissions.at | 4 +- tests/output/ascii.at | 6 +- tests/output/pivot-table-test.c | 4 +- utilities/pspp-convert.c | 2 +- 108 files changed, 2799 insertions(+), 1452 deletions(-) diff --git a/doc/matrices.texi b/doc/matrices.texi index 58dea2f31b..f366e5fc79 100644 --- a/doc/matrices.texi +++ b/doc/matrices.texi @@ -2184,7 +2184,7 @@ with the given @i{width}. The input area must be a multiple of @code{F@i{width}.0} format. @item -@code{FORMAT=@i{count}F} divides the input area into @i{count} +@code{FORMAT="@i{count}F"} divides the input area into integer @i{count} equal-width fields per line. The input area must be a multiple of @i{count} columns wide. Another format type may be substituted for @code{F}. diff --git a/src/data/dict-class.h b/src/data/dict-class.h index e3872e81c0..807a107f63 100644 --- a/src/data/dict-class.h +++ b/src/data/dict-class.h @@ -30,10 +30,10 @@ masks. */ enum dict_class { - DC_ORDINARY = 0x0001, /* Ordinary identifier. */ - DC_SYSTEM = 0x0002, /* System variable. */ - DC_SCRATCH = 0x0004, /* Scratch variable. */ - DC_ALL = 0x0007 /* All of the above. */ + DC_ORDINARY = 1 << 0, /* Ordinary identifier. */ + DC_SYSTEM = 1 << 1, /* System variable. */ + DC_SCRATCH = 1 << 2, /* Scratch variable. */ +#define DC_ALL (DC_ORDINARY | DC_SYSTEM | DC_SCRATCH) }; enum dict_class dict_class_from_id (const char *name); diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 94a2faf33b..8cea15e749 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -215,7 +215,7 @@ advance (struct pfm_reader *r) r->line_length = 0; } if (c == EOF) - error (r, _("unexpected end of file")); + error (r, _("Unexpected end of file")); if (r->trans != NULL) c = r->trans[c]; diff --git a/src/language/command.c b/src/language/command.c index bffd13ebb0..ab5bab904a 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -127,7 +127,7 @@ static const struct command commands[] = static const size_t n_commands = sizeof commands / sizeof *commands; static bool in_correct_state (const struct command *, enum cmd_state); -static void report_state_mismatch (const struct command *, enum cmd_state); +static char *report_state_mismatch (const struct command *, enum cmd_state); static void set_completion_state (enum cmd_state); /* Command parser. */ @@ -205,25 +205,32 @@ do_parse_command (struct lexer *lexer, utf8_to_title (command->name), utf8_to_title (command->name))); + int end = n_tokens - 1; if (command->function == NULL) { - msg (SE, _("%s is not yet implemented."), command->name); + lex_ofs_error (lexer, 0, end, _("%s is not yet implemented."), + command->name); result = CMD_NOT_IMPLEMENTED; } else if ((command->flags & F_TESTING) && !settings_get_testing_mode ()) { - msg (SE, _("%s may be used only in testing mode."), command->name); + lex_ofs_error (lexer, 0, end, _("%s may be used only in testing mode."), + command->name); result = CMD_FAILURE; } else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED) { - msg (SE, _("%s may be used only in enhanced syntax mode."), - command->name); + lex_ofs_error (lexer, 0, end, + _("%s may be used only in enhanced syntax mode."), + command->name); result = CMD_FAILURE; } else if (!in_correct_state (command, state)) { - report_state_mismatch (command, state); + char *message = report_state_mismatch (command, state); + lex_ofs_error (lexer, 0, end, "%s", message); + free (message); + result = CMD_FAILURE; } else @@ -342,17 +349,18 @@ parse_command_name (struct lexer *lexer, int *n_tokens) ds_truncate (&s, ds_length (&s) - 2); } + *n_tokens = (word + 1) + missing_words; if (command == NULL) { if (ds_is_empty (&s)) - lex_error (lexer, _("expecting command name")); + lex_error (lexer, _("Syntax error expecting command name.")); else - msg (SE, _("Unknown command `%s'."), ds_cstr (&s)); + lex_ofs_error (lexer, 0, *n_tokens - 1, + _("Unknown command `%s'."), ds_cstr (&s)); } ds_destroy (&s); - *n_tokens = (word + 1) + missing_words; return command; } @@ -364,9 +372,9 @@ in_correct_state (const struct command *command, enum cmd_state state) return command->states & (1 << state); } -/* Emits an appropriate error message for trying to invoke +/* Returns an appropriate error message for trying to invoke COMMAND in STATE. */ -static void +static char * report_state_mismatch (const struct command *command, enum cmd_state state) { assert (!in_correct_state (command, state)); @@ -380,56 +388,49 @@ report_state_mismatch (const struct command *command, enum cmd_state state) { /* One allowed state. */ case S_INITIAL: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined."), command->name); - break; + return xasprintf (_("%s is allowed only before the active dataset has " + "been defined."), command->name); case S_DATA: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined."), command->name); - break; + return xasprintf (_("%s is allowed only after the active dataset has " + "been defined."), command->name); case S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only inside %s."), + command->name, "INPUT PROGRAM"); case S_FILE_TYPE: - msg (SE, _("%s is allowed only inside %s."), command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only inside %s."), command->name, "FILE TYPE"); /* Two allowed states. */ case S_INITIAL | S_DATA: NOT_REACHED (); case S_INITIAL | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined or inside %s."), + command->name, "INPUT PROGRAM"); case S_INITIAL | S_FILE_TYPE: - msg (SE, _("%s is allowed only before the active dataset has been defined or inside %s."), - command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined or inside %s."), + command->name, "FILE TYPE"); case S_DATA | S_INPUT_PROGRAM: - msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is allowed only after the active dataset " + "has been defined or inside %s."), + command->name, "INPUT PROGRAM"); case S_DATA | S_FILE_TYPE: - msg (SE, _("%s is allowed only after the active dataset has been defined or inside %s."), - command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only after the active dataset " + "has been defined or inside %s."), + command->name, "FILE TYPE"); case S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only inside %s or inside %s."), command->name, - "INPUT PROGRAM", "FILE TYPE"); - break; + return xasprintf (_("%s is allowed only inside %s or inside %s."), + command->name, "INPUT PROGRAM", "FILE TYPE"); /* Three allowed states. */ case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only after the active dataset has " - "been defined, inside INPUT PROGRAM, or inside " - "FILE TYPE."), command->name); - break; + return xasprintf (_("%s is allowed only after the active dataset has " + "been defined, inside INPUT PROGRAM, or inside " + "FILE TYPE."), command->name); case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE: - msg (SE, _("%s is allowed only before the active dataset has " - "been defined, inside INPUT PROGRAM, or inside " - "FILE TYPE."), command->name); - break; + return xasprintf (_("%s is allowed only before the active dataset " + "has been defined, inside INPUT PROGRAM, or " + "inside FILE TYPE."), command->name); case S_INITIAL | S_DATA | S_FILE_TYPE: NOT_REACHED (); case S_INITIAL | S_DATA | S_INPUT_PROGRAM: @@ -445,32 +446,32 @@ report_state_mismatch (const struct command *command, enum cmd_state state) break; case CMD_STATE_INPUT_PROGRAM: - msg (SE, _("%s is not allowed inside %s."), - command->name, "INPUT PROGRAM"); - break; + return xasprintf (_("%s is not allowed inside %s."), + command->name, "INPUT PROGRAM"); case CMD_STATE_FILE_TYPE: - msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); - break; + return xasprintf (_("%s is not allowed inside %s."), + command->name, "FILE TYPE"); case CMD_STATE_NESTED_DATA: case CMD_STATE_NESTED_INPUT_PROGRAM: switch ((int) command->states & S_NESTED_ANY) { case 0: - msg (SE, _("%s is not allowed inside DO IF or LOOP."), command->name); - break; + return xasprintf (_("%s is not allowed inside DO IF or LOOP."), + command->name); case S_NESTED_DATA: - msg (SE, _("In INPUT PROGRAM, " - "%s is not allowed inside DO IF or LOOP."), command->name); - break; + return xasprintf (_("In INPUT PROGRAM, " + "%s is not allowed inside DO IF or LOOP."), + command->name); default: NOT_REACHED (); } - break; } + + NOT_REACHED (); } /* Command name completion. */ diff --git a/src/language/control/define.c b/src/language/control/define.c index e1d9622ff4..27f5093504 100644 --- a/src/language/control/define.c +++ b/src/language/control/define.c @@ -77,8 +77,9 @@ dup_arg_type (struct lexer *lexer, bool *saw_arg_type) { if (*saw_arg_type) { - lex_error (lexer, _("Only one of !TOKENS, !CHAREND, !ENCLOSE, or " - "!CMDEND is allowed.")); + lex_next_error (lexer, -1, -1, + _("Only one of !TOKENS, !CHAREND, !ENCLOSE, or " + "!CMDEND is allowed.")); return false; } else @@ -98,13 +99,13 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) macro-expanded. */ if (lex_token (lexer) != T_STRING) { - lex_error (lexer, _("expecting identifier")); + lex_error (lexer, _("Syntax error expecting identifier.")); return CMD_FAILURE; } const char *name = lex_tokcstr (lexer); if (!id_is_plausible (name + (name[0] == '!'), false)) { - lex_error (lexer, _("expecting identifier")); + lex_error (lexer, _("Syntax error expecting identifier.")); return CMD_FAILURE; } @@ -117,6 +118,7 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) goto error; size_t allocated_params = 0; + int keyword_ofs = 0; while (!lex_match (lexer, T_RPAREN)) { if (m->n_params >= allocated_params) @@ -132,8 +134,11 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { if (param_index > 0 && !m->params[param_index - 1].positional) { - lex_error (lexer, _("Positional parameters must precede " - "keyword parameters.")); + lex_next_error (lexer, -1, -1, + _("Positional parameters must precede " + "keyword parameters.")); + lex_ofs_msg (lexer, SN, keyword_ofs, keyword_ofs, + _("Here is a previous keyword parameter.")); goto error; } @@ -142,6 +147,8 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) } else { + if (keyword_ofs == 0) + keyword_ofs = lex_ofs (lexer); if (lex_token (lexer) == T_MACRO_ID) { lex_error (lexer, _("Keyword macro parameter must be named in " @@ -173,8 +180,9 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { if (saw_default) { - lex_error (lexer, - _("!DEFAULT is allowed only once per argument.")); + lex_next_error ( + lexer, -1, -1, + _("!DEFAULT is allowed only once per argument.")); goto error; } saw_default = true; @@ -267,7 +275,8 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { if (lex_token (lexer) != T_STRING) { - lex_error (lexer, _("Expecting macro body or !ENDDEFINE")); + lex_error (lexer, + _("Syntax error expecting macro body or !ENDDEFINE.")); ds_destroy (&body); goto error; } diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index 66c3e78e37..162118488c 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -62,10 +62,12 @@ start_clause (struct lexer *lexer, struct dataset *ds, && !do_if->clauses[do_if->n_clauses - 1].condition) { if (condition) - msg (SE, _("ELSE IF is not allowed following ELSE " - "within DO IF...END IF.")); + lex_ofs_error (lexer, 0, 1, + _("ELSE IF is not allowed following ELSE " + "within DO IF...END IF.")); else - msg (SE, _("Only one ELSE is allowed within DO IF...END IF.")); + lex_ofs_error (lexer, 0, 0, + _("Only one ELSE is allowed within DO IF...END IF.")); msg_at (SN, do_if->clauses[do_if->n_clauses - 1].location, _("This is the location of the previous ELSE clause.")); diff --git a/src/language/control/loop.c b/src/language/control/loop.c index dfc4db2e89..13af822546 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -163,7 +163,7 @@ parse_if_clause (struct lexer *lexer, struct dataset *ds, { if (*condition != NULL) { - lex_sbc_only_once ("IF"); + lex_sbc_only_once (lexer, "IF"); return false; } @@ -214,7 +214,7 @@ parse_index_clause (struct dataset *ds, struct lexer *lexer, if (*e != NULL) { - lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY"); + lex_sbc_only_once (lexer, e == &loop->last_expr ? "TO" : "BY"); return false; } *e = expr_parse (lexer, ds, VAL_NUMERIC); diff --git a/src/language/control/repeat.c b/src/language/control/repeat.c index 8876c8fb9e..cb6a6779fa 100644 --- a/src/language/control/repeat.c +++ b/src/language/control/repeat.c @@ -123,7 +123,8 @@ parse_specification (struct lexer *lexer, struct dictionary *dict, size_t name_len = strlen (name); if (find_dummy_var (dummies, name, name_len)) { - msg (SE, _("Dummy variable name `%s' is given twice."), name); + lex_error (lexer, _("Dummy variable name `%s' is given twice."), + name); goto error; } @@ -359,7 +360,7 @@ parse_numbers (struct lexer *lexer, struct dummy_var *dv) { if (!lex_is_integer (lexer)) { - msg (SE, _("Ranges may only have integer bounds.")); + lex_error (lexer, _("Ranges may only have integer bounds.")); return false; } @@ -373,7 +374,8 @@ parse_numbers (struct lexer *lexer, struct dummy_var *dv) long b = lex_integer (lexer); if (b < a) { - msg (SE, _("%ld TO %ld is an invalid range."), a, b); + lex_next_error (lexer, -2, 0, + _("%ld TO %ld is an invalid range."), a, b); return false; } lex_get (lexer); diff --git a/src/language/control/temporary.c b/src/language/control/temporary.c index c751441372..cdcfc76250 100644 --- a/src/language/control/temporary.c +++ b/src/language/control/temporary.c @@ -35,12 +35,13 @@ /* Parses the TEMPORARY command. */ int -cmd_temporary (struct lexer *lexer UNUSED, struct dataset *ds) +cmd_temporary (struct lexer *lexer, struct dataset *ds) { if (!proc_in_temporary_transformations (ds)) proc_start_temporary_transformations (ds); else - msg (SE, _("This command may only appear once between " - "procedures and procedure-like commands.")); + lex_ofs_error (lexer, 0, 0, + _("This command may only appear once between " + "procedures and procedure-like commands.")); return CMD_SUCCESS; } diff --git a/src/language/data-io/combine-files.c b/src/language/data-io/combine-files.c index 27e511595e..9f39cad775 100644 --- a/src/language/data-io/combine-files.c +++ b/src/language/data-io/combine-files.c @@ -211,15 +211,18 @@ combine_files (enum comb_command_type command, { if (!dataset_has_source (ds)) { - msg (SE, _("Cannot specify the active dataset since none " - "has been defined.")); + lex_next_error (lexer, -1, -1, + _("Cannot specify the active dataset since none " + "has been defined.")); goto error; } if (proc_make_temporary_transformations_permanent (ds)) - msg (SE, _("This command may not be used after TEMPORARY when " - "the active dataset is an input source. " - "Temporary transformations will be made permanent.")); + lex_next_error (lexer, -1, -1, + _("This command may not be used after TEMPORARY " + "when the active dataset is an input source. " + "Temporary transformations will be made " + "permanent.")); file->dict = dict_clone (dataset_dict (ds)); } @@ -244,16 +247,13 @@ combine_files (enum comb_command_type command, else if (lex_match_id (lexer, "IN")) { lex_match (lexer, T_EQUALS); - if (lex_token (lexer) != T_ID) - { - lex_error (lexer, NULL); - goto error; - } + if (!lex_force_id (lexer)) + goto error; if (file->in_name) { - msg (SE, _("Multiple IN subcommands for a single FILE or " - "TABLE.")); + lex_error (lexer, _("Multiple IN subcommands for a single FILE " + "or TABLE.")); goto error; } file->in_name = xstrdup (lex_tokcstr (lexer)); @@ -279,7 +279,7 @@ combine_files (enum comb_command_type command, if (saw_by) { - lex_sbc_only_once ("BY"); + lex_sbc_only_once (lexer, "BY"); goto error; } saw_by = true; @@ -325,7 +325,7 @@ combine_files (enum comb_command_type command, { if (first_name != NULL) { - lex_sbc_only_once ("FIRST"); + lex_sbc_only_once (lexer, "FIRST"); goto error; } @@ -339,7 +339,7 @@ combine_files (enum comb_command_type command, { if (last_name != NULL) { - lex_sbc_only_once ("LAST"); + lex_sbc_only_once (lexer, "LAST"); goto error; } diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index e464db1223..546e33f21e 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -120,7 +120,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds) { if (data_parser_get_records (parser) > 0) { - lex_sbc_only_once ("RECORDS"); + lex_sbc_only_once (lexer, "RECORDS"); goto error; } lex_match (lexer, T_EQUALS); @@ -143,12 +143,14 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds) { if (!in_input_program ()) { - msg (SE, _("The %s subcommand may only be used within %s."), "END", "INPUT PROGRAM"); + lex_next_error (lexer, -1, -1, + _("The %s subcommand may only be used within %s."), + "END", "INPUT PROGRAM"); goto error; } if (end) { - lex_sbc_only_once ("END"); + lex_sbc_only_once (lexer, "END"); goto error; } @@ -186,8 +188,9 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds) if (has_type) { - msg (SE, _("Only one of FIXED, FREE, or LIST may " - "be specified.")); + lex_next_error (lexer, -1, -1, + _("Only one of FIXED, FREE, or LIST may " + "be specified.")); goto error; } has_type = true; @@ -446,7 +449,8 @@ parse_free (struct lexer *lexer, struct dictionary *dict, return NULL; if (!fmt_from_name (type, &input.type)) { - msg (SE, _("Unknown format type `%s'."), type); + lex_next_error (lexer, -1, -1, + _("Unknown format type `%s'."), type); return NULL; } diff --git a/src/language/data-io/data-reader.c b/src/language/data-io/data-reader.c index 70ff2756df..d34067e819 100644 --- a/src/language/data-io/data-reader.c +++ b/src/language/data-io/data-reader.c @@ -742,8 +742,9 @@ cmd_begin_data (struct lexer *lexer, struct dataset *ds) if (!fh_is_locked (fh_inline_file (), FH_ACC_READ)) { - msg (SE, _("This command is not valid here since the current " - "input program does not access the inline file.")); + lex_ofs_error (lexer, 0, lex_ofs (lexer) - 1, + _("This command is not valid here since the current " + "input program does not access the inline file.")); return CMD_CASCADING_FAILURE; } lex_match (lexer, T_ENDCMD); diff --git a/src/language/data-io/dataset.c b/src/language/data-io/dataset.c index d0d4f0a8d3..a04fec5268 100644 --- a/src/language/data-io/dataset.c +++ b/src/language/data-io/dataset.c @@ -61,7 +61,7 @@ parse_dataset_name (struct lexer *lexer, struct session *session) if (ds != NULL) lex_get (lexer); else - msg (SE, _("There is no dataset named %s."), lex_tokcstr (lexer)); + lex_error (lexer, _("There is no dataset named %s."), lex_tokcstr (lexer)); return ds; } diff --git a/src/language/data-io/file-handle.c b/src/language/data-io/file-handle.c index 8dcc1028cf..01c56de196 100644 --- a/src/language/data-io/file-handle.c +++ b/src/language/data-io/file-handle.c @@ -58,9 +58,9 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) handle_name = xstrdup (lex_tokcstr (lexer)); if (fh_from_id (handle_name)) { - msg (SE, _("File handle %s is already defined. " - "Use %s before redefining a file handle."), - handle_name, "CLOSE FILE HANDLE"); + lex_error (lexer, _("File handle %s is already defined. " + "Use %s before redefining a file handle."), + handle_name, "CLOSE FILE HANDLE"); goto exit; } @@ -74,7 +74,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (file_name) { - lex_sbc_only_once ("NAME"); + lex_sbc_only_once (lexer, "NAME"); goto exit; } @@ -89,7 +89,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (lrecl) { - lex_sbc_only_once ("LRECL"); + lex_sbc_only_once (lexer, "LRECL"); goto exit; } @@ -103,7 +103,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (tabwidth >= 0) { - lex_sbc_only_once ("TABWIDTH"); + lex_sbc_only_once (lexer, "TABWIDTH"); goto exit; } lex_match (lexer, T_EQUALS); @@ -117,7 +117,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (mode != MODE_DEFAULT) { - lex_sbc_only_once ("MODE"); + lex_sbc_only_once (lexer, "MODE"); goto exit; } lex_match (lexer, T_EQUALS); @@ -140,7 +140,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (ends >= 0) { - lex_sbc_only_once ("ENDS"); + lex_sbc_only_once (lexer, "ENDS"); goto exit; } lex_match (lexer, T_EQUALS); @@ -159,7 +159,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (recform) { - lex_sbc_only_once ("RECFORM"); + lex_sbc_only_once (lexer, "RECFORM"); goto exit; } lex_match (lexer, T_EQUALS); @@ -181,7 +181,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) { if (encoding) { - lex_sbc_only_once ("ENCODING"); + lex_sbc_only_once (lexer, "ENCODING"); goto exit; } @@ -323,8 +323,6 @@ struct file_handle * fh_parse (struct lexer *lexer, enum fh_referent referent_mask, struct session *session) { - struct file_handle *handle; - if (session != NULL && lex_token (lexer) == T_ID) { struct dataset *ds; @@ -337,13 +335,16 @@ fh_parse (struct lexer *lexer, enum fh_referent referent_mask, } } + int start_ofs = lex_ofs (lexer); + struct file_handle *handle; if (lex_match_id (lexer, "INLINE")) handle = fh_inline_file (); else { if (lex_token (lexer) != T_ID && !lex_is_string (lexer)) { - lex_error (lexer, _("expecting a file name or handle name")); + lex_error (lexer, + _("Syntax error expecting a file name or handle name.")); return NULL; } @@ -358,8 +359,9 @@ fh_parse (struct lexer *lexer, enum fh_referent referent_mask, if (!(fh_get_referent (handle) & referent_mask)) { - msg (SE, _("Handle for %s not allowed here."), - referent_name (fh_get_referent (handle))); + lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1, + _("Handle for %s not allowed here."), + referent_name (fh_get_referent (handle))); fh_unref (handle); return NULL; } diff --git a/src/language/data-io/get-data.c b/src/language/data-io/get-data.c index 0c60bd3d63..e746e9a05c 100644 --- a/src/language/data-io/get-data.c +++ b/src/language/data-io/get-data.c @@ -124,8 +124,7 @@ cmd_get_data (struct lexer *lexer, struct dataset *ds) spreadsheet_unref (spreadsheet); } else - msg (SE, _("Unsupported TYPE %s."), tok); - + lex_error_expecting (lexer, "TXT", "PSQL", "GNM", "ODS"); error: destroy_spreadsheet_read_info (&opts); @@ -276,8 +275,7 @@ parse_spreadsheet (struct lexer *lexer, char **filename, } else { - msg (SE, _("%s must be followed by either \"%s\" or \"%s\"."), - "/SHEET", "NAME", "INDEX"); + lex_error_expecting (lexer, "NAME", "INDEX"); goto error; } } @@ -299,8 +297,7 @@ parse_spreadsheet (struct lexer *lexer, char **filename, } else { - msg (SE, _("%s must be followed by either \"%s\" or \"%s\"."), - "/CELLRANGE", "FULL", "RANGE"); + lex_error_expecting (lexer, "FULL", "RANGE"); goto error; } } @@ -318,8 +315,7 @@ parse_spreadsheet (struct lexer *lexer, char **filename, } else { - msg (SE, _("%s must be followed by either \"%s\" or \"%s\"."), - "/READNAMES", "ON", "OFF"); + lex_error_expecting (lexer, "ON", "OFF"); goto error; } } @@ -468,6 +464,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "IMPORTCASES")) { + int start_ofs = lex_ofs (lexer) - 1; lex_match (lexer, T_EQUALS); if (lex_match (lexer, T_ALL)) { @@ -485,8 +482,9 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) goto error; lex_get (lexer); } - msg (SW, _("Ignoring obsolete IMPORTCASES subcommand. (N OF CASES " - "or SAMPLE may be used to substitute.)")); + lex_ofs_msg (lexer, SW, start_ofs, lex_ofs (lexer) - 1, + _("Ignoring obsolete IMPORTCASES subcommand. (N OF " + "CASES or SAMPLE may be used to substitute.)")); } else if (lex_match_id_n (lexer, "DELIMITERS", 4)) { @@ -532,8 +530,8 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) if (settings_get_syntax () == COMPATIBLE && ss_length (lex_tokss (lexer)) != 1) { - msg (SE, _("In compatible syntax mode, the QUALIFIER string " - "must contain exactly one character.")); + lex_error (lexer, _("In compatible syntax mode, the QUALIFIER " + "string must contain exactly one character.")); goto error; } @@ -567,6 +565,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) lex_get (lexer); } + int name_ofs = lex_ofs (lexer); const char * tstr = lex_tokcstr (lexer); if (tstr == NULL) { @@ -605,7 +604,8 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) goto error; if (!fmt_from_name (fmt_type_name, &fmt_type)) { - msg (SE, _("Unknown format type `%s'."), fmt_type_name); + lex_next_error (lexer, -1, -1, + _("Unknown format type `%s'."), fmt_type_name); goto error; } /* Compose input format. */ @@ -630,7 +630,8 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds) v = dict_create_var (dict, name, fmt_var_width (&input)); if (v == NULL) { - msg (SE, _("%s is a duplicate variable name."), name); + lex_ofs_error (lexer, name_ofs, name_ofs, + _("%s is a duplicate variable name."), name); goto error; } var_set_both_formats (v, &output); diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index b9e2c326fe..46ee3567f0 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -294,7 +294,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds) if (e) { - lex_sbc_only_once ("COLUMN"); + lex_sbc_only_once (lexer, "COLUMN"); goto error; } diff --git a/src/language/data-io/list.c b/src/language/data-io/list.c index c98b6f9a52..8a55f58a12 100644 --- a/src/language/data-io/list.c +++ b/src/language/data-io/list.c @@ -256,4 +256,3 @@ cmd_list (struct lexer *lexer, struct dataset *ds) free (cmd.v_variables); return CMD_FAILURE; } - diff --git a/src/language/data-io/matrix-data.c b/src/language/data-io/matrix-data.c index f741b4d54c..4ae4ef70cd 100644 --- a/src/language/data-io/matrix-data.c +++ b/src/language/data-io/matrix-data.c @@ -1033,7 +1033,9 @@ cmd_matrix_data (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "CELLS")) { if (mf.input_rowtype) - msg (SW, _("CELLS is ignored when VARIABLES includes ROWTYPE_")); + lex_next_msg (lexer, SW, + -1, -1, _("CELLS is ignored when VARIABLES " + "includes ROWTYPE_")); lex_match (lexer, T_EQUALS); @@ -1058,7 +1060,14 @@ cmd_matrix_data (struct lexer *lexer, struct dataset *ds) if (open || in_parens || (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)) { - lex_error (lexer, _("Row type keyword expected.")); + const char *rowtypes[] = { +#define RT(NAME, DIMS) #NAME, + ROWTYPES +#undef RT + "N_VECTOR", "SD", + }; + lex_error_expecting_array ( + lexer, rowtypes, sizeof rowtypes / sizeof *rowtypes); goto error; } break; diff --git a/src/language/data-io/placement-parser.c b/src/language/data-io/placement-parser.c index dddbb05767..c56e089a96 100644 --- a/src/language/data-io/placement-parser.c +++ b/src/language/data-io/placement-parser.c @@ -103,8 +103,8 @@ parse_var_placements (struct lexer *lexer, struct pool *pool, size_t n_vars, } else { - msg (SE, _("SPSS-like or Fortran-like format " - "specification expected after variable names.")); + lex_error (lexer, _("SPSS-like or Fortran-like format " + "specification expected after variable names.")); return false; } } @@ -233,7 +233,8 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, enum fmt_use use, { if (!fmt_from_name (type, &f.type)) { - msg (SE, _("Unknown format type `%s'."), type); + lex_next_error (lexer, -1, -1, + _("Unknown format type `%s'."), type); return false; } if (!fmt_check (&f, use)) @@ -300,16 +301,26 @@ execute_placement_format (const struct fmt_spec *format, } static bool -parse_column__ (int value, int base, int *column) +parse_column__ (struct lexer *lexer, bool negative, int base, int *column) { assert (base == 0 || base == 1); + + if (!lex_force_int (lexer)) + return false; + long int value = lex_integer (lexer); + if (negative) + value = -value; + lex_get (lexer); + *column = value - base + 1; if (*column < 1) { if (base == 1) - msg (SE, _("Column positions for fields must be positive.")); + lex_next_error (lexer, -1, -1, + _("Column positions for fields must be positive.")); else - msg (SE, _("Column positions for fields must not be negative.")); + lex_next_error (lexer, -1, -1, + _("Column positions for fields must not be negative.")); return false; } return true; @@ -326,14 +337,7 @@ parse_column__ (int value, int base, int *column) bool parse_column (struct lexer *lexer, int base, int *column) { - assert (base == 0 || base == 1); - - if (!lex_force_int (lexer) - || !parse_column__ (lex_integer (lexer), base, column)) - return false; - - lex_get (lexer); - return true; + return parse_column__ (lexer, false, base, column); } /* Parse a column or a range of columns, specified as a single @@ -354,23 +358,23 @@ parse_column_range (struct lexer *lexer, int base, int *first_column, int *last_column, bool *range_specified) { + int start_ofs = lex_ofs (lexer); + /* First column. */ - if (!lex_force_int (lexer) - || !parse_column__ (lex_integer (lexer), base, first_column)) + if (!parse_column__ (lexer, false, base, first_column)) return false; - lex_get (lexer); /* Last column. */ if (lex_is_integer (lexer) && lex_integer (lexer) < 0) { - if (!parse_column__ (-lex_integer (lexer), base, last_column)) + if (!parse_column__ (lexer, true, base, last_column)) return false; - lex_get (lexer); if (*last_column < *first_column) { - msg (SE, _("The ending column for a field must be " - "greater than the starting column.")); + lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1, + _("The ending column for a field must be " + "greater than the starting column.")); return false; } diff --git a/src/language/data-io/print-space.c b/src/language/data-io/print-space.c index b908927bdf..7a16d818cb 100644 --- a/src/language/data-io/print-space.c +++ b/src/language/data-io/print-space.c @@ -79,7 +79,7 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds) expr = expr_parse (lexer, ds, VAL_NUMERIC); if (lex_token (lexer) != T_ENDCMD) { - lex_error (lexer, _("expecting end of command")); + lex_error (lexer, _("Syntax error expecting end of command.")); goto error; } } diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 657d53c350..3b5f901b53 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -190,7 +190,8 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds, print_table = false; else { - lex_error (lexer, _("expecting a valid subcommand")); + lex_error_expecting (lexer, "OUTFILE", "ENCODING", "RECORDS", + "TABLE", "NOTABLE"); goto error; } } diff --git a/src/language/data-io/save-translate.c b/src/language/data-io/save-translate.c index a565f4471c..3b68367997 100644 --- a/src/language/data-io/save-translate.c +++ b/src/language/data-io/save-translate.c @@ -93,7 +93,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) { if (handle != NULL) { - lex_sbc_only_once ("OUTFILE"); + lex_sbc_only_once (lexer, "OUTFILE"); goto error; } @@ -107,7 +107,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) { if (type != 0) { - lex_sbc_only_once ("TYPE"); + lex_sbc_only_once (lexer, "TYPE"); goto error; } @@ -165,8 +165,8 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) /* XXX should support multibyte UTF-8 delimiters */ if (ss_length (lex_tokss (lexer)) != 1) { - msg (SE, _("The %s string must contain exactly one " - "character."), "DELIMITER"); + lex_error (lexer, _("The %s string must contain exactly " + "one character."), "DELIMITER"); goto error; } delimiter = ss_first (lex_tokss (lexer)); @@ -180,8 +180,8 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) /* XXX should support multibyte UTF-8 qualifiers */ if (ss_length (lex_tokss (lexer)) != 1) { - msg (SE, _("The %s string must contain exactly one " - "character."), "QUALIFIER"); + lex_error (lexer, _("The %s string must contain exactly " + "one character."), "QUALIFIER"); goto error; } qualifier = ss_first (lex_tokss (lexer)); diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index 88f3c75ee5..bf78276b84 100644 --- a/src/language/data-io/save.c +++ b/src/language/data-io/save.c @@ -198,7 +198,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, { if (handle != NULL) { - lex_sbc_only_once ("OUTFILE"); + lex_sbc_only_once (lexer, "OUTFILE"); goto error; } @@ -212,7 +212,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, { if (metadata != NULL) { - lex_sbc_only_once ("METADATA"); + lex_sbc_only_once (lexer, "METADATA"); goto error; } diff --git a/src/language/data-io/trim.c b/src/language/data-io/trim.c index 4616b431d2..ad25f400aa 100644 --- a/src/language/data-io/trim.c +++ b/src/language/data-io/trim.c @@ -55,7 +55,7 @@ parse_dict_trim (struct lexer *lexer, struct dictionary *dict, bool relax) return parse_dict_rename (lexer, dict, relax); else { - lex_error (lexer, _("expecting a valid subcommand")); + lex_error_expecting (lexer, "MAP", "DROP", "KEEP", "RENAME"); return false; } } diff --git a/src/language/dictionary/delete-variables.c b/src/language/dictionary/delete-variables.c index 1c38074f63..1063b1652e 100644 --- a/src/language/dictionary/delete-variables.c +++ b/src/language/dictionary/delete-variables.c @@ -22,6 +22,7 @@ #include "data/dataset.h" #include "data/dictionary.h" #include "language/command.h" +#include "language/lexer/lexer.h" #include "language/lexer/variable-parser.h" #include "libpspp/message.h" @@ -37,9 +38,10 @@ cmd_delete_variables (struct lexer *lexer, struct dataset *ds) bool ok; if (proc_make_temporary_transformations_permanent (ds)) - msg (SE, _("%s may not be used after %s. " - "Temporary transformations will be made permanent."), - "DELETE VARIABLES", "TEMPORARY"); + lex_ofs_error (lexer, 0, lex_ofs (lexer) - 1, + _("%s may not be used after %s. " + "Temporary transformations will be made permanent."), + "DELETE VARIABLES", "TEMPORARY"); if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars, PV_NONE)) goto error; diff --git a/src/language/dictionary/missing-values.c b/src/language/dictionary/missing-values.c index 8d82b480cb..425c50db3e 100644 --- a/src/language/dictionary/missing-values.c +++ b/src/language/dictionary/missing-values.c @@ -123,9 +123,9 @@ cmd_missing_values (struct lexer *lexer, struct dataset *ds) utf8_trunc_len = utf8_encoding_trunc_len (utf8_s, encoding, MV_MAX_STRING); if (utf8_trunc_len < utf8_len) - msg (SE, _("Truncating missing value to maximum " - "acceptable length (%d bytes)."), - MV_MAX_STRING); + lex_error (lexer, _("Truncating missing value to maximum " + "acceptable length (%d bytes)."), + MV_MAX_STRING); /* Recode to dictionary encoding and add. */ raw_s = recode_string (encoding, "UTF-8", diff --git a/src/language/dictionary/modify-variables.c b/src/language/dictionary/modify-variables.c index e022586dac..e14b46e04f 100644 --- a/src/language/dictionary/modify-variables.c +++ b/src/language/dictionary/modify-variables.c @@ -76,9 +76,10 @@ int cmd_modify_vars (struct lexer *lexer, struct dataset *ds) { if (proc_make_temporary_transformations_permanent (ds)) - msg (SE, _("%s may not be used after %s. " - "Temporary transformations will be made permanent."), - "MODIFY VARS", "TEMPORARY"); + lex_ofs_error (lexer, 0, lex_ofs (lexer) - 1, + _("%s may not be used after %s. " + "Temporary transformations will be made permanent."), + "MODIFY VARS", "TEMPORARY"); /* Bits indicated whether we've already encountered a subcommand of this type. */ @@ -107,7 +108,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds) { if (already_encountered & 1) { - lex_sbc_only_once ("REORDER"); + lex_sbc_only_once (lexer, "REORDER"); goto done; } already_encountered |= 1; @@ -187,7 +188,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds) { if (already_encountered & 2) { - lex_sbc_only_once ("RENAME"); + lex_sbc_only_once (lexer, "RENAME"); goto done; } already_encountered |= 2; @@ -240,10 +241,11 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds) { if (already_encountered & 4) { - msg (SE, - _("%s subcommand may be given at most once. It may " - "not be given in conjunction with the %s subcommand."), - "KEEP", "DROP"); + lex_next_error (lexer, -1, -1, + _("%s subcommand may be given at most once. " + "It may not be given in conjunction with the " + "%s subcommand."), + "KEEP", "DROP"); goto done; } already_encountered |= 4; @@ -291,9 +293,10 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds) if (already_encountered & 4) { - msg (SE, _("%s subcommand may be given at most once. It may " - "not be given in conjunction with the %s " - "subcommand."), + lex_next_error (lexer, -1, -1, + _("%s subcommand may be given at most once. " + "It may not be given in conjunction with the " + "%s subcommand."), "DROP", "KEEP" ); goto done; @@ -327,11 +330,8 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds) } else { - if (lex_token (lexer) == T_ID) - msg (SE, _("Unrecognized subcommand name `%s'."), - lex_tokcstr (lexer)); - else - msg (SE, _("Subcommand name expected.")); + lex_error_expecting (lexer, "REORDER", "RENAME", "KEEP", + "DROP", "MAP"); goto done; } diff --git a/src/language/dictionary/mrsets.c b/src/language/dictionary/mrsets.c index 3b96da3a6c..0ea5cb8c82 100644 --- a/src/language/dictionary/mrsets.c +++ b/src/language/dictionary/mrsets.c @@ -146,7 +146,7 @@ parse_group (struct lexer *lexer, struct dictionary *dict, { if (!lex_is_integer (lexer)) { - msg (SE, _("Numeric VALUE must be an integer.")); + lex_error (lexer, _("Numeric VALUE must be an integer.")); goto error; } value_destroy (&mrset->counted, mrset->width); @@ -481,8 +481,8 @@ parse_mrset_names (struct lexer *lexer, struct dictionary *dict, return false; if (dict_lookup_mrset (dict, lex_tokcstr (lexer)) == NULL) { - msg (SE, _("No multiple response set named %s."), - lex_tokcstr (lexer)); + lex_error (lexer, _("No multiple response set named %s."), + lex_tokcstr (lexer)); stringi_set_destroy (mrset_names); return false; } diff --git a/src/language/dictionary/numeric.c b/src/language/dictionary/numeric.c index c04e8eba7a..ae9f25325a 100644 --- a/src/language/dictionary/numeric.c +++ b/src/language/dictionary/numeric.c @@ -64,8 +64,9 @@ cmd_numeric (struct lexer *lexer, struct dataset *ds) if (fmt_is_string (f.type)) { char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("Format type %s may not be used with a numeric " - "variable."), fmt_to_string (&f, str)); + lex_next_error (lexer, -1, -1, + _("Format type %s may not be used with a numeric " + "variable."), fmt_to_string (&f, str)); goto fail; } @@ -135,8 +136,9 @@ cmd_string (struct lexer *lexer, struct dataset *ds) if (!fmt_is_string (f.type)) { char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("Format type %s may not be used with a string " - "variable."), fmt_to_string (&f, str)); + lex_next_error (lexer, -2, -2, + _("Format type %s may not be used with a string " + "variable."), fmt_to_string (&f, str)); goto fail; } if (!fmt_check_output (&f)) diff --git a/src/language/dictionary/rename-variables.c b/src/language/dictionary/rename-variables.c index 33d8f6887f..94331c4afe 100644 --- a/src/language/dictionary/rename-variables.c +++ b/src/language/dictionary/rename-variables.c @@ -48,8 +48,10 @@ cmd_rename_variables (struct lexer *lexer, struct dataset *ds) int status = CMD_CASCADING_FAILURE; if (proc_make_temporary_transformations_permanent (ds)) - msg (SE, _("%s may not be used after %s. " - "Temporary transformations will be made permanent."), "RENAME VARS", "TEMPORARY"); + lex_ofs_error (lexer, 0, lex_ofs (lexer) - 1, + _("%s may not be used after %s. " + "Temporary transformations will be made permanent."), + "RENAME VARS", "TEMPORARY"); do { diff --git a/src/language/dictionary/sys-file-info.c b/src/language/dictionary/sys-file-info.c index 7f5216134c..45c352579c 100644 --- a/src/language/dictionary/sys-file-info.c +++ b/src/language/dictionary/sys-file-info.c @@ -718,7 +718,7 @@ display_vectors (const struct dictionary *dict, int sorted) size_t n_vectors = dict_get_n_vectors (dict); if (n_vectors == 0) { - msg (SW, _("No vectors defined.")); + msg (SN, _("No vectors defined.")); return; } diff --git a/src/language/dictionary/value-labels.c b/src/language/dictionary/value-labels.c index 0fb8471652..235c57273b 100644 --- a/src/language/dictionary/value-labels.c +++ b/src/language/dictionary/value-labels.c @@ -149,7 +149,9 @@ get_label (struct lexer *lexer, struct variable **vars, size_t n_vars, MAX_LABEL_LEN); if (ds_length (&label) > trunc_len) { - msg (SW, _("Truncating value label to %d bytes."), MAX_LABEL_LEN); + lex_next_msg (lexer, SW, 0, 0, + _("Truncating value label to %d bytes."), + MAX_LABEL_LEN); ds_truncate (&label, trunc_len); } diff --git a/src/language/dictionary/vector.c b/src/language/dictionary/vector.c index 16617f87e0..02687e51a9 100644 --- a/src/language/dictionary/vector.c +++ b/src/language/dictionary/vector.c @@ -63,16 +63,18 @@ cmd_vector (struct lexer *lexer, struct dataset *ds) if (dict_lookup_vector (dict, lex_tokcstr (lexer))) { - msg (SE, _("A vector named %s already exists."), - lex_tokcstr (lexer)); + lex_next_error (lexer, 0, 0, + _("A vector named %s already exists."), + lex_tokcstr (lexer)); goto fail; } for (i = 0; i < n_vectors; i++) if (!utf8_strcasecmp (vectors[i], lex_tokcstr (lexer))) { - msg (SE, _("Vector name %s is given twice."), - lex_tokcstr (lexer)); + lex_next_error (lexer, 0, 0, + _("Vector name %s is given twice."), + lex_tokcstr (lexer)); goto fail; } @@ -95,8 +97,8 @@ cmd_vector (struct lexer *lexer, struct dataset *ds) if (n_vectors > 1) { - msg (SE, _("A slash must separate each vector " - "specification in VECTOR's long form.")); + lex_error (lexer, _("A slash must separate each vector " + "specification in VECTOR's long form.")); goto fail; } @@ -145,7 +147,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds) } if (n_vars == 0) { - lex_error (lexer, _("expecting vector length")); + lex_error (lexer, _("Syntax error expecting vector length.")); goto fail; } diff --git a/src/language/dictionary/weight.c b/src/language/dictionary/weight.c index 185165dcbb..d99c2acb0c 100644 --- a/src/language/dictionary/weight.c +++ b/src/language/dictionary/weight.c @@ -46,12 +46,14 @@ cmd_weight (struct lexer *lexer, struct dataset *ds) return CMD_CASCADING_FAILURE; if (var_is_alpha (v)) { - msg (SE, _("The weighting variable must be numeric.")); + lex_next_error (lexer, -1, -1, + _("The weighting variable must be numeric.")); return CMD_CASCADING_FAILURE; } if (dict_class_from_id (var_get_name (v)) == DC_SCRATCH) { - msg (SE, _("The weighting variable may not be scratch.")); + lex_next_error (lexer, -1, -1, + _("The weighting variable may not be scratch.")); return CMD_CASCADING_FAILURE; } diff --git a/src/language/expressions/evaluate.c b/src/language/expressions/evaluate.c index 8b47f445ee..e07deeaf81 100644 --- a/src/language/expressions/evaluate.c +++ b/src/language/expressions/evaluate.c @@ -148,6 +148,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED) if (!lex_force_id (lexer)) goto done; + int name_ofs = lex_ofs (lexer); name = xstrdup (lex_tokcstr (lexer)); lex_get (lexer); @@ -175,7 +176,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED) } else { - lex_error (lexer, _("expecting number or string")); + lex_error (lexer, _("Syntax error expecting number or string.")); goto done; } @@ -188,7 +189,8 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED) v = dict_create_var (d, name, width); if (v == NULL) { - msg (SE, _("Duplicate variable name %s."), name); + lex_ofs_error (lexer, name_ofs, name_ofs, + _("Duplicate variable name %s."), name); value_destroy (&value, width); goto done; } diff --git a/src/language/expressions/parse.c b/src/language/expressions/parse.c index d06d633d5b..f1800f3775 100644 --- a/src/language/expressions/parse.c +++ b/src/language/expressions/parse.c @@ -912,7 +912,7 @@ parse_sysvar (struct lexer *lexer, struct expression *e) return expr_allocate_number (e, settings_get_viewwidth ()); else { - msg (SE, _("Unknown system variable %s."), lex_tokcstr (lexer)); + lex_error (lexer, _("Unknown system variable %s."), lex_tokcstr (lexer)); return NULL; } } @@ -960,7 +960,7 @@ parse_primary__ (struct lexer *lexer, struct expression *e) return expr_allocate_format (e, &fmt); /* All attempts failed. */ - msg (SE, _("Unknown identifier %s."), lex_tokcstr (lexer)); + lex_error (lexer, _("Unknown identifier %s."), lex_tokcstr (lexer)); return NULL; } break; @@ -1332,7 +1332,8 @@ parse_function (struct lexer *lexer, struct expression *e) const struct operation *first, *last; if (!lookup_function (lex_tokcstr (lexer), &first, &last)) { - msg (SE, _("No function or vector named %s."), lex_tokcstr (lexer)); + lex_error (lexer, _("No function or vector named %s."), + lex_tokcstr (lexer)); ds_destroy (&func_name); return NULL; } diff --git a/src/language/lexer/format-parser.c b/src/language/lexer/format-parser.c index aa30852d11..c2187e5a2f 100644 --- a/src/language/lexer/format-parser.c +++ b/src/language/lexer/format-parser.c @@ -84,7 +84,7 @@ parse_abstract_format_specifier__ (struct lexer *lexer, return true; error: - lex_error (lexer, _("expecting valid format specifier")); + lex_error (lexer, _("Syntax error expecting valid format specifier.")); return false; } @@ -115,14 +115,14 @@ parse_format_specifier (struct lexer *lexer, struct fmt_spec *format) if (!fmt_from_name (type, &format->type)) { - msg (SE, _("Unknown format type `%s'."), type); + lex_error (lexer, _("Unknown format type `%s'."), type); return false; } if (format->w == 0 && !strchr (lex_tokcstr (lexer), '0')) { - msg (SE, _("Format specifier `%s' lacks required width."), - lex_tokcstr (lexer)); + lex_error (lexer, _("Format specifier `%s' lacks required width."), + lex_tokcstr (lexer)); return false; } @@ -137,12 +137,12 @@ parse_format_specifier_name (struct lexer *lexer, enum fmt_type *type) { if (lex_token (lexer) != T_ID) { - lex_error (lexer, _("expecting format type")); + lex_error (lexer, _("Syntax error expecting format type.")); return false; } if (!fmt_from_name (lex_tokcstr (lexer), type)) { - msg (SE, _("Unknown format type `%s'."), lex_tokcstr (lexer)); + lex_error (lexer, _("Unknown format type `%s'."), lex_tokcstr (lexer)); return false; } lex_get (lexer); diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index 1074ea243a..9a67f96922 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -85,6 +85,8 @@ static struct msg_point lex_token_start_point (const struct lex_source *, static struct msg_point lex_token_end_point (const struct lex_source *, const struct lex_token *); +static size_t lex_ofs_at_phrase__ (struct lexer *, int ofs, const char *s); + /* Source offset of the last byte in TOKEN. */ static size_t lex_token_end (const struct lex_token *token) @@ -290,9 +292,10 @@ static void lex_source_push_parse (struct lex_source *, struct lex_token *); static void lex_source_clear_parse (struct lex_source *); static bool lex_source_get_parse (struct lex_source *); -static void lex_source_error_valist (struct lex_source *, int ofs0, int ofs1, - const char *format, va_list) - PRINTF_FORMAT (4, 0); +static void lex_source_msg_valist (struct lex_source *, enum msg_class, + int ofs0, int ofs1, + const char *format, va_list) + PRINTF_FORMAT (5, 0); static const struct lex_token *lex_source_next__ (const struct lex_source *, int n); @@ -425,42 +428,77 @@ lex_error (struct lexer *lexer, const char *format, ...) va_list args; va_start (args, format); - lex_ofs_error_valist (lexer, lex_ofs (lexer), lex_ofs (lexer), format, args); + lex_ofs_msg_valist (lexer, SE, lex_ofs (lexer), lex_ofs (lexer), + format, args); va_end (args); } -/* Prints a syntax error message containing the current token and - given message MESSAGE (if non-null). */ +/* Prints a syntax error message for the span of tokens N0 through N1, + inclusive, from the current token in LEXER, adding message MESSAGE (if + non-null). */ void -lex_error_valist (struct lexer *lexer, const char *format, va_list args) +lex_next_error (struct lexer *lexer, int n0, int n1, const char *format, ...) { - lex_ofs_error_valist (lexer, lex_ofs (lexer), lex_ofs (lexer), format, args); + va_list args; + + va_start (args, format); + int ofs = lex_ofs (lexer); + lex_ofs_msg_valist (lexer, SE, n0 + ofs, n1 + ofs, format, args); + va_end (args); +} + +/* Prints a syntax error message for the span of tokens with offsets OFS0 + through OFS1, inclusive, within the current command in LEXER, adding message + MESSAGE (if non-null). */ +void +lex_ofs_error (struct lexer *lexer, int ofs0, int ofs1, const char *format, ...) +{ + va_list args; + + va_start (args, format); + lex_ofs_msg_valist (lexer, SE, ofs0, ofs1, format, args); + va_end (args); +} + +/* Prints a message of the given CLASS containing the current token and given + message MESSAGE (if non-null). */ +void +lex_msg (struct lexer *lexer, enum msg_class class, const char *format, ...) +{ + va_list args; + + va_start (args, format); + lex_ofs_msg_valist (lexer, class, lex_ofs (lexer), lex_ofs (lexer), + format, args); + va_end (args); } /* Prints a syntax error message for the span of tokens N0 through N1, inclusive, from the current token in LEXER, adding message MESSAGE (if non-null). */ void -lex_next_error (struct lexer *lexer, int n0, int n1, const char *format, ...) +lex_next_msg (struct lexer *lexer, enum msg_class class, int n0, int n1, + const char *format, ...) { va_list args; va_start (args, format); int ofs = lex_ofs (lexer); - lex_ofs_error_valist (lexer, n0 + ofs, n1 + ofs, format, args); + lex_ofs_msg_valist (lexer, class, n0 + ofs, n1 + ofs, format, args); va_end (args); } -/* Prints a syntax error message for the span of tokens with offsets OFS0 +/* Prints a message of the given CLASS for the span of tokens with offsets OFS0 through OFS1, inclusive, within the current command in LEXER, adding message MESSAGE (if non-null). */ void -lex_ofs_error (struct lexer *lexer, int ofs0, int ofs1, const char *format, ...) +lex_ofs_msg (struct lexer *lexer, enum msg_class class, int ofs0, int ofs1, + const char *format, ...) { va_list args; va_start (args, format); - lex_ofs_error_valist (lexer, ofs0, ofs1, format, args); + lex_ofs_msg_valist (lexer, class, ofs0, ofs1, format, args); va_end (args); } @@ -505,42 +543,45 @@ lex_error_expecting_array (struct lexer *lexer, const char **options, size_t n) break; case 1: - lex_error (lexer, _("expecting %s"), options[0]); + lex_error (lexer, _("Syntax error expecting %s."), options[0]); break; case 2: - lex_error (lexer, _("expecting %s or %s"), options[0], options[1]); + lex_error (lexer, _("Syntax error expecting %s or %s."), + options[0], options[1]); break; case 3: - lex_error (lexer, _("expecting %s, %s, or %s"), options[0], options[1], - options[2]); + lex_error (lexer, _("Syntax error expecting %s, %s, or %s."), + options[0], options[1], options[2]); break; case 4: - lex_error (lexer, _("expecting %s, %s, %s, or %s"), + lex_error (lexer, _("Syntax error expecting %s, %s, %s, or %s."), options[0], options[1], options[2], options[3]); break; case 5: - lex_error (lexer, _("expecting %s, %s, %s, %s, or %s"), + lex_error (lexer, _("Syntax error expecting %s, %s, %s, %s, or %s."), options[0], options[1], options[2], options[3], options[4]); break; case 6: - lex_error (lexer, _("expecting %s, %s, %s, %s, %s, or %s"), + lex_error (lexer, _("Syntax error expecting %s, %s, %s, %s, %s, or %s."), options[0], options[1], options[2], options[3], options[4], options[5]); break; case 7: - lex_error (lexer, _("expecting %s, %s, %s, %s, %s, %s, or %s"), + lex_error (lexer, _("Syntax error expecting %s, %s, %s, %s, %s, %s, " + "or %s."), options[0], options[1], options[2], options[3], options[4], options[5], options[6]); break; case 8: - lex_error (lexer, _("expecting %s, %s, %s, %s, %s, %s, %s, or %s"), + lex_error (lexer, _("Syntax error expecting %s, %s, %s, %s, %s, %s, %s, " + "or %s."), options[0], options[1], options[2], options[3], options[4], options[5], options[6], options[7]); break; @@ -554,7 +595,7 @@ lex_error_expecting_array (struct lexer *lexer, const char **options, size_t n) ds_put_cstr (&s, ", "); ds_put_cstr (&s, options[i]); } - lex_error (lexer, _("expecting one of the following: %s"), + lex_error (lexer, _("Syntax error expecting one of the following: %s."), ds_cstr (&s)); ds_destroy (&s); } @@ -563,16 +604,21 @@ lex_error_expecting_array (struct lexer *lexer, const char **options, size_t n) } /* Reports an error to the effect that subcommand SBC may only be specified - once. - - This function does not take a lexer as an argument or use lex_error(), - because the result would ordinarily just be redundant: "Syntax error at - SUBCOMMAND: Subcommand SUBCOMMAND may only be specified once.", which does - not help the user find the error. */ + once. */ void -lex_sbc_only_once (const char *sbc) +lex_sbc_only_once (struct lexer *lexer, const char *sbc) { - msg (SE, _("Subcommand %s may only be specified once."), sbc); + int ofs = lex_ofs (lexer) - 1; + if (lex_ofs_token (lexer, ofs)->type == T_EQUALS) + ofs--; + + /* lex_ofs_at_phrase__() handles subcommand names that are keywords, such as + BY. */ + if (lex_ofs_at_phrase__ (lexer, ofs, sbc)) + lex_ofs_error (lexer, ofs, ofs, + _("Subcommand %s may only be specified once."), sbc); + else + msg (SE, _("Subcommand %s may only be specified once."), sbc); } /* Reports an error to the effect that subcommand SBC is missing. @@ -592,7 +638,7 @@ lex_sbc_missing (const char *sbc) void lex_spec_only_once (struct lexer *lexer, const char *sbc, const char *spec) { - lex_error (lexer, _("%s may only be specified once within subcommand %s"), + lex_error (lexer, _("%s may only be specified once within subcommand %s."), spec, sbc); } @@ -601,37 +647,18 @@ lex_spec_only_once (struct lexer *lexer, const char *sbc, const char *spec) void lex_spec_missing (struct lexer *lexer, const char *sbc, const char *spec) { - lex_error (lexer, _("Required %s specification missing from %s subcommand"), - sbc, spec); + lex_error (lexer, _("Required %s specification missing from %s subcommand."), + spec, sbc); } /* Prints a syntax error message for the span of tokens with offsets OFS0 through OFS1, inclusive, within the current command in LEXER, adding message MESSAGE (if non-null) with the given ARGS. */ void -lex_ofs_error_valist (struct lexer *lexer, int ofs0, int ofs1, - const char *format, va_list args) +lex_ofs_msg_valist (struct lexer *lexer, enum msg_class class, + int ofs0, int ofs1, const char *format, va_list args) { - struct lex_source *src = lex_source__ (lexer); - - if (src != NULL) - lex_source_error_valist (src, ofs0, ofs1, format, args); - else - { - struct string s; - - ds_init_empty (&s); - ds_put_format (&s, _("Syntax error at end of input")); - if (format != NULL) - { - ds_put_cstr (&s, ": "); - ds_put_vformat (&s, format, args); - } - if (ds_last (&s) != '.') - ds_put_byte (&s, '.'); - msg (SE, "%s", ds_cstr (&s)); - ds_destroy (&s); - } + lex_source_msg_valist (lex_source__ (lexer), class, ofs0, ofs1, format, args); } /* Checks that we're at end of command. @@ -643,7 +670,7 @@ lex_end_of_command (struct lexer *lexer) { if (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_STOP) { - lex_error (lexer, _("expecting end of command")); + lex_error (lexer, _("Syntax error expecting end of command.")); return CMD_FAILURE; } else @@ -845,7 +872,7 @@ lex_force_string (struct lexer *lexer) return true; else { - lex_error (lexer, _("expecting string")); + lex_error (lexer, _("Syntax error expecting string.")); return false; } } @@ -874,7 +901,7 @@ lex_force_int (struct lexer *lexer) return true; else { - lex_error (lexer, _("expecting integer")); + lex_error (lexer, _("Syntax error expecting integer.")); return false; } } @@ -901,23 +928,25 @@ lex_force_int_range (struct lexer *lexer, const char *name, long min, long max) /* Weird, maybe a bug in the caller. Just report that we needed an integer. */ if (name) - lex_error (lexer, _("Integer expected for %s."), name); + lex_error (lexer, _("Syntax error expecting integer for %s."), name); else - lex_error (lexer, _("Integer expected.")); + lex_error (lexer, _("Syntax error expecting integer.")); } else if (min == max) { if (name) - lex_error (lexer, _("Expected %ld for %s."), min, name); + lex_error (lexer, _("Syntax error expecting %ld for %s."), min, name); else - lex_error (lexer, _("Expected %ld."), min); + lex_error (lexer, _("Syntax error expecting %ld."), min); } else if (min + 1 == max) { if (name) - lex_error (lexer, _("Expected %ld or %ld for %s."), min, min + 1, name); + lex_error (lexer, _("Syntax error expecting %ld or %ld for %s."), + min, min + 1, name); else - lex_error (lexer, _("Expected %ld or %ld."), min, min + 1); + lex_error (lexer, _("Syntax error expecting %ld or %ld."), + min, min + 1); } else { @@ -928,10 +957,12 @@ lex_force_int_range (struct lexer *lexer, const char *name, long min, long max) { if (name) lex_error (lexer, - _("Expected integer between %ld and %ld for %s."), + _("Syntax error expecting integer " + "between %ld and %ld for %s."), min, max, name); else - lex_error (lexer, _("Expected integer between %ld and %ld."), + lex_error (lexer, _("Syntax error expecting integer " + "between %ld and %ld."), min, max); } else if (report_lower_bound) @@ -939,44 +970,53 @@ lex_force_int_range (struct lexer *lexer, const char *name, long min, long max) if (min == 0) { if (name) - lex_error (lexer, _("Expected non-negative integer for %s."), + lex_error (lexer, _("Syntax error expecting " + "non-negative integer for %s."), name); else - lex_error (lexer, _("Expected non-negative integer.")); + lex_error (lexer, _("Syntax error expecting " + "non-negative integer.")); } else if (min == 1) { if (name) - lex_error (lexer, _("Expected positive integer for %s."), + lex_error (lexer, _("Syntax error expecting " + "positive integer for %s."), name); else - lex_error (lexer, _("Expected positive integer.")); + lex_error (lexer, _("Syntax error expecting " + "positive integer.")); } else { if (name) - lex_error (lexer, _("Expected integer %ld or greater for %s."), + lex_error (lexer, _("Syntax error expecting " + "integer %ld or greater for %s."), min, name); else - lex_error (lexer, _("Expected integer %ld or greater."), min); + lex_error (lexer, _("Syntax error expecting " + "integer %ld or greater."), min); } } else if (report_upper_bound) { if (name) lex_error (lexer, - _("Expected integer less than or equal to %ld for %s."), + _("Syntax error expecting integer less than or equal " + "to %ld for %s."), max, name); else - lex_error (lexer, _("Expected integer less than or equal to %ld."), + lex_error (lexer, _("Syntax error expecting integer less than or " + "equal to %ld."), max); } else { if (name) - lex_error (lexer, _("Integer expected for %s."), name); + lex_error (lexer, _("Syntax error expecting integer for %s."), + name); else - lex_error (lexer, _("Integer expected.")); + lex_error (lexer, _("Syntax error expecting integer.")); } } return false; @@ -990,7 +1030,7 @@ lex_force_num (struct lexer *lexer) if (lex_is_number (lexer)) return true; - lex_error (lexer, _("expecting number")); + lex_error (lexer, _("Syntax error expecting number.")); return false; } @@ -1012,16 +1052,17 @@ lex_force_num_range_closed (struct lexer *lexer, const char *name, /* Weird, maybe a bug in the caller. Just report that we needed an number. */ if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } else if (min == max) { if (name) - lex_error (lexer, _("Expected %g for %s."), min, name); + lex_error (lexer, _("Syntax error expecting number %g for %s."), + min, name); else - lex_error (lexer, _("Expected %g."), min); + lex_error (lexer, _("Syntax error expecting number %g."), min); } else { @@ -1032,10 +1073,12 @@ lex_force_num_range_closed (struct lexer *lexer, const char *name, { if (name) lex_error (lexer, - _("Expected number between %g and %g for %s."), + _("Syntax error expecting number " + "between %g and %g for %s."), min, max, name); else - lex_error (lexer, _("Expected number between %g and %g."), + lex_error (lexer, _("Syntax error expecting number " + "between %g and %g."), min, max); } else if (report_lower_bound) @@ -1043,36 +1086,42 @@ lex_force_num_range_closed (struct lexer *lexer, const char *name, if (min == 0) { if (name) - lex_error (lexer, _("Expected non-negative number for %s."), + lex_error (lexer, _("Syntax error expecting " + "non-negative number for %s."), name); else - lex_error (lexer, _("Expected non-negative number.")); + lex_error (lexer, _("Syntax error expecting " + "non-negative number.")); } else { if (name) - lex_error (lexer, _("Expected number %g or greater for %s."), + lex_error (lexer, _("Syntax error expecting number " + "%g or greater for %s."), min, name); else - lex_error (lexer, _("Expected number %g or greater."), min); + lex_error (lexer, _("Syntax error expecting number " + "%g or greater."), min); } } else if (report_upper_bound) { if (name) lex_error (lexer, - _("Expected number less than or equal to %g for %s."), + _("Syntax error expecting number " + "less than or equal to %g for %s."), max, name); else - lex_error (lexer, _("Expected number less than or equal to %g."), + lex_error (lexer, _("Syntax error expecting number " + "less than or equal to %g."), max); } else { if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } } return false; @@ -1096,9 +1145,9 @@ lex_force_num_range_halfopen (struct lexer *lexer, const char *name, /* Weird, maybe a bug in the caller. Just report that we needed an number. */ if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } else { @@ -1108,10 +1157,11 @@ lex_force_num_range_halfopen (struct lexer *lexer, const char *name, if (report_lower_bound && report_upper_bound) { if (name) - lex_error (lexer, _("Expected number in [%g,%g) for %s."), + lex_error (lexer, _("Syntax error expecting number " + "in [%g,%g) for %s."), min, max, name); else - lex_error (lexer, _("Expected number in [%g,%g)."), + lex_error (lexer, _("Syntax error expecting number in [%g,%g)."), min, max); } else if (report_lower_bound) @@ -1119,40 +1169,46 @@ lex_force_num_range_halfopen (struct lexer *lexer, const char *name, if (min == 0) { if (name) - lex_error (lexer, _("Expected non-negative number for %s."), + lex_error (lexer, _("Syntax error expecting " + "non-negative number for %s."), name); else - lex_error (lexer, _("Expected non-negative number.")); + lex_error (lexer, _("Syntax error expecting " + "non-negative number.")); } else { if (name) - lex_error (lexer, _("Expected number %g or greater for %s."), + lex_error (lexer, _("Syntax error expecting " + "number %g or greater for %s."), min, name); else - lex_error (lexer, _("Expected number %g or greater."), min); + lex_error (lexer, _("Syntax error expecting " + "number %g or greater."), min); } } else if (report_upper_bound) { if (name) lex_error (lexer, - _("Expected number less than %g for %s."), max, name); + _("Syntax error expecting " + "number less than %g for %s."), max, name); else - lex_error (lexer, _("Expected number less than %g."), max); + lex_error (lexer, _("Syntax error expecting " + "number less than %g."), max); } else { if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } } return false; } -/* If the current token is an number in the open range (MIN,MAX], does +/* If the current token is an number in the open range (MIN,MAX), does nothing and returns true. Otherwise, reports an error and returns false. If NAME is nonnull, then it is used in the error message. */ bool @@ -1170,9 +1226,9 @@ lex_force_num_range_open (struct lexer *lexer, const char *name, /* Weird, maybe a bug in the caller. Just report that we needed an number. */ if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } else { @@ -1182,43 +1238,52 @@ lex_force_num_range_open (struct lexer *lexer, const char *name, if (report_lower_bound && report_upper_bound) { if (name) - lex_error (lexer, _("Expected number in (%g,%g) for %s."), + lex_error (lexer, _("Syntax error expecting number " + "in (%g,%g) for %s."), min, max, name); else - lex_error (lexer, _("Expected number in (%g,%g)."), min, max); + lex_error (lexer, _("Syntax error expecting number " + "in (%g,%g)."), min, max); } else if (report_lower_bound) { if (min == 0) { if (name) - lex_error (lexer, _("Expected positive number for %s."), name); + lex_error (lexer, _("Syntax error expecting " + "positive number for %s."), name); else - lex_error (lexer, _("Expected positive number.")); + lex_error (lexer, _("Syntax error expecting " + "positive number.")); } else { if (name) - lex_error (lexer, _("Expected number greater than %g for %s."), + lex_error (lexer, _("Syntax error expecting number " + "greater than %g for %s."), min, name); else - lex_error (lexer, _("Expected number greater than %g."), min); + lex_error (lexer, _("Syntax error expecting number " + "greater than %g."), min); } } else if (report_upper_bound) { if (name) - lex_error (lexer, _("Expected number less than %g for %s."), + lex_error (lexer, _("Syntax error expecting number " + "less than %g for %s."), max, name); else - lex_error (lexer, _("Expected number less than %g."), max); + lex_error (lexer, _("Syntax error expecting number " + "less than %g."), max); } else { if (name) - lex_error (lexer, _("Number expected for %s."), name); + lex_error (lexer, _("Syntax error expecting number " + "for %s."), name); else - lex_error (lexer, _("Number expected.")); + lex_error (lexer, _("Syntax error expecting number.")); } } return false; @@ -1232,7 +1297,7 @@ lex_force_id (struct lexer *lexer) if (lex_token (lexer) == T_ID) return true; - lex_error (lexer, _("expecting identifier")); + lex_error (lexer, _("Syntax error expecting identifier.")); return false; } @@ -1546,7 +1611,7 @@ lex_tokens_match (const struct token *actual, const struct token *expected) } static size_t -lex_at_phrase__ (struct lexer *lexer, const char *s) +lex_ofs_at_phrase__ (struct lexer *lexer, int ofs, const char *s) { struct string_lexer slex; struct token token; @@ -1555,7 +1620,7 @@ lex_at_phrase__ (struct lexer *lexer, const char *s) string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE, true); while (string_lexer_next (&slex, &token)) { - bool match = lex_tokens_match (lex_next (lexer, i++), &token); + bool match = lex_tokens_match (lex_ofs_token (lexer, ofs + i++), &token); token_uninit (&token); if (!match) return 0; @@ -1572,7 +1637,7 @@ lex_at_phrase__ (struct lexer *lexer, const char *s) bool lex_at_phrase (struct lexer *lexer, const char *s) { - return lex_at_phrase__ (lexer, s) > 0; + return lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s) > 0; } /* If LEXER is positioned at the sequence of tokens that may be parsed from S, @@ -1584,7 +1649,7 @@ lex_at_phrase (struct lexer *lexer, const char *s) bool lex_match_phrase (struct lexer *lexer, const char *s) { - size_t n = lex_at_phrase__ (lexer, s); + size_t n = lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s); if (n > 0) lex_get_n (lexer, n); return n > 0; @@ -1653,6 +1718,7 @@ lex_token_location (const struct lex_source *src, .file_name = intern_new_if_nonnull (src->reader->file_name), .start = lex_token_start_point (src, t0), .end = lex_token_end_point (src, t1), + .src = CONST_CAST (struct lex_source *, src), }; } @@ -1920,63 +1986,39 @@ lex_source_get_macro_call (struct lex_source *src, int ofs0, int ofs1) } static void -lex_source_error_valist (struct lex_source *src, int ofs0, int ofs1, - const char *format, va_list args) +lex_source_msg_valist (struct lex_source *src, enum msg_class class, + int ofs0, int ofs1, const char *format, va_list args) { - const struct lex_token *token; - struct string s; - - ds_init_empty (&s); + struct string s = DS_EMPTY_INITIALIZER; - token = lex_source_ofs__ (src, ofs0); - if (token->token.type == T_ENDCMD) - ds_put_cstr (&s, _("Syntax error at end of command")); - else + if (src) { - /* Get the syntax that caused the error. */ - char *raw_syntax = lex_source_syntax__ (src, ofs0, ofs1); - char syntax[64]; - str_ellipsize (ss_cstr (raw_syntax), syntax, sizeof syntax); - free (raw_syntax); - /* Get the macro call(s) that expanded to the syntax that caused the error. */ char call[64]; str_ellipsize (lex_source_get_macro_call (src, ofs0, ofs1), call, sizeof call); - - if (syntax[0]) - { - if (call[0]) - ds_put_format (&s, - _("Syntax error at `%s' (in expansion of `%s')"), - syntax, call); - else - ds_put_format (&s, _("Syntax error at `%s'"), syntax); - } - else - { - if (call[0]) - ds_put_format (&s, _("Syntax error in syntax expanded from `%s'"), - call); - else - ds_put_cstr (&s, _("Syntax error")); - } + if (call[0]) + ds_put_format (&s, _("In syntax expanded from `%s'"), call); } + else + ds_put_cstr (&s, _("At end of input")); + if (!ds_is_empty (&s)) + ds_put_cstr (&s, ": "); if (format) - { - ds_put_cstr (&s, ": "); - ds_put_vformat (&s, format, args); - } + ds_put_vformat (&s, format, args); + else + ds_put_cstr (&s, _("Syntax error.")); + if (ds_last (&s) != '.') ds_put_byte (&s, '.'); struct msg *m = xmalloc (sizeof *m); *m = (struct msg) { - .category = MSG_C_SYNTAX, - .severity = MSG_S_ERROR, - .location = lex_source_get_location (src, ofs0, ofs1), + .category = msg_class_to_category (class), + .severity = msg_class_to_severity (class), + .location = src ? lex_source_get_location (src, ofs0, ofs1) : NULL, .text = ds_steal_cstr (&s), }; msg_emit (m); @@ -1990,8 +2032,7 @@ lex_get_error (struct lex_source *src, const struct lex_token *token) syntax, sizeof syntax); struct string s = DS_EMPTY_INITIALIZER; - ds_put_format (&s, _("Syntax error at `%s'"), syntax); - ds_put_format (&s, ": %s", token->token.string.string); + ds_put_cstr (&s, token->token.string.string); struct msg *m = xmalloc (sizeof *m); *m = (struct msg) { @@ -2374,7 +2415,7 @@ lex_set_message_handler (struct lexer *lexer, msg_set_handler (&msg_handler); } -void +struct lex_source * lex_source_ref (const struct lex_source *src_) { struct lex_source *src = CONST_CAST (struct lex_source *, src_); @@ -2383,6 +2424,7 @@ lex_source_ref (const struct lex_source *src_) assert (src->n_refs > 0); src->n_refs++; } + return src; } void @@ -2590,6 +2632,13 @@ lex_source_get_line (const struct lex_source *src, int line) return ss_empty (); size_t ofs = src->lines[line - 1]; - size_t end = line >= src->n_lines ? src->length : src->lines[line]; + size_t end; + if (line < src->n_lines) + end = src->lines[line]; + else + { + const char *newline = memchr (src->buffer + ofs, '\n', src->length - ofs); + end = newline ? newline - src->buffer : src->length; + } return ss_buffer (&src->buffer[ofs], end - ofs); } diff --git a/src/language/lexer/lexer.h b/src/language/lexer/lexer.h index ed4711213a..c00f70646d 100644 --- a/src/language/lexer/lexer.h +++ b/src/language/lexer/lexer.h @@ -174,12 +174,25 @@ 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 *); -/* Issuing errors. */ +/* Issuing errors and warnings. */ void lex_error (struct lexer *, const char *, ...) PRINTF_FORMAT (2, 3); void lex_next_error (struct lexer *, int n0, int n1, const char *, ...) PRINTF_FORMAT (4, 5); void lex_ofs_error (struct lexer *, int ofs0, int ofs1, const char *, ...) PRINTF_FORMAT (4, 5); + +void lex_msg (struct lexer *, enum msg_class, const char *, ...) + PRINTF_FORMAT (3, 4); +void lex_next_msg (struct lexer *, enum msg_class, int n0, int n1, + const char *, ...) + PRINTF_FORMAT (5, 6); +void lex_ofs_msg (struct lexer *, enum msg_class, int ofs0, int ofs1, + const char *, ...) + PRINTF_FORMAT (5, 6); +void lex_ofs_msg_valist (struct lexer *lexer, enum msg_class, + int ofs0, int ofs1, const char *format, va_list) + PRINTF_FORMAT (5, 0); + int lex_end_of_command (struct lexer *); void lex_error_expecting (struct lexer *, ...) SENTINEL(0); @@ -188,7 +201,7 @@ void lex_error_expecting (struct lexer *, ...) SENTINEL(0); void lex_error_expecting_valist (struct lexer *, va_list); void lex_error_expecting_array (struct lexer *, const char **, size_t n); -void lex_sbc_only_once (const char *); +void lex_sbc_only_once (struct lexer *, const char *); void lex_sbc_missing (const char *); void lex_spec_only_once (struct lexer *, const char *subcommand, @@ -196,12 +209,6 @@ void lex_spec_only_once (struct lexer *, const char *subcommand, void lex_spec_missing (struct lexer *, const char *subcommand, const char *specification); -void lex_error_valist (struct lexer *, const char *, va_list) - PRINTF_FORMAT (2, 0); -void lex_ofs_error_valist (struct lexer *lexer, int ofs0, int ofs1, - const char *format, va_list) - PRINTF_FORMAT (4, 0); - /* Error handling. */ enum segmenter_mode lex_get_syntax_mode (const struct lexer *); enum lex_error_mode lex_get_error_mode (const struct lexer *); @@ -213,7 +220,7 @@ void lex_discard_noninteractive (struct lexer *); void lex_set_message_handler (struct lexer *, void (*output_msg) (const struct msg *, struct lexer *)); -void lex_source_ref (const struct lex_source *); +struct lex_source *lex_source_ref (const struct lex_source *); void lex_source_unref (struct lex_source *); struct substring lex_source_get_line (const struct lex_source *, int line); diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index e5805f0356..15ed9f12d2 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -821,7 +821,7 @@ macro_call_create__ (const struct macro_set *macros, /* If TOKEN is the first token of a call to a macro in MACROS, create a new macro expander, initializes *MCP to it. Returns 0 if more tokens are needed and should be added via macro_call_add() or 1 if the caller should next call - macro_call_get_expansion(). + macro_call_expand(). If TOKEN is not the first token of a macro call, returns -1 and sets *MCP to NULL. */ @@ -866,8 +866,8 @@ macro_call_destroy (struct macro_call *mc) Returns a positive number to indicate that the returned number of tokens invoke a macro. The number returned might be less than the number of tokens added because it can take a few tokens of lookahead to determine whether the - macro invocation is finished. The caller should call - macro_call_get_expansion() to obtain the expansion. */ + macro invocation is finished. The caller should call macro_call_expand() to + obtain the expansion. */ int macro_call_add (struct macro_call *mc, const struct macro_token *mt, const struct msg_location *loc) diff --git a/src/language/lexer/value-parser.c b/src/language/lexer/value-parser.c index 23b4def274..c91fa89da1 100644 --- a/src/language/lexer/value-parser.c +++ b/src/language/lexer/value-parser.c @@ -48,6 +48,8 @@ bool parse_num_range (struct lexer *lexer, double *x, double *y, const enum fmt_type *format) { + int start_ofs = lex_ofs (lexer); + if (lex_match_id (lexer, "LO") || lex_match_id (lexer, "LOWEST")) *x = LOWEST; else if (!parse_number (lexer, x, format)) @@ -63,15 +65,17 @@ parse_num_range (struct lexer *lexer, if (*y < *x) { double t; - msg (SW, _("The high end of the range (%.*g) is below the low end " - "(%.*g). The range will be treated as if reversed."), - DBL_DIG + 1, *y, DBL_DIG + 1, *x); + lex_ofs_msg (lexer, SW, start_ofs, lex_ofs (lexer) - 1, + ("The high end of the range (%.*g) is below the low end " + "(%.*g). The range will be treated as if reversed."), + DBL_DIG + 1, *y, DBL_DIG + 1, *x); t = *x; *x = *y; *y = t; } else if (*x == *y) - msg (SW, _("Ends of range are equal (%.*g)."), DBL_DIG + 1, *x); + lex_ofs_msg (lexer, SW, start_ofs, lex_ofs (lexer) - 1, + _("Ends of range are equal (%.*g)."), DBL_DIG + 1, *x); return true; } @@ -79,7 +83,9 @@ parse_num_range (struct lexer *lexer, { if (*x == LOWEST) { - msg (SE, _("%s or %s must be part of a range."), "LO", "LOWEST"); + lex_next_msg (lexer, SW, -1, -1, + _("%s or %s must be part of a range."), + "LO", "LOWEST"); return false; } *y = *x; @@ -110,7 +116,8 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format) *x = v.f; if (*x == SYSMIS) { - msg (SE, _("System-missing value is not valid here.")); + lex_next_error (lexer, -1, -1, + _("System-missing value is not valid here.")); return false; } return true; diff --git a/src/language/lexer/variable-parser.c b/src/language/lexer/variable-parser.c index 14635a209e..7d30a2ad92 100644 --- a/src/language/lexer/variable-parser.c +++ b/src/language/lexer/variable-parser.c @@ -83,7 +83,7 @@ parse_vs_variable_idx (struct lexer *lexer, const struct var_set *vs, if (!is_vs_name_token (lexer, vs)) { - lex_error (lexer, _("expecting variable name")); + lex_error (lexer, _("Syntax error expecting variable name.")); return false; } else if (var_set_lookup_var_idx (vs, lex_tokcstr (lexer), idx)) @@ -93,7 +93,7 @@ parse_vs_variable_idx (struct lexer *lexer, const struct var_set *vs, } else { - msg (SE, _("%s is not a variable name."), lex_tokcstr (lexer)); + lex_error (lexer, _("%s is not a variable name."), lex_tokcstr (lexer)); return false; } } @@ -195,37 +195,45 @@ parse_var_idx_class (struct lexer *lexer, const struct var_set *vs, PV_OPTS, which also affects what variables are allowed in appropriate ways. */ static void -add_variable (struct variable ***v, size_t *nv, size_t *mv, +add_variable (struct lexer *lexer, + struct variable ***v, size_t *nv, size_t *mv, char *included, int pv_opts, - const struct var_set *vs, size_t idx) + const struct var_set *vs, size_t idx, + int start_ofs, int end_ofs) { struct variable *add = var_set_get_var (vs, idx); const char *add_name = var_get_name (add); if ((pv_opts & PV_NUMERIC) && !var_is_numeric (add)) - msg (SW, _("%s is not a numeric variable. It will not be " - "included in the variable list."), add_name); + lex_ofs_msg (lexer, SW, start_ofs, end_ofs, + _("%s is not a numeric variable. It will not be " + "included in the variable list."), add_name); else if ((pv_opts & PV_STRING) && !var_is_alpha (add)) - msg (SE, _("%s is not a string variable. It will not be " - "included in the variable list."), add_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("%s is not a string variable. It will not be " + "included in the variable list."), add_name); else if ((pv_opts & PV_NO_SCRATCH) && dict_class_from_id (add_name) == DC_SCRATCH) - msg (SE, _("Scratch variables (such as %s) are not allowed " - "here."), add_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Scratch variables (such as %s) are not allowed " + "here."), add_name); else if ((pv_opts & (PV_SAME_TYPE | PV_SAME_WIDTH)) && *nv && var_get_type (add) != var_get_type ((*v)[0])) - msg (SE, _("%s and %s are not the same type. All variables in " - "this variable list must be of the same type. %s " - "will be omitted from the list."), - var_get_name ((*v)[0]), add_name, add_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("%s and %s are not the same type. All variables in " + "this variable list must be of the same type. %s " + "will be omitted from the list."), + var_get_name ((*v)[0]), add_name, add_name); else if ((pv_opts & PV_SAME_WIDTH) && *nv && var_get_width (add) != var_get_width ((*v)[0])) - msg (SE, _("%s and %s are string variables with different widths. " - "All variables in this variable list must have the " - "same width. %s will be omitted from the list."), - var_get_name ((*v)[0]), add_name, add_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("%s and %s are string variables with different widths. " + "All variables in this variable list must have the " + "same width. %s will be omitted from the list."), + var_get_name ((*v)[0]), add_name, add_name); else if ((pv_opts & PV_NO_DUPLICATE) && included && included[idx]) - msg (SE, _("Variable %s appears twice in variable list."), add_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Variable %s appears twice in variable list."), add_name); else if ((pv_opts & PV_DUPLICATE) || !included || !included[idx]) { if (*nv >= *mv) @@ -245,16 +253,19 @@ add_variable (struct variable ***v, size_t *nv, size_t *mv, duplicates if indicated by PV_OPTS, which also affects what variables are allowed in appropriate ways. */ static void -add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included, +add_variables (struct lexer *lexer, + struct variable ***v, size_t *nv, size_t *mv, char *included, int pv_opts, const struct var_set *vs, int first_idx, int last_idx, - enum dict_class class) + enum dict_class class, + int start_ofs, int end_ofs) { size_t i; for (i = first_idx; i <= last_idx; i++) if (dict_class_from_id (var_get_name (var_set_get_var (vs, i))) == class) - add_variable (v, nv, mv, included, pv_opts, vs, i); + add_variable (lexer, v, nv, mv, included, pv_opts, vs, i, + start_ofs, end_ofs); } /* Note that if parse_variables() returns false, *v is free()'d. @@ -309,9 +320,11 @@ parse_var_set_vars (struct lexer *lexer, const struct var_set *vs, do { + int start_ofs = lex_ofs (lexer); if (lex_match (lexer, T_ALL)) - add_variables (v, nv, &mv, included, pv_opts, - vs, 0, var_set_get_n (vs) - 1, DC_ORDINARY); + add_variables (lexer, v, nv, &mv, included, pv_opts, + vs, 0, var_set_get_n (vs) - 1, DC_ORDINARY, + start_ofs, start_ofs); else { enum dict_class class; @@ -321,7 +334,8 @@ parse_var_set_vars (struct lexer *lexer, const struct var_set *vs, goto fail; if (!lex_match (lexer, T_TO)) - add_variable (v, nv, &mv, included, pv_opts, vs, first_idx); + add_variable (lexer, v, nv, &mv, included, pv_opts, vs, first_idx, + start_ofs, start_ofs); else { size_t last_idx; @@ -331,6 +345,8 @@ parse_var_set_vars (struct lexer *lexer, const struct var_set *vs, if (!parse_var_idx_class (lexer, vs, &last_idx, &last_class)) goto fail; + int end_ofs = lex_ofs (lexer) - 1; + first_var = var_set_get_var (vs, first_idx); last_var = var_set_get_var (vs, last_idx); @@ -338,27 +354,56 @@ parse_var_set_vars (struct lexer *lexer, const struct var_set *vs, { const char *first_name = var_get_name (first_var); const char *last_name = var_get_name (last_var); - msg (SE, _("%s TO %s is not valid syntax since %s " - "precedes %s in the dictionary."), - first_name, last_name, first_name, last_name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("%s TO %s is not valid syntax since %s " + "precedes %s in the dictionary."), + first_name, last_name, first_name, last_name); goto fail; } if (class != last_class) { - msg (SE, _("When using the TO keyword to specify several " - "variables, both variables must be from " - "the same variable dictionaries, of either " - "ordinary, scratch, or system variables. " - "%s is a %s variable, whereas %s is %s."), - var_get_name (first_var), dict_class_to_name (class), - var_get_name (last_var), - dict_class_to_name (last_class)); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("With the syntax TO , variables " + "and must be both regular variables " + "or both scratch variables.")); + struct pair + { + const char *name; + enum dict_class class; + int ofs; + } + pairs[2] = { + { var_get_name (first_var), class, start_ofs }, + { var_get_name (last_var), last_class, end_ofs }, + }; + for (size_t i = 0; i < 2; i++) + switch (pairs[i].class) + { + case DC_ORDINARY: + lex_ofs_msg (lexer, SN, pairs[i].ofs, pairs[i].ofs, + _("%s is a regular variable."), + pairs[i].name); + break; + + case DC_SCRATCH: + lex_ofs_msg (lexer, SN, pairs[i].ofs, pairs[i].ofs, + _("%s is a scratch variable."), + pairs[i].name); + break; + + case DC_SYSTEM: + lex_ofs_msg (lexer, SN, pairs[i].ofs, pairs[i].ofs, + _("%s is a system variable."), + pairs[i].name); + break; + } goto fail; } - add_variables (v, nv, &mv, included, pv_opts, - vs, first_idx, last_idx, class); + add_variables (lexer, v, nv, &mv, included, pv_opts, + vs, first_idx, last_idx, class, + start_ofs, lex_ofs (lexer) - 1); } } @@ -389,7 +434,7 @@ parse_DATA_LIST_var (struct lexer *lexer, const struct dictionary *d) { if (!is_dict_name_token (lexer, d)) { - lex_error (lexer, "expecting variable name"); + lex_error (lexer, ("Syntax error expecting variable name.")); return NULL; } if (!dict_id_is_valid (d, lex_tokcstr (lexer), true)) @@ -406,7 +451,7 @@ parse_DATA_LIST_var (struct lexer *lexer, const struct dictionary *d) the number of digits in the suffix into *N_DIGITSP, and returns the number of bytes in the root. On failure, returns 0. */ static int -extract_numeric_suffix (const char *name, +extract_numeric_suffix (struct lexer *lexer, int ofs, const char *name, unsigned long int *numberp, int *n_digitsp) { size_t root_len, n_digits; @@ -421,16 +466,18 @@ extract_numeric_suffix (const char *name, if (n_digits == 0) { - msg (SE, _("`%s' cannot be used with TO because it does not end in " - "a digit."), name); + lex_ofs_error (lexer, ofs, ofs, + _("`%s' cannot be used with TO because it does not end in " + "a digit."), name); return 0; } *numberp = strtoull (name + root_len, NULL, 10); if (*numberp == ULONG_MAX) { - msg (SE, _("Numeric suffix on `%s' is larger than supported with TO."), - name); + lex_ofs_error (lexer, ofs, ofs, + _("Numeric suffix on `%s' is larger than supported with TO."), + name); return 0; } *n_digitsp = n_digits; @@ -438,14 +485,15 @@ extract_numeric_suffix (const char *name, } static bool -add_var_name (char *name, +add_var_name (struct lexer *lexer, int start_ofs, int end_ofs, char *name, char ***names, size_t *n_vars, size_t *allocated_vars, struct stringi_set *set, int pv_opts) { if (pv_opts & PV_NO_DUPLICATE && !stringi_set_insert (set, name)) { - msg (SE, _("Variable %s appears twice in variable list."), - name); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Variable %s appears twice in variable list."), + name); return false; } @@ -497,12 +545,14 @@ parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict, do { + int start_ofs = lex_ofs (lexer); name1 = parse_DATA_LIST_var (lexer, dict); if (!name1) goto exit; if (dict_class_from_id (name1) == DC_SCRATCH && pv_opts & PV_NO_SCRATCH) { - msg (SE, _("Scratch variables not allowed here.")); + lex_ofs_error (lexer, start_ofs, start_ofs, + _("Scratch variables not allowed here.")); goto exit; } if (lex_match (lexer, T_TO)) @@ -515,23 +565,28 @@ parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict, name2 = parse_DATA_LIST_var (lexer, dict); if (!name2) goto exit; + int end_ofs = lex_ofs (lexer) - 1; - root_len1 = extract_numeric_suffix (name1, &num1, &n_digits1); + root_len1 = extract_numeric_suffix (lexer, start_ofs, + name1, &num1, &n_digits1); if (root_len1 == 0) goto exit; - root_len2 = extract_numeric_suffix (name2, &num2, &n_digits2); + root_len2 = extract_numeric_suffix (lexer, end_ofs, + name2, &num2, &n_digits2); if (root_len2 == 0) goto exit; if (root_len1 != root_len2 || memcasecmp (name1, name2, root_len1)) { - msg (SE, _("Prefixes don't match in use of TO convention.")); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Prefixes don't match in use of TO convention.")); goto exit; } if (num1 > num2) { - msg (SE, _("Bad bounds in use of TO convention.")); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Bad bounds in use of TO convention.")); goto exit; } @@ -540,7 +595,8 @@ parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict, char *name = xasprintf ("%.*s%0*lu", root_len1, name1, n_digits1, number); - if (!add_var_name (name, &names, &n_vars, &allocated_vars, + if (!add_var_name (lexer, start_ofs, end_ofs, + name, &names, &n_vars, &allocated_vars, &set, pv_opts)) { free (name); @@ -555,7 +611,8 @@ parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict, } else { - if (!add_var_name (name1, &names, &n_vars, &allocated_vars, + if (!add_var_name (lexer, start_ofs, start_ofs, + name1, &names, &n_vars, &allocated_vars, &set, pv_opts)) goto exit; name1 = NULL; @@ -721,7 +778,7 @@ var_syntax_parse (struct lexer *lexer, struct var_syntax **vs, size_t *n_vs) if (lex_token (lexer) != T_ID) { - lex_error (lexer, _("expecting variable name")); + lex_error (lexer, _("Syntax error expecting variable name.")); goto error; } @@ -731,20 +788,24 @@ var_syntax_parse (struct lexer *lexer, struct var_syntax **vs, size_t *n_vs) if (allocated_vs >= *n_vs) *vs = x2nrealloc (*vs, &allocated_vs, sizeof **vs); struct var_syntax *new = &(*vs)[(*n_vs)++]; - *new = (struct var_syntax) { .first = ss_xstrdup (lex_tokss (lexer)) }; + *new = (struct var_syntax) { + .first = ss_xstrdup (lex_tokss (lexer)), + .first_ofs = lex_ofs (lexer) + }; lex_get (lexer); if (lex_match (lexer, T_TO)) { if (lex_token (lexer) != T_ID) { - lex_error (lexer, _("expecting variable name")); + lex_error (lexer, _("Syntax error expecting variable name.")); goto error; } new->last = ss_xstrdup (lex_tokss (lexer)); lex_get (lexer); } + new->last_ofs = lex_ofs (lexer) - 1; } while (lex_token (lexer) == T_ID); return true; @@ -761,9 +822,12 @@ error: array of pointers to variables and *N_VARS to the length of the array and returns true. On error, sets *VARS to NULL and *N_VARS to 0. + The LEXER is just used for error messages. + For the moment, only honors PV_NUMERIC in OPTS. */ bool -var_syntax_evaluate (const struct var_syntax *vs, size_t n_vs, +var_syntax_evaluate (struct lexer *lexer, + const struct var_syntax *vs, size_t n_vs, const struct dictionary *dict, struct variable ***vars, size_t *n_vars, int opts) { @@ -775,19 +839,23 @@ var_syntax_evaluate (const struct var_syntax *vs, size_t n_vs, size_t allocated_vars = 0; for (size_t i = 0; i < n_vs; i++) { + int first_ofs = vs[i].first_ofs; struct variable *first = dict_lookup_var (dict, vs[i].first); if (!first) { - msg (SE, _("%s is not a variable name."), vs[i].first); + lex_ofs_error (lexer, first_ofs, first_ofs, + _("%s is not a variable name."), vs[i].first); goto error; } + int last_ofs = vs[i].last_ofs; struct variable *last = (vs[i].last ? dict_lookup_var (dict, vs[i].last) : first); if (!last) { - msg (SE, _("%s is not a variable name."), vs[i].last); + lex_ofs_error (lexer, last_ofs, last_ofs, + _("%s is not a variable name."), vs[i].last); goto error; } @@ -795,10 +863,11 @@ var_syntax_evaluate (const struct var_syntax *vs, size_t n_vs, size_t last_idx = var_get_dict_index (last); if (last_idx < first_idx) { - msg (SE, _("%s TO %s is not valid syntax since %s " - "precedes %s in the dictionary."), - vs[i].first, vs[i].last, - vs[i].first, vs[i].last); + lex_ofs_error (lexer, first_ofs, last_ofs, + _("%s TO %s is not valid syntax since %s " + "precedes %s in the dictionary."), + vs[i].first, vs[i].last, + vs[i].first, vs[i].last); goto error; } @@ -807,7 +876,9 @@ var_syntax_evaluate (const struct var_syntax *vs, size_t n_vs, struct variable *v = dict_get_var (dict, j); if (opts & PV_NUMERIC && !var_is_numeric (v)) { - msg (SW, _("%s is not a numeric variable."), var_get_name (v)); + lex_ofs_error (lexer, first_ofs, last_ofs, + _("%s is not a numeric variable."), + var_get_name (v)); goto error; } diff --git a/src/language/lexer/variable-parser.h b/src/language/lexer/variable-parser.h index 66e8efab6c..5815dc458b 100644 --- a/src/language/lexer/variable-parser.h +++ b/src/language/lexer/variable-parser.h @@ -82,11 +82,20 @@ struct var_syntax { char *first; /* Always nonnull. */ char *last; /* Nonnull for var ranges (e.g. "a TO b"). */ + + /* For error reporting. + + This only works if var_syntax_parse() and var_syntax_evaluate() are + called while we're parsing the same source file. That matches the + current use case in MATRIX; if that changes, then this will need to + switch to use struct msg_location instead. */ + int first_ofs; + int last_ofs; }; void var_syntax_destroy (struct var_syntax *, size_t n); bool var_syntax_parse (struct lexer *, struct var_syntax **, size_t *); -bool var_syntax_evaluate (const struct var_syntax *, size_t, +bool var_syntax_evaluate (struct lexer *, const struct var_syntax *, size_t, const struct dictionary *, struct variable ***, size_t *, int opts); diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 4151860e10..944ba7b922 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -445,7 +445,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, /* Get the name of the aggregation function. */ if (lex_token (lexer) != T_ID) { - lex_error (lexer, _("expecting aggregation function")); + lex_error (lexer, _("Syntax error expecting aggregation function.")); goto error; } @@ -457,8 +457,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, break; if (NULL == function->name) { - msg (SE, _("Unknown aggregation function %s."), - ds_cstr (&function_name)); + lex_error (lexer, _("Unknown aggregation function %s."), + ds_cstr (&function_name)); goto error; } ds_destroy (&function_name); @@ -476,26 +476,28 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, else { /* Parse list of source variables. */ - { - int pv_opts = PV_NO_SCRATCH; - - if (func_index == SUM || func_index == MEAN || func_index == SD) - pv_opts |= PV_NUMERIC; - else if (function->n_args) - pv_opts |= PV_SAME_TYPE; - - if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts)) - goto error; - } + int pv_opts = PV_NO_SCRATCH; + if (func_index == SUM || func_index == MEAN || func_index == SD) + pv_opts |= PV_NUMERIC; + else if (function->n_args) + pv_opts |= PV_SAME_TYPE; + + int vars_start_ofs = lex_ofs (lexer); + if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts)) + goto error; + int vars_end_ofs = lex_ofs (lexer) - 1; /* Parse function arguments, for those functions that require arguments. */ + int args_start_ofs = 0; if (function->n_args != 0) for (i = 0; i < function->n_args; i++) { int type; lex_match (lexer, T_COMMA); + if (i == 0) + args_start_ofs = lex_ofs (lexer); if (lex_is_string (lexer)) { arg[i].c = recode_string (dict_get_encoding (agr->dict), @@ -510,21 +512,35 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, } else { - msg (SE, _("Missing argument %zu to %s."), - i + 1, function->name); + lex_error (lexer, _("Missing argument %zu to %s."), + i + 1, function->name); goto error; } - - lex_get (lexer); - if (type != var_get_type (src[0])) { msg (SE, _("Arguments to %s must be of same type as " "source variables."), function->name); + if (type == VAL_NUMERIC) + { + lex_next_msg (lexer, SN, 0, 0, + _("The argument is numeric.")); + lex_ofs_msg (lexer, SN, vars_start_ofs, vars_end_ofs, + _("The variables have string type.")); + } + else + { + lex_next_msg (lexer, SN, 0, 0, + _("The argument is a string.")); + lex_ofs_msg (lexer, SN, vars_start_ofs, vars_end_ofs, + _("The variables are numeric.")); + } goto error; } + + lex_get (lexer); } + int args_end_ofs = lex_ofs (lexer) - 1; /* Trailing rparen. */ if (!lex_force_match (lexer, T_RPAREN)) @@ -554,10 +570,11 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, arg[0] = arg[1]; arg[1] = t; - msg (SW, _("The value arguments passed to the %s function " - "are out-of-order. They will be treated as if " - "they had been specified in the correct order."), - function->name); + lex_ofs_msg (lexer, SW, args_start_ofs, args_end_ofs, + _("The value arguments passed to the %s function " + "are out of order. They will be treated as if " + "they had been specified in the correct order."), + function->name); } } @@ -674,7 +691,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, if (lex_token (lexer) == T_ENDCMD) return true; - lex_error (lexer, "expecting end of command"); + lex_error (lexer, "Syntax error expecting end of command."); return false; } continue; diff --git a/src/language/stats/autorecode.c b/src/language/stats/autorecode.c index 499f149d22..0cd81ac920 100644 --- a/src/language/stats/autorecode.c +++ b/src/language/stats/autorecode.c @@ -203,7 +203,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) if (lex_token (lexer) != T_ENDCMD) { - lex_error (lexer, _("expecting end of command")); + lex_error (lexer, _("Syntax error expecting end of command.")); goto error; } diff --git a/src/language/stats/crosstabs.c b/src/language/stats/crosstabs.c index bb63e98253..1b203083e0 100644 --- a/src/language/stats/crosstabs.c +++ b/src/language/stats/crosstabs.c @@ -305,6 +305,7 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds) .descending = false, }; bool show_tables = true; + int exclude_ofs = 0; lex_match (lexer, T_SLASH); for (;;) { @@ -316,6 +317,7 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "MISSING")) { lex_match (lexer, T_EQUALS); + exclude_ofs = lex_ofs (lexer); if (lex_match_id (lexer, "TABLE")) proc.exclude = MV_ANY; else if (lex_match_id (lexer, "INCLUDE")) @@ -472,8 +474,9 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds) /* Missing values. */ if (proc.mode == GENERAL && !proc.exclude) { - msg (SE, _("Missing mode %s not allowed in general mode. " - "Assuming %s."), "REPORT", "MISSING=TABLE"); + lex_ofs_error (lexer, exclude_ofs, exclude_ofs, + _("Missing mode %s not allowed in general mode. " + "Assuming %s."), "REPORT", "MISSING=TABLE"); proc.exclude = MV_ANY; } @@ -656,7 +659,8 @@ parse_crosstabs_variables (struct lexer *lexer, struct dataset *ds, { if (proc->n_pivots) { - msg (SE, _("%s must be specified before %s."), "VARIABLES", "TABLES"); + lex_next_error (lexer, -1, -1, _("%s must be specified before %s."), + "VARIABLES", "TABLES"); return false; } diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index d0c0a8482b..514765962a 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -295,7 +295,7 @@ parse_ctables_summary_function (struct lexer *lexer, } } - lex_error (lexer, _("Expecting summary function name.")); + lex_error (lexer, _("Syntax error expecting summary function name.")); return false; } @@ -1602,8 +1602,7 @@ struct ctables_category }; }; - /* Source location. This is null for CCT_TOTAL, CCT_VALUE, CCT_LABEL, - CCT_FUNCTION, CCT_EXCLUDED_MISSING. */ + /* Source location (sometimes NULL). */ struct msg_location *location; }; @@ -2975,6 +2974,7 @@ struct ctables_table enum pivot_axis_type label_axis[PIVOT_N_AXES]; enum pivot_axis_type clabels_from_axis; enum pivot_axis_type clabels_to_axis; + int clabels_start_ofs, clabels_end_ofs; const struct variable *clabels_example; struct hmap clabels_values_map; struct ctables_value **clabels_values; @@ -4092,6 +4092,8 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, bool show_totals = false; char *total_label = NULL; bool totals_before = false; + int key_start_ofs = 0; + int key_end_ofs = 0; while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD) { if (!c->n_cats && lex_match_id (lexer, "ORDER")) @@ -4109,7 +4111,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, } else if (!c->n_cats && lex_match_id (lexer, "KEY")) { - int start_ofs = lex_ofs (lexer) - 1; + key_start_ofs = lex_ofs (lexer) - 1; lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "VALUE")) cat.type = CCT_VALUE; @@ -4146,9 +4148,13 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, bool UNUSED b = lex_force_match (lexer, T_LPAREN); goto error; } + } + key_end_ofs = lex_ofs (lexer) - 1; - lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1, - _("Data-dependent sorting is not implemented.")); + if (cat.type == CCT_FUNCTION) + { + lex_ofs_error (lexer, key_start_ofs, key_end_ofs, + _("Data-dependent sorting is not implemented.")); goto error; } } @@ -4219,6 +4225,9 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, if (!c->n_cats) { + if (key_start_ofs) + cat.location = lex_ofs_location (lexer, key_start_ofs, key_end_ofs); + if (c->n_cats >= allocated_cats) c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats); c->cats[c->n_cats++] = cat; @@ -4893,15 +4902,13 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t) } static bool -ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a) +ctables_check_label_position (struct ctables_table *t, struct lexer *lexer, + enum pivot_axis_type a) { enum pivot_axis_type label_pos = t->label_axis[a]; if (label_pos == a) return true; - const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS"; - const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE"; - const struct ctables_stack *stack = &t->stacks[a]; if (!stack->n) return true; @@ -4920,17 +4927,29 @@ ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a) for (size_t i = 0; i < c0->n_cats; i++) if (c0->cats[i].type == CCT_FUNCTION) { - msg (SE, _("%s=%s is not allowed with sorting based " - "on a summary function."), - subcommand_name, pos_name); + msg (SE, _("Category labels may not be moved to another axis when " + "sorting by a summary function.")); + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, t->clabels_end_ofs, + _("This syntax moves category labels to another axis.")); + msg_at (SN, c0->cats[i].location, + _("This syntax requests sorting by a summary function.")); return false; } - if (n0->n - 1 == n0->scale_idx) + + for (size_t i = 0; i < stack->n; i++) { - msg (SE, _("%s=%s requires the variables to be moved to be categorical, " - "but %s is a scale variable."), - subcommand_name, pos_name, var_get_name (v0)); - return false; + const struct ctables_nest *ni = &stack->nests[i]; + assert (ni->n > 0); + const struct variable *vi = ni->vars[ni->n - 1]; + if (n0->n - 1 == ni->scale_idx) + { + msg (SE, _("To move category labels from one axis to another, " + "the variables whose labels are to be moved must be " + "categorical, but %s is scale."), var_get_name (vi)); + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, t->clabels_end_ofs, + _("This syntax moves category labels to another axis.")); + return false; + } } for (size_t i = 1; i < stack->n; i++) @@ -4940,41 +4959,39 @@ ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a) const struct variable *vi = ni->vars[ni->n - 1]; struct ctables_categories *ci = t->categories[var_get_dict_index (vi)]; - if (ni->n - 1 == ni->scale_idx) - { - msg (SE, _("%s=%s requires the variables to be moved to be " - "categorical, but %s is a scale variable."), - subcommand_name, pos_name, var_get_name (vi)); - return false; - } if (var_get_width (v0) != var_get_width (vi)) { - msg (SE, _("%s=%s requires the variables to be " - "moved to have the same width, but %s has " - "width %d and %s has width %d."), - subcommand_name, pos_name, + msg (SE, _("To move category labels from one axis to another, " + "the variables whose labels are to be moved must all " + "have the same width, but %s has width %d and %s has " + "width %d."), var_get_name (v0), var_get_width (v0), var_get_name (vi), var_get_width (vi)); + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, t->clabels_end_ofs, + _("This syntax moves category labels to another axis.")); return false; } if (!val_labs_equal (var_get_value_labels (v0), var_get_value_labels (vi))) { - msg (SE, _("%s=%s requires the variables to be " - "moved to have the same value labels, but %s " - "and %s have different value labels."), - subcommand_name, pos_name, + msg (SE, _("To move category labels from one axis to another, " + "the variables whose labels are to be moved must all " + "have the same value labels, but %s and %s have " + "different value labels."), var_get_name (v0), var_get_name (vi)); + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, t->clabels_end_ofs, + _("This syntax moves category labels to another axis.")); return false; } if (!ctables_categories_equal (c0, ci)) { - msg (SE, _("%s=%s requires the variables to be " - "moved to have the same category " - "specifications, but %s and %s have different " - "category specifications."), - subcommand_name, pos_name, + msg (SE, _("To move category labels from one axis to another, " + "the variables whose labels are to be moved must all " + "have the same category specifications, but %s and %s " + "have different category specifications."), var_get_name (v0), var_get_name (vi)); + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, t->clabels_end_ofs, + _("This syntax moves category labels to another axis.")); return false; } } @@ -5051,7 +5068,7 @@ enumerate_sum_vars (const struct ctables_axis *a, } static bool -ctables_prepare_table (struct ctables_table *t) +ctables_prepare_table (struct ctables_table *t, struct lexer *lexer) { for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) if (t->axes[a]) @@ -5288,8 +5305,8 @@ ctables_prepare_table (struct ctables_table *t) enumerate_sum_vars (t->axes[t->summary_axis], &t->sum_vars, &t->n_sum_vars, &allocated_sum_vars); - return (ctables_check_label_position (t, PIVOT_AXIS_ROW) - && ctables_check_label_position (t, PIVOT_AXIS_COLUMN)); + return (ctables_check_label_position (t, lexer, PIVOT_AXIS_ROW) + && ctables_check_label_position (t, lexer, PIVOT_AXIS_COLUMN)); } static void @@ -5800,7 +5817,8 @@ ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct) = ctables_find_postcompute (ct, lex_tokcstr (lexer)); if (!pc) { - msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer)); + lex_error (lexer, _("Unknown computed category &%s."), + lex_tokcstr (lexer)); goto error; } lex_get (lexer); @@ -6017,6 +6035,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) double widths[2] = { SYSMIS, SYSMIS }; double units_per_inch = 72.0; + int start_ofs = lex_ofs (lexer); while (lex_token (lexer) != T_SLASH) { if (lex_match_id (lexer, "MINCOLWIDTH")) @@ -6087,7 +6106,9 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) if (widths[0] != SYSMIS && widths[1] != SYSMIS && widths[0] > widths[1]) { - msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH.")); + lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1, + _("MINCOLWIDTH must not be greater than " + "MAXCOLWIDTH.")); goto error; } @@ -6200,6 +6221,15 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS", "SMISSING", "PCOMPUTE", "PPROPERTIES", "WEIGHT", "HIDESMALLCOUNTS", "TABLE"); + if (lex_match_id (lexer, "SLABELS") + || lex_match_id (lexer, "CLABELS") + || lex_match_id (lexer, "CRITERIA") + || lex_match_id (lexer, "CATEGORIES") + || lex_match_id (lexer, "TITLES") + || lex_match_id (lexer, "SIGTEST") + || lex_match_id (lexer, "COMPARETEST")) + lex_next_msg (lexer, SN, -1, -1, + _("TABLE must appear before this subcommand.")); goto error; } @@ -6343,7 +6373,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) if (lex_token (lexer) == T_ENDCMD) { - if (!ctables_prepare_table (t)) + if (!ctables_prepare_table (t, lexer)) goto error; break; } @@ -6386,6 +6416,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "CLABELS")) { + int start_ofs = lex_ofs (lexer) - 1; if (lex_match_id (lexer, "AUTO")) { t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW; @@ -6423,6 +6454,24 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) "COLLABELS"); goto error; } + int end_ofs = lex_ofs (lexer) - 1; + + if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW + && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN) + { + msg (SE, _("ROWLABELS and COLLABELS may not both be " + "specified.")); + + lex_ofs_msg (lexer, SN, t->clabels_start_ofs, + t->clabels_end_ofs, + _("This is the first specification.")); + lex_ofs_msg (lexer, SN, start_ofs, end_ofs, + _("This is the second specification.")); + goto error; + } + + t->clabels_start_ofs = start_ofs; + t->clabels_end_ofs = end_ofs; } else if (lex_match_id (lexer, "CRITERIA")) { @@ -6540,7 +6589,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "COMPARETEST")) { - int start_ofs = lex_ofs (lexer); + int start_ofs = lex_ofs (lexer) - 1; if (!t->pairwise) { t->pairwise = xmalloc (sizeof *t->pairwise); @@ -6690,6 +6739,16 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS", "CRITERIA", "CATEGORIES", "TITLES", "SIGTEST", "COMPARETEST"); + if (lex_match_id (lexer, "FORMAT") + || lex_match_id (lexer, "VLABELS") + || lex_match_id (lexer, "MRSETS") + || lex_match_id (lexer, "SMISSING") + || lex_match_id (lexer, "PCOMPUTE") + || lex_match_id (lexer, "PPROPERTIES") + || lex_match_id (lexer, "WEIGHT") + || lex_match_id (lexer, "HIDESMALLCOUNTS")) + lex_next_msg (lexer, SN, -1, -1, + _("This subcommand must appear before TABLE.")); goto error; } @@ -6698,19 +6757,12 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) } if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW) - { - t->clabels_from_axis = PIVOT_AXIS_ROW; - if (t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN) - { - msg (SE, _("ROWLABELS and COLLABELS may not both be specified.")); - goto error; - } - } + t->clabels_from_axis = PIVOT_AXIS_ROW; else if (t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN) t->clabels_from_axis = PIVOT_AXIS_COLUMN; t->clabels_to_axis = t->label_axis[t->clabels_from_axis]; - if (!ctables_prepare_table (t)) + if (!ctables_prepare_table (t, lexer)) goto error; } while (lex_token (lexer) != T_ENDCMD); diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 160e45610f..5f8c980852 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -335,11 +335,8 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) if (lex_match (lexer, T_LPAREN)) { - if (lex_token (lexer) != T_ID) - { - lex_error (lexer, NULL); - goto error; - } + if (!lex_force_id (lexer)) + goto error; if (try_name (dict, dsc, lex_tokcstr (lexer))) { struct dsc_var *dsc_var = &dsc->vars[dsc->n_vars - 1]; @@ -347,8 +344,9 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) n_zs++; } else - msg (SE, _("Z-score variable name %s would be" - " a duplicate variable name."), lex_tokcstr (lexer)); + lex_error (lexer, _("Z-score variable name %s would be " + "a duplicate variable name."), + lex_tokcstr (lexer)); lex_get (lexer); if (!lex_force_match (lexer, T_RPAREN)) goto error; @@ -468,13 +466,15 @@ match_statistic (struct lexer *lexer) { if (lex_token (lexer) == T_ID) { - enum dsc_statistic stat; - - for (stat = 0; stat < DSC_N_STATS; stat++) + for (enum dsc_statistic stat = 0; stat < DSC_N_STATS; stat++) if (lex_match_id (lexer, dsc_info[stat].identifier)) return stat; - lex_error (lexer, _("expecting statistic name: reverting to default")); + const char *stat_names[DSC_N_STATS]; + for (enum dsc_statistic stat = 0; stat < DSC_N_STATS; stat++) + stat_names[stat] = dsc_info[stat].identifier; + lex_error_expecting_array (lexer, stat_names, + sizeof stat_names / sizeof *stat_names); lex_get (lexer); } diff --git a/src/language/stats/examine.c b/src/language/stats/examine.c index 19c42fcad5..446f9058e9 100644 --- a/src/language/stats/examine.c +++ b/src/language/stats/examine.c @@ -1758,7 +1758,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) if (totals_seen && nototals_seen) { - msg (SE, _("%s and %s are mutually exclusive"), "TOTAL", "NOTOTAL"); + msg (SE, _("%s and %s are mutually exclusive."), "TOTAL", "NOTOTAL"); goto error; } diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c index 993f8975a6..113d565367 100644 --- a/src/language/stats/flip.c +++ b/src/language/stats/flip.c @@ -97,8 +97,10 @@ cmd_flip (struct lexer *lexer, struct dataset *ds) bool ok; if (proc_make_temporary_transformations_permanent (ds)) - msg (SW, _("%s ignores %s. " - "Temporary transformations will be made permanent."), "FLIP", "TEMPORARY"); + lex_ofs_msg (lexer, SW, 0, lex_ofs (lexer) - 1, + _("%s ignores %s. " + "Temporary transformations will be made permanent."), + "FLIP", "TEMPORARY"); flip = pool_create_container (struct flip_pgm, pool); flip->n_vars = 0; diff --git a/src/language/stats/graph.c b/src/language/stats/graph.c index 8157bb2958..5c56191052 100644 --- a/src/language/stats/graph.c +++ b/src/language/stats/graph.c @@ -840,7 +840,7 @@ cmd_graph (struct lexer *lexer, struct dataset *ds) const struct variable *v = NULL; if (!lex_match_variable (lexer,graph.dict,&v)) { - lex_error (lexer, _("Variable expected")); + lex_error (lexer, _("Syntax error expecting variable name.")); goto error; } graph.by_var[0] = v; @@ -880,7 +880,6 @@ cmd_graph (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "FOOTNOTE")) { lex_error (lexer, _("%s is not yet implemented."),"FOOTNOTE"); - lex_error (lexer, _("FOOTNOTE is not implemented yet for GRAPH")); goto error; } else if (lex_match_id (lexer, "MISSING")) diff --git a/src/language/stats/matrix.c b/src/language/stats/matrix.c index 37b565e05e..ba6a140207 100644 --- a/src/language/stats/matrix.c +++ b/src/language/stats/matrix.c @@ -89,9 +89,13 @@ struct msave_common /* Common configuration for all MSAVEs. */ struct msg_location *location; /* Range of lines for first MSAVE. */ struct file_handle *outfile; /* Output file for all the MSAVEs. */ + struct msg_location *outfile_location; struct string_array variables; /* VARIABLES subcommand. */ + struct msg_location *variables_location; struct string_array fnames; /* FNAMES subcommand. */ + struct msg_location *fnames_location; struct string_array snames; /* SNAMES subcommand. */ + struct msg_location *snames_location; /* Collects and owns factors and splits. The individual msave_command structs point to these but do not own them. (This is because factors @@ -4742,7 +4746,8 @@ matrix_lvalue_parse (struct matrix_state *s) { if (!lvalue->var) { - msg (SE, _("Undefined variable %s."), lex_tokcstr (s->lexer)); + lex_error (s->lexer, _("Undefined variable %s."), + lex_tokcstr (s->lexer)); goto error; } @@ -5173,6 +5178,7 @@ struct matrix_command struct matrix_get { + struct lexer *lexer; struct matrix_lvalue *dst; struct dataset *dataset; struct file_handle *file; @@ -5924,7 +5930,7 @@ matrix_break_parse (struct matrix_state *s) { if (!s->in_loop) { - msg (SE, _("BREAK not inside LOOP.")); + lex_next_error (s->lexer, -1, -1, _("BREAK not inside LOOP.")); return NULL; } @@ -6022,7 +6028,7 @@ matrix_release_parse (struct matrix_state *s) cmd->release.vars[cmd->release.n_vars++] = var; } else - lex_error (s->lexer, _("Variable name expected.")); + lex_error (s->lexer, _("Syntax error expecting variable name.")); lex_get (s->lexer); if (!lex_match (s->lexer, T_COMMA)) @@ -6441,6 +6447,10 @@ matrix_read_parse (struct matrix_state *s) if (!read->dst) goto error; + int by_ofs = 0; + int format_ofs = 0; + int record_width_start = 0, record_width_end = 0; + int by = 0; int repetitions = 0; int record_width = 0; @@ -6471,6 +6481,7 @@ matrix_read_parse (struct matrix_state *s) { lex_match (s->lexer, T_EQUALS); + record_width_start = lex_ofs (s->lexer); if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX)) goto error; read->c1 = lex_integer (s->lexer); @@ -6479,6 +6490,7 @@ matrix_read_parse (struct matrix_state *s) || !lex_force_int_range (s->lexer, "TO", read->c1, INT_MAX)) goto error; read->c2 = lex_integer (s->lexer) + 1; + record_width_end = lex_ofs (s->lexer); lex_get (s->lexer); record_width = read->c2 - read->c1; @@ -6488,12 +6500,20 @@ matrix_read_parse (struct matrix_state *s) read->c2 - read->c1)) goto error; by = lex_integer (s->lexer); + by_ofs = lex_ofs (s->lexer); + int field_end = lex_ofs (s->lexer); lex_get (s->lexer); if (record_width % by) { - msg (SE, _("BY %d does not evenly divide record width %d."), - by, record_width); + lex_ofs_error ( + s->lexer, record_width_start, field_end, + _("Field width %d does not evenly divide record width %d."), + by, record_width); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates the record width.")); + lex_ofs_msg (s->lexer, SN, by_ofs, by_ofs, + _("This syntax specifies the field width.")); goto error; } } @@ -6527,7 +6547,7 @@ matrix_read_parse (struct matrix_state *s) { if (seen_format) { - lex_sbc_only_once ("FORMAT"); + lex_sbc_only_once (s->lexer, "FORMAT"); goto error; } seen_format = true; @@ -6537,6 +6557,7 @@ matrix_read_parse (struct matrix_state *s) if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer)) goto error; + format_ofs = lex_ofs (s->lexer); const char *p = lex_tokcstr (s->lexer); if (c_isdigit (p[0])) { @@ -6578,6 +6599,8 @@ matrix_read_parse (struct matrix_state *s) { msg (SE, _("SIZE is required for reading data into a full matrix " "(as opposed to a submatrix).")); + msg_at (SN, read->dst->var_location, + _("This expression designates a full matrix.")); goto error; } @@ -6618,6 +6641,10 @@ matrix_read_parse (struct matrix_state *s) { msg (SE, _("%d repetitions cannot fit in record width %d."), repetitions, record_width); + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + _("This syntax designates the number of repetitions.")); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates the record width.")); goto error; } int w = (repetitions ? record_width / repetitions @@ -6625,14 +6652,26 @@ matrix_read_parse (struct matrix_state *s) : by); if (by && w != by) { + msg (SE, _("This command specifies two different field widths.")); if (repetitions) - msg (SE, _("FORMAT specifies %d repetitions with record width %d, " - "which implies field width %d, " - "but BY specifies field width %d."), - repetitions, record_width, w, by); + { + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + ngettext ("This syntax specifies %d repetition.", + "This syntax specifies %d repetitions.", + repetitions), + repetitions); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates record width %d, " + "which divided by %d repetitions implies " + "field width %d."), + record_width, repetitions, w); + } else - msg (SE, _("FORMAT specifies field width %d but BY specifies %d."), - w, by); + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + _("This syntax specifies field width %d."), w); + + lex_ofs_msg (s->lexer, SN, by_ofs, by_ofs, + _("This syntax specifies field width %d."), by); goto error; } read->w = w; @@ -6988,6 +7027,10 @@ matrix_write_parse (struct matrix_state *s) if (!write->expression) goto error; + int by_ofs = 0; + int format_ofs = 0; + int record_width_start = 0, record_width_end = 0; + int by = 0; int repetitions = 0; int record_width = 0; @@ -7019,6 +7062,8 @@ matrix_write_parse (struct matrix_state *s) { lex_match (s->lexer, T_EQUALS); + record_width_start = lex_ofs (s->lexer); + if (!lex_force_int_range (s->lexer, "FIELD", 1, INT_MAX)) goto error; write->c1 = lex_integer (s->lexer); @@ -7027,6 +7072,7 @@ matrix_write_parse (struct matrix_state *s) || !lex_force_int_range (s->lexer, "TO", write->c1, INT_MAX)) goto error; write->c2 = lex_integer (s->lexer) + 1; + record_width_end = lex_ofs (s->lexer); lex_get (s->lexer); record_width = write->c2 - write->c1; @@ -7035,13 +7081,21 @@ matrix_write_parse (struct matrix_state *s) if (!lex_force_int_range (s->lexer, "BY", 1, write->c2 - write->c1)) goto error; + by_ofs = lex_ofs (s->lexer); + int field_end = lex_ofs (s->lexer); by = lex_integer (s->lexer); lex_get (s->lexer); if (record_width % by) { - msg (SE, _("BY %d does not evenly divide record width %d."), - by, record_width); + lex_ofs_error ( + s->lexer, record_width_start, field_end, + _("Field width %d does not evenly divide record width %d."), + by, record_width); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates the record width.")); + lex_ofs_msg (s->lexer, SN, by_ofs, by_ofs, + _("This syntax specifies the field width.")); goto error; } } @@ -7067,7 +7121,7 @@ matrix_write_parse (struct matrix_state *s) { if (has_format || write->format) { - lex_sbc_only_once ("FORMAT"); + lex_sbc_only_once (s->lexer, "FORMAT"); goto error; } @@ -7076,6 +7130,7 @@ matrix_write_parse (struct matrix_state *s) if (lex_token (s->lexer) != T_STRING && !lex_force_id (s->lexer)) goto error; + format_ofs = lex_ofs (s->lexer); const char *p = lex_tokcstr (s->lexer); if (c_isdigit (p[0])) { @@ -7151,8 +7206,10 @@ matrix_write_parse (struct matrix_state *s) */ if (repetitions > record_width) { - msg (SE, _("%d repetitions cannot fit in record width %d."), - repetitions, record_width); + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + _("This syntax designates the number of repetitions.")); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates the record width.")); goto error; } int w = (repetitions ? record_width / repetitions @@ -7160,14 +7217,26 @@ matrix_write_parse (struct matrix_state *s) : by); if (by && w != by) { + msg (SE, _("This command specifies two different field widths.")); if (repetitions) - msg (SE, _("FORMAT specifies %d repetitions with record width %d, " - "which implies field width %d, " - "but BY specifies field width %d."), - repetitions, record_width, w, by); + { + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + ngettext ("This syntax specifies %d repetition.", + "This syntax specifies %d repetitions.", + repetitions), + repetitions); + lex_ofs_msg (s->lexer, SN, record_width_start, record_width_end, + _("This syntax designates record width %d, " + "which divided by %d repetitions implies " + "field width %d."), + record_width, repetitions, w); + } else - msg (SE, _("FORMAT specifies field width %d but BY specifies %d."), - w, by); + lex_ofs_msg (s->lexer, SN, format_ofs, format_ofs, + _("This syntax specifies field width %d."), w); + + lex_ofs_msg (s->lexer, SN, by_ofs, by_ofs, + _("This syntax specifies field width %d."), by); goto error; } if (w && !write->format) @@ -7181,10 +7250,11 @@ matrix_write_parse (struct matrix_state *s) if (write->format && fmt_var_width (write->format) > sizeof (double)) { - char s[FMT_STRING_LEN_MAX + 1]; - fmt_to_string (write->format, s); - msg (SE, _("Format %s is too wide for %zu-byte matrix elements."), - s, sizeof (double)); + char fs[FMT_STRING_LEN_MAX + 1]; + fmt_to_string (write->format, fs); + lex_ofs_error (s->lexer, format_ofs, format_ofs, + _("Format %s is too wide for %zu-byte matrix elements."), + fs, sizeof (double)); goto error; } @@ -7291,6 +7361,7 @@ matrix_get_parse (struct matrix_state *s) *cmd = (struct matrix_command) { .type = MCMD_GET, .get = { + .lexer = s->lexer, .dataset = s->dataset, .user = { .treatment = MGET_ERROR }, .system = { .treatment = MGET_ERROR }, @@ -7335,7 +7406,7 @@ matrix_get_parse (struct matrix_state *s) if (get->n_vars) { - lex_sbc_only_once ("VARIABLES"); + lex_sbc_only_once (s->lexer, "VARIABLES"); goto error; } @@ -7418,7 +7489,7 @@ matrix_get_execute__ (struct matrix_command *cmd, struct casereader *reader, if (get->n_vars) { - if (!var_syntax_evaluate (get->vars, get->n_vars, dict, + if (!var_syntax_evaluate (get->lexer, get->vars, get->n_vars, dict, &vars, &n_vars, PV_NUMERIC)) return; } @@ -7540,7 +7611,7 @@ matrix_open_casereader (const struct matrix_command *cmd, { if (dict_get_n_vars (dataset_dict (dataset)) == 0) { - msg_at (ME, cmd->location, + msg_at (SE, cmd->location, _("The %s command cannot read an empty active file."), command_name); return false; @@ -7579,21 +7650,39 @@ matrix_get_execute (struct matrix_command *cmd) static bool variables_changed (const char *keyword, - const struct string_array *new, - const struct string_array *old) -{ - if (new->n) - { - if (!old->n) - { - msg (SE, _("%s may only be specified on MSAVE if it was specified " - "on the first MSAVE within MATRIX."), keyword); + const struct string_array *new_vars, + const struct msg_location *new_vars_location, + const struct msg_location *new_location, + const struct string_array *old_vars, + const struct msg_location *old_vars_location, + const struct msg_location *old_location) +{ + if (new_vars->n) + { + if (!old_vars->n) + { + msg_at (SE, new_location, + _("%s may only be specified on MSAVE if it was specified " + "on the first MSAVE within MATRIX."), keyword); + msg_at (SN, old_location, + _("The first MSAVE in MATRIX did not specify %s."), + keyword); + msg_at (SN, new_vars_location, + _("This is the specification of %s on a later MSAVE."), + keyword); return true; } - else if (!string_array_equal_case (old, new)) - { - msg (SE, _("%s must specify the same variables each time within " - "a given MATRIX."), keyword); + if (!string_array_equal_case (old_vars, new_vars)) + { + msg_at (SE, new_location, + _("%s must specify the same variables on each MSAVE " + "within a given MATRIX."), keyword); + msg_at (SE, old_vars_location, + _("This is the specification of %s on the first MSAVE."), + keyword); + msg_at (SE, new_vars_location, + _("This is a different specification of %s on a later MSAVE."), + keyword); return true; } } @@ -7605,14 +7694,25 @@ msave_common_changed (const struct msave_common *old, const struct msave_common *new) { if (new->outfile && !fh_equal (old->outfile, new->outfile)) - msg (SE, _("OUTFILE must name the same file on each MSAVE " - "within a single MATRIX command.")); - else if (variables_changed ("VARIABLES", &new->variables, &old->variables) - || variables_changed ("FNAMES", &new->fnames, &old->fnames) - || variables_changed ("SNAMES", &new->snames, &old->snames)) - msg_at (SN, old->location, - _("This is the location of the first MSAVE command.")); - else + { + msg (SE, _("OUTFILE must name the same file on each MSAVE " + "within a single MATRIX command.")); + msg_at (SN, old->outfile_location, + _("This is the OUTFILE on the first MSAVE command.")); + msg_at (SN, new->outfile_location, + _("This is the OUTFILE on a later MSAVE command.")); + return false; + } + + if (!variables_changed ("VARIABLES", + &new->variables, new->variables_location, new->location, + &old->variables, old->variables_location, old->location) + && !variables_changed ("FNAMES", + &new->fnames, new->fnames_location, new->location, + &old->fnames, old->fnames_location, old->location) + && !variables_changed ("SNAMES", + &new->snames, new->snames_location, new->location, + &old->snames, old->snames_location, old->location)) return false; return true; @@ -7625,9 +7725,13 @@ msave_common_destroy (struct msave_common *common) { msg_location_destroy (common->location); fh_unref (common->outfile); + msg_location_destroy (common->outfile_location); string_array_destroy (&common->variables); + msg_location_destroy (common->variables_location); string_array_destroy (&common->fnames); + msg_location_destroy (common->fnames_location); string_array_destroy (&common->snames); + msg_location_destroy (common->snames_location); for (size_t i = 0; i < common->n_factors; i++) matrix_expr_destroy (common->factors[i]); @@ -7661,17 +7765,22 @@ match_rowtype (struct lexer *lexer) } static bool -parse_var_names (struct lexer *lexer, struct string_array *sa) +parse_var_names (struct lexer *lexer, struct string_array *sa, + struct msg_location **locationp) { lex_match (lexer, T_EQUALS); string_array_clear (sa); + msg_location_destroy (*locationp); + *locationp = NULL; struct dictionary *dict = dict_create (get_default_encoding ()); char **names; size_t n_names; + int start_ofs = lex_ofs (lexer); bool ok = parse_DATA_LIST_vars (lexer, dict, &names, &n_names, PV_NO_DUPLICATE | PV_NO_SCRATCH); + int end_ofs = lex_ofs (lexer) - 1; dict_unref (dict); if (ok) @@ -7680,16 +7789,17 @@ parse_var_names (struct lexer *lexer, struct string_array *sa) if (ss_equals_case (ss_cstr (names[i]), ss_cstr ("ROWTYPE_")) || ss_equals_case (ss_cstr (names[i]), ss_cstr ("VARNAME_"))) { - msg (SE, _("Variable name %s is reserved."), names[i]); + lex_ofs_error (lexer, start_ofs, end_ofs, + _("Variable name %s is reserved."), names[i]); for (size_t j = 0; j < n_names; j++) free (names[i]); free (names); return false; } - string_array_clear (sa); sa->strings = names; sa->n = sa->allocated = n_names; + *locationp = lex_ofs_location (lexer, start_ofs, end_ofs); } return ok; } @@ -7728,23 +7838,30 @@ matrix_msave_parse (struct matrix_state *s) lex_match (s->lexer, T_EQUALS); fh_unref (common->outfile); + int start_ofs = lex_ofs (s->lexer); common->outfile = fh_parse (s->lexer, FH_REF_FILE, NULL); if (!common->outfile) goto error; + msg_location_destroy (common->outfile_location); + common->outfile_location = lex_ofs_location (s->lexer, start_ofs, + lex_ofs (s->lexer) - 1); } else if (lex_match_id (s->lexer, "VARIABLES")) { - if (!parse_var_names (s->lexer, &common->variables)) + if (!parse_var_names (s->lexer, &common->variables, + &common->variables_location)) goto error; } else if (lex_match_id (s->lexer, "FNAMES")) { - if (!parse_var_names (s->lexer, &common->fnames)) + if (!parse_var_names (s->lexer, &common->fnames, + &common->fnames_location)) goto error; } else if (lex_match_id (s->lexer, "SNAMES")) { - if (!parse_var_names (s->lexer, &common->snames)) + if (!parse_var_names (s->lexer, &common->snames, + &common->snames_location)) goto error; } else if (lex_match_id (s->lexer, "SPLIT")) @@ -7782,12 +7899,12 @@ matrix_msave_parse (struct matrix_state *s) { if (common->fnames.n && !factors) { - msg (SE, _("FNAMES requires FACTOR.")); + msg_at (SE, common->fnames_location, _("FNAMES requires FACTOR.")); goto error; } if (common->snames.n && !splits) { - msg (SE, _("SNAMES requires SPLIT.")); + msg_at (SE, common->snames_location, _("SNAMES requires SPLIT.")); goto error; } if (!common->outfile) @@ -7869,8 +7986,7 @@ msave_add_vars (struct dictionary *d, const struct string_array *vars) } static struct dictionary * -msave_create_dict (const struct msave_common *common, - const struct msg_location *location) +msave_create_dict (const struct msave_common *common) { struct dictionary *dict = dict_create (get_default_encoding ()); @@ -7887,7 +8003,8 @@ msave_create_dict (const struct msave_common *common, const char *dup_factor = msave_add_vars (dict, &common->fnames); if (dup_factor) { - msg_at (SE, location, _("Duplicate or invalid FACTOR variable name %s."), + msg_at (SE, common->fnames_location, + _("Duplicate or invalid FACTOR variable name %s."), dup_factor); goto error; } @@ -7897,7 +8014,8 @@ msave_create_dict (const struct msave_common *common, const char *dup_var = msave_add_vars (dict, &common->variables); if (dup_var) { - msg_at (SE, location, _("Duplicate or invalid variable name %s."), + msg_at (SE, common->variables_location, + _("Duplicate or invalid variable name %s."), dup_var); goto error; } @@ -7976,7 +8094,7 @@ matrix_msave_execute (struct matrix_command *cmd) if (!common->writer) { - struct dictionary *dict = msave_create_dict (common, cmd->location); + struct dictionary *dict = msave_create_dict (common); if (!dict) goto error; @@ -8851,7 +8969,8 @@ matrix_commands_parse (struct matrix_state *s, struct matrix_commands *c, if (lex_at_phrase (s->lexer, "END MATRIX")) { - msg (SE, _("Premature END MATRIX within %s."), command_name); + lex_next_error (s->lexer, 0, 1, + _("Premature END MATRIX within %s."), command_name); return false; } diff --git a/src/language/stats/npar.c b/src/language/stats/npar.c index eada5d1649..d7b2cff853 100644 --- a/src/language/stats/npar.c +++ b/src/language/stats/npar.c @@ -424,7 +424,7 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests npt->missing++; if (npt->missing > 1) { - lex_sbc_only_once ("MISSING"); + lex_sbc_only_once (lexer, "MISSING"); goto lossage; } while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD) @@ -451,7 +451,7 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests npt->method++; if (npt->method > 1) { - lex_sbc_only_once ("METHOD"); + lex_sbc_only_once (lexer, "METHOD"); goto lossage; } switch (npar_method (lexer, nps)) @@ -500,7 +500,7 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests } if (lex_token (lexer) != T_ENDCMD) { - lex_error (lexer, _("expecting end of command")); + lex_error (lexer, _("Syntax error expecting end of command.")); goto lossage; } @@ -688,7 +688,8 @@ npar_runs (struct lexer *lexer, struct dataset *ds, } else { - lex_error (lexer, _("Expecting %s, %s, %s or a number."), "MEAN", "MEDIAN", "MODE"); + lex_error (lexer, _("Syntax error expecting %s, %s, %s or a number."), + "MEAN", "MEDIAN", "MODE"); return 0; } diff --git a/src/language/stats/oneway.c b/src/language/stats/oneway.c index 6ad71f14c8..c65683e246 100644 --- a/src/language/stats/oneway.c +++ b/src/language/stats/oneway.c @@ -517,8 +517,9 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds) } else { - msg (SE, _("The post hoc analysis method %s is not supported."), lex_tokcstr (lexer)); - lex_error (lexer, NULL); + lex_error (lexer, + _("The post hoc analysis method %s is not supported."), + lex_tokcstr (lexer)); goto error; } } diff --git a/src/language/stats/quick-cluster.c b/src/language/stats/quick-cluster.c index 0cd08d02a9..161b9768b1 100644 --- a/src/language/stats/quick-cluster.c +++ b/src/language/stats/quick-cluster.c @@ -905,8 +905,7 @@ quick_cluster_parse (struct lexer *lexer, struct qc *qc) } else { - lex_error (lexer, _("Expecting %s or %s."), - "CLUSTER", "DISTANCE"); + lex_error_expecting (lexer, "CLUSTER", "DISTANCE"); return false; } } diff --git a/src/language/stats/rank.c b/src/language/stats/rank.c index ad113676cb..5baa4ca6ce 100644 --- a/src/language/stats/rank.c +++ b/src/language/stats/rank.c @@ -328,11 +328,11 @@ parse_into (struct lexer *lexer, struct rank *cmd, const char *name = lex_tokcstr (lexer); if (var_count >= subcase_get_n_fields (&cmd->sc)) - msg (SE, _("Too many variables in %s clause."), "INTO"); + lex_error (lexer, _("Too many variables in %s clause."), "INTO"); else if (dict_lookup_var (cmd->dict, name) != NULL) - msg (SE, _("Variable %s already exists."), name); + lex_error (lexer, _("Variable %s already exists."), name); else if (string_set_contains (new_names, name)) - msg (SE, _("Duplicate variable name %s."), name); + lex_error (lexer, _("Duplicate variable name %s."), name); else { string_set_insert (new_names, name); diff --git a/src/language/stats/regression.c b/src/language/stats/regression.c index b4448dd9e5..8605638de9 100644 --- a/src/language/stats/regression.c +++ b/src/language/stats/regression.c @@ -212,6 +212,8 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) bool variables_seen = false; bool method_seen = false; bool dependent_seen = false; + int save_start = 0; + int save_end = 0; while (lex_token (lexer) != T_ENDCMD) { lex_match (lexer, T_SLASH); @@ -220,12 +222,14 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) { if (method_seen) { - msg (SE, _("VARIABLES may not appear after %s"), "METHOD"); + lex_next_error (lexer, -1, -1, + _("VARIABLES may not appear after %s"), "METHOD"); goto error; } if (dependent_seen) { - msg (SE, _("VARIABLES may not appear after %s"), "DEPENDENT"); + lex_next_error (lexer, -1, -1, + _("VARIABLES may not appear after %s"), "DEPENDENT"); goto error; } variables_seen = true; @@ -338,6 +342,7 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "SAVE")) { + save_start = lex_ofs (lexer) - 1; lex_match (lexer, T_EQUALS); while (lex_token (lexer) != T_ENDCMD @@ -357,6 +362,7 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) goto error; } } + save_end = lex_ofs (lexer) - 1; } else { @@ -408,12 +414,14 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) } if (proc_make_temporary_transformations_permanent (ds)) - msg (SW, _("REGRESSION with SAVE ignores TEMPORARY. " - "Temporary transformations will be made permanent.")); + lex_ofs_msg (lexer, SW, save_start, save_end, + _("REGRESSION with SAVE ignores TEMPORARY. " + "Temporary transformations will be made permanent.")); if (dict_get_filter (dict)) - msg (SW, _("REGRESSION with SAVE ignores FILTER. " - "All cases will be processed.")); + lex_ofs_msg (lexer, SW, save_start, save_end, + _("REGRESSION with SAVE ignores FILTER. " + "All cases will be processed.")); workspace.writer = autopaging_writer_create (proto); caseproto_unref (proto); diff --git a/src/language/stats/reliability.c b/src/language/stats/reliability.c index 5816a2304c..9c79421792 100644 --- a/src/language/stats/reliability.c +++ b/src/language/stats/reliability.c @@ -277,11 +277,15 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "STATISTICS")) { + int statistics_start = lex_ofs (lexer) - 1; lex_match (lexer, T_EQUALS); - msg (SW, _("The STATISTICS subcommand is not yet implemented. " - "No statistics will be produced.")); while (lex_match (lexer, T_ID)) continue; + int statistics_end = lex_ofs (lexer) - 1; + + lex_ofs_msg (lexer, SW, statistics_start, statistics_end, + _("The STATISTICS subcommand is not yet implemented. " + "No statistics will be produced.")); } else { diff --git a/src/language/stats/t-test-parser.c b/src/language/stats/t-test-parser.c index 8810301c67..84759d8d10 100644 --- a/src/language/stats/t-test-parser.c +++ b/src/language/stats/t-test-parser.c @@ -93,6 +93,7 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds) tt.mode = MODE_INDEP; lex_match (lexer, T_EQUALS); + int groups_start = lex_ofs (lexer); if (NULL == (gvar = parse_variable (lexer, dict))) goto exit; @@ -127,11 +128,13 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds) cut = false; n = 0; } + int groups_end = lex_ofs (lexer) - 1; if (n != 2 && var_is_alpha (gvar)) { - msg (SE, _("When applying %s to a string variable, two " - "values must be specified."), "GROUPS"); + lex_ofs_error (lexer, groups_start, groups_end, + _("When applying %s to a string variable, two " + "values must be specified."), "GROUPS"); goto exit; } } @@ -142,7 +145,9 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds) if (tt.n_vars > 0) { - msg (SE, _("%s subcommand may not be used with %s."), "VARIABLES", "PAIRS"); + lex_next_error (lexer, -1, -1, + _("%s subcommand may not be used with %s."), + "VARIABLES", "PAIRS"); goto exit; } @@ -238,7 +243,9 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds) { if (tt.mode == MODE_PAIRED) { - msg (SE, _("%s subcommand may not be used with %s."), "VARIABLES", "PAIRS"); + lex_next_error (lexer, -1, -1, + _("%s subcommand may not be used with %s."), + "VARIABLES", "PAIRS"); goto exit; } diff --git a/src/language/tests/float-format.c b/src/language/tests/float-format.c index 48a49116f2..16ac95c5e3 100644 --- a/src/language/tests/float-format.c +++ b/src/language/tests/float-format.c @@ -76,7 +76,7 @@ parse_float_format (struct lexer *lexer, enum float_format *format) *format = fp_formats[i].format; return true; } - lex_error (lexer, "expecting floating-point format identifier"); + lex_error (lexer, "Syntax error expecting floating-point format identifier."); return false; } diff --git a/src/language/tests/moments-test.c b/src/language/tests/moments-test.c index 34408739b4..bd030d7ed7 100644 --- a/src/language/tests/moments-test.c +++ b/src/language/tests/moments-test.c @@ -47,7 +47,7 @@ read_values (struct lexer *lexer, double **values, double **weights, size_t *n) { if (!lex_is_number (lexer)) { - lex_error (lexer, _("expecting weight value")); + lex_error (lexer, _("Syntax error expecting weight value.")); return false; } weight = lex_tokval (lexer); diff --git a/src/language/utilities/cd.c b/src/language/utilities/cd.c index ec5e7646f4..d82ce406a8 100644 --- a/src/language/utilities/cd.c +++ b/src/language/utilities/cd.c @@ -42,8 +42,8 @@ cmd_cd (struct lexer *lexer, struct dataset *ds UNUSED) if (-1 == chdir (path)) { int err = errno; - msg (SE, _("Cannot change directory to %s: %s"), path, - strerror (err)); + lex_error (lexer, _("Cannot change directory to %s: %s"), path, + strerror (err)); goto error; } diff --git a/src/language/utilities/date.c b/src/language/utilities/date.c index 8afbe6562d..36a04b2385 100644 --- a/src/language/utilities/date.c +++ b/src/language/utilities/date.c @@ -30,6 +30,6 @@ cmd_use (struct lexer *lexer, struct dataset *ds UNUSED) if (lex_match (lexer, T_ALL)) return CMD_SUCCESS; - msg (SW, _("Only %s is currently implemented."), "USE ALL"); + lex_msg (lexer, SW, _("Only %s is currently implemented."), "USE ALL"); return CMD_FAILURE; } diff --git a/src/language/utilities/host.c b/src/language/utilities/host.c index d730e02634..45fca6175b 100644 --- a/src/language/utilities/host.c +++ b/src/language/utilities/host.c @@ -53,14 +53,11 @@ #define N_(msgid) msgid #if !HAVE_FORK +#define TIME_LIMIT_SUPPORTED 0 static bool run_commands (const struct string_array *commands, double time_limit) { - if (time_limit != DBL_MAX) - { - msg (SE, _("Time limit not supported on this platform.")); - return false; - } + assert (time_limit == DBL_MAX); for (size_t i = 0; i < commands->n; i++) { @@ -80,6 +77,7 @@ run_commands (const struct string_array *commands, double time_limit) return true; } #else +#define TIME_LIMIT_SUPPORTED 1 static bool run_command (const char *command, struct timespec timeout) { @@ -289,7 +287,9 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED) { if (settings_get_safer_mode ()) { - msg (SE, _("This command not allowed when the %s option is set."), "SAFER"); + lex_next_error (lexer, -1, -1, + _("This command not allowed when the %s option is set."), + "SAFER"); return CMD_FAILURE; } @@ -314,6 +314,7 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED) double time_limit = DBL_MAX; if (lex_match_id (lexer, "TIMELIMIT")) { + int time_limit_start = lex_ofs (lexer) - 1; if (!lex_force_match (lexer, T_EQUALS) || !lex_force_num (lexer)) { @@ -324,6 +325,15 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED) double num = lex_number (lexer); lex_get (lexer); time_limit = num < 0.0 ? 0.0 : num; + + int time_limit_end = lex_ofs (lexer) - 1; + if (!TIME_LIMIT_SUPPORTED) + { + lex_ofs_error (lexer, time_limit_start, time_limit_end, + _("Time limit not supported on this platform.")); + string_array_destroy (&commands); + return false; + } } enum cmd_result result = lex_end_of_command (lexer); diff --git a/src/language/utilities/permissions.c b/src/language/utilities/permissions.c index 771eb72832..1854cff9f4 100644 --- a/src/language/utilities/permissions.c +++ b/src/language/utilities/permissions.c @@ -43,6 +43,14 @@ int change_permissions(const char *file_name, enum PER per); int cmd_permissions (struct lexer *lexer, struct dataset *ds UNUSED) { + if (settings_get_safer_mode ()) + { + lex_next_error (lexer, -1, -1, + _("This command not allowed when the %s option is set."), + "SAFER"); + return 0; + } + char *fn = NULL; const char *str = NULL; lex_match (lexer, T_SLASH); @@ -100,12 +108,6 @@ change_permissions (const char *file_name, enum PER per) struct stat buf; mode_t mode; - if (settings_get_safer_mode ()) - { - msg (SE, _("This command not allowed when the %s option is set."), "SAFER"); - return 0; - } - locale_file_name = utf8_to_filename (file_name); if (-1 == stat(locale_file_name, &buf)) { diff --git a/src/language/utilities/set.c b/src/language/utilities/set.c index e7c17765d6..a547e5104a 100644 --- a/src/language/utilities/set.c +++ b/src/language/utilities/set.c @@ -35,6 +35,7 @@ #include "language/command.h" #include "language/lexer/format-parser.h" #include "language/lexer/lexer.h" +#include "language/lexer/token.h" #include "libpspp/assertion.h" #include "libpspp/compiler.h" #include "libpspp/copyleft.h" @@ -78,6 +79,13 @@ match_subcommand (struct lexer *lexer, const char *name) return false; } +static int +subcommand_start_ofs (struct lexer *lexer) +{ + int ofs = lex_ofs (lexer) - 1; + return lex_ofs_token (lexer, ofs)->type == T_EQUALS ? ofs - 1 : ofs; +} + static int parse_enum_valist (struct lexer *lexer, va_list args) { @@ -156,16 +164,6 @@ force_parse_bool (struct lexer *lexer) "OFF", false, "NO", false); } -static bool -force_parse_int (struct lexer *lexer, int *integerp) -{ - if (!lex_force_int (lexer)) - return false; - *integerp = lex_integer (lexer); - lex_get (lexer); - return true; -} - static bool parse_output_routing (struct lexer *lexer, enum settings_output_type type) { @@ -302,9 +300,12 @@ show_real_format (enum float_format float_format) static bool parse_unimplemented (struct lexer *lexer, const char *name) { - msg (SW, _("%s is not yet implemented."), name); + int start = subcommand_start_ofs (lexer); if (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD) lex_get (lexer); + int end = lex_ofs (lexer) - 1; + + lex_ofs_msg (lexer, SW, start, end, _("%s is not yet implemented."), name); return true; } @@ -488,7 +489,7 @@ parse_EPOCH (struct lexer *lexer) } else { - lex_error (lexer, _("expecting %s or year"), "AUTOMATIC"); + lex_error (lexer, _("Syntax error expecting %s or year."), "AUTOMATIC"); return false; } @@ -516,22 +517,23 @@ show_ERRORS (const struct dataset *ds UNUSED) static bool parse_FORMAT (struct lexer *lexer) { + int start = subcommand_start_ofs (lexer); struct fmt_spec fmt; - lex_match (lexer, T_EQUALS); if (!parse_format_specifier (lexer, &fmt)) return false; if (!fmt_check_output (&fmt)) return false; + int end = lex_ofs (lexer) - 1; if (fmt_is_string (fmt.type)) { char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("%s requires numeric output format as an argument. " - "Specified format %s is of type string."), - "FORMAT", - fmt_to_string (&fmt, str)); + lex_ofs_error (lexer, start, end, + _("%s requires numeric output format as an argument. " + "Specified format %s is of type string."), + "FORMAT", fmt_to_string (&fmt, str)); return false; } @@ -672,7 +674,7 @@ parse_LOCALE (struct lexer *lexer) set_default_encoding (s); else if (!set_encoding_from_locale (s)) { - msg (ME, _("%s is not a recognized encoding or locale name"), s); + lex_error (lexer, _("%s is not a recognized encoding or locale name"), s); return false; } @@ -781,14 +783,10 @@ show_MPRINT (const struct dataset *ds UNUSED) static bool parse_MXERRS (struct lexer *lexer) { - int n; - if (!force_parse_int (lexer, &n)) + if (!lex_force_int_range (lexer, "MXERRS", 1, INT_MAX)) return false; - - if (n >= 1) - settings_set_max_messages (MSG_S_ERROR, n); - else - msg (SE, _("%s must be at least 1."), "MXERRS"); + settings_set_max_messages (MSG_S_ERROR, lex_integer (lexer)); + lex_get (lexer); return true; } @@ -801,14 +799,10 @@ show_MXERRS (const struct dataset *ds UNUSED) static bool parse_MXLOOPS (struct lexer *lexer) { - int n; - if (!force_parse_int (lexer, &n)) + if (!lex_force_int_range (lexer, "MXLOOPS", 1, INT_MAX)) return false; - - if (n >= 1) - settings_set_mxloops (n); - else - msg (SE, _("%s must be at least 1."), "MXLOOPS"); + settings_set_mxloops (lex_integer (lexer)); + lex_get (lexer); return true; } @@ -821,14 +815,10 @@ show_MXLOOPS (const struct dataset *ds UNUSED) static bool parse_MXWARNS (struct lexer *lexer) { - int n; - if (!force_parse_int (lexer, &n)) + if (!lex_force_int_range (lexer, "MXWARNS", 0, INT_MAX)) return false; - - if (n >= 0) - settings_set_max_messages (MSG_S_WARNING, n); - else - msg (SE, _("%s must not be negative."), "MXWARNS"); + settings_set_max_messages (MSG_S_WARNING, lex_integer (lexer)); + lex_get (lexer); return true; } @@ -1383,7 +1373,7 @@ static struct settings *saved_settings[MAX_SAVED_SETTINGS]; static int n_saved_settings; int -cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) +cmd_preserve (struct lexer *lexer, struct dataset *ds UNUSED) { if (n_saved_settings < MAX_SAVED_SETTINGS) { @@ -1392,16 +1382,17 @@ cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) } else { - msg (SE, _("Too many %s commands without a %s: at most " - "%d levels of saved settings are allowed."), - "PRESERVE", "RESTORE", - MAX_SAVED_SETTINGS); + lex_next_error (lexer, -1, -1, + _("Too many %s commands without a %s: at most " + "%d levels of saved settings are allowed."), + "PRESERVE", "RESTORE", + MAX_SAVED_SETTINGS); return CMD_CASCADING_FAILURE; } } int -cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) +cmd_restore (struct lexer *lexer, struct dataset *ds UNUSED) { if (n_saved_settings > 0) { @@ -1412,7 +1403,8 @@ cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) } else { - msg (SE, _("%s without matching %s."), "RESTORE", "PRESERVE"); + lex_next_error (lexer, -1, -1, + _("%s without matching %s."), "RESTORE", "PRESERVE"); return CMD_FAILURE; } } diff --git a/src/language/xforms/compute.c b/src/language/xforms/compute.c index 5c330f65a8..61e67f33fa 100644 --- a/src/language/xforms/compute.c +++ b/src/language/xforms/compute.c @@ -374,7 +374,8 @@ lvalue_parse (struct lexer *lexer, struct dataset *ds) lvalue->vector = dict_lookup_vector (dict, lex_tokcstr (lexer)); if (lvalue->vector == NULL) { - msg (SE, _("There is no vector named %s."), lex_tokcstr (lexer)); + lex_error (lexer, _("There is no vector named %s."), + lex_tokcstr (lexer)); goto lossage; } diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 9db76f6c65..a4e1431661 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -122,7 +122,7 @@ cmd_count (struct lexer *lexer, struct dataset *ds) { if (var_is_alpha (dv->var)) { - msg (SE, _("Destination cannot be a string variable.")); + lex_error (lexer, _("Destination cannot be a string variable.")); goto fail; } } diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index 467a18652d..42fa9ff215 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -279,8 +279,9 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns, if (trns->src_type != VAL_STRING || (have_dst_type && trns->dst_type != VAL_NUMERIC)) { - msg (SE, _("CONVERT requires string input values and " - "numeric output values.")); + lex_next_error (lexer, -1, -1, + _("CONVERT requires string input values and " + "numeric output values.")); return false; } } @@ -336,7 +337,8 @@ parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool, if (lex_token (lexer) == T_ID && lex_id_match (ss_cstr ("THRU"), lex_tokss (lexer))) { - msg (SE, _("%s is not allowed with string variables."), "THRU"); + lex_error (lexer, _("%s is not allowed with string variables."), + "THRU"); return false; } } @@ -419,7 +421,7 @@ parse_map_out (struct lexer *lexer, struct pool *pool, struct map_out *out) } else { - lex_error (lexer, _("expecting output value")); + lex_error (lexer, _("Syntax error expecting output value.")); return false; } return true; @@ -520,11 +522,12 @@ parse_dst_vars (struct lexer *lexer, struct recode_trns *trns, const struct variable *v = trns->dst_vars[i]; if (v != NULL && var_get_type (v) != trns->dst_type) { - msg (SE, _("Type mismatch. Cannot store %s data in " - "%s variable %s."), - trns->dst_type == VAL_STRING ? _("string") : _("numeric"), - var_is_alpha (v) ? _("string") : _("numeric"), - var_get_name (v)); + if (trns->dst_type == VAL_STRING) + msg (SE, _("Type mismatch. Cannot store string data in " + "numeric variable %s."), var_get_name (v)); + else + msg (SE, _("Type mismatch. Cannot store numeric data in " + "string variable %s."), var_get_name (v)); return false; } } diff --git a/src/language/xforms/sample.c b/src/language/xforms/sample.c index 665cd4468e..037cff4a38 100644 --- a/src/language/xforms/sample.c +++ b/src/language/xforms/sample.c @@ -70,12 +70,8 @@ cmd_sample (struct lexer *lexer, struct dataset *ds) unsigned long max = gsl_rng_max (get_rng ()); type = TYPE_FRACTION; - if (lex_tokval (lexer) <= 0 || lex_tokval (lexer) >= 1) - { - msg (SE, _("The sampling factor must be between 0 and 1 " - "exclusive.")); - return CMD_FAILURE; - } + if (!lex_force_num_range_open (lexer, "SAMPLE", 0, 1)) + return CMD_FAILURE; frac = lex_tokval (lexer) * (max - min) + min; a = b = 0; diff --git a/src/language/xforms/select-if.c b/src/language/xforms/select-if.c index deb13047e9..2648f9f0c8 100644 --- a/src/language/xforms/select-if.c +++ b/src/language/xforms/select-if.c @@ -56,7 +56,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds) if (lex_token (lexer) != T_ENDCMD) { expr_free (e); - lex_error (lexer, _("expecting end of command")); + lex_error (lexer, _("Syntax error expecting end of command.")); return CMD_CASCADING_FAILURE; } @@ -100,35 +100,33 @@ cmd_filter (struct lexer *lexer, struct dataset *ds) struct dictionary *dict = dataset_dict (ds); if (lex_match_id (lexer, "OFF")) dict_set_filter (dict, NULL); - else if (lex_token (lexer) == T_ENDCMD) + else if (lex_match (lexer, T_BY)) { - msg (SW, _("Syntax error expecting OFF or BY. " - "Turning off case filtering.")); - dict_set_filter (dict, NULL); - } - else - { - struct variable *v; - - lex_match (lexer, T_BY); - v = parse_variable (lexer, dict); + struct variable *v = parse_variable (lexer, dict); if (!v) return CMD_FAILURE; if (var_is_alpha (v)) { - msg (SE, _("The filter variable must be numeric.")); + lex_next_error (lexer, -1, -1, + _("The filter variable must be numeric.")); return CMD_FAILURE; } if (dict_class_from_id (var_get_name (v)) == DC_SCRATCH) { - msg (SE, _("The filter variable may not be scratch.")); + lex_next_error (lexer, -1, -1, + _("The filter variable may not be scratch.")); return CMD_FAILURE; } dict_set_filter (dict, v); } + else + { + lex_error_expecting (lexer, "OFF", "BY"); + return CMD_FAILURE; + } return CMD_SUCCESS; } diff --git a/src/libpspp/message.h b/src/libpspp/message.h index 11e5b9d98e..d994a369f8 100644 --- a/src/libpspp/message.h +++ b/src/libpspp/message.h @@ -151,7 +151,7 @@ struct msg_handler void (*output_msg) (const struct msg *, void *aux); void *aux; - void (*lex_source_ref) (const struct lex_source *); + struct lex_source *(*lex_source_ref) (const struct lex_source *); void (*lex_source_unref) (struct lex_source *); struct substring (*lex_source_get_line) (const struct lex_source *, int line); diff --git a/tests/language/command.at b/tests/language/command.at index e9cbb919a0..71e50819e0 100644 --- a/tests/language/command.at +++ b/tests/language/command.at @@ -16,6 +16,32 @@ dnl along with this program. If not, see . dnl AT_BANNER([command parser]) +AT_SETUP([command parser negative tests]) +AT_DATA([command.sps], [dnl +DATA X. +XYZZY. +CLOSE FILE XYZZY. +foo. +]) +AT_CHECK([pspp command.sps], [1], [dnl +command.sps:1.1-1.6: error: Unknown command `DATA X'. + 1 | DATA X. + | ^~~~~~ + +command.sps:2.1-2.5: error: Unknown command `XYZZY'. + 2 | XYZZY. + | ^~~~~ + +command.sps:3.1-3.16: error: Unknown command `CLOSE FILE XYZZY'. + 3 | CLOSE FILE XYZZY. + | ^~~~~~~~~~~~~~~~ + +command.sps:4.1-4.3: error: Unknown command `foo'. + 4 | foo. + | ^~~ +]) +AT_CLEANUP + dnl Tests for a bug which crashed pspp when given certain invalid input. AT_SETUP([command parser crash bug]) AT_DATA([command.sps], [dnl @@ -23,16 +49,20 @@ DATA rubbish. EXECUTE. ]) AT_CHECK([pspp -O format=csv command.sps], [1], [dnl -command.sps:1: error: Unknown command `DATA rubbish'. +"command.sps:1.1-1.12: error: Unknown command `DATA rubbish'. + 1 | DATA rubbish. + | ^~~~~~~~~~~~" -command.sps:2: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined. +"command.sps:2.1-2.7: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined. + 2 | EXECUTE. + | ^~~~~~~" ]) AT_CLEANUP dnl Tests for a bug where FINISH or EXIT wasn't executed until the lexer dnl read the first token of the next command. dnl -dnl (If this reecurs, the test will run forever.) +dnl (If this recurs, the test will run forever.) AT_SETUP([FINISH executes immediately]) AT_CHECK([(echo "FINISH."; while echo ; do true; done) | pspp], [0], [ignore], [ignore]) AT_CLEANUP diff --git a/tests/language/control/define.at b/tests/language/control/define.at index 8ca40cbaba..e528509b1e 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -240,6 +240,8 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:8.18: error: DEBUG EXPAND: Reached end of command expecting 1 more token in argument !3 to macro !p. + 8 | !p a1 a2 b1 b2 c1. + | ^ (a1 a2, b1 b2, c1) @@ -247,6 +249,8 @@ token in argument !3 to macro !p. define.sps:10.12: error: DEBUG EXPAND: Reached end of command expecting 1 more token in argument !2 to macro !p. + 10 | !p a1 a2 b1. + | ^ (a1 a2, b1, z) @@ -254,6 +258,8 @@ token in argument !2 to macro !p. define.sps:12.6: error: DEBUG EXPAND: Reached end of command expecting 1 more token in argument !1 to macro !p. + 12 | !p a1. + | ^ (a1, y, z) @@ -358,6 +364,8 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:8.9: error: DEBUG EXPAND: Reached end of command expecting ":" in argument !3 to macro !p. + 8 | !p a,b;c. + | ^ (a, b, c) @@ -365,6 +373,8 @@ argument !3 to macro !p. define.sps:10.7: error: DEBUG EXPAND: Reached end of command expecting ";" in argument !2 to macro !p. + 10 | !p a,b. + | ^ (a, b, z) @@ -372,6 +382,8 @@ argument !2 to macro !p. define.sps:12.5: error: DEBUG EXPAND: Reached end of command expecting "," in argument !1 to macro !p. + 12 | !p a. + | ^ (a, y, z) @@ -429,11 +441,15 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:8.12: error: DEBUG EXPAND: Reached end of command expecting "}" in argument !3 to macro !p. + 8 | !p (a){c. + | ^ (a, b, c) define.sps:9.11: error: DEBUG EXPAND: Reached end of command expecting "}" in argument !3 to macro !p. + 9 | !p (a){. + | ^ (a, b, ) @@ -441,11 +457,15 @@ argument !3 to macro !p. define.sps:11.9: error: DEBUG EXPAND: Reached end of command expecting ">" in argument !2 to macro !p. + 11 | !p (a)" in argument !2 to macro !p. + 12 | !p (a)<. + | ^ (a, , z) @@ -453,11 +473,15 @@ argument !2 to macro !p. define.sps:14.6: error: DEBUG EXPAND: Reached end of command expecting ")" in argument !1 to macro !p. + 14 | !p (a. + | ^ (a, y, z) define.sps:15.5: error: DEBUG EXPAND: Reached end of command expecting ")" in argument !1 to macro !p. + 15 | !p (. + | ^ (, y, z) @@ -470,7 +494,9 @@ AT_DATA([define.sps], [dnl DEFINE !macro(!x !TOKENS(1). ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl -"define.sps:1.15-1.16: error: DEFINE: Syntax error at `!x': Keyword macro parameter must be named in definition without ""!"" prefix." +"define.sps:1.15-1.16: error: DEFINE: Keyword macro parameter must be named in definition without ""!"" prefix. + 1 | DEFINE !macro@{:@!x !TOKENS(1). + | ^~" ]) AT_CLEANUP @@ -479,7 +505,9 @@ AT_DATA([define.sps], [dnl DEFINE !macro(if=!TOKENS(1). ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl -"define.sps:1.15-1.16: error: DEFINE: Syntax error at `if': Cannot use macro keyword ""if"" as an argument name." +"define.sps:1.15-1.16: error: DEFINE: Cannot use macro keyword ""if"" as an argument name. + 1 | DEFINE !macro@{:@if=!TOKENS(1). + | ^~" ]) AT_CLEANUP @@ -516,11 +544,15 @@ AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:3.8: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. + 3 | !k arg1. + | ^ k( ) define.sps:4.9: error: DEBUG EXPAND: Reached end of command expecting 1 more token in argument !arg1 to macro !k. + 4 | !k arg1=. + | ^ k( ) ]) @@ -568,21 +600,29 @@ AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:6.8: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. + 6 | !k arg1. + | ^ k(, ) define.sps:7.9: error: DEBUG EXPAND: Reached end of command expecting "/" in argument !arg1 to macro !k. + 7 | !k arg1=. + | ^ k(, ) define.sps:8.10: error: DEBUG EXPAND: Reached end of command expecting "/" in argument !arg1 to macro !k. + 8 | !k arg1=x. + | ^ k(x, ) define.sps:9.18: error: DEBUG EXPAND: Reached end of command expecting "/" in argument !arg2 to macro !k. + 9 | !k arg1=x/ arg2=y. + | ^ k(x, y) ]) @@ -634,16 +674,22 @@ AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:6.8: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. + 6 | !k arg1. + | ^ k(, ) define.sps:7.9: error: DEBUG EXPAND: Found `.' while expecting `@{:@' reading argument !arg1 to macro !k. + 7 | !k arg1=. + | ^ k(, ) define.sps:8.9: error: DEBUG EXPAND: Found `x' while expecting `@{:@' reading argument !arg1 to macro !k. + 8 | !k arg1=x. + | ^ k(, ) @@ -651,21 +697,29 @@ note: unexpanded token "x" define.sps:9.11: error: DEBUG EXPAND: Reached end of command expecting "@:}@" in argument !arg1 to macro !k. + 9 | !k arg1=@{:@x. + | ^ k(x, ) define.sps:10.17: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg2 to macro !k. + 10 | !k arg1=(x) arg2. + | ^ k(x, ) define.sps:11.18: error: DEBUG EXPAND: Found `.' while expecting `{' reading argument !arg2 to macro !k. + 11 | !k arg1=(x) arg2=. + | ^ k(x, ) define.sps:12.18: error: DEBUG EXPAND: Found `y' while expecting `{' reading argument !arg2 to macro !k. + 12 | !k arg1=(x) arg2=y. + | ^ k(x, ) @@ -673,6 +727,8 @@ note: unexpanded token "y" define.sps:13.18: error: DEBUG EXPAND: Found `@{:@' while expecting `{' reading argument !arg2 to macro !k. + 13 | !k arg1=(x) arg2=@{:@y. + | ^ k(x, ) @@ -980,6 +1036,8 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1-10: At `"ba' in the expansion of `!s',dnl " define.sps:12.1-12.2: error: DEBUG EXPAND: Unterminated string constant. + 12 | !s. + | ^~ nana. nan. @@ -1100,9 +1158,13 @@ define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', -define.sps:4.1-4.6: error: DEFINE: Maximum nesting level 50 exceeded. (Use SET MNEST to change the limit.)" +define.sps:4.1-4.6: error: DEFINE: Maximum nesting level 50 exceeded. (Use SET MNEST to change the limit.) + 4 | !macro. + | ^~~~~~" -define.sps:4.1-4.6: error: Syntax error at `!macro' (in expansion of `!macro'): expecting command name. +"define.sps:4.1-4.6: error: In syntax expanded from `!macro': Syntax error expecting command name. + 4 | !macro. + | ^~~~~~" ]) AT_CLEANUP @@ -1371,12 +1433,16 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1-3: At `!x' in the expansion of `!for', define.sps:10.1-10.12: error: DEBUG EXPAND: Cannot use argument name or macro keyword as !DO variable. + 10 | !for x=1 y=5. + | ^~~~~~~~~~~~ !DO 1 = 1 !TO 5 !var !DOEND. define.sps:5-7: At `!noexpand' in the expansion of `!for2', define.sps:11.1-11.13: error: DEBUG EXPAND: Cannot use argument name or macro keyword as !DO variable. + 11 | !for2 x=1 y=5. + | ^~~~~~~~~~~~~ !DO !noexpand = 1 !TO 5 !var !DOEND. ]) @@ -1421,6 +1487,8 @@ In the expansion of `!DO', define.sps:3-5: inside the expansion of `!for', define.sps:14.1-14.8: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number of iterations 3. (Use SET MITERATE to change the limit.) + 14 | !for 1 5. + | ^~~~~~~~ 1 2 3 4. @@ -1428,6 +1496,8 @@ In the expansion of `!DO', define.sps:7-9: inside the expansion of `!forby', define.sps:15.1-15.12: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number of iterations 3. (Use SET MITERATE to change the limit.) + 15 | !forby 1 5 1. + | ^~~~~~~~~~~~ 1 2 3 4. @@ -1447,6 +1517,8 @@ In the expansion of `!DO', define.sps:7-9: inside the expansion of `!forby', define.sps:23.1-23.13: error: DEBUG EXPAND: Numerical !DO loop exceeded maximum number of iterations 3. (Use SET MITERATE to change the limit.) + 23 | !forby 5 1 -1. + | ^~~~~~~~~~~~~ 5 4 3 2. @@ -1526,6 +1598,8 @@ In the expansion of `!DO', define.sps:1-3: inside the expansion of `!for', define.sps:7.1-7.10: error: DEBUG EXPAND: !DO loop over list exceeded maximum number of iterations 2. (Use SET MITERATE to change the limit.) + 7 | !for a b c. + | ^~~~~~~~~~ ( (a) (b) ). @@ -1533,6 +1607,8 @@ In the expansion of `!DO', define.sps:1-3: inside the expansion of `!for', define.sps:8.1-8.23: error: DEBUG EXPAND: !DO loop over list exceeded maximum number of iterations 2. (Use SET MITERATE to change the limit.) + 8 | !for 'foo bar baz quux'. + | ^~~~~~~~~~~~~~~~~~~~~~~ ( (foo) (bar) ). @@ -1607,15 +1683,21 @@ DEBUG EXPAND. ]) AT_CHECK([pspp --testing-mode define.sps -O format=csv], [1], [dnl "define.sps:1-3: At `!x' in the expansion of `!macro', -define.sps:10.1-10.10: error: DEBUG EXPAND: Cannot use argument name or macro keyword ""!x"" as !LET variable." +define.sps:10.1-10.10: error: DEBUG EXPAND: Cannot use argument name or macro keyword ""!x"" as !LET variable. + 10 | !macro x=1. + | ^~~~~~~~~~" !LET 1 = 1 "define.sps:5-7: At `!do' in the expansion of `!macro2', -define.sps:11.1-11.7: error: DEBUG EXPAND: Cannot use argument name or macro keyword ""!do"" as !LET variable." +define.sps:11.1-11.7: error: DEBUG EXPAND: Cannot use argument name or macro keyword ""!do"" as !LET variable. + 11 | !macro2. + | ^~~~~~~" "define.sps:5-7: At `=' in the expansion of `!macro2', -define.sps:11.1-11.7: error: DEBUG EXPAND: Expected macro variable name following !DO." +define.sps:11.1-11.7: error: DEBUG EXPAND: Expected macro variable name following !DO. + 11 | !macro2. + | ^~~~~~~" !LET !do = x ]) @@ -1668,7 +1750,9 @@ DATA LIST NOTABLE /a b 1-2. COMPUTE x = !vars x. ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl -define.sps:3.13-3.19: error: COMPUTE: Syntax error at `b' (in expansion of `!vars x'): expecting end of command. +"define.sps:3.13-3.19: error: COMPUTE: In syntax expanded from `!vars x': Syntax error expecting end of command. + 3 | COMPUTE x = !vars x. + | ^~~~~~~" ]) AT_CLEANUP @@ -1768,48 +1852,64 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:3: At `x' in the expansion of `!c', define.sps:20.1-20.2: error: DEBUG EXPAND: `,' or `@:}@' expected in call to macro function !SUBSTR. + 20 | !c. + | ^~ !SUBSTR(1 x) define.sps:4: In the expansion of `!d', define.sps:21.1-21.2: error: DEBUG EXPAND: Missing `@:}@' in call to macro function !SUBSTR. + 21 | !d. + | ^~ !SUBSTR@{:@1 define.sps:5: In the expansion of `!narg_blanks', define.sps:22.1-22.12: error: DEBUG EXPAND: Macro function !BLANKS takes one argument (not 0). + 22 | !narg_blanks. + | ^~~~~~~~~~~~ !BLANKS( ) define.sps:6: In the expansion of `!narg_concat', define.sps:23.1-23.12: error: DEBUG EXPAND: Macro function !CONCAT needs at least one argument. + 23 | !narg_concat. + | ^~~~~~~~~~~~ !CONCAT( ) define.sps:7: In the expansion of `!narg_eval', define.sps:24.1-24.10: error: DEBUG EXPAND: Macro function !EVAL takes one argument (not 0). + 24 | !narg_eval. + | ^~~~~~~~~~ !EVAL( ) define.sps:8: In the expansion of `!narg_head', define.sps:25.1-25.10: error: DEBUG EXPAND: Macro function !HEAD takes one argument (not 0). + 25 | !narg_head. + | ^~~~~~~~~~ !HEAD( ) define.sps:9: In the expansion of `!narg_index', define.sps:26.1-26.11: error: DEBUG EXPAND: Macro function !INDEX takes two arguments (not 0). + 26 | !narg_index. + | ^~~~~~~~~~~ !INDEX( ) define.sps:10: In the expansion of `!narg_length', define.sps:27.1-27.12: error: DEBUG EXPAND: Macro function !LENGTH takes one argument (not 0). + 27 | !narg_length. + | ^~~~~~~~~~~~ !LENGTH( ) @@ -1818,30 +1918,40 @@ argument (not 0). define.sps:12: In the expansion of `!narg_quote', define.sps:29.1-29.11: error: DEBUG EXPAND: Macro function !QUOTE takes one argument (not 0). + 29 | !narg_quote. + | ^~~~~~~~~~~ !QUOTE( ) define.sps:13: In the expansion of `!narg_substr', define.sps:30.1-30.12: error: DEBUG EXPAND: Macro function !SUBSTR takes two or three arguments (not 0). - + 30 | !narg_substr. + | ^~~~~~~~~~~~ + !SUBSTR( ) define.sps:14: In the expansion of `!narg_tail', define.sps:31.1-31.10: error: DEBUG EXPAND: Macro function !TAIL takes one argument (not 0). + 31 | !narg_tail. + | ^~~~~~~~~~ !TAIL( ) define.sps:15: In the expansion of `!narg_unquote', define.sps:32.1-32.13: error: DEBUG EXPAND: Macro function !UNQUOTE takes one argument (not 0). + 32 | !narg_unquote. + | ^~~~~~~~~~~~~ !UNQUOTE( ) define.sps:16: In the expansion of `!narg_upcase', define.sps:33.1-33.12: error: DEBUG EXPAND: Macro function !UPCASE takes one argument (not 0). + 33 | !narg_upcase. + | ^~~~~~~~~~~~ !UPCASE( ) ]) @@ -1861,18 +1971,24 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1: In the expansion of `!a', define.sps:5.1-5.2: error: DEBUG EXPAND: Argument to !BLANKS must be non- negative integer (not "x"). + 5 | !a. + | ^~ !BLANKS(x). define.sps:2: In the expansion of `!b', define.sps:6.1-6.2: error: DEBUG EXPAND: Second argument of !SUBSTR must be positive integer (not "y"). + 6 | !b. + | ^~ !SUBSTR(x, y). define.sps:3: In the expansion of `!c', define.sps:7.1-7.2: error: DEBUG EXPAND: Third argument of !SUBSTR must be non- negative integer (not "z"). + 7 | !c. + | ^~ !SUBSTR(x, 1, z). ]) @@ -1892,6 +2008,8 @@ DEBUG EXPAND. AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1-2: At `.' in the expansion of `!a', define.sps:5.1-5.2: error: DEBUG EXPAND: Expecting ')' in macro expression. + 5 | !a. + | ^~ !LET !x = (1. @@ -1899,12 +2017,16 @@ At `x' in the expansion of `!DO', define.sps:2: inside the expansion of `!b', define.sps:6.1-6.2: error: DEBUG EXPAND: Macro expression must evaluate to a number (not "x"). + 6 | !b. + | ^~ !DO !x = x. define.sps:3: At `)' in the expansion of `!c', define.sps:7.1-7.2: error: DEBUG EXPAND: Expecting literal or function invocation in macro expression. + 7 | !c. + | ^~ !LET !x = ( ). ]) @@ -1924,18 +2046,24 @@ DEBUG EXPAND. AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1: In the expansion of `!a', define.sps:5.1-5.2: error: DEBUG EXPAND: !THEN expected in macro !IF construct. + 5 | !a. + | ^~ !IF 1 define.sps:2: In the expansion of `!b', define.sps:6.1-6.2: error: DEBUG EXPAND: !ELSE or !IFEND expected in macro !IF construct. + 6 | !b. + | ^~ !IF 1 !THEN define.sps:3: In the expansion of `!c', define.sps:7.1-7.2: error: DEBUG EXPAND: !IFEND expected in macro !IF construct. + 7 | !c. + | ^~ !IF 1 !THEN !ELSE ]) @@ -1958,22 +2086,30 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1: In the expansion of `!a', define.sps:6.1-6.2: error: DEBUG EXPAND: Expected macro variable name following !LET. + 6 | !a. + | ^~ !LET define.sps:2: At `0' in the expansion of `!b', define.sps:7.1-7.2: error: DEBUG EXPAND: Expected macro variable name following !LET. + 7 | !b. + | ^~ !LET 0 define.sps:3: In the expansion of `!c', define.sps:8.1-8.2: error: DEBUG EXPAND: Expected `=' following !LET. + 8 | !c. + | ^~ !LET !x define.sps:4: At `y' in the expansion of `!d', define.sps:9.1-9.2: error: DEBUG EXPAND: Expected `=' following !LET. + 9 | !d. + | ^~ !LET !x y ]) @@ -2008,23 +2144,31 @@ AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1: In the expansion of `!a', define.sps:12.1-12.2: error: DEBUG EXPAND: Expected macro variable name following !DO. + 12 | !a. + | ^~ !DO define.sps:2: At `0' in the expansion of `!b', define.sps:13.1-13.2: error: DEBUG EXPAND: Expected macro variable name following !DO. + 13 | !b. + | ^~ !DO 0 define.sps:3: In the expansion of `!c', define.sps:14.1-14.2: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop. + 14 | !c. + | ^~ !DO !x In the expansion of `!DO', define.sps:4: inside the expansion of `!d', define.sps:15.1-15.2: error: DEBUG EXPAND: Missing !DOEND. + 15 | !d. + | ^~ !DO !x !in(x) @@ -2032,33 +2176,45 @@ At `x' in the expansion of `!DO', define.sps:5: inside the expansion of `!e', define.sps:16.1-16.2: error: DEBUG EXPAND: Macro expression must evaluate to a number (not "x"). + 16 | !e. + | ^~ !DO !x = x. At `x' in the expansion of `!DO', define.sps:6: inside the expansion of `!f', define.sps:17.1-17.2: error: DEBUG EXPAND: Expected !TO in numerical !DO loop. + 17 | !f. + | ^~ !DO !x = 5 x In the expansion of `!DO', define.sps:7: inside the expansion of `!g', define.sps:18.1-18.2: error: DEBUG EXPAND: !BY value cannot be zero. + 18 | !g. + | ^~ !DO !x = 5 !TO 6 !BY 0 define.sps:8: In the expansion of `!h', define.sps:19.1-19.2: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop. + 19 | !h. + | ^~ !DO !x define.sps:9: At `0' in the expansion of `!i', define.sps:20.1-20.2: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop. + 20 | !i. + | ^~ !DO !x 0 define.sps:10: At `!BREAK' in the expansion of `!j', define.sps:21.1-21.2: error: DEBUG EXPAND: !BREAK outside !DO. + 21 | !j. + | ^~ ]) AT_CLEANUP @@ -2106,63 +2262,114 @@ DEFINE !macro(x=!TOKENS(1) !CMDEND) !ENDDEFINE. DEFINE !macro() ]) AT_CHECK([pspp define.sps], [1], [dnl -define.sps:1.36-1.40: error: DEFINE: Syntax error at `'x y'': String must -contain exactly one token. - -define.sps:2.40-2.46: error: DEFINE: Syntax error at `!TOKENS': Positional -parameters must precede keyword parameters. - -define.sps:3.15-3.16: error: DEFINE: Syntax error at `!a': Keyword macro -parameter must be named in definition without "!" prefix. - -define.sps:4.15-4.16: error: DEFINE: Syntax error at `do': Cannot use macro -keyword "do" as an argument name. - -define.sps:5.8: error: DEFINE: Syntax error at `0': expecting identifier. - -define.sps:6.10: error: DEFINE: Syntax error at `y': expecting `@{:@'. - -define.sps:7.15: error: DEFINE: Syntax error at `1': expecting identifier. - -define.sps:8.17: error: DEFINE: Syntax error at `2': expecting !TOKENS, ! +define.sps:1.36-1.40: error: DEFINE: String must contain exactly one token. + 1 | DEFINE !macro(!POSITIONAL !CHAREND('x y')) !ENDDEFINE. + | ^~~~~ + +define.sps:2.28-2.38: error: DEFINE: Positional parameters must precede keyword +parameters. + 2 | DEFINE !macro(a=!TOKENS(1)/!POSITIONAL !TOKENS(1)) !ENDDEFINE. + | ^~~~~~~~~~~ + +define.sps:2.15: note: DEFINE: Here is a previous keyword parameter. + 2 | DEFINE !macro(a=!TOKENS(1)/!POSITIONAL !TOKENS(1)) !ENDDEFINE. + | ^ + +define.sps:3.15-3.16: error: DEFINE: Keyword macro parameter must be named in +definition without "!" prefix. + 3 | DEFINE !macro(!a=!TOKENS(1)) !ENDDEFINE. + | ^~ + +define.sps:4.15-4.16: error: DEFINE: Cannot use macro keyword "do" as an +argument name. + 4 | DEFINE !macro(do=!TOKENS(1)) !ENDDEFINE. + | ^~ + +define.sps:5.8: error: DEFINE: Syntax error expecting identifier. + 5 | DEFINE 0() !ENDDEFINE. + | ^ + +define.sps:6.10: error: DEFINE: Syntax error expecting `@{:@'. + 6 | DEFINE x y () !ENDDEFINE. + | ^ + +define.sps:7.15: error: DEFINE: Syntax error expecting identifier. + 7 | DEFINE !macro(1) !ENDDEFINE. + | ^ + +define.sps:8.17: error: DEFINE: Syntax error expecting !TOKENS, !CHAREND, ! +ENCLOSE, or !CMDEND. + 8 | DEFINE !macro(x 2) !ENDDEFINE. + | ^ + +define.sps:9.26: error: DEFINE: Syntax error expecting `@{:@'. + 9 | DEFINE !macro(x=!DEFAULT 3) !ENDDEFINE. + | ^ + +define.sps:10.25: error: DEFINE: Syntax error expecting `@{:@'. + 10 | DEFINE !macro(x=!TOKENS 4) !ENDDEFINE. + | ^ + +define.sps:11.25: error: DEFINE: Syntax error expecting positive integer for ! +TOKENS. + 11 | DEFINE !macro(x=!TOKENS(x)) !ENDDEFINE. + | ^ + +define.sps:12.27: error: DEFINE: Syntax error expecting `@:}@'. + 12 | DEFINE !macro(x=!TOKENS(1 5)) !ENDDEFINE. + | ^ + +define.sps:13.26: error: DEFINE: Syntax error expecting `@{:@'. + 13 | DEFINE !macro(x=!ENCLOSE 6) !ENDDEFINE. + | ^ + +define.sps:14.30: error: DEFINE: Syntax error expecting `,'. + 14 | DEFINE !macro(x=!ENCLOSE('x' y)) !ENDDEFINE. + | ^ + +define.sps:15.30: error: DEFINE: Syntax error expecting string. + 15 | DEFINE !macro(x=!ENCLOSE('x',y)) !ENDDEFINE. + | ^ + +define.sps:16.34: error: DEFINE: Syntax error expecting `@:}@'. + 16 | DEFINE !macro(x=!ENCLOSE('x','y' z)) !ENDDEFINE. + | ^ + +define.sps:17.26: error: DEFINE: Syntax error expecting `@{:@'. + 17 | DEFINE !macro(x=!CHAREND 7) !ENDDEFINE. + | ^ + +define.sps:18.26: error: DEFINE: Syntax error expecting string. + 18 | DEFINE !macro(x=!CHAREND(8)) !ENDDEFINE. + | ^ + +define.sps:19.30: error: DEFINE: Syntax error expecting `@:}@'. + 19 | DEFINE !macro(x=!CHAREND('x' 9)) !ENDDEFINE. + | ^ + +define.sps:20.17-20.20: error: DEFINE: Syntax error expecting !TOKENS, ! CHAREND, !ENCLOSE, or !CMDEND. + 20 | DEFINE !macro(x=!WTF) !ENDDEFINE. + | ^~~~ -define.sps:9.26: error: DEFINE: Syntax error at `3': expecting `@{:@'. - -define.sps:10.25: error: DEFINE: Syntax error at `4': expecting `('. - -define.sps:11.25: error: DEFINE: Syntax error at `x': Expected positive integer -for !TOKENS. - -define.sps:12.27: error: DEFINE: Syntax error at `5': expecting `)'. - -define.sps:13.26: error: DEFINE: Syntax error at `6': expecting `('. +define.sps:21.28: error: DEFINE: Syntax error expecting `/'. + 21 | DEFINE !macro(x=!TOKENS(1) x) !ENDDEFINE. + | ^ -define.sps:14.30: error: DEFINE: Syntax error at `y': expecting `,'. +define.sps:22.28-22.35: error: DEFINE: !DEFAULT is allowed only once per +argument. + 22 | DEFINE !macro(x=!DEFAULT() !DEFAULT()) !ENDDEFINE. + | ^~~~~~~~ -define.sps:15.30: error: DEFINE: Syntax error at `y': expecting string. +define.sps:23.28-23.34: error: DEFINE: Only one of !TOKENS, !CHAREND, !ENCLOSE, +or !CMDEND is allowed. + 23 | DEFINE !macro(x=!TOKENS(1) !CMDEND) !ENDDEFINE. + | ^~~~~~~ -define.sps:16.34: error: DEFINE: Syntax error at `z': expecting `)'. - -define.sps:17.26: error: DEFINE: Syntax error at `7': expecting `('. - -define.sps:18.26: error: DEFINE: Syntax error at `8': expecting string. - -define.sps:19.30: error: DEFINE: Syntax error at `9': expecting `)'. - -define.sps:20.17-20.20: error: DEFINE: Syntax error at `!WTF': expecting ! -TOKENS, !CHAREND, !ENCLOSE, or !CMDEND. - -define.sps:21.28: error: DEFINE: Syntax error at `x': expecting `/'. - -define.sps:22.36: error: DEFINE: Syntax error at `(': !DEFAULT is allowed only -once per argument. - -define.sps:23.35: error: DEFINE: Syntax error at `)': Only one of !TOKENS, ! -CHAREND, !ENCLOSE, or !CMDEND is allowed. - -define.sps:25.1: error: DEFINE: Syntax error at end of command: Expecting macro -body or !ENDDEFINE. +define.sps:25.1: error: DEFINE: Syntax error expecting macro body or ! +ENDDEFINE. + 25 | + | ^ ]) AT_CLEANUP @@ -2203,20 +2410,29 @@ foobar two -define.sps:13.12-13.20: error: ECHO: Syntax error at `"strings"': expecting end -of command. - -define.sps:14.12-14.17: error: N OF CASES: Syntax error at `-/**/1': Expected -positive integer for N OF CASES. - -define.sps:15.12-15.19: error: N OF CASES: Syntax error at `!minus 1': Expected -positive integer for N OF CASES. - -define.sps:16.12-16.17: error: N OF CASES: Syntax error at `- !one': Expected -positive integer for N OF CASES. - -define.sps:17.12-17.22: error: N OF CASES: Syntax error at `!minus !one': -Expected positive integer for N OF CASES. +define.sps:13.12-13.20: error: ECHO: Syntax error expecting end of command. + 13 | ECHO "two" "strings". + | ^~~~~~~~~ + +define.sps:14.12-14.17: error: N OF CASES: Syntax error expecting positive +integer for N OF CASES. + 14 | N OF CASES -/**/1. + | ^~~~~~ + +define.sps:15.12-15.19: error: N OF CASES: Syntax error expecting positive +integer for N OF CASES. + 15 | N OF CASES !minus 1. + | ^~~~~~~~ + +define.sps:16.12-16.17: error: N OF CASES: Syntax error expecting positive +integer for N OF CASES. + 16 | N OF CASES - !one. + | ^~~~~~ + +define.sps:17.12-17.22: error: N OF CASES: Syntax error expecting positive +integer for N OF CASES. + 17 | N OF CASES !minus !one. + | ^~~~~~~~~~~ ]) AT_CLEANUP diff --git a/tests/language/control/do-if.at b/tests/language/control/do-if.at index 1a1889bb97..04e965b226 100644 --- a/tests/language/control/do-if.at +++ b/tests/language/control/do-if.at @@ -98,7 +98,9 @@ do-if.sps:7: error: ELSE: This command cannot appear outside DO IF...END IF. do-if.sps:8: error: ELSE IF: This command cannot appear outside DO IF...END IF. -do-if.sps:12: error: DO IF: Only one ELSE is allowed within DO IF...END IF. +"do-if.sps:12.1-12.4: error: DO IF: Only one ELSE is allowed within DO IF...END IF. + 12 | ELSE. + | ^~~~" "do-if.sps:11.1-11.5: note: DO IF: This is the location of the previous ELSE clause. 11 | ELSE. @@ -108,7 +110,9 @@ do-if.sps:12: error: DO IF: Only one ELSE is allowed within DO IF...END IF. 10 | DO IF 0. | ^~~~~~~~" -do-if.sps:17: error: DO IF: ELSE IF is not allowed following ELSE within DO IF...END IF. +"do-if.sps:17.1-17.7: error: DO IF: ELSE IF is not allowed following ELSE within DO IF...END IF. + 17 | ELSE IF 0. + | ^~~~~~~" "do-if.sps:16.1-16.5: note: DO IF: This is the location of the previous ELSE clause. 16 | ELSE. @@ -118,8 +122,10 @@ do-if.sps:17: error: DO IF: ELSE IF is not allowed following ELSE within DO IF.. 15 | DO IF 0. | ^~~~~~~~" -do-if.sps:20.7: error: DO IF: Syntax error at `!'. +"do-if.sps:20.7: error: DO IF: Syntax error. + 20 | DO IF !. + | ^" -error: DO IF: Syntax error at end of input. +error: DO IF: At end of input: Syntax error. ]) AT_CLEANUP diff --git a/tests/language/control/do-repeat.at b/tests/language/control/do-repeat.at index 91f6b4bd1b..b40f7cf541 100644 --- a/tests/language/control/do-repeat.at +++ b/tests/language/control/do-repeat.at @@ -161,6 +161,6 @@ DATA LIST NOTABLE /x 1. DO REPEAT y = 1 TO 10. ]) AT_CHECK([pspp -O format=csv do-repeat.sps], [1], [dnl -error: DO REPEAT: Syntax error at end of input: expecting END. +error: DO REPEAT: At end of input: Syntax error expecting END. ]) AT_CLEANUP diff --git a/tests/language/control/loop.at b/tests/language/control/loop.at index d8ed287885..7f1f6e3b32 100644 --- a/tests/language/control/loop.at +++ b/tests/language/control/loop.at @@ -310,32 +310,56 @@ LOOP. loop.sps:5: error: LOOP: Only one index clause may be specified. -loop.sps:7.6: error: LOOP: Syntax error at `5'. +loop.sps:7.6: error: LOOP: Syntax error. + 7 | LOOP 5. + | ^ -loop.sps:9.8: error: LOOP: Syntax error at `!': expecting `='. +loop.sps:9.8: error: LOOP: Syntax error expecting `='. + 9 | LOOP B !. + | ^ -loop.sps:11.8: error: LOOP: Syntax error at `!'. +loop.sps:11.8: error: LOOP: Syntax error. + 11 | LOOP B=!. + | ^ -loop.sps:13.13: error: LOOP: Syntax error at `!'. +loop.sps:13.13: error: LOOP: Syntax error. + 13 | LOOP A=1 TO !. + | ^ -loop.sps:15.13: error: LOOP: Syntax error at `!'. +loop.sps:15.13: error: LOOP: Syntax error. + 15 | LOOP A=1 BY !. + | ^ -loop.sps:17: error: LOOP: Subcommand TO may only be specified once. +loop.sps:17.20-17.21: error: LOOP: Subcommand TO may only be specified once. + 17 | LOOP A=1 TO 5 BY 5 TO !. + | ^~ -loop.sps:19: error: LOOP: Subcommand BY may only be specified once. +loop.sps:19.21-19.22: error: LOOP: Subcommand BY may only be specified once. + 19 | LOOP A=1 BY 5 TO 10 BY !. + | ^~ loop.sps:21: error: LOOP: Required subcommand TO was not specified. -loop.sps:23.6: error: LOOP: Syntax error at `!'. +loop.sps:23.6: error: LOOP: Syntax error. + 23 | LOOP !. + | ^ -loop.sps:26: error: LOOP: Subcommand IF may only be specified once. +loop.sps:26.11-26.12: error: LOOP: Subcommand IF may only be specified once. + 26 | LOOP IF 1 IF 0. + | ^~ -loop.sps:29.9: error: LOOP: Syntax error at `!'. +loop.sps:29.9: error: LOOP: Syntax error. + 29 | LOOP IF !. + | ^ -loop.sps:33.13: error: LOOP: Syntax error at `!'. +loop.sps:33.13: error: LOOP: Syntax error. + 33 | END LOOP IF !. + | ^ -loop.sps:36.10: error: LOOP: Syntax error at `!': expecting end of command. +loop.sps:36.10: error: LOOP: Syntax error expecting end of command. + 36 | END LOOP !. + | ^ -error: LOOP: Syntax error at end of input. +error: LOOP: At end of input: Syntax error. ]) AT_CLEANUP \ No newline at end of file diff --git a/tests/language/data-io/data-list.at b/tests/language/data-io/data-list.at index ee576ae474..d7e98db79e 100644 --- a/tests/language/data-io/data-list.at +++ b/tests/language/data-io/data-list.at @@ -410,7 +410,9 @@ EXECUTE. ]) AT_CHECK([pspp -O format=csv data-list.sps], [1], [dnl -data-list.sps:1.41-1.42: error: DATA LIST: Syntax error at `-1': Expected non-negative integer for SKIP. +"data-list.sps:1.41-1.42: error: DATA LIST: Syntax error expecting non-negative integer for SKIP. + 1 | DATA LIST LIST FILE='f.in' NOTABLE SKIP=-1 /a b c d. + | ^~" data-list.sps:3: error: Stopping syntax file processing here to avoid a cascade of dependent command failures. ]) @@ -426,7 +428,9 @@ EXECUTE. ]) AT_CHECK([pspp -O format=csv data-list.sps], [1], [dnl -data-list.sps:1.44-1.45: error: DATA LIST: Syntax error at `-1': Expected non-negative integer for RECORDS. +"data-list.sps:1.44-1.45: error: DATA LIST: Syntax error expecting non-negative integer for RECORDS. + 1 | DATA LIST LIST FILE='f.in' NOTABLE RECORDS=-1 /a b c d. + | ^~" data-list.sps:3: error: Stopping syntax file processing here to avoid a cascade of dependent command failures. ]) diff --git a/tests/language/data-io/dataset.at b/tests/language/data-io/dataset.at index ea3bcc6f09..c484f16b81 100644 --- a/tests/language/data-io/dataset.at +++ b/tests/language/data-io/dataset.at @@ -132,7 +132,9 @@ x Table: Datasets second (active dataset) -dataset.pspp:10: error: LIST: LIST is allowed only after the active dataset has been defined. +"dataset.pspp:10.1-10.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 10 | LIST. + | ^~~~" ]) AT_CLEANUP @@ -213,7 +215,9 @@ one (active dataset) 5 @&t@ -dataset.pspp:16: error: LIST: LIST is allowed only after the active dataset has been defined. +"dataset.pspp:16.1-16.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 16 | LIST. + | ^~~~" Table: Data List x diff --git a/tests/language/data-io/get-data-txt.at b/tests/language/data-io/get-data-txt.at index 950c2ad7a9..f09dbabc3c 100644 --- a/tests/language/data-io/get-data-txt.at +++ b/tests/language/data-io/get-data-txt.at @@ -315,15 +315,25 @@ get data /type=txt /file='test.data' /importcase=percent 95 /variables x f8.0. get data /type=txt /file='test.data' /importcase=percent 100 /variables x f8.0. ]) AT_CHECK([pspp -O format=csv get-data.sps], [0], [dnl -get-data.sps:1: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.) +"get-data.sps:1.39-1.57: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.). + 1 | get data /type=txt /file='test.data' /importcase=first 10 /variables x f8.0. + | ^~~~~~~~~~~~~~~~~~~" -get-data.sps:2: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.) +"get-data.sps:2.39-2.58: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.). + 2 | get data /type=txt /file='test.data' /importcase=percent 1 /variables x f8.0. + | ^~~~~~~~~~~~~~~~~~~~" -get-data.sps:3: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.) +"get-data.sps:3.39-3.59: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.). + 3 | get data /type=txt /file='test.data' /importcase=percent 35 /variables x f8.0. + | ^~~~~~~~~~~~~~~~~~~~~" -get-data.sps:4: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.) +"get-data.sps:4.39-4.59: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.). + 4 | get data /type=txt /file='test.data' /importcase=percent 95 /variables x f8.0. + | ^~~~~~~~~~~~~~~~~~~~~" -get-data.sps:5: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.) +"get-data.sps:5.39-5.60: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.). + 5 | get data /type=txt /file='test.data' /importcase=percent 100 /variables x f8.0. + | ^~~~~~~~~~~~~~~~~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/data-io/inpt-pgm.at b/tests/language/data-io/inpt-pgm.at index 0e93ed654a..79c71be8b6 100644 --- a/tests/language/data-io/inpt-pgm.at +++ b/tests/language/data-io/inpt-pgm.at @@ -28,7 +28,9 @@ END DATA. END INPUT PROGRAM. ]) AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl -input-program.sps:3: error: BEGIN DATA: BEGIN DATA is not allowed inside INPUT PROGRAM. +"input-program.sps:3.1-3.10: error: BEGIN DATA: BEGIN DATA is not allowed inside INPUT PROGRAM. + 3 | BEGIN DATA + | ^~~~~~~~~~" ]) AT_CLEANUP @@ -44,7 +46,7 @@ END INPUT PROGRAM. DESCRIPTIVES x. ]) AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl -error: DESCRIPTIVES: Syntax error at end of input: expecting BEGIN. +error: DESCRIPTIVES: At end of input: Syntax error expecting BEGIN. ]) AT_CLEANUP @@ -59,7 +61,9 @@ EXECUTE. AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl input-program.sps:3: error: INPUT PROGRAM: Input program must contain DATA LIST or END FILE. -input-program.sps:4: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined. +"input-program.sps:4.1-4.7: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined. + 4 | EXECUTE. + | ^~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/data-io/matrix-data.at b/tests/language/data-io/matrix-data.at index 50017c3389..9f65d6eca7 100644 --- a/tests/language/data-io/matrix-data.at +++ b/tests/language/data-io/matrix-data.at @@ -211,7 +211,9 @@ list. ]) AT_CHECK([pspp -O format=csv matrix-data.sps], [0], [dnl -matrix-data.sps:4: warning: MATRIX DATA: CELLS is ignored when VARIABLES includes ROWTYPE_ +"matrix-data.sps:4.6-4.10: warning: MATRIX DATA: CELLS is ignored when VARIABLES includes ROWTYPE_. + 4 | /cells = 2. + | ^~~~~" Table: Data List ROWTYPE_,VARNAME_,var01,var02,var03,var04 @@ -1185,7 +1187,9 @@ MATRIX DATA VARIABLES=v/XYZZY. AT_CHECK([pspp matrix-data.sps -O format=csv], [1], [dnl matrix-data.sps:1: error: MATRIX DATA: VARIABLES may not include VARNAME_. -matrix-data.sps:2: error: MATRIX DATA: Variable v appears twice in variable list. +"matrix-data.sps:2.25: error: MATRIX DATA: Variable v appears twice in variable list. + 2 | MATRIX DATA VARIABLES=v v v. + | ^" matrix-data.sps:3: error: MATRIX DATA: ROWTYPE_ is not allowed on SPLIT or FACTORS. @@ -1205,29 +1209,53 @@ matrix-data.sps:13: error: MATRIX DATA: VARIABLES includes ROWTYPE_ but the cont matrix-data.sps:14: error: MATRIX DATA: Cannot specify N on CONTENTS along with the N subcommand. -matrix-data.sps:15.35-15.39: error: MATRIX DATA: Syntax error at `XYZZY': Row type keyword expected. +"matrix-data.sps:15.35-15.39: error: MATRIX DATA: Syntax error expecting one of the following: CORR, COV, MAT, N_MATRIX, PROX, COUNT, DFE, MEAN, MSE, STDDEV, N, N_SCALAR, N_VECTOR, SD. + 15 | MATRIX DATA VARIABLES=v1/CONTENTS=XYZZY. + | ^~~~~" -matrix-data.sps:16.36: error: MATRIX DATA: Syntax error at end of command: Row type keyword expected. +"matrix-data.sps:16.36: error: MATRIX DATA: Syntax error expecting one of the following: CORR, COV, MAT, N_MATRIX, PROX, COUNT, DFE, MEAN, MSE, STDDEV, N, N_SCALAR, N_VECTOR, SD. + 16 | MATRIX DATA VARIABLES=v1/CONTENTS=@{:@. + | ^" -matrix-data.sps:17.40: error: MATRIX DATA: Syntax error at end of command: Row type keyword expected. +"matrix-data.sps:17.40: error: MATRIX DATA: Syntax error expecting one of the following: CORR, COV, MAT, N_MATRIX, PROX, COUNT, DFE, MEAN, MSE, STDDEV, N, N_SCALAR, N_VECTOR, SD. + 17 | MATRIX DATA VARIABLES=v1/CONTENTS=@{:@CORR. + | ^" -matrix-data.sps:18.35: error: MATRIX DATA: Syntax error at `)': Row type keyword expected. +"matrix-data.sps:18.35: error: MATRIX DATA: Syntax error expecting one of the following: CORR, COV, MAT, N_MATRIX, PROX, COUNT, DFE, MEAN, MSE, STDDEV, N, N_SCALAR, N_VECTOR, SD. + 18 | MATRIX DATA VARIABLES=v1/CONTENTS=@:}@. + | ^" -matrix-data.sps:19.12: error: MATRIX DATA: Syntax error at end of command: expecting VARIABLES. +"matrix-data.sps:19.12: error: MATRIX DATA: Syntax error expecting VARIABLES. + 19 | MATRIX DATA. + | ^" -matrix-data.sps:20.24: error: MATRIX DATA: Syntax error at `*': expecting `/'. +"matrix-data.sps:20.24: error: MATRIX DATA: Syntax error expecting `/'. + 20 | MATRIX DATA VARIABLES=v*. + | ^" -matrix-data.sps:21.27-21.28: error: MATRIX DATA: Syntax error at `-1': Expected non-negative integer for N. +"matrix-data.sps:21.27-21.28: error: MATRIX DATA: Syntax error expecting non-negative integer for N. + 21 | MATRIX DATA VARIABLES=v/N=-1. + | ^~" -matrix-data.sps:22.32-22.36: error: MATRIX DATA: Syntax error at `XYZZY'. +"matrix-data.sps:22.32-22.36: error: MATRIX DATA: Syntax error. + 22 | MATRIX DATA VARIABLES=v/FORMAT=XYZZY. + | ^~~~~" -matrix-data.sps:23.30-23.32: error: MATRIX DATA: Syntax error at `123': expecting a file name or handle name. +"matrix-data.sps:23.30-23.32: error: MATRIX DATA: Syntax error expecting a file name or handle name. + 23 | MATRIX DATA VARIABLES=v/FILE=123. + | ^~~" -matrix-data.sps:24.31-24.33: error: MATRIX DATA: Syntax error at `123': expecting variable name. +"matrix-data.sps:24.31-24.33: error: MATRIX DATA: Syntax error expecting variable name. + 24 | MATRIX DATA VARIABLES=v/SPLIT=123. + | ^~~" -matrix-data.sps:25.31-25.32: error: MATRIX DATA: Syntax error at `-1': Expected non-negative integer for CELLS. +"matrix-data.sps:25.31-25.32: error: MATRIX DATA: Syntax error expecting non-negative integer for CELLS. + 25 | MATRIX DATA VARIABLES=v/CELLS=-1. + | ^~" -matrix-data.sps:26.25-26.29: error: MATRIX DATA: Syntax error at `XYZZY'. +"matrix-data.sps:26.25-26.29: error: MATRIX DATA: Syntax error. + 26 | MATRIX DATA VARIABLES=v/XYZZY. + | ^~~~~" ]) AT_CLEANUP diff --git a/tests/language/data-io/mconvert.at b/tests/language/data-io/mconvert.at index fccd435f65..a5b96c3733 100644 --- a/tests/language/data-io/mconvert.at +++ b/tests/language/data-io/mconvert.at @@ -158,7 +158,9 @@ LIST. AT_CHECK([pspp -O format=csv input.sps]) AT_CHECK([pspp -O format=csv mconvert.sps], [1], [dnl -mconvert.sps:2: error: LIST: LIST is allowed only after the active dataset has been defined. +"mconvert.sps:2.1-2.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 2 | LIST. + | ^~~~" ]) AT_CHECK([pspp -O format=csv output.sps], [0], [dnl Table: Data List diff --git a/tests/language/data-io/print.at b/tests/language/data-io/print.at index c9dd0908ea..465240cc22 100644 --- a/tests/language/data-io/print.at +++ b/tests/language/data-io/print.at @@ -174,7 +174,9 @@ PRINT F8.2 LIST. ]) AT_CHECK([pspp -O format=csv print.sps], [1], [dnl -print.sps:7.7-7.10: error: PRINT: Syntax error at `F8.2': expecting a valid subcommand. +"print.sps:7.7-7.10: error: PRINT: Syntax error expecting OUTFILE, ENCODING, RECORDS, TABLE, or NOTABLE. + 7 | PRINT F8.2 + | ^~~~" Table: Data List a,b diff --git a/tests/language/dictionary/formats.at b/tests/language/dictionary/formats.at index b53f114b85..98019ae7e5 100644 --- a/tests/language/dictionary/formats.at +++ b/tests/language/dictionary/formats.at @@ -86,13 +86,17 @@ z,A3 "formats.sps:2: error: FORMATS: Output format E6.1 specifies 1 decimal place, but the given width does not allow for any decimals." -formats.sps:3: error: FORMATS: a and y are not the same type. All variables in this variable list must be of the same type. y will be omitted from the list. +"formats.sps:3.11: error: FORMATS: a and y are not the same type. All variables in this variable list must be of the same type. y will be omitted from the list. + 3 | FORMATS a y (F4). + | ^" formats.sps:4: error: FORMATS: String variable with width 1 is not compatible with format A2. formats.sps:5: error: FORMATS: String variable with width 2 is not compatible with format AHEX2. -formats.sps:6: error: FORMATS: x and y are string variables with different widths. All variables in this variable list must have the same width. y will be omitted from the list. +"formats.sps:6.11: error: FORMATS: x and y are string variables with different widths. All variables in this variable list must have the same width. y will be omitted from the list. + 6 | FORMATS x y (A2). + | ^" formats.sps:6: error: FORMATS: String variable with width 1 is not compatible with format A2. ]) diff --git a/tests/language/dictionary/missing-values.at b/tests/language/dictionary/missing-values.at index fd74838591..15a779180f 100644 --- a/tests/language/dictionary/missing-values.at +++ b/tests/language/dictionary/missing-values.at @@ -173,11 +173,17 @@ MISSING VALUES num1 (2 THRU 1). AT_CHECK([pspp -O format=csv missing-values.sps], [1], [dnl missing-values.sps:5: error: MISSING VALUES: Missing values provided are too long to assign to variable of width 3. -missing-values.sps:8: error: MISSING VALUES: Truncating missing value to maximum acceptable length (8 bytes). +"missing-values.sps:8.25-8.37: error: MISSING VALUES: Truncating missing value to maximum acceptable length (8 bytes). + 8 | MISSING VALUES longstr ('abcdefghijk'). + | ^~~~~~~~~~~~~" -missing-values.sps:11.26-11.29: error: MISSING VALUES: Syntax error at `THRU': expecting string. +"missing-values.sps:11.26-11.29: error: MISSING VALUES: Syntax error expecting string. + 11 | MISSING VALUES str1 ('a' THRU 'z'). + | ^~~~" -missing-values.sps:11: error: MISSING VALUES: THRU is not a variable name. +"missing-values.sps:11.26-11.29: error: MISSING VALUES: THRU is not a variable name. + 11 | MISSING VALUES str1 ('a' THRU 'z'). + | ^~~~" missing-values.sps:14: error: MISSING VALUES: Cannot mix numeric variables (e.g. num1) and string variables (e.g. str1) within a single list. @@ -189,6 +195,8 @@ missing-values.sps:19: error: MISSING VALUES: Too many numeric missing values. missing-values.sps:20: error: MISSING VALUES: Too many string missing values. At most three individual values are allowed. -missing-values.sps:23: warning: MISSING VALUES: The high end of the range (1) is below the low end (2). The range will be treated as if reversed. +"missing-values.sps:23.22-23.29: warning: MISSING VALUES: The high end of the range (1) is below the low end (2). The range will be treated as if reversed. + 23 | MISSING VALUES num1 (2 THRU 1). + | ^~~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/dictionary/mrsets.at b/tests/language/dictionary/mrsets.at index 99b2d07305..bddbbd1919 100644 --- a/tests/language/dictionary/mrsets.at +++ b/tests/language/dictionary/mrsets.at @@ -218,8 +218,10 @@ AT_DATA([mrsets.sps], [DEFINE_MRSETS_DATA MRSETS /MDGROUP VALUE=1.5. ]) -AT_CHECK([pspp -O format=csv mrsets.sps], [1], - [mrsets.sps:6: error: MRSETS: Numeric VALUE must be an integer. +AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl +"mrsets.sps:6.23-6.25: error: MRSETS: Numeric VALUE must be an integer. + 6 | MRSETS /MDGROUP VALUE=1.5. + | ^~~" ]) AT_CLEANUP @@ -228,8 +230,10 @@ AT_DATA([mrsets.sps], [DEFINE_MRSETS_DATA MRSETS /MCGROUP VARIABLES=a b c. ]) -AT_CHECK([pspp -O format=csv mrsets.sps], [1], - [mrsets.sps:6.32: error: MRSETS: Syntax error at end of command: Required MCGROUP specification missing from NAME subcommand. +AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl +"mrsets.sps:6.32: error: MRSETS: Required NAME specification missing from MCGROUP subcommand. + 6 | MRSETS /MCGROUP VARIABLES=a b c. + | ^" ]) AT_CLEANUP @@ -238,8 +242,10 @@ AT_DATA([mrsets.sps], [DEFINE_MRSETS_DATA MRSETS /MCGROUP NAME=$Mcgroup. ]) -AT_CHECK([pspp -O format=csv mrsets.sps], [1], - [mrsets.sps:6.30: error: MRSETS: Syntax error at end of command: Required MCGROUP specification missing from VARIABLES subcommand. +AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl +"mrsets.sps:6.30: error: MRSETS: Required VARIABLES specification missing from MCGROUP subcommand. + 6 | MRSETS /MCGROUP NAME=$Mcgroup. + | ^" ]) AT_CLEANUP @@ -248,10 +254,14 @@ AT_DATA([mrsets.sps], [DEFINE_MRSETS_DATA MRSETS /MCGROUP NAME=$mygroup VARIABLES=a b x y. ]) -AT_CHECK([pspp -O format=csv mrsets.sps], [1], - [mrsets.sps:6: error: MRSETS: a and x are not the same type. All variables in this variable list must be of the same type. x will be omitted from the list. +AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl +"mrsets.sps:6.45: error: MRSETS: a and x are not the same type. All variables in this variable list must be of the same type. x will be omitted from the list. + 6 | MRSETS /MCGROUP NAME=$mygroup VARIABLES=a b x y. + | ^" -mrsets.sps:6: error: MRSETS: a and y are not the same type. All variables in this variable list must be of the same type. y will be omitted from the list. +"mrsets.sps:6.47: error: MRSETS: a and y are not the same type. All variables in this variable list must be of the same type. y will be omitted from the list. + 6 | MRSETS /MCGROUP NAME=$mygroup VARIABLES=a b x y. + | ^" ]) AT_CLEANUP @@ -295,9 +305,13 @@ AT_DATA([mrsets.sps], [MRSETS /DISPLAY NAME=[$x]. MRSETS /DELETE NAME=[$y]. ]]) -AT_CHECK([pspp -O format=csv mrsets.sps], [1], - [mrsets.sps:6: error: MRSETS: No multiple response set named $x. +AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl +"mrsets.sps:6.23-6.24: error: MRSETS: No multiple response set named $x. + 6 | MRSETS /DISPLAY NAME=[[$x]]. + | ^~" -mrsets.sps:7: error: MRSETS: No multiple response set named $y. +"mrsets.sps:7.22-7.23: error: MRSETS: No multiple response set named $y. + 7 | MRSETS /DELETE NAME=[[$y]]. + | ^~" ]) AT_CLEANUP diff --git a/tests/language/dictionary/rename-variables.at b/tests/language/dictionary/rename-variables.at index 021698243c..2bac987693 100644 --- a/tests/language/dictionary/rename-variables.at +++ b/tests/language/dictionary/rename-variables.at @@ -98,7 +98,9 @@ RENAME VARIABLES warp auxiliary=foobar xyzzy. ]) AT_CHECK([pspp -o pspp.csv rename-variables.sps], [1], [dnl -rename-variables.sps:2.23-2.31: error: RENAME VARIABLES: Syntax error at `auxiliary': expecting `='. +rename-variables.sps:2.23-2.31: error: RENAME VARIABLES: Syntax error expecting `='. + 2 | RENAME VARIABLES warp auxiliary=foobar xyzzy. + | ^~~~~~~~~ ]) AT_CLEANUP diff --git a/tests/language/dictionary/value-labels.at b/tests/language/dictionary/value-labels.at index c09b8ef080..df15982860 100644 --- a/tests/language/dictionary/value-labels.at +++ b/tests/language/dictionary/value-labels.at @@ -128,7 +128,9 @@ END DATA. VALUE LABELS /var=a 'label for a'. ]) AT_CHECK([pspp -O format=csv value-labels.sps], [1], [dnl -value-labels.sps:9: error: VALUE LABELS: var is not a variable name. +"value-labels.sps:9.15-9.17: error: VALUE LABELS: var is not a variable name. + 9 | VALUE LABELS /var=a 'label for a'. + | ^~~" ]) AT_CLEANUP diff --git a/tests/language/expressions/evaluate.at b/tests/language/expressions/evaluate.at index 14059b8337..4cce31d174 100644 --- a/tests/language/expressions/evaluate.at +++ b/tests/language/expressions/evaluate.at @@ -725,8 +725,10 @@ c'). To disable this warning, insert parentheses. 1 >= 2 = 2 ge 3 => false -evaluate.sps:17.24: error: DEBUG EVALUATE: Syntax error at `!': expecting end -of command. +evaluate.sps:17.24: error: DEBUG EVALUATE: Syntax error expecting end of +command. + 17 | DEBUG EVALUATE /3 ne 2 != 1. + | ^ 3 ne 2 != 1 => error @@ -749,7 +751,9 @@ c'). To disable this warning, insert parentheses. 2 le 2 => true -evaluate.sps:25.21: error: DEBUG EVALUATE: Syntax error at `='. +evaluate.sps:25.21: error: DEBUG EVALUATE: Syntax error. + 25 | DEBUG EVALUATE /2 < = 2. + | ^ 2 < = 2 => error @@ -950,7 +954,9 @@ for opt in OPT NOOPT; do 2 ge 2 => true -evaluate.sps:8.21: error: DEBUG EVALUATE: Syntax error at `='. +evaluate.sps:8.21: error: DEBUG EVALUATE: Syntax error. + 8 | DEBUG EVALUATE /2 > = 2. + | ^ 2 > = 2 => error @@ -1118,12 +1124,16 @@ evaluate.sps:36.27-36.30: note: DEBUG EVALUATE: This operand has type 'number'. 'asdf ' ~= "asdf " => false -evaluate.sps:41.21: error: DEBUG EVALUATE: Syntax error at `>'. +evaluate.sps:41.21: error: DEBUG EVALUATE: Syntax error. + 41 | DEBUG EVALUATE /1 < > 1. + | ^ 1 < > 1 => error -evaluate.sps:42.19: error: DEBUG EVALUATE: Syntax error at `~': expecting end -of command. +evaluate.sps:42.19: error: DEBUG EVALUATE: Syntax error expecting end of +command. + 42 | DEBUG EVALUATE /1 ~ = 1. + | ^ 1 ~ = 1 => error ]) @@ -2020,15 +2030,21 @@ ANY(string, string[, string]...). any(a10, 'b', 'c', 'd') => error -evaluate.sps:37: error: DEBUG EVALUATE: Unknown identifier b. +evaluate.sps:37.26: error: DEBUG EVALUATE: Unknown identifier b. + 37 | DEBUG EVALUATE /any('a', b, 'c', 'd'). + | ^ any('a', b, 'c', 'd') => error -evaluate.sps:38: error: DEBUG EVALUATE: Unknown identifier c. +evaluate.sps:38.31: error: DEBUG EVALUATE: Unknown identifier c. + 38 | DEBUG EVALUATE /any('a', 'b', c, 'd'). + | ^ any('a', 'b', c, 'd') => error -evaluate.sps:39: error: DEBUG EVALUATE: Unknown identifier d. +evaluate.sps:39.36: error: DEBUG EVALUATE: Unknown identifier d. + 39 | DEBUG EVALUATE /any('a', 'b', 'c', d). + | ^ any('a', 'b', 'c', d) => error ]]) diff --git a/tests/language/expressions/parse.at b/tests/language/expressions/parse.at index 0ea9486eed..96e42c13ea 100644 --- a/tests/language/expressions/parse.at +++ b/tests/language/expressions/parse.at @@ -33,7 +33,9 @@ COMPUTE x=y. END IF. ]) AT_CHECK([pspp -O format=csv parse.sps], [1], [dnl -parse.sps:10: error: IF: Unknown identifier y. +"parse.sps:10.6: error: IF: Unknown identifier y. + 10 | IF ( y > 0 ) . + | ^" parse.sps:11: error: Stopping syntax file processing here to avoid a cascade of dependent command failures. ]) @@ -102,7 +104,9 @@ DATA LIST NOTABLE/x 1. COMPUTE x=$nonexistent. ]) AT_CHECK([pspp parse.sps], [1], [dnl -parse.sps:2: error: COMPUTE: Unknown system variable $nonexistent. +parse.sps:2.11-2.22: error: COMPUTE: Unknown system variable $nonexistent. + 2 | COMPUTE x=$nonexistent. + | ^~~~~~~~~~~~ ]) AT_CLEANUP @@ -113,7 +117,9 @@ DATA LIST NOTABLE/x 1. COMPUTE x=y. ]) AT_CHECK([pspp parse.sps], [1], [dnl -parse.sps:2: error: COMPUTE: Unknown identifier y. +parse.sps:2.11: error: COMPUTE: Unknown identifier y. + 2 | COMPUTE x=y. + | ^ ]) AT_CLEANUP @@ -472,19 +478,22 @@ DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc'). for opt in OPT NOOPT; do AS_BOX([$opt]) sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps - AT_CHECK([pspp --testing-mode evaluate.sps], [1], -[[evaluate.sps:3: error: DEBUG EVALUATE: Unknown system variable $nonexistent. + AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl +evaluate.sps:3.17-3.28: error: DEBUG EVALUATE: Unknown system variable +$nonexistent. + 3 | DEBUG EVALUATE /$nonexistent. + | ^~~~~~~~~~~~ $nonexistent => error -evaluate.sps:4.17-4.27: error: DEBUG EVALUATE: RANGE(number, number, number[, -number, number]...) must have an odd number of arguments. +evaluate.sps:4.17-4.27: error: DEBUG EVALUATE: RANGE(number, number, number[[, +number, number]]...) must have an odd number of arguments. 4 | DEBUG EVALUATE /RANGE(1, 2). | ^~~~~~~~~~~ RANGE(1, 2) => error -evaluate.sps:5.17-5.34: error: DEBUG EVALUATE: CONCAT(string[, string]...) +evaluate.sps:5.17-5.34: error: DEBUG EVALUATE: CONCAT(string[[, string]]...) function cannot accept suffix .1 to specify the minimum number of valid arguments. 5 | DEBUG EVALUATE /CONCAT.1('a', 'b'). @@ -492,12 +501,16 @@ arguments. CONCAT.1('a', 'b') => error -evaluate.sps:6: error: DEBUG EVALUATE: No function or vector named foobar. +evaluate.sps:6.17-6.22: error: DEBUG EVALUATE: No function or vector named +foobar. + 6 | DEBUG EVALUATE /foobar(x). + | ^~~~~~ foobar(x) => error -evaluate.sps:7.30: error: DEBUG EVALUATE: Syntax error at `b': expecting `,' or -`)'. +evaluate.sps:7.30: error: DEBUG EVALUATE: Syntax error expecting `,' or `@:}@'. + 7 | DEBUG EVALUATE /CONCAT.1('a' b). + | ^ CONCAT.1('a' b) => error @@ -518,6 +531,6 @@ evaluate.sps:9.36-9.40: note: DEBUG EVALUATE: This vector index has type | ^~~~~ v('abc') => error -]]) +]) done AT_CLEANUP diff --git a/tests/language/lexer/lexer.at b/tests/language/lexer/lexer.at index 725c260657..5b6b660ecd 100644 --- a/tests/language/lexer/lexer.at +++ b/tests/language/lexer/lexer.at @@ -50,29 +50,53 @@ u'110000' � ]) AT_CHECK([pspp -O format=csv lexer.sps], [1], [dnl -"lexer.sps:1.1-1.6: error: Syntax error at `x'123'': String of hex digits has 3 characters, which is not a multiple of 2." +"lexer.sps:1.1-1.6: error: String of hex digits has 3 characters, which is not a multiple of 2. + 1 | x'123' + | ^~~~~~" -lexer.sps:2.1-2.5: error: Syntax error at `x'1x'': `x' is not a valid hex digit. +"lexer.sps:2.1-2.5: error: `x' is not a valid hex digit. + 2 | x'1x' + | ^~~~~" -"lexer.sps:3.1-3.3: error: Syntax error at `u''': Unicode string contains 0 bytes, which is not in the valid range of 1 to 8 bytes." +"lexer.sps:3.1-3.3: error: Unicode string contains 0 bytes, which is not in the valid range of 1 to 8 bytes. + 3 | u'' + | ^~~" -"lexer.sps:4.1-4.12: error: Syntax error at `u'012345678'': Unicode string contains 9 bytes, which is not in the valid range of 1 to 8 bytes." +"lexer.sps:4.1-4.12: error: Unicode string contains 9 bytes, which is not in the valid range of 1 to 8 bytes. + 4 | u'012345678' + | ^~~~~~~~~~~~" -lexer.sps:5.1-5.7: error: Syntax error at `u'd800'': U+D800 is not a valid Unicode code point. +"lexer.sps:5.1-5.7: error: U+D800 is not a valid Unicode code point. + 5 | u'd800' + | ^~~~~~~" -lexer.sps:6.1-6.9: error: Syntax error at `u'110000'': U+110000 is not a valid Unicode code point. +"lexer.sps:6.1-6.9: error: U+110000 is not a valid Unicode code point. + 6 | u'110000' + | ^~~~~~~~~" -lexer.sps:7.1-7.4: error: Syntax error at `'foo': Unterminated string constant. +"lexer.sps:7.1-7.4: error: Unterminated string constant. + 7 | 'foo + | ^~~~" -lexer.sps:8.1-8.70: error: Syntax error at `'very long unterminated string that be ellipsized in its err...': Unterminated string constant. +"lexer.sps:8.1-8.70: error: Unterminated string constant. + 8 | 'very long unterminated string that be ellipsized in its error message + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" -lexer.sps:9.1-9.2: error: Syntax error at `1e': Missing exponent following `1e'. +"lexer.sps:9.1-9.2: error: Missing exponent following `1e'. + 9 | 1e .x + | ^~" -lexer.sps:9.4: error: Syntax error at `.': expecting command name. +"lexer.sps:9.4: error: Syntax error expecting command name. + 9 | 1e .x + | ^" -lexer.sps:10.1: error: Syntax error at `^': Bad character `^' in input. +"lexer.sps:10.1: error: Bad character `^' in input. + 10 | ^ + | ^" -lexer.sps:11.1-11.2: error: Syntax error at `�': Bad character U+FFFD in input. +"lexer.sps:11.1-11.2: error: Bad character U+FFFD in input. + 11 | � + | ^~" ]) AT_CLEANUP @@ -83,11 +107,15 @@ printf "datA dist list notable file='input.txt'/a b c. lis|.\0" > lexer.sps AT_CHECK([pspp -O format=csv lexer.sps], [1], [dnl -lexer.sps:1: error: Unknown command `datA dist'. +"lexer.sps:1.1-1.9: error: Unknown command `datA dist'. + 1 | datA dist list notable file='input.txt'/a b c. + | ^~~~~~~~~" -lexer.sps:2: error: LIST: LIST is allowed only after the active dataset has been defined. +"lexer.sps:2.1-2.3: error: LIST: LIST is allowed only after the active dataset has been defined. + 2 | lis|." -lexer.sps:2.6: error: LIST: Syntax error at `...': Bad character U+0000 in input. +"lexer.sps:2.6: error: LIST: Bad character U+0000 in input. + 2 | lis|." ]) AT_CLEANUP @@ -99,7 +127,9 @@ AT_SETUP([lexer crash due to overflow]) printf "DATA LIST/5555555555555555." > lexer.sps AT_CHECK([pspp -O format=csv lexer.sps], [1], [dnl -lexer.sps:1.11-1.26: error: DATA LIST: Syntax error at `5555555555555555': Expected integer between 1 and 2147483647. +"lexer.sps:1.11-1.26: error: DATA LIST: Syntax error expecting integer between 1 and 2147483647. + 1 | DATA LIST/5555555555555555. + | ^~~~~~~~~~~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/stats/aggregate.at b/tests/language/stats/aggregate.at index e574fc51f3..2b208d3198 100644 --- a/tests/language/stats/aggregate.at +++ b/tests/language/stats/aggregate.at @@ -57,98 +57,105 @@ m4_if([$1], [active], [OUTFILE=*], [outfile=aggregate]) dnl m4_if([$2], [presorted], [/PRESORTED]) dnl m4_if([$3], [columnwise], [/MISSING=COLUMNWISE]) - /DOCUMENT - /BREAK=g - /N = n - /NI = n./ - NU = nu - /NUI = nu./ - NFGT2 = fgt(n, 2) - /NFGT2I = fgt.(n, 2) - /SFGT2 = fgt(s, '2') - /SFGT2I = fgt.(s, '2') - /NFIN23 = fin(n, 2, 3) - /NFIN23I = fin.(n, 2, 3) - /SFIN23 = fin(s, '2', '3') - /SFIN23I = fin.(s, '2', '3') - /NFLT2 = flt(n, 2) - /NFLT2I = flt.(n, 2) - /SFLT2 = flt(s, '2') - /SFLT2I = flt.(s, '2') - /NFIRST = first(n) - /NFIRSTI = first.(n) - /SFIRST = first(s) - /SFIRSTI = first.(s) - /NFOUT23 = fout(n, 3, 2) - /NFOUT23I = fout.(n, 3, 2) - /SFOUT23 = fout(s, '3', '2') - /SFOUT23I = fout.(s, '3', '2') - /NLAST = last(n) - /NLASTI = last.(n) - /SLAST = last(s) - /SLASTI = last.(s) - /NMAX = max(n) - /NMAXI = max.(n) - /SMAX = max(s) - /SMAXI = max.(s) - /NMEAN = mean(n) - /NMEANI = mean.(n) - /NMIN = min(n) - /NMINI = min.(n) - /SMIN = min(s) - /SMINI = min.(s) - /NN = n(n) - /NNI = n.(n) - /SN = n(s) - /SNI = n.(s) - /NNMISS = nmiss(n) - /NNMISSI = nmiss.(n) - /SNMISS = nmiss(s) - /SNMISSI = nmiss.(s) - /NNU = nu(n) - /NNUI = nu.(n) - /SNU = nu(s) - /SNUI = nu.(s) - /NNUMISS = numiss(n) - /NNUMISSI = numiss.(n) - /SNUMISS = numiss(s) - /SNUMISSI = numiss.(s) - /NPGT2 = pgt(n, 2) - /NPGT2I = pgt.(n, 2) - /SPGT2 = pgt(s, '2') - /SPGT2I = pgt.(s, '2') - /NPIN23 = pin(n, 2, 3) - /NPIN23I = pin.(n, 2, 3) - /SPIN23 = pin(s, '2', '3') - /SPIN23I = pin.(s, '2', '3') - /NPLT2 = plt(n, 2) - /NPLT2I = plt.(n, 2) - /SPLT2 = plt(s, '2') - /SPLT2I = plt.(s, '2') - /NPOUT23 = pout(n, 2, 3) - /NPOUT23I = pout.(n, 2, 3) - /SPOUT23 = pout(s, '2', '3') - /SPOUT23I = pout.(s, '2', '3') - /NMEDIAN = median(n) - /NMEDIANI = median.(n) - /NSD = sd(n) - /NSDI = sd.(n) - /NSUM = sum(n) - /NSUMI = sum.(n). + /DOCUMENT + /BREAK=g + /N = n + /NI = n./ + NU = nu + /NUI = nu./ + NFGT2 = fgt(n, 2) + /NFGT2I = fgt.(n, 2) + /SFGT2 = fgt(s, '2') + /SFGT2I = fgt.(s, '2') + /NFIN23 = fin(n, 2, 3) + /NFIN23I = fin.(n, 2, 3) + /SFIN23 = fin(s, '2', '3') + /SFIN23I = fin.(s, '2', '3') + /NFLT2 = flt(n, 2) + /NFLT2I = flt.(n, 2) + /SFLT2 = flt(s, '2') + /SFLT2I = flt.(s, '2') + /NFIRST = first(n) + /NFIRSTI = first.(n) + /SFIRST = first(s) + /SFIRSTI = first.(s) + /NFOUT23 = fout(n, 3, 2) + /NFOUT23I = fout.(n, 3, 2) + /SFOUT23 = fout(s, '3', '2') + /SFOUT23I = fout.(s, '3', '2') + /NLAST = last(n) + /NLASTI = last.(n) + /SLAST = last(s) + /SLASTI = last.(s) + /NMAX = max(n) + /NMAXI = max.(n) + /SMAX = max(s) + /SMAXI = max.(s) + /NMEAN = mean(n) + /NMEANI = mean.(n) + /NMIN = min(n) + /NMINI = min.(n) + /SMIN = min(s) + /SMINI = min.(s) + /NN = n(n) + /NNI = n.(n) + /SN = n(s) + /SNI = n.(s) + /NNMISS = nmiss(n) + /NNMISSI = nmiss.(n) + /SNMISS = nmiss(s) + /SNMISSI = nmiss.(s) + /NNU = nu(n) + /NNUI = nu.(n) + /SNU = nu(s) + /SNUI = nu.(s) + /NNUMISS = numiss(n) + /NNUMISSI = numiss.(n) + /SNUMISS = numiss(s) + /SNUMISSI = numiss.(s) + /NPGT2 = pgt(n, 2) + /NPGT2I = pgt.(n, 2) + /SPGT2 = pgt(s, '2') + /SPGT2I = pgt.(s, '2') + /NPIN23 = pin(n, 2, 3) + /NPIN23I = pin.(n, 2, 3) + /SPIN23 = pin(s, '2', '3') + /SPIN23I = pin.(s, '2', '3') + /NPLT2 = plt(n, 2) + /NPLT2I = plt.(n, 2) + /SPLT2 = plt(s, '2') + /SPLT2I = plt.(s, '2') + /NPOUT23 = pout(n, 2, 3) + /NPOUT23I = pout.(n, 2, 3) + /SPOUT23 = pout(s, '2', '3') + /SPOUT23I = pout.(s, '2', '3') + /NMEDIAN = median(n) + /NMEDIANI = median.(n) + /NSD = sd(n) + /NSDI = sd.(n) + /NSUM = sum(n) + /NSUMI = sum.(n). m4_if([$1], [external], [GET FILE='aggregate.sys'.], [$1], [dataset], [DATASET ACTIVATE aggregate.]) LIST. ]) - AT_CHECK([pspp -O format=csv aggregate.sps], [0], [stdout]) - AT_CHECK([[sed 's/^[^:]*:[0-9]*: //' < stdout]], [0], - [m4_if([$3], [itemwise], - [warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. + AT_CHECK([pspp -O format=csv aggregate.sps], [0], + [m4_if([$3], [itemwise], [dnl +"aggregate.sps:29.28-29.31: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 29 | /NFOUT23 = fout(n, 3, 2) + | ^~~~" + +"aggregate.sps:30.30-30.33: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 30 | /NFOUT23I = fout.(n, 3, 2) + | ^~~~" + +"aggregate.sps:31.28-31.35: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 31 | /SFOUT23 = fout(s, '3', '2') + | ^~~~~~~~" + +"aggregate.sps:32.30-32.37: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 32 | /SFOUT23I = fout.(s, '3', '2') + | ^~~~~~~~" Table: Data List G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT2I,SFLT2,SFLT2I,NFIRST,NFIRSTI,SFIRST,SFIRSTI,NFOUT23,NFOUT23I,SFOUT23,SFOUT23I,NLAST,NLASTI,SLAST,SLASTI,NMAX,NMAXI,SMAX,SMAXI,NMEAN,NMEANI,NMIN,NMINI,SMIN,SMINI,NN,NNI,SN,SNI,NNMISS,NNMISSI,SNMISS,SNMISSI,NNU,NNUI,SNU,SNUI,NNUMISS,NNUMISSI,SNUMISS,SNUMISSI,NPGT2,NPGT2I,SPGT2,SPGT2I,NPIN23,NPIN23I,SPIN23,SPIN23I,NPLT2,NPLT2I,SPLT2,SPLT2I,NPOUT23,NPOUT23I,SPOUT23,SPOUT23I,NMEDIAN,NMEDIANI,NSD,NSDI,NSUM,NSUMI @@ -157,13 +164,22 @@ G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT 3,2.00,2.00,1,1,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000,1.000,1.000,1,1,1,1,1.000,1.000,1.000,1.000,1,1,1,1,1,1,1,1,1.00,1.00,1,1,1,1,2.00,2.00,2.00,2.00,.00,.00,.00,.00,1,1,1,1,0,0,0,0,.0,.0,.0,.0,.0,.0,.0,.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,1.00,1.00,.00,.00,2.00,2.00 4,1.00,1.00,1,1,. ,. ,. ,1.000,. ,. ,. ,.000,. ,. ,. ,.000,.,.,,4,. ,. ,. ,1.000,.,.,,4,.,.,,4,. ,. ,.,.,,4,.00,.00,.00,1.00,1.00,1.00,1.00,.00,0,0,0,1,1,1,1,0,. ,. ,. ,100.0,. ,. ,. ,.0,. ,. ,. ,.0,. ,. ,. ,100.0,NaN,NaN,. ,. ,. ,. @&t@ ], - [warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. - -warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order. They will be treated as if they had been specified in the correct order. + [dnl +"aggregate.sps:29.28-29.31: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 29 | /NFOUT23 = fout(n, 3, 2) + | ^~~~" + +"aggregate.sps:30.30-30.33: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 30 | /NFOUT23I = fout.(n, 3, 2) + | ^~~~" + +"aggregate.sps:31.28-31.35: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 31 | /SFOUT23 = fout(s, '3', '2') + | ^~~~~~~~" + +"aggregate.sps:32.30-32.37: warning: AGGREGATE: The value arguments passed to the FOUT function are out of order. They will be treated as if they had been specified in the correct order. + 32 | /SFOUT23I = fout.(s, '3', '2') + | ^~~~~~~~" Table: Data List G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT2I,SFLT2,SFLT2I,NFIRST,NFIRSTI,SFIRST,SFIRSTI,NFOUT23,NFOUT23I,SFOUT23,SFOUT23I,NLAST,NLASTI,SLAST,SLASTI,NMAX,NMAXI,SMAX,SMAXI,NMEAN,NMEANI,NMIN,NMINI,SMIN,SMINI,NN,NNI,SN,SNI,NNMISS,NNMISSI,SNMISS,SNMISSI,NNU,NNUI,SNU,SNUI,NNUMISS,NNUMISSI,SNUMISS,SNUMISSI,NPGT2,NPGT2I,SPGT2,SPGT2I,NPIN23,NPIN23I,SPIN23,SPIN23I,NPLT2,NPLT2I,SPLT2,SPLT2I,NPOUT23,NPOUT23I,SPOUT23,SPOUT23I,NMEDIAN,NMEDIANI,NSD,NSDI,NSUM,NSUMI diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 9ea42e7572..5bc111787c 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -214,7 +214,7 @@ CTABLES /TABLE qn1 /COMPARETEST MERGE=**. CTABLES /TABLE qn1 /COMPARETEST STYLE=**. CTABLES /TABLE qn1 /COMPARETEST SHOWSIG=**. CTABLES /TABLE qn1 /COMPARETEST **. -CTABLES /TABLE qn1 / **. +CTABLES /TABLE qn1 /FORMAT. CTABLES /TABLE qn1 /CLABELS ROWLABELS=OPPOSITE /CLABELS COLLABELS=OPPOSITE. CTABLES /TABLE qn20 > qnd1. CTABLES /TABLE qn1 [ROWPCT] > qnsa1. @@ -222,40 +222,58 @@ NUMERIC datetime (DATETIME17.0). CTABLES /TABLE qn1 /CATEGORIES VARIABLES=datetime ['123']. ]]) AT_CHECK([pspp ctables.sps -O box=unicode -O width=80], [1], -[[ctables.sps:2.8: error: CTABLES: Syntax error at end of command: expecting `/'. +[[ctables.sps:2.8: error: CTABLES: Syntax error expecting `/'. + 2 | CTABLES. + | ^ -ctables.sps:3.29-3.33: error: CTABLES: Syntax error at `'foo'': Expected non- -negative number for MINCOLWIDTH. +ctables.sps:3.29-3.33: error: CTABLES: Syntax error expecting non-negative +number for MINCOLWIDTH. + 3 | CTABLES /FORMAT MINCOLWIDTH='foo'. + | ^~~~~ -ctables.sps:4.21-4.22: error: CTABLES: Syntax error at `**': expecting -identifier. +ctables.sps:4.21-4.22: error: CTABLES: Syntax error expecting identifier. + 4 | CTABLES /TABLE qn1 [**]. + | ^~ -ctables.sps:5.21-5.32: error: CTABLES: Syntax error at `NOTAFUNCTION': Expecting -summary function name. +ctables.sps:5.21-5.32: error: CTABLES: Syntax error expecting summary function +name. + 5 | CTABLES /TABLE qn1 [NOTAFUNCTION]. + | ^~~~~~~~~~~~ -ctables.sps:6.20: error: CTABLES: Syntax error at end of command: expecting `@:}@'. +ctables.sps:6.20: error: CTABLES: Syntax error expecting `@:}@'. + 6 | CTABLES /TABLE @{:@qn1. + | ^ -ctables.sps:7.16-7.17: error: CTABLES: Syntax error at `**': expecting -identifier. +ctables.sps:7.16-7.17: error: CTABLES: Syntax error expecting identifier. + 7 | CTABLES /TABLE **. + | ^~ -ctables.sps:8: error: CTABLES: NOTAVAR is not a variable name. +ctables.sps:8.16-8.22: error: CTABLES: NOTAVAR is not a variable name. + 8 | CTABLES /TABLE NOTAVAR. + | ^~~~~~~ ctables.sps:10.16-10.24: error: CTABLES: Cannot use string variable string as a scale variable. 10 | CTABLES /TABLE string[S]. | ^~~~~~~~~ -ctables.sps:11.27-11.29: error: CTABLES: Syntax error at `101': Expected number -between 0 and 100 for PTILE. +ctables.sps:11.27-11.29: error: CTABLES: Syntax error expecting number between 0 +and 100 for PTILE. + 11 | CTABLES /TABLE qn1 [PTILE 101]. + | ^~~ ctables.sps:12: error: CTABLES: Output format F0.1 specifies width 0, but F requires a width between 1 and 40. -ctables.sps:13.26-13.36: error: CTABLES: Syntax error at `NEGPAREN1.2': Output -format NEGPAREN requires width 2 or greater. +ctables.sps:13.26-13.36: error: CTABLES: Output format NEGPAREN requires width 2 +or greater. + 13 | CTABLES /TABLE qn1 [MEAN NEGPAREN1.2]. + | ^~~~~~~~~~~ -ctables.sps:14.26-14.36: error: CTABLES: Syntax error at `NEGPAREN3.4': Output -format NEGPAREN requires width greater than decimals. +ctables.sps:14.26-14.36: error: CTABLES: Output format NEGPAREN requires width +greater than decimals. + 14 | CTABLES /TABLE qn1 [MEAN NEGPAREN3.4]. + | ^~~~~~~~~~~ ctables.sps:15.21-15.24: error: CTABLES: Summary function MEAN applies only to scale variables. @@ -266,7 +284,9 @@ ctables.sps:15.16-15.18: note: CTABLES: 'QN1' is not a scale variable. 15 | CTABLES /TABLE qn1 [MEAN TOTALS]. | ^~~ -ctables.sps:15.32: error: CTABLES: Syntax error at `@:>@': expecting `@<:@'. +ctables.sps:15.32: error: CTABLES: Syntax error expecting `@<:@'. + 15 | CTABLES /TABLE qn1 [MEAN TOTALS]. + | ^ ctables.sps:16.21-16.24: error: CTABLES: Summary function MEAN applies only to scale variables. @@ -277,80 +297,135 @@ ctables.sps:16.16-16.18: note: CTABLES: 'QN1' is not a scale variable. 16 | CTABLES /TABLE qn1 [MEAN TOTALS[STDDEV]%]. | ^~~ -ctables.sps:16.40: error: CTABLES: Syntax error at `%': expecting `@:>@'. +ctables.sps:16.40: error: CTABLES: Syntax error expecting `@:>@'. + 16 | CTABLES /TABLE qn1 [MEAN TOTALS[STDDEV]%]. + | ^ -ctables.sps:17.56: error: CTABLES: Syntax error at `x': expecting string. +ctables.sps:17.56: error: CTABLES: Syntax error expecting string. + 17 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [SUBTOTAL=x]. + | ^ -ctables.sps:18.50-18.51: error: CTABLES: Syntax error at `**': expecting THRU. +ctables.sps:18.50-18.51: error: CTABLES: Syntax error expecting THRU. + 18 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [LO **]. + | ^~ -ctables.sps:19.55: error: CTABLES: Syntax error at `x': expecting number. +ctables.sps:19.55: error: CTABLES: Syntax error expecting number. + 19 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [LO THRU x]. + | ^ -ctables.sps:20.54-20.55: error: CTABLES: Syntax error at `**': expecting number. +ctables.sps:20.54-20.55: error: CTABLES: Syntax error expecting number. + 20 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [1 THRU **]. + | ^~ -ctables.sps:21.56-21.57: error: CTABLES: Syntax error at `**': expecting string. +ctables.sps:21.56-21.57: error: CTABLES: Syntax error expecting string. + 21 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 ['x' THRU **]. + | ^~ -ctables.sps:22.48-22.49: error: CTABLES: Syntax error at `**': expecting -identifier. +ctables.sps:22.48-22.49: error: CTABLES: Syntax error expecting identifier. + 22 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&**]. + | ^~ ctables.sps:23.47-23.48: error: CTABLES: Unknown postcompute &x. 23 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&x]. | ^~ -ctables.sps:24.61-24.63: error: CTABLES: Syntax error at `101': Expected number -between 0 and 100 for PTILE. +ctables.sps:24.61-24.63: error: CTABLES: Syntax error expecting number between 0 +and 100 for PTILE. + 24 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=PTILE(qn1, 101). + | ^~~ -ctables.sps:25.58: error: CTABLES: Syntax error at end of command: expecting -`@:}@'. +ctables.sps:25.58: error: CTABLES: Syntax error expecting `@:}@'. + 25 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=MEAN(qn1. + | ^ -ctables.sps:26.54: error: CTABLES: Syntax error at end of command: expecting -`@{:@'. +ctables.sps:26.54: error: CTABLES: Syntax error expecting `@{:@'. + 26 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=MEAN. + | ^ -ctables.sps:27.54-27.55: error: CTABLES: Syntax error at `**': expecting INCLUDE -or EXCLUDE. +ctables.sps:27.54-27.55: error: CTABLES: Syntax error expecting INCLUDE or +EXCLUDE. + 27 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 MISSING=**. + | ^~ -ctables.sps:28.52-28.53: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:28.52-28.53: error: CTABLES: Syntax error expecting YES or NO. + 28 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 TOTAL=**. + | ^~ -ctables.sps:29.52-29.53: error: CTABLES: Syntax error at `**': expecting string. +ctables.sps:29.52-29.53: error: CTABLES: Syntax error expecting string. + 29 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 LABEL=**. + | ^~ -ctables.sps:30.55-30.56: error: CTABLES: Syntax error at `**': expecting BEFORE -or AFTER. +ctables.sps:30.55-30.56: error: CTABLES: Syntax error expecting BEFORE or AFTER. + 30 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 POSITION=**. + | ^~ -ctables.sps:31.52-31.53: error: CTABLES: Syntax error at `**': expecting INCLUDE -or EXCLUDE. +ctables.sps:31.52-31.53: error: CTABLES: Syntax error expecting INCLUDE or +EXCLUDE. + 31 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 EMPTY=**. + | ^~ -ctables.sps:32.46-32.47: error: CTABLES: Syntax error at `**': expecting ORDER, -KEY, MISSING, TOTAL, LABEL, POSITION, or EMPTY. +ctables.sps:32.46-32.47: error: CTABLES: Syntax error expecting ORDER, KEY, +MISSING, TOTAL, LABEL, POSITION, or EMPTY. + 32 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 **. + | ^~ -ctables.sps:33.54-33.55: error: CTABLES: Syntax error at `**': expecting TOTAL, -LABEL, POSITION, or EMPTY. +ctables.sps:33.54-33.55: error: CTABLES: Syntax error expecting TOTAL, LABEL, +POSITION, or EMPTY. + 33 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [1,2,3] **. + | ^~ -ctables.sps:34.36: error: CTABLES: Syntax error at `0': Expected positive -integer for SUBTOTAL. +ctables.sps:34.36: error: CTABLES: Syntax error expecting positive integer for +SUBTOTAL. + 34 | CTABLES /PCOMPUTE &k=EXPR(SUBTOTAL[0]). + | ^ -ctables.sps:35.37-35.38: error: CTABLES: Syntax error at `**': expecting `@:>@'. +ctables.sps:35.37-35.38: error: CTABLES: Syntax error expecting `@:>@'. + 35 | CTABLES /PCOMPUTE &k=EXPR(SUBTOTAL[1**]). + | ^~ -ctables.sps:36.31-36.32: error: CTABLES: Syntax error at `**': expecting THRU. +ctables.sps:36.31-36.32: error: CTABLES: Syntax error expecting THRU. + 36 | CTABLES /PCOMPUTE &k=EXPR([LO **]). + | ^~ -ctables.sps:37.36-37.37: error: CTABLES: Syntax error at `**': expecting number. +ctables.sps:37.36-37.37: error: CTABLES: Syntax error expecting number. + 37 | CTABLES /PCOMPUTE &k=EXPR([LO THRU **]). + | ^~ -ctables.sps:38.35-38.36: error: CTABLES: Syntax error at `**': expecting number. +ctables.sps:38.35-38.36: error: CTABLES: Syntax error expecting number. + 38 | CTABLES /PCOMPUTE &k=EXPR([1 THRU **]). + | ^~ -ctables.sps:39.29-39.30: error: CTABLES: Syntax error at `**': expecting `@:>@'. +ctables.sps:39.29-39.30: error: CTABLES: Syntax error expecting `@:>@'. + 39 | CTABLES /PCOMPUTE &k=EXPR([1**]). + | ^~ -ctables.sps:40.29: error: CTABLES: Syntax error at `x': expecting `@:}@'. +ctables.sps:40.29: error: CTABLES: Syntax error expecting `@:}@'. + 40 | CTABLES /PCOMPUTE &k=EXPR((1x)). + | ^ -ctables.sps:41.19-41.20: error: CTABLES: Syntax error at `**': expecting &. +ctables.sps:41.19-41.20: error: CTABLES: Syntax error expecting &. + 41 | CTABLES /PCOMPUTE **k. + | ^~ -ctables.sps:42.20: error: CTABLES: Syntax error at `1': expecting identifier. +ctables.sps:42.20: error: CTABLES: Syntax error expecting identifier. + 42 | CTABLES /PCOMPUTE &1. + | ^ -ctables.sps:43.21-43.22: error: CTABLES: Syntax error at `**': expecting `='. +ctables.sps:43.21-43.22: error: CTABLES: Syntax error expecting `='. + 43 | CTABLES /PCOMPUTE &k**. + | ^~ -ctables.sps:44.22-44.23: error: CTABLES: Syntax error at `**': expecting EXPR. +ctables.sps:44.22-44.23: error: CTABLES: Syntax error expecting EXPR. + 44 | CTABLES /PCOMPUTE &k=**. + | ^~ -ctables.sps:45.26-45.27: error: CTABLES: Syntax error at `**': expecting `('. +ctables.sps:45.26-45.27: error: CTABLES: Syntax error expecting `@{:@'. + 45 | CTABLES /PCOMPUTE &k=EXPR**. + | ^~ -ctables.sps:46.28: error: CTABLES: Syntax error at `x': expecting `)'. +ctables.sps:46.28: error: CTABLES: Syntax error expecting `@:}@'. + 46 | CTABLES /PCOMPUTE &k=EXPR(1x). + | ^ ctables.sps:47.31-47.49: warning: CTABLES: New definition of &k will override the previous definition. @@ -361,152 +436,249 @@ ctables.sps:47.10-47.28: note: CTABLES: This is the previous definition. 47 | CTABLES /PCOMPUTE &k=EXPR(1) /PCOMPUTE &k=EXPR(2). | ^~~~~~~~~~~~~~~~~~~ -ctables.sps:47.50: error: CTABLES: Syntax error at end of command: expecting -`/'. +ctables.sps:47.50: error: CTABLES: Syntax error expecting `/'. + 47 | CTABLES /PCOMPUTE &k=EXPR(1) /PCOMPUTE &k=EXPR(2). + | ^ -ctables.sps:48.53-48.64: error: CTABLES: Syntax error at `NOTAFUNCTION': -Expecting summary function name. +ctables.sps:48.53-48.64: error: CTABLES: Syntax error expecting summary function +name. + 48 | CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k FORMAT=NOTAFUNCTION. + | ^~~~~~~~~~~~ -ctables.sps:49.59-49.60: error: CTABLES: Syntax error at `**': Expected number -between 0 and 100 for PTILE. +ctables.sps:49.59-49.60: error: CTABLES: Syntax error expecting number between 0 +and 100 for PTILE. + 49 | CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k FORMAT=PTILE **. + | ^~ -ctables.sps:50.52-50.53: error: CTABLES: Syntax error at `**': expecting string. +ctables.sps:50.52-50.53: error: CTABLES: Syntax error expecting string. + 50 | CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k LABEL=**. + | ^~ -ctables.sps:51.61-51.62: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:51.61-51.62: error: CTABLES: Syntax error expecting YES or NO. + 51 | CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k HIDESOURCECATS=**. + | ^~ -ctables.sps:52.46-52.47: error: CTABLES: Syntax error at `**': expecting LABEL, -FORMAT, or HIDESOURCECATS. +ctables.sps:52.46-52.47: error: CTABLES: Syntax error expecting LABEL, FORMAT, +or HIDESOURCECATS. + 52 | CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k **. + | ^~ -ctables.sps:53.23-53.24: error: CTABLES: Syntax error at `**': expecting string. +ctables.sps:53.23-53.24: error: CTABLES: Syntax error expecting string. + 53 | CTABLES /FORMAT EMPTY=**. + | ^~ -ctables.sps:54.25-54.26: error: CTABLES: Syntax error at `**': expecting string. +ctables.sps:54.25-54.26: error: CTABLES: Syntax error expecting string. + 54 | CTABLES /FORMAT MISSING=**. + | ^~ -ctables.sps:55.17-55.18: error: CTABLES: Syntax error at `**': expecting -MINCOLWIDTH, MAXCOLWIDTH, UNITS, EMPTY, or MISSING. +ctables.sps:55.17-55.18: error: CTABLES: Syntax error expecting MINCOLWIDTH, +MAXCOLWIDTH, UNITS, EMPTY, or MISSING. + 55 | CTABLES /FORMAT **. + | ^~ -ctables.sps:56: error: CTABLES: MINCOLWIDTH must not be greater than +ctables.sps:56.17-56.45: error: CTABLES: MINCOLWIDTH must not be greater than MAXCOLWIDTH. + 56 | CTABLES /FORMAT MINCOLWIDTH=20 MAXCOLWIDTH=10/. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ctables.sps:57.18-57.19: error: CTABLES: Syntax error expecting VARIABLES. + 57 | CTABLES /VLABELS **. + | ^~ + +ctables.sps:58.28-58.34: error: CTABLES: NOTAVAR is not a variable name. + 58 | CTABLES /VLABELS VARIABLES=NOTAVAR. + | ^~~~~~~ + +ctables.sps:59.32-59.33: error: CTABLES: Syntax error expecting DISPLAY. + 59 | CTABLES /VLABELS VARIABLES=qn1 **. + | ^~ + +ctables.sps:60.40-60.41: error: CTABLES: Syntax error expecting DEFAULT, NAME, +LABEL, BOTH, or NONE. + 60 | CTABLES /VLABELS VARIABLES=qn1 DISPLAY=**. + | ^~ + +ctables.sps:61.17-61.18: error: CTABLES: Syntax error expecting COUNTDUPLICATES. + 61 | CTABLES /MRSETS **. + | ^~ + +ctables.sps:62.33-62.34: error: CTABLES: Syntax error expecting YES or NO. + 62 | CTABLES /MRSETS COUNTDUPLICATES=**. + | ^~ + +ctables.sps:63.19-63.20: error: CTABLES: Syntax error expecting VARIABLE or +LISTWISE. + 63 | CTABLES /SMISSING **. + | ^~ + +ctables.sps:64.17-64.18: error: CTABLES: Syntax error expecting VARIABLE. + 64 | CTABLES /WEIGHT **. + | ^~ + +ctables.sps:65.26-65.32: error: CTABLES: NOTAVAR is not a variable name. + 65 | CTABLES /WEIGHT VARIABLE=NOTAVAR. + | ^~~~~~~ + +ctables.sps:66.32: error: CTABLES: Syntax error expecting integer 2 or greater +for HIDESMALLCOUNTS COUNT. + 66 | CTABLES /HIDESMALLCOUNTS COUNT=1. + | ^ + +ctables.sps:67.10-67.13: error: CTABLES: Syntax error expecting one of the +following: FORMAT, VLABELS, MRSETS, SMISSING, PCOMPUTE, PPROPERTIES, WEIGHT, +HIDESMALLCOUNTS, TABLE. + 67 | CTABLES /QUUX. + | ^~~~ + +ctables.sps:68.33: error: CTABLES: Syntax error expecting `/'. + 68 | CTABLES /HIDESMALLCOUNTS COUNT=2. + | ^ + +ctables.sps:69.19-69.20: error: CTABLES: Syntax error expecting `/'. + 69 | CTABLES /TABLE qn1**. + | ^~ + +ctables.sps:70.38-70.39: error: CTABLES: Syntax error expecting COLUMN, ROW, or +LAYER. + 70 | CTABLES /TABLE qn1 /SLABELS POSITION=**. + | ^~ + +ctables.sps:71.37-71.38: error: CTABLES: Syntax error expecting YES or NO. + 71 | CTABLES /TABLE qn1 /SLABELS VISIBLE=**. + | ^~ + +ctables.sps:72.29-72.30: error: CTABLES: Syntax error expecting POSITION or +VISIBLE. + 72 | CTABLES /TABLE qn1 /SLABELS **. + | ^~ + +ctables.sps:73.39-73.40: error: CTABLES: Syntax error expecting OPPOSITE or +LAYER. + 73 | CTABLES /TABLE qn1 /CLABELS ROWLABELS=**. + | ^~ + +ctables.sps:74.39-74.40: error: CTABLES: Syntax error expecting OPPOSITE or +LAYER. + 74 | CTABLES /TABLE qn1 /CLABELS COLLABELS=**. + | ^~ + +ctables.sps:75.29-75.30: error: CTABLES: Syntax error expecting AUTO, ROWLABELS, +or COLLABELS. + 75 | CTABLES /TABLE qn1 /CLABELS **. + | ^~ + +ctables.sps:76.30-76.31: error: CTABLES: Syntax error expecting CILEVEL. + 76 | CTABLES /TABLE qn1 /CRITERIA **. + | ^~ + +ctables.sps:77.38-77.40: error: CTABLES: Syntax error expecting number in +@<:@0,100@:}@ for CILEVEL. + 77 | CTABLES /TABLE qn1 /CRITERIA CILEVEL=101. + | ^~~ + +ctables.sps:78.28-78.29: error: CTABLES: Syntax error expecting CAPTION, CORNER, +or TITLE. + 78 | CTABLES /TABLE qn1 /TITLES **. + | ^~ + +ctables.sps:79.34-79.35: error: CTABLES: Syntax error expecting CHISQUARE. + 79 | CTABLES /TABLE qn1 /SIGTEST TYPE=**. + | ^~ + +ctables.sps:80.35-80.36: error: CTABLES: Syntax error expecting number in @<:@0,1@:}@ +for ALPHA. + 80 | CTABLES /TABLE qn1 /SIGTEST ALPHA=**. + | ^~ -ctables.sps:57.18-57.19: error: CTABLES: Syntax error at `**': expecting -VARIABLES. - -ctables.sps:58: error: CTABLES: NOTAVAR is not a variable name. - -ctables.sps:59.32-59.33: error: CTABLES: Syntax error at `**': expecting -DISPLAY. - -ctables.sps:60.40-60.41: error: CTABLES: Syntax error at `**': expecting -DEFAULT, NAME, LABEL, BOTH, or NONE. - -ctables.sps:61.17-61.18: error: CTABLES: Syntax error at `**': expecting -COUNTDUPLICATES. - -ctables.sps:62.33-62.34: error: CTABLES: Syntax error at `**': expecting YES or -NO. - -ctables.sps:63.19-63.20: error: CTABLES: Syntax error at `**': expecting -VARIABLE or LISTWISE. - -ctables.sps:64.17-64.18: error: CTABLES: Syntax error at `**': expecting -VARIABLE. - -ctables.sps:65: error: CTABLES: NOTAVAR is not a variable name. - -ctables.sps:66.32: error: CTABLES: Syntax error at `1': Expected integer 2 or -greater for HIDESMALLCOUNTS COUNT. - -ctables.sps:67.10-67.13: error: CTABLES: Syntax error at `QUUX': expecting one -of the following: FORMAT, VLABELS, MRSETS, SMISSING, PCOMPUTE, PPROPERTIES, -WEIGHT, HIDESMALLCOUNTS, TABLE. - -ctables.sps:68.33: error: CTABLES: Syntax error at end of command: expecting -`/'. - -ctables.sps:69.19-69.20: error: CTABLES: Syntax error at `**': expecting `/'. - -ctables.sps:70.38-70.39: error: CTABLES: Syntax error at `**': expecting COLUMN, -ROW, or LAYER. - -ctables.sps:71.37-71.38: error: CTABLES: Syntax error at `**': expecting YES or -NO. - -ctables.sps:72.29-72.30: error: CTABLES: Syntax error at `**': expecting -POSITION or VISIBLE. - -ctables.sps:73.39-73.40: error: CTABLES: Syntax error at `**': expecting -OPPOSITE or LAYER. - -ctables.sps:74.39-74.40: error: CTABLES: Syntax error at `**': expecting -OPPOSITE or LAYER. - -ctables.sps:75.29-75.30: error: CTABLES: Syntax error at `**': expecting AUTO, -ROWLABELS, or COLLABELS. - -ctables.sps:76.30-76.31: error: CTABLES: Syntax error at `**': expecting -CILEVEL. - -ctables.sps:77.38-77.40: error: CTABLES: Syntax error at `101': Expected number -in @<:@0,100@:}@ for CILEVEL. - -ctables.sps:78.28-78.29: error: CTABLES: Syntax error at `**': expecting -CAPTION, CORNER, or TITLE. - -ctables.sps:79.34-79.35: error: CTABLES: Syntax error at `**': expecting -CHISQUARE. - -ctables.sps:80.35-80.36: error: CTABLES: Syntax error at `**': Expected number -in @<:@0,1@:}@ for ALPHA. +ctables.sps:81.43-81.44: error: CTABLES: Syntax error expecting YES or NO. + 81 | CTABLES /TABLE qn1 /SIGTEST INCLUDEMRSETS=**. + | ^~ -ctables.sps:81.43-81.44: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:82.40-82.41: error: CTABLES: Syntax error expecting ALLVISIBLE or +SUBTOTALS. + 82 | CTABLES /TABLE qn1 /SIGTEST CATEGORIES=**. + | ^~ -ctables.sps:82.40-82.41: error: CTABLES: Syntax error at `**': expecting -ALLVISIBLE or SUBTOTALS. +ctables.sps:83.29-83.30: error: CTABLES: Syntax error expecting TYPE, ALPHA, +INCLUDEMRSETS, or CATEGORIES. + 83 | CTABLES /TABLE qn1 /SIGTEST **. + | ^~ -ctables.sps:83.29-83.30: error: CTABLES: Syntax error at `**': expecting TYPE, -ALPHA, INCLUDEMRSETS, or CATEGORIES. +ctables.sps:84.38-84.39: error: CTABLES: Syntax error expecting PROP or MEAN. + 84 | CTABLES /TABLE qn1 /COMPARETEST TYPE=**. + | ^~ -ctables.sps:84.38-84.39: error: CTABLES: Syntax error at `**': expecting PROP or -MEAN. +ctables.sps:85.39-85.40: error: CTABLES: Syntax error expecting number in (0,1) +for ALPHA. + 85 | CTABLES /TABLE qn1 /COMPARETEST ALPHA=**. + | ^~ -ctables.sps:85.39-85.40: error: CTABLES: Syntax error at `**': Expected number -in (0,1) for ALPHA. +ctables.sps:86.39: error: CTABLES: Syntax error expecting number in (0,1) for +ALPHA. + 86 | CTABLES /TABLE qn1 /COMPARETEST ALPHA=0,5. + | ^ -ctables.sps:86.39: error: CTABLES: Syntax error at `0': Expected number in (0,1) -for ALPHA. +ctables.sps:87.40-87.41: error: CTABLES: Syntax error expecting BONFERRONI, BH, +or NONE. + 87 | CTABLES /TABLE qn1 /COMPARETEST ADJUST=**. + | ^~ -ctables.sps:87.40-87.41: error: CTABLES: Syntax error at `**': expecting -BONFERRONI, BH, or NONE. +ctables.sps:88.47-88.48: error: CTABLES: Syntax error expecting YES or NO. + 88 | CTABLES /TABLE qn1 /COMPARETEST INCLUDEMRSETS=**. + | ^~ -ctables.sps:88.47-88.48: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:89.47-89.48: error: CTABLES: Syntax error expecting ALLCATS or +TESTEDCATS. + 89 | CTABLES /TABLE qn1 /COMPARETEST MEANSVARIANCE=**. + | ^~ -ctables.sps:89.47-89.48: error: CTABLES: Syntax error at `**': expecting ALLCATS -or TESTEDCATS. +ctables.sps:90.44-90.45: error: CTABLES: Syntax error expecting ALLVISIBLE or +SUBTOTALS. + 90 | CTABLES /TABLE qn1 /COMPARETEST CATEGORIES=**. + | ^~ -ctables.sps:90.44-90.45: error: CTABLES: Syntax error at `**': expecting -ALLVISIBLE or SUBTOTALS. +ctables.sps:91.39-91.40: error: CTABLES: Syntax error expecting YES or NO. + 91 | CTABLES /TABLE qn1 /COMPARETEST MERGE=**. + | ^~ -ctables.sps:91.39-91.40: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:92.39-92.40: error: CTABLES: Syntax error expecting APA or SIMPLE. + 92 | CTABLES /TABLE qn1 /COMPARETEST STYLE=**. + | ^~ -ctables.sps:92.39-92.40: error: CTABLES: Syntax error at `**': expecting APA or -SIMPLE. +ctables.sps:93.41-93.42: error: CTABLES: Syntax error expecting YES or NO. + 93 | CTABLES /TABLE qn1 /COMPARETEST SHOWSIG=**. + | ^~ -ctables.sps:93.41-93.42: error: CTABLES: Syntax error at `**': expecting YES or -NO. +ctables.sps:94.33-94.34: error: CTABLES: Syntax error expecting one of the +following: TYPE, ALPHA, ADJUST, INCLUDEMRSETS, MEANSVARIANCE, CATEGORIES, MERGE, +STYLE, SHOWSIG. + 94 | CTABLES /TABLE qn1 /COMPARETEST **. + | ^~ -ctables.sps:94.33-94.34: error: CTABLES: Syntax error at `**': expecting one of -the following: TYPE, ALPHA, ADJUST, INCLUDEMRSETS, MEANSVARIANCE, CATEGORIES, -MERGE, STYLE, SHOWSIG. +ctables.sps:95.21-95.26: error: CTABLES: Syntax error expecting TABLE, SLABELS, +CLABELS, CRITERIA, CATEGORIES, TITLES, SIGTEST, or COMPARETEST. + 95 | CTABLES /TABLE qn1 /FORMAT. + | ^~~~~~ -ctables.sps:95.22-95.23: error: CTABLES: Syntax error at `**': expecting TABLE, -SLABELS, CLABELS, CRITERIA, CATEGORIES, TITLES, SIGTEST, or COMPARETEST. +ctables.sps:95.21-95.26: note: CTABLES: This subcommand must appear before +TABLE. + 95 | CTABLES /TABLE qn1 /FORMAT. + | ^~~~~~ ctables.sps:96: error: CTABLES: ROWLABELS and COLLABELS may not both be specified. +ctables.sps:96.21-96.46: note: CTABLES: This is the first specification. + 96 | CTABLES /TABLE qn1 /CLABELS ROWLABELS=OPPOSITE /CLABELS +COLLABELS=OPPOSITE. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + +ctables.sps:96.49-96.74: note: CTABLES: This is the second specification. + 96 | CTABLES /TABLE qn1 /CLABELS ROWLABELS=OPPOSITE /CLABELS +COLLABELS=OPPOSITE. + | +^~~~~~~~~~~~~~~~~~~~~~~~~~ + ctables.sps:97.16-97.26: error: CTABLES: Cannot nest scale variables. 97 | CTABLES /TABLE qn20 > qnd1. | ^~~~~~~~~~~ @@ -573,140 +745,155 @@ CTABLES /TABLE qn113 /COMPARETEST TYPE=PROP. CTABLES /TABLE qn113 [COUNT.UCL]. CTABLES /TABLE qn1 /CATEGORIES **. + +CTABLES /TITLES. ]]) -AT_CHECK([pspp ctables.sps -O box=unicode -O width=80], [1], -[[ctables.sps:2.76-2.78: error: CTABLES: Computed category &pc references a -category not included in the category list. - 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES -VARIABLES=qn1 [&pc]. - | -^~~ +AT_CHECK([pspp ctables.sps -O box=unicode -O width=120], [1], +[[ctables.sps:2.76-2.78: error: CTABLES: Computed category &pc references a category not included in the category list. + 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. + | ^~~ ctables.sps:2.28-2.35: note: CTABLES: This is the missing category. - 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES -VARIABLES=qn1 [&pc]. + 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. | ^~~~~~~~ -ctables.sps:2.76-2.79: note: CTABLES: To fix the problem, add subtotals to the -list of categories here. - 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES -VARIABLES=qn1 [&pc]. - | -^~~~ +ctables.sps:2.76-2.79: note: CTABLES: To fix the problem, add subtotals to the list of categories here. + 2 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. + | ^~~~ -ctables.sps:3.73-3.75: error: CTABLES: Computed category &pc references a -category not included in the category list. - 3 | CTABLES /PCOMPUTE &pc=EXPR(TOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 -[&pc]. - | -^~~ +ctables.sps:3.73-3.75: error: CTABLES: Computed category &pc references a category not included in the category list. + 3 | CTABLES /PCOMPUTE &pc=EXPR(TOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. + | ^~~ ctables.sps:3.28-3.32: note: CTABLES: This is the missing category. - 3 | CTABLES /PCOMPUTE &pc=EXPR(TOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 -[&pc]. + 3 | CTABLES /PCOMPUTE &pc=EXPR(TOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. | ^~~~~ -ctables.sps:3: note: CTABLES: To fix the problem, add TOTAL=YES to the -variable's CATEGORIES specification. +ctables.sps:3: note: CTABLES: To fix the problem, add TOTAL=YES to the variable's CATEGORIES specification. -ctables.sps:4.76-4.99: error: CTABLES: These categories include 2 instances of -SUBTOTAL or HSUBTOTAL, so references from computed categories must refer to -subtotals by position, e.g. SUBTOTAL[1]. - 4 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES -VARIABLES=qn1 [&pc, SUBTOTAL, SUBTOTAL]. - | -^~~~~~~~~~~~~~~~~~~~~~~~ +ctables.sps:4.76-4.99: error: CTABLES: These categories include 2 instances of SUBTOTAL or HSUBTOTAL, so references from +computed categories must refer to subtotals by position, e.g. SUBTOTAL[1]. + 4 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc, SUBTOTAL, SUBTOTAL]. + | ^~~~~~~~~~~~~~~~~~~~~~~~ -ctables.sps:4.28-4.35: note: CTABLES: This is the reference that lacks a -position. - 4 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES -VARIABLES=qn1 [&pc, SUBTOTAL, SUBTOTAL]. +ctables.sps:4.28-4.35: note: CTABLES: This is the reference that lacks a position. + 4 | CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc, SUBTOTAL, SUBTOTAL]. | ^~~~~~~~ -ctables.sps:7.47-7.54: error: CTABLES: This category specification may be -applied only to string variables, but this subcommand tries to apply it to -numeric variable QN1. +ctables.sps:7.47-7.54: error: CTABLES: This category specification may be applied only to string variables, but this +subcommand tries to apply it to numeric variable QN1. 7 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 ['string']. | ^~~~~~~~ -ctables.sps:8.53: error: CTABLES: This category specification may be applied -only to numeric variables, but this subcommand tries to apply it to string -variable string. +ctables.sps:8.53: error: CTABLES: This category specification may be applied only to numeric variables, but this +subcommand tries to apply it to string variable string. 8 | CTABLES /TABLE string /CATEGORIES VARIABLES=string [1]. | ^ -ctables.sps:10.74-10.86: error: CTABLES: Syntax error at `KEY=MEAN(qn1)': Data- -dependent sorting is not implemented. +ctables.sps:10.74-10.86: error: CTABLES: Data-dependent sorting is not implemented. + 10 | CTABLES /TABLE qn1 /CLABELS ROWLABELS=OPPOSITE /CATEGORIES VARIABLES=qn1 KEY=MEAN(qn1). + | ^~~~~~~~~~~~~ + +ctables.sps:12: error: CTABLES: To move category labels from one axis to another, the variables whose labels are to be +moved must be categorical, but qnd1 is scale. + +ctables.sps:12.22-12.47: note: CTABLES: This syntax moves category labels to another axis. + 12 | CTABLES /TABLE qnd1 /CLABELS ROWLABELS=OPPOSITE. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + +ctables.sps:13: error: CTABLES: To move category labels from one axis to another, the variables whose labels are to be +moved must all have the same width, but QN1 has width 0 and string has width 8. + +ctables.sps:13.30-13.55: note: CTABLES: This syntax moves category labels to another axis. + 13 | CTABLES /TABLE qn1 + string /CLABELS ROWLABELS=OPPOSITE. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ -ctables.sps:12: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be -moved to be categorical, but qnd1 is a scale variable. +ctables.sps:14: error: CTABLES: To move category labels from one axis to another, the variables whose labels are to be +moved must all have the same value labels, but QN1 and QNSA1 have different value labels. -ctables.sps:13: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be -moved to have the same width, but QN1 has width 0 and string has width 8. +ctables.sps:14.29-14.54: note: CTABLES: This syntax moves category labels to another axis. + 14 | CTABLES /TABLE qn1 + qnsa1 /CLABELS ROWLABELS=OPPOSITE. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ -ctables.sps:14: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be -moved to have the same value labels, but QN1 and QNSA1 have different value -labels. +ctables.sps:15: error: CTABLES: To move category labels from one axis to another, the variables whose labels are to be +moved must all have the same category specifications, but QN105BA and QN105BB have different category specifications. -ctables.sps:15: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be -moved to have the same category specifications, but QN105BA and QN105BB have -different category specifications. +ctables.sps:15.35-15.60: note: CTABLES: This syntax moves category labels to another axis. + 15 | CTABLES /TABLE qn105ba + qn105bb /CLABELS ROWLABELS=OPPOSITE /CATEGORIES VARIABLES=qn105ba [1,2,3]. + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ -ctables.sps:17.27-17.33: warning: CTABLES: The exponentiation operator (`**') is -left-associative: `a**b**c' equals `(a**b)**c', not `a**(b**c)'. To disable -this warning, insert parentheses. +ctables.sps:17.27-17.33: warning: CTABLES: The exponentiation operator (`**') is left-associative: `a**b**c' equals +`(a**b)**c', not `a**(b**c)'. To disable this warning, insert parentheses. 17 | CTABLES /PCOMPUTE &x=EXPR(1**2**3). | ^~~~~~~ -ctables.sps:17.35: error: CTABLES: Syntax error at end of command: expecting -`/'. +ctables.sps:17.35: error: CTABLES: Syntax error expecting `/'. + 17 | CTABLES /PCOMPUTE &x=EXPR(1**2**3). + | ^ -ctables.sps:18.28-18.29: error: CTABLES: Syntax error at `**'. +ctables.sps:18.28-18.29: error: CTABLES: Syntax error. + 18 | CTABLES /PCOMPUTE &x=EXPR([**]). + | ^~ -ctables.sps:19.27-19.28: error: CTABLES: Syntax error at `**'. +ctables.sps:19.27-19.28: error: CTABLES: Syntax error. + 19 | CTABLES /PCOMPUTE &x=EXPR(**). + | ^~ -ctables.sps:21.15: error: CTABLES: Syntax error at end of command: At least one -variable must be specified. +ctables.sps:21.15: error: CTABLES: At least one variable must be specified. + 21 | CTABLES /TABLE. + | ^ ctables.sps:23: error: CTABLES: Summaries may appear only on one axis. -ctables.sps:23.50-23.54: note: CTABLES: This variable on the layers axis has a -summary. +ctables.sps:23.50-23.54: note: CTABLES: This variable on the layers axis has a summary. 23 | CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. | ^~~~~ -ctables.sps:23.16-23.20: note: CTABLES: This variable on the rows axis has a -summary. +ctables.sps:23.16-23.20: note: CTABLES: This variable on the rows axis has a summary. 23 | CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. | ^~~~~ -ctables.sps:23.33-23.37: note: CTABLES: This variable on the columns axis has a -summary. +ctables.sps:23.33-23.37: note: CTABLES: This variable on the columns axis has a summary. 23 | CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. | ^~~~~ -ctables.sps:23.33-23.37: note: CTABLES: This is a scale variable, so it always -has a summary even if the syntax does not explicitly specify one. +ctables.sps:23.33-23.37: note: CTABLES: This is a scale variable, so it always has a summary even if the syntax does not +explicitly specify one. 23 | CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. | ^~~~~ -ctables.sps:25.46-25.63: error: CTABLES: Syntax error at `KEY=PTILE(qn1, 50)': -Data-dependent sorting is not implemented. +ctables.sps:25.46-25.63: error: CTABLES: Data-dependent sorting is not implemented. + 25 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=PTILE(qn1, 50). + | ^~~~~~~~~~~~~~~~~~ + +ctables.sps:27.16-27.21: error: CTABLES: Multiple response set support not implemented. + 27 | CTABLES /TABLE $mrset. + | ^~~~~~ + +ctables.sps:29.23-29.44: error: CTABLES: Support for SIGTEST not yet implemented. + 29 | CTABLES /TABLE qn113 /SIGTEST TYPE=CHISQUARE. + | ^~~~~~~~~~~~~~~~~~~~~~ -ctables.sps:27.16-27.21: error: CTABLES: Syntax error at `$mrset': Multiple -response set support not implemented. +ctables.sps:30.23-30.43: error: CTABLES: Support for COMPARETEST not yet implemented. + 30 | CTABLES /TABLE qn113 /COMPARETEST TYPE=PROP. + | ^~~~~~~~~~~~~~~~~~~~~ -ctables.sps:29.23-29.44: error: CTABLES: Syntax error at `SIGTEST -TYPE=CHISQUARE': Support for SIGTEST not yet implemented. +ctables.sps:32.23-32.31: error: CTABLES: Support for LCL, UCL, and SE summary functions is not yet implemented. + 32 | CTABLES /TABLE qn113 [COUNT.UCL]. + | ^~~~~~~~~ -ctables.sps:30.35-30.43: error: CTABLES: Syntax error at `TYPE=PROP': Support -for COMPARETEST not yet implemented. +ctables.sps:34.32-34.33: error: CTABLES: Syntax error expecting VARIABLES. + 34 | CTABLES /TABLE qn1 /CATEGORIES **. + | ^~ -ctables.sps:32.23-32.31: error: CTABLES: Syntax error at `COUNT.UCL': Support -for LCL, UCL, and SE summary functions is not yet implemented. +ctables.sps:36.10-36.15: error: CTABLES: Syntax error expecting one of the following: FORMAT, VLABELS, MRSETS, SMISSING, +PCOMPUTE, PPROPERTIES, WEIGHT, HIDESMALLCOUNTS, TABLE. + 36 | CTABLES /TITLES. + | ^~~~~~ -ctables.sps:34.32-34.33: error: CTABLES: Syntax error at `**': expecting -VARIABLES. +ctables.sps:36.10-36.15: note: CTABLES: TABLE must appear before this subcommand. + 36 | CTABLES /TITLES. + | ^~~~~~ ]]) AT_CLEANUP diff --git a/tests/language/stats/descriptives.at b/tests/language/stats/descriptives.at index 8a1c26a7d4..c06737d2b2 100644 --- a/tests/language/stats/descriptives.at +++ b/tests/language/stats/descriptives.at @@ -454,9 +454,14 @@ END DATA. DESCRIPTIVES ALL/STATISTICS=COUNT MEAN. ]) AT_CHECK([pspp descriptives.sps], [1], [dnl -descriptives.sps:5.29-5.33: error: DESCRIPTIVES: Syntax error at `COUNT': -expecting statistic name: reverting to default. - -descriptives.sps:5.35-5.38: error: DESCRIPTIVES: Syntax error at `MEAN'. +descriptives.sps:5.29-5.33: error: DESCRIPTIVES: Syntax error expecting one of +the following: MEAN, SEMEAN, STDDEV, VARIANCE, KURTOSIS, SEKURTOSIS, SKEWNESS, +SESKEWNESS, RANGE, MINIMUM, MAXIMUM, SUM. + 5 | DESCRIPTIVES ALL/STATISTICS=COUNT MEAN. + | ^~~~~ + +descriptives.sps:5.35-5.38: error: DESCRIPTIVES: Syntax error. + 5 | DESCRIPTIVES ALL/STATISTICS=COUNT MEAN. + | ^~~~ ]) AT_CLEANUP diff --git a/tests/language/stats/flip.at b/tests/language/stats/flip.at index 155350dde7..f462b1fe2b 100644 --- a/tests/language/stats/flip.at +++ b/tests/language/stats/flip.at @@ -43,7 +43,9 @@ x,11,12,13,14 y,16,17,18,19 z,21,22,23,24 -flip.sps:12: warning: FLIP: FLIP ignores TEMPORARY. Temporary transformations will be made permanent. +"flip.sps:12.1-12.4: warning: FLIP: FLIP ignores TEMPORARY. Temporary transformations will be made permanent. + 12 | flip newnames=n. + | ^~~~" Table: Data List CASE_LBL,v,w,x,y,z diff --git a/tests/language/stats/matrix.at b/tests/language/stats/matrix.at index b0e62d0b1c..a152cbf009 100644 --- a/tests/language/stats/matrix.at +++ b/tests/language/stats/matrix.at @@ -930,15 +930,21 @@ COMPUTE y(5)=1. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.10: error: COMPUTE: Syntax error at end of command: expecting `='. +matrix.sps:2.10: error: COMPUTE: Syntax error expecting `='. + 2 | COMPUTE x. + | ^ -matrix.sps:3.11: error: COMPUTE: Syntax error at end of command. +matrix.sps:3.11: error: COMPUTE: Syntax error. + 3 | COMPUTE x=. + | ^ matrix.sps:4.9: error: MATRIX: Undefined variable x. 4 | COMPUTE x(5)=1. | ^ -matrix.sps:5: error: COMPUTE: Undefined variable y. +matrix.sps:5.9: error: COMPUTE: Undefined variable y. + 5 | COMPUTE y(5)=1. + | ^ ]) AT_CLEANUP @@ -3121,7 +3127,9 @@ BREAK. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2: error: BREAK: BREAK not inside LOOP. +matrix.sps:2.1-2.5: error: BREAK: BREAK not inside LOOP. + 2 | BREAK. + | ^~~~~ ]) AT_CLEANUP @@ -3302,59 +3310,130 @@ xyzzy . ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.6: error: READ: Syntax error at `!': expecting identifier. +matrix.sps:2.6: error: READ: Syntax error expecting identifier. + 2 | READ !. + | ^ -matrix.sps:3.13: error: READ: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:3.13: error: READ: Syntax error expecting a file name or handle +name. + 3 | READ x/FILE=!. + | ^ -matrix.sps:4.17: error: READ: Syntax error at `!': expecting string. +matrix.sps:4.17: error: READ: Syntax error expecting string. + 4 | READ x/ENCODING=!. + | ^ -matrix.sps:5.14: error: READ: Syntax error at `!': Expected positive integer -for FIELD. +matrix.sps:5.14: error: READ: Syntax error expecting positive integer for +FIELD. + 5 | READ x/FIELD=!. + | ^ -matrix.sps:6.16: error: READ: Syntax error at `!': expecting `TO'. +matrix.sps:6.16: error: READ: Syntax error expecting `TO'. + 6 | READ x/FIELD=1 !. + | ^ -matrix.sps:7.19: error: READ: Syntax error at `!': Expected positive integer -for TO. +matrix.sps:7.19: error: READ: Syntax error expecting positive integer for TO. + 7 | READ x/FIELD=1 TO !. + | ^ -matrix.sps:8.19: error: READ: Syntax error at `0': Expected positive integer -for TO. +matrix.sps:8.19: error: READ: Syntax error expecting positive integer for TO. + 8 | READ x/FIELD=1 TO 0. + | ^ -matrix.sps:9.25: error: READ: Syntax error at `!': Expected integer between 1 -and 10 for BY. +matrix.sps:9.25: error: READ: Syntax error expecting integer between 1 and 10 +for BY. + 9 | READ x/FIELD=1 TO 10 BY !. + | ^ -matrix.sps:10: error: READ: BY 6 does not evenly divide record width 10. +matrix.sps:10.14-10.25: error: READ: Field width 6 does not evenly divide +record width 10. + 10 | READ x/FIELD=1 TO 10 BY 6. + | ^~~~~~~~~~~~ + +matrix.sps:10.14-10.20: note: READ: This syntax designates the record width. + 10 | READ x/FIELD=1 TO 10 BY 6. + | ^~~~~~~ -matrix.sps:11.13: error: READ: Syntax error at `!'. +matrix.sps:10.25: note: READ: This syntax specifies the field width. + 10 | READ x/FIELD=1 TO 10 BY 6. + | ^ -matrix.sps:12.13: error: READ: Syntax error at `!': expecting RECTANGULAR or -SYMMETRIC. +matrix.sps:11.13: error: READ: Syntax error. + 11 | READ x/SIZE=!. + | ^ -matrix.sps:13.15: error: READ: Syntax error at `!': expecting identifier. +matrix.sps:12.13: error: READ: Syntax error expecting RECTANGULAR or SYMMETRIC. + 12 | READ x/MODE=!. + | ^ -matrix.sps:14: error: READ: Subcommand FORMAT may only be specified once. +matrix.sps:13.15: error: READ: Syntax error expecting identifier. + 13 | READ x/FORMAT=!. + | ^ + +matrix.sps:14.20-14.25: error: READ: Subcommand FORMAT may only be specified +once. + 14 | READ x/FORMAT=F8.2/FORMAT=F8.2. + | ^~~~~~ -matrix.sps:15.15-15.22: error: READ: Syntax error at `'5XYZZY'': Unknown format -XYZZY. +matrix.sps:15.15-15.22: error: READ: Unknown format XYZZY. + 15 | READ x/FORMAT='5XYZZY'. + | ^~~~~~~~ -matrix.sps:16: error: READ: Unknown format type `XYZZY'. +matrix.sps:16.15-16.19: error: READ: Unknown format type `XYZZY'. + 16 | READ x/FORMAT=XYZZY. + | ^~~~~ -matrix.sps:17.8: error: READ: Syntax error at `!': expecting FILE, FIELD, MODE, -REREAD, or FORMAT. +matrix.sps:17.8: error: READ: Syntax error expecting FILE, FIELD, MODE, REREAD, +or FORMAT. + 17 | READ x/!. + | ^ matrix.sps:18: error: READ: Required subcommand FIELD was not specified. matrix.sps:19: error: READ: SIZE is required for reading data into a full matrix (as opposed to a submatrix). +matrix.sps:19.6: note: READ: This expression designates a full matrix. + 19 | READ x/FIELD=1 TO 10. + | ^ + matrix.sps:20: error: READ: Required subcommand FILE was not specified. matrix.sps:21: error: READ: 15 repetitions cannot fit in record width 10. -matrix.sps:22: error: READ: FORMAT specifies field width 5 but BY specifies 2. +matrix.sps:21.57-21.61: note: READ: This syntax designates the number of +repetitions. + 21 | READ x/FIELD=1 TO 10/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT='15F'. + | ^~~~~ + +matrix.sps:21.14-21.20: note: READ: This syntax designates the record width. + 21 | READ x/FIELD=1 TO 10/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT='15F'. + | ^~~~~~~ + +matrix.sps:22: error: READ: This command specifies two different field widths. -matrix.sps:23: error: READ: FORMAT specifies 2 repetitions with record width -10, which implies field width 5, but BY specifies field width 2. +matrix.sps:22.62-22.63: note: READ: This syntax specifies field width 5. + 22 | READ x/FIELD=1 TO 10 BY 2/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT=F5. + | ^~ + +matrix.sps:22.25: note: READ: This syntax specifies field width 2. + 22 | READ x/FIELD=1 TO 10 BY 2/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT=F5. + | ^ + +matrix.sps:23: error: READ: This command specifies two different field widths. + +matrix.sps:23.62-23.65: note: READ: This syntax specifies 2 repetitions. + 23 | READ x/FIELD=1 TO 10 BY 2/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT='2F'. + | ^~~~ + +matrix.sps:23.14-23.20: note: READ: This syntax designates record width 10, +which divided by 2 repetitions implies field width 5. + 23 | READ x/FIELD=1 TO 10 BY 2/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT='2F'. + | ^~~~~~~ + +matrix.sps:23.25: note: READ: This syntax specifies field width 2. + 23 | READ x/FIELD=1 TO 10 BY 2/SIZE={1,2}/FILE='xyzzy.txt'/FORMAT='2F'. + | ^ matrix.sps:24.27-24.35: error: MATRIX: SIZE must evaluate to a scalar or a 2- element vector, not a 2×2 matrix. @@ -3456,52 +3535,108 @@ WRITE {1,2}/FIELD=1 TO 10/OUTFILE='matrix.txt'/MODE=TRIANGULAR. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.7: error: WRITE: Syntax error at `!'. +matrix.sps:2.7: error: WRITE: Syntax error. + 2 | WRITE !. + | ^ -matrix.sps:3.17: error: WRITE: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:3.17: error: WRITE: Syntax error expecting a file name or handle +name. + 3 | WRITE 1/OUTFILE=!. + | ^ -matrix.sps:4.18: error: WRITE: Syntax error at `!': expecting string. +matrix.sps:4.18: error: WRITE: Syntax error expecting string. + 4 | WRITE 1/ENCODING=!. + | ^ -matrix.sps:5.15: error: WRITE: Syntax error at `!': Expected positive integer -for FIELD. +matrix.sps:5.15: error: WRITE: Syntax error expecting positive integer for +FIELD. + 5 | WRITE 1/FIELD=!. + | ^ -matrix.sps:6.17: error: WRITE: Syntax error at `!': expecting `TO'. +matrix.sps:6.17: error: WRITE: Syntax error expecting `TO'. + 6 | WRITE 1/FIELD=1 !. + | ^ -matrix.sps:7.20: error: WRITE: Syntax error at `0': Expected positive integer -for TO. +matrix.sps:7.20: error: WRITE: Syntax error expecting positive integer for TO. + 7 | WRITE 1/FIELD=1 TO 0. + | ^ -matrix.sps:8.26-8.27: error: WRITE: Syntax error at `20': Expected integer -between 1 and 10 for BY. +matrix.sps:8.26-8.27: error: WRITE: Syntax error expecting integer between 1 +and 10 for BY. + 8 | WRITE 1/FIELD=1 TO 10 BY 20. + | ^~ + +matrix.sps:9.15-9.26: error: WRITE: Field width 6 does not evenly divide record +width 10. + 9 | WRITE 1/FIELD=1 TO 10 BY 6. + | ^~~~~~~~~~~~ + +matrix.sps:9.15-9.21: note: WRITE: This syntax designates the record width. + 9 | WRITE 1/FIELD=1 TO 10 BY 6. + | ^~~~~~~ + +matrix.sps:9.26: note: WRITE: This syntax specifies the field width. + 9 | WRITE 1/FIELD=1 TO 10 BY 6. + | ^ + +matrix.sps:10.14-10.24: error: WRITE: Syntax error expecting RECTANGULAR or +TRIANGULAR. + 10 | WRITE 1/MODE=TRAPEZOIDAL. + | ^~~~~~~~~~~ + +matrix.sps:11.19-11.24: error: WRITE: Subcommand FORMAT may only be specified +once. + 11 | WRITE 1/FORMAT=F5/FORMAT=F5. + | ^~~~~~ -matrix.sps:9: error: WRITE: BY 6 does not evenly divide record width 10. +matrix.sps:12.16-12.22: error: WRITE: Unknown format ASDF. + 12 | WRITE 1/FORMAT='5ASDF'. + | ^~~~~~~ -matrix.sps:10.14-10.24: error: WRITE: Syntax error at `TRAPEZOIDAL': expecting -RECTANGULAR or TRIANGULAR. +matrix.sps:13.16-13.20: error: WRITE: Unknown format type `ASDF'. + 13 | WRITE 1/FORMAT=ASDF5. + | ^~~~~ -matrix.sps:11: error: WRITE: Subcommand FORMAT may only be specified once. +matrix.sps:14.9: error: WRITE: Syntax error expecting OUTFILE, FIELD, MODE, +HOLD, or FORMAT. + 14 | WRITE 1/!. + | ^ -matrix.sps:12.16-12.22: error: WRITE: Syntax error at `'5ASDF'': Unknown format -ASDF. +matrix.sps:15: error: WRITE: Required subcommand FIELD was not specified. -matrix.sps:13: error: WRITE: Unknown format type `ASDF'. +matrix.sps:16: error: WRITE: Required subcommand OUTFILE was not specified. -matrix.sps:14.9: error: WRITE: Syntax error at `!': expecting OUTFILE, FIELD, -MODE, HOLD, or FORMAT. +matrix.sps:17.51-17.55: note: WRITE: This syntax designates the number of +repetitions. + 17 | WRITE 1/FIELD=1 TO 10/OUTFILE='matrix.txt'/FORMAT='15F'. + | ^~~~~ -matrix.sps:15: error: WRITE: Required subcommand FIELD was not specified. +matrix.sps:17.15-17.21: note: WRITE: This syntax designates the record width. + 17 | WRITE 1/FIELD=1 TO 10/OUTFILE='matrix.txt'/FORMAT='15F'. + | ^~~~~~~ -matrix.sps:16: error: WRITE: Required subcommand OUTFILE was not specified. +matrix.sps:18: error: WRITE: This command specifies two different field widths. + +matrix.sps:18.56-18.59: note: WRITE: This syntax specifies 5 repetitions. + 18 | WRITE 1/FIELD=1 TO 10 BY 5/OUTFILE='matrix.txt'/FORMAT='5F'. + | ^~~~ -matrix.sps:17: error: WRITE: 15 repetitions cannot fit in record width 10. +matrix.sps:18.15-18.21: note: WRITE: This syntax designates record width 10, +which divided by 5 repetitions implies field width 2. + 18 | WRITE 1/FIELD=1 TO 10 BY 5/OUTFILE='matrix.txt'/FORMAT='5F'. + | ^~~~~~~ -matrix.sps:18: error: WRITE: FORMAT specifies 5 repetitions with record width -10, which implies field width 2, but BY specifies field width 5. +matrix.sps:18.26: note: WRITE: This syntax specifies field width 5. + 18 | WRITE 1/FIELD=1 TO 10 BY 5/OUTFILE='matrix.txt'/FORMAT='5F'. + | ^ matrix.sps:19: error: WRITE: Output format E5.0 specifies width 5, but E requires a width between 6 and 40. -matrix.sps:20: error: WRITE: Format A9 is too wide for 8-byte matrix elements. +matrix.sps:20.51-20.52: error: WRITE: Format A9 is too wide for 8-byte matrix +elements. + 20 | WRITE 1/FIELD=1 TO 10/OUTFILE='matrix.txt'/FORMAT=A9. + | ^~ matrix.sps:21.7-21.11: error: MATRIX: WRITE with MODE=TRIANGULAR requires a square matrix but the matrix to be written has dimensions 1×2. @@ -3697,38 +3832,64 @@ GET x/VARIABLES=a. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:12.5: error: GET: Syntax error at `!': expecting identifier. +matrix.sps:12.5: error: GET: Syntax error expecting identifier. + 12 | GET !. + | ^ -matrix.sps:13.17: error: GET: Syntax error at `!': expecting variable name. +matrix.sps:13.17: error: GET: Syntax error expecting variable name. + 13 | GET x/VARIABLES=!. + | ^ -matrix.sps:14.12: error: GET: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:14.12: error: GET: Syntax error expecting a file name or handle +name. + 14 | GET x/FILE=!. + | ^ -matrix.sps:15.16: error: GET: Syntax error at `!': expecting string. +matrix.sps:15.16: error: GET: Syntax error expecting string. + 15 | GET x/ENCODING=!. + | ^ -matrix.sps:16.13: error: GET: Syntax error at `!': expecting identifier. +matrix.sps:16.13: error: GET: Syntax error expecting identifier. + 16 | GET x/NAMES=!. + | ^ -matrix.sps:17.15: error: GET: Syntax error at `!'. +matrix.sps:17.15: error: GET: Syntax error. + 17 | GET x/MISSING=!. + | ^ -matrix.sps:18.14: error: GET: Syntax error at `!'. +matrix.sps:18.14: error: GET: Syntax error. + 18 | GET x/SYSMIS=!. + | ^ -matrix.sps:19.7: error: GET: Syntax error at `!': expecting FILE, VARIABLES, -NAMES, MISSING, or SYSMIS. +matrix.sps:19.7: error: GET: Syntax error expecting FILE, VARIABLES, NAMES, +MISSING, or SYSMIS. + 19 | GET x/!. + | ^ -matrix.sps:20.17: error: GET: Syntax error at `!': expecting variable name. +matrix.sps:20.17: error: GET: Syntax error expecting variable name. + 20 | GET x/VARIABLES=!. + | ^ -matrix.sps:21.22: error: GET: Syntax error at `!': expecting variable name. +matrix.sps:21.22: error: GET: Syntax error expecting variable name. + 21 | GET x/VARIABLES=x TO !. + | ^ -matrix.sps:22: error: MATRIX: x is not a variable name. +matrix.sps:22.17: error: MATRIX: x is not a variable name. + 22 | GET x/VARIABLES=x. + | ^ -matrix.sps:23: error: MATRIX: c TO a is not valid syntax since c precedes a in -the dictionary. +matrix.sps:23.17-23.22: error: MATRIX: c TO a is not valid syntax since c +precedes a in the dictionary. + 23 | GET x/VARIABLES=c TO a. + | ^~~~~~ -matrix.sps:24: warning: MATRIX: d is not a numeric variable. +matrix.sps:24.17: error: MATRIX: d is not a numeric variable. + 24 | GET x/VARIABLES=d. + | ^ matrix.sps:25: error: MATRIX: Variable d is not numeric. -error: The GET command cannot read an empty active file. +matrix.sps:30: error: MATRIX: The GET command cannot read an empty active file. ]) AT_CLEANUP @@ -3821,17 +3982,27 @@ SAVE {1,2}/OUTFILE='matrix5.sav'/STRINGS=a, b. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.6: error: SAVE: Syntax error at `!'. +matrix.sps:2.6: error: SAVE: Syntax error. + 2 | SAVE !. + | ^ -matrix.sps:3.16: error: SAVE: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:3.16: error: SAVE: Syntax error expecting a file name or handle +name. + 3 | SAVE 1/OUTFILE=!. + | ^ -matrix.sps:4.18: error: SAVE: Syntax error at `!': expecting variable name. +matrix.sps:4.18: error: SAVE: Syntax error expecting variable name. + 4 | SAVE 1/VARIABLES=!. + | ^ -matrix.sps:5.14: error: SAVE: Syntax error at `!'. +matrix.sps:5.14: error: SAVE: Syntax error. + 5 | SAVE 1/NAMES=!. + | ^ -matrix.sps:6.8: error: SAVE: Syntax error at `!': expecting OUTFILE, VARIABLES, -NAMES, or STRINGS. +matrix.sps:6.8: error: SAVE: Syntax error expecting OUTFILE, VARIABLES, NAMES, +or STRINGS. + 6 | SAVE 1/!. + | ^ matrix.sps:7: error: SAVE: Required subcommand OUTFILE was not specified. @@ -4185,18 +4356,28 @@ MGET TYPE=CORR !. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.6: error: MGET: Syntax error at `!': expecting FILE or TYPE. +matrix.sps:2.6: error: MGET: Syntax error expecting FILE or TYPE. + 2 | MGET !. + | ^ -matrix.sps:3.11: error: MGET: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:3.11: error: MGET: Syntax error expecting a file name or handle +name. + 3 | MGET FILE=!. + | ^ -matrix.sps:4.15: error: MGET: Syntax error at `!': expecting string. +matrix.sps:4.15: error: MGET: Syntax error expecting string. + 4 | MGET ENCODING=!. + | ^ -matrix.sps:5.11: error: MGET: Syntax error at `!': expecting COV, CORR, MEAN, -STDDEV, N, or COUNT. +matrix.sps:5.11: error: MGET: Syntax error expecting COV, CORR, MEAN, STDDEV, +N, or COUNT. + 5 | MGET TYPE=!. + | ^ -matrix.sps:6.16: error: MGET: Syntax error at `!': expecting COV, CORR, MEAN, -STDDEV, N, or COUNT. +matrix.sps:6.16: error: MGET: Syntax error expecting COV, CORR, MEAN, STDDEV, +N, or COUNT. + 6 | MGET TYPE=CORR !. + | ^ ]) AT_CLEANUP @@ -4554,52 +4735,108 @@ MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/VARIABLES=ROWTYPE_. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.7: error: MSAVE: Syntax error at `!'. +matrix.sps:2.7: error: MSAVE: Syntax error. + 2 | MSAVE !. + | ^ -matrix.sps:3.14: error: MSAVE: Syntax error at `!': expecting COV, CORR, MEAN, -STDDEV, N, or COUNT. +matrix.sps:3.14: error: MSAVE: Syntax error expecting COV, CORR, MEAN, STDDEV, +N, or COUNT. + 3 | MSAVE 1/TYPE=!. + | ^ -matrix.sps:4.17: error: MSAVE: Syntax error at `!': expecting a file name or -handle name. +matrix.sps:4.17: error: MSAVE: Syntax error expecting a file name or handle +name. + 4 | MSAVE 1/OUTFILE=!. + | ^ -matrix.sps:5.19: error: MSAVE: Syntax error at `!': expecting variable name. +matrix.sps:5.19: error: MSAVE: Syntax error expecting variable name. + 5 | MSAVE 1/VARIABLES=!. + | ^ -matrix.sps:6.16: error: MSAVE: Syntax error at `!': expecting variable name. +matrix.sps:6.16: error: MSAVE: Syntax error expecting variable name. + 6 | MSAVE 1/FNAMES=!. + | ^ -matrix.sps:7.16: error: MSAVE: Syntax error at `!': expecting variable name. +matrix.sps:7.16: error: MSAVE: Syntax error expecting variable name. + 7 | MSAVE 1/SNAMES=!. + | ^ -matrix.sps:8.15: error: MSAVE: Syntax error at `!'. +matrix.sps:8.15: error: MSAVE: Syntax error. + 8 | MSAVE 1/SPLIT=!. + | ^ -matrix.sps:9.16: error: MSAVE: Syntax error at `!'. +matrix.sps:9.16: error: MSAVE: Syntax error. + 9 | MSAVE 1/FACTOR=!. + | ^ -matrix.sps:10.9: error: MSAVE: Syntax error at `!': expecting TYPE, OUTFILE, -VARIABLES, FNAMES, SNAMES, SPLIT, or FACTOR. +matrix.sps:10.9: error: MSAVE: Syntax error expecting TYPE, OUTFILE, VARIABLES, +FNAMES, SNAMES, SPLIT, or FACTOR. + 10 | MSAVE 1/!. + | ^ matrix.sps:11: error: MSAVE: Required subcommand TYPE was not specified. -matrix.sps:12: error: MSAVE: FNAMES requires FACTOR. +matrix.sps:12.25: error: MSAVE: FNAMES requires FACTOR. + 12 | MSAVE 1/TYPE=COV/FNAMES=x. + | ^ -matrix.sps:13: error: MSAVE: SNAMES requires SPLIT. +matrix.sps:13.25: error: MSAVE: SNAMES requires SPLIT. + 13 | MSAVE 1/TYPE=COV/SNAMES=x. + | ^ matrix.sps:14: error: MSAVE: Required subcommand OUTFILE was not specified. matrix.sps:20: error: MSAVE: OUTFILE must name the same file on each MSAVE within a single MATRIX command. -matrix.sps:21: error: MSAVE: VARIABLES must specify the same variables each -time within a given MATRIX. +matrix.sps:16.26-16.37: note: MSAVE: This is the OUTFILE on the first MSAVE +command. + 16 | MSAVE 1/TYPE=COV/OUTFILE='matrix.sav' + | ^~~~~~~~~~~~ + +matrix.sps:20.26-20.38: note: MSAVE: This is the OUTFILE on a later MSAVE +command. + 20 | MSAVE 1/TYPE=COV/OUTFILE='matrix2.sav'. + | ^~~~~~~~~~~~~ -matrix.sps:16-19: note: MSAVE: This is the location of the first MSAVE command. +matrix.sps:21: error: MSAVE: VARIABLES must specify the same variables on each +MSAVE within a given MATRIX. -matrix.sps:22: error: MSAVE: FNAMES must specify the same variables each time -within a given MATRIX. +matrix.sps:19.16: error: MSAVE: This is the specification of VARIABLES on the +first MSAVE. + 19 | /VARIABLES=w. + | ^ -matrix.sps:16-19: note: MSAVE: This is the location of the first MSAVE command. +matrix.sps:21.28: error: MSAVE: This is a different specification of VARIABLES +on a later MSAVE. + 21 | MSAVE 1/TYPE=COV/VARIABLES=x. + | ^ -matrix.sps:23: error: MSAVE: SNAMES must specify the same variables each time -within a given MATRIX. +matrix.sps:22: error: MSAVE: FNAMES must specify the same variables on each +MSAVE within a given MATRIX. -matrix.sps:16-19: note: MSAVE: This is the location of the first MSAVE command. +matrix.sps:17.23: error: MSAVE: This is the specification of FNAMES on the +first MSAVE. + 17 | /FACTOR=1 /FNAMES=y + | ^ + +matrix.sps:22.25: error: MSAVE: This is a different specification of FNAMES on +a later MSAVE. + 22 | MSAVE 1/TYPE=COV/FNAMES=x. + | ^ + +matrix.sps:23: error: MSAVE: SNAMES must specify the same variables on each +MSAVE within a given MATRIX. + +matrix.sps:18.22: error: MSAVE: This is the specification of SNAMES on the +first MSAVE. + 18 | /SPLIT=2 /SNAMES=z + | ^ + +matrix.sps:23.25: error: MSAVE: This is a different specification of SNAMES on +a later MSAVE. + 23 | MSAVE 1/TYPE=COV/SNAMES=x. + | ^ matrix.sps:28.7-28.11: error: MATRIX: Matrix on MSAVE has 2 columns but there are 1 variables. @@ -4630,25 +4867,46 @@ values were supplied. 31 | MSAVE 0/TYPE=COV/FACTOR=1/SPLIT={1;2}. | ^~~~~ -matrix.sps:35: error: MSAVE: Variable x appears twice in variable list. +matrix.sps:35.49: error: MSAVE: Variable x appears twice in variable list. + 35 | MSAVE 1/TYPE=COV/OUTFILE='matrix4.sav'/SNAMES=x,x/SPLIT=1. + | ^ -matrix.sps:39: error: MATRIX: Duplicate or invalid FACTOR variable name x. +matrix.sps:39.56: error: MATRIX: Duplicate or invalid FACTOR variable name x. + 39 | MSAVE 1/TYPE=COV/OUTFILE='matrix5.sav'/SNAMES=x/FNAMES=x/SPLIT=1/ +FACTOR=1. + | ^ -matrix.sps:43: error: MATRIX: Duplicate or invalid variable name x. +matrix.sps:43.50: error: MATRIX: Duplicate or invalid variable name x. + 43 | MSAVE 1/TYPE=COV/OUTFILE='matrix6.sav'/VARIABLES=x/FNAMES=x/FACTOR=1. + | ^ -matrix.sps:47: error: MATRIX: Duplicate or invalid variable name x. +matrix.sps:47.50: error: MATRIX: Duplicate or invalid variable name x. + 47 | MSAVE 1/TYPE=COV/OUTFILE='matrix6.sav'/VARIABLES=x/SNAMES=x/SPLIT=1. + | ^ -matrix.sps:51: error: MSAVE: Variable name VARNAME_ is reserved. +matrix.sps:51.47-51.54: error: MSAVE: Variable name VARNAME_ is reserved. + 51 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/SNAMES=VARNAME_. + | ^~~~~~~~ -matrix.sps:52: error: MSAVE: Variable name ROWTYPE_ is reserved. +matrix.sps:52.47-52.54: error: MSAVE: Variable name ROWTYPE_ is reserved. + 52 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/SNAMES=ROWTYPE_. + | ^~~~~~~~ -matrix.sps:53: error: MSAVE: Variable name VARNAME_ is reserved. +matrix.sps:53.47-53.54: error: MSAVE: Variable name VARNAME_ is reserved. + 53 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/FNAMES=VARNAME_. + | ^~~~~~~~ -matrix.sps:54: error: MSAVE: Variable name ROWTYPE_ is reserved. +matrix.sps:54.47-54.54: error: MSAVE: Variable name ROWTYPE_ is reserved. + 54 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/FNAMES=ROWTYPE_. + | ^~~~~~~~ -matrix.sps:55: error: MSAVE: Variable name VARNAME_ is reserved. +matrix.sps:55.50-55.57: error: MSAVE: Variable name VARNAME_ is reserved. + 55 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/VARIABLES=VARNAME_. + | ^~~~~~~~ -matrix.sps:56: error: MSAVE: Variable name ROWTYPE_ is reserved. +matrix.sps:56.50-56.57: error: MSAVE: Variable name ROWTYPE_ is reserved. + 56 | MSAVE 1/TYPE=COV/OUTFILE='matrix7.sav'/VARIABLES=ROWTYPE_. + | ^~~~~~~~ ]) AT_CLEANUP @@ -4683,8 +4941,9 @@ DISPLAY !. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.9: error: DISPLAY: Syntax error at `!': expecting DICTIONARY or -STATUS. +matrix.sps:2.9: error: DISPLAY: Syntax error expecting DICTIONARY or STATUS. + 2 | DISPLAY !. + | ^ ]) AT_CLEANUP @@ -4722,12 +4981,20 @@ RELEASE x. END MATRIX. ]) AT_CHECK([pspp matrix.sps], [1], [dnl -matrix.sps:2.9: error: RELEASE: Syntax error at `!': expecting end of command. +matrix.sps:2.9: error: RELEASE: Syntax error expecting end of command. + 2 | RELEASE !. + | ^ -matrix.sps:3.9: error: RELEASE: Syntax error at `x': Variable name expected. +matrix.sps:3.9: error: RELEASE: Syntax error expecting variable name. + 3 | RELEASE x. + | ^ -matrix.sps:5.12: error: RELEASE: Syntax error at `!': expecting end of command. +matrix.sps:5.12: error: RELEASE: Syntax error expecting end of command. + 5 | RELEASE x, !. + | ^ -matrix.sps:7.11: error: RELEASE: Syntax error at `y': expecting end of command. +matrix.sps:7.11: error: RELEASE: Syntax error expecting end of command. + 7 | RELEASE x y. + | ^ ]) AT_CLEANUP \ No newline at end of file diff --git a/tests/language/stats/quick-cluster.at b/tests/language/stats/quick-cluster.at index f3d0d24283..62d9facf32 100644 --- a/tests/language/stats/quick-cluster.at +++ b/tests/language/stats/quick-cluster.at @@ -270,7 +270,9 @@ end data. QUICK CLUSTER x y /UNSUPPORTED. ]) AT_CHECK([pspp -O format=csv quick-cluster.sps], [1], [dnl -quick-cluster.sps:7.20-7.30: error: QUICK CLUSTER: Syntax error at `UNSUPPORTED'. +"quick-cluster.sps:7.20-7.30: error: QUICK CLUSTER: Syntax error. + 7 | QUICK CLUSTER x y /UNSUPPORTED. + | ^~~~~~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/stats/rank.at b/tests/language/stats/rank.at index bd3f8becb4..3351741f1b 100644 --- a/tests/language/stats/rank.at +++ b/tests/language/stats/rank.at @@ -595,12 +595,20 @@ RANK x /RANK INTO foo bar wiz. ]) AT_CHECK([pspp -O format=csv rank.sps], [1], [dnl -rank.sps:15.1: error: RANK: Syntax error at end of command: expecting `@{:@'. +"rank.sps:15.1: error: RANK: Syntax error expecting `@{:@'. + 15 | . + | ^" -rank.sps:19.11: error: RANK: Syntax error at `d': Expected positive integer for NTILES. +"rank.sps:19.11: error: RANK: Syntax error expecting positive integer for NTILES. + 19 | /NTILES(d) + | ^" -rank.sps:25: error: RANK: Variable x already exists. +"rank.sps:25.13: error: RANK: Variable x already exists. + 25 | /RANK INTO x. + | ^" -rank.sps:30: error: RANK: Too many variables in INTO clause. +"rank.sps:30.18-30.20: error: RANK: Too many variables in INTO clause. + 30 | /RANK INTO foo bar wiz. + | ^~~" ]) AT_CLEANUP diff --git a/tests/language/stats/regression.at b/tests/language/stats/regression.at index f4977f359a..686c4edd6a 100644 --- a/tests/language/stats/regression.at +++ b/tests/language/stats/regression.at @@ -38,7 +38,9 @@ list. ]) AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl -regression.sps:16: warning: REGRESSION: REGRESSION with SAVE ignores FILTER. All cases will be processed. +"regression.sps:16.82-16.96: warning: REGRESSION: REGRESSION with SAVE ignores FILTER. All cases will be processed. + 16 | regression /variables=v0 v1 v2 /statistics defaults /dependent=v2 /method=enter /save=pred resid. + | ^~~~~~~~~~~~~~~" Table: Model Summary (v2) R,R Square,Adjusted R Square,Std. Error of the Estimate diff --git a/tests/language/stats/reliability.at b/tests/language/stats/reliability.at index 77cd27620d..6897195084 100644 --- a/tests/language/stats/reliability.at +++ b/tests/language/stats/reliability.at @@ -199,8 +199,10 @@ RELIABILITY /VARIABLES=var6 var8 var15 var17 . ]) -AT_CHECK([pspp -o pspp.csv -o pspp.txt reliability.sps], [0], - [reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented. No statistics will be produced. +AT_CHECK([pspp -o pspp.csv -o pspp.txt reliability.sps], [0], [dnl +reliability.sps:174.4-174.40: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented. No statistics will be produced. + 174 | /STATISTICS = DESCRIPTIVES COVARIANCES + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ]) AT_CHECK([cat pspp.csv], [0], [dnl Scale: Everything @@ -234,7 +236,9 @@ Spearman-Brown Coefficient,Equal Length,,.75 ,Unequal Length,,.75 Guttman Split-Half Coefficient,,,.75 -reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented. No statistics will be produced. +"reliability.sps:174.4-174.40: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented. No statistics will be produced. + 174 | /STATISTICS = DESCRIPTIVES COVARIANCES + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" Scale: Totals diff --git a/tests/language/stats/t-test.at b/tests/language/stats/t-test.at index c1e96e557e..7b36fb4aae 100644 --- a/tests/language/stats/t-test.at +++ b/tests/language/stats/t-test.at @@ -805,7 +805,9 @@ end data. t-test /GROUPS=indep('a') /var=dep1 dep2. ]) AT_CHECK([pspp -O format=csv t-test.sps], [1], [dnl -"t-test.sps:17: error: T-TEST: When applying GROUPS to a string variable, two values must be specified." +"t-test.sps:17.16-17.25: error: T-TEST: When applying GROUPS to a string variable, two values must be specified. + 17 | t-test /GROUPS=indep('a') /var=dep1 dep2. + | ^~~~~~~~~~" ]) AT_CLEANUP diff --git a/tests/language/utilities/host.at b/tests/language/utilities/host.at index 53aac78d8a..a460e4977f 100644 --- a/tests/language/utilities/host.at +++ b/tests/language/utilities/host.at @@ -138,6 +138,8 @@ SET SAFER=ON. HOST COMMAND=[['sleep 10']] TIMELIMIT=0.1. ]) AT_CHECK([pspp -O format=csv host.sps], [1], [dnl -host.sps:2: error: HOST: This command not allowed when the SAFER option is set. +"host.sps:2.1-2.4: error: HOST: This command not allowed when the SAFER option is set. + 2 | HOST COMMAND=[['sleep 10']] TIMELIMIT=0.1. + | ^~~~" ]) AT_CLEANUP diff --git a/tests/language/utilities/insert.at b/tests/language/utilities/insert.at index 8867ac28c1..91485cbaf6 100644 --- a/tests/language/utilities/insert.at +++ b/tests/language/utilities/insert.at @@ -37,10 +37,18 @@ INSERT LIST. ]) AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl -batch.sps:2.1-2.4: error: INPUT PROGRAM: Syntax error at `loop': expecting end of command. -batch.sps:3: error: COMPUTE: COMPUTE is allowed only after the active dataset has been defined or inside INPUT PROGRAM. -batch.sps:4: error: END CASE: END CASE is allowed only inside INPUT PROGRAM. -insert.sps:4: error: LIST: LIST is allowed only after the active dataset has been defined. +batch.sps:2.1-2.4: error: INPUT PROGRAM: Syntax error expecting end of command. + 2 | loop #i = 1 to 5 + | ^~~~ +batch.sps:3.4-3.10: error: COMPUTE: COMPUTE is allowed only after the active dataset has been defined or inside INPUT PROGRAM. + 3 | + compute z = #i + | ^~~~~~~ +batch.sps:4.4-4.11: error: END CASE: END CASE is allowed only inside INPUT PROGRAM. + 4 | + end case + | ^~~~~~~~ +insert.sps:4.1-4.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 4 | LIST. + | ^~~~ ]) AT_CLEANUP @@ -81,7 +89,9 @@ END DATA. ]) AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl Dir1/foo.sps:1: error: INSERT: Can't find `bar.sps' in include file search path. -insert.sps:2: error: LIST: LIST is allowed only after the active dataset has been defined. +insert.sps:2.1-2.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 2 | LIST. + | ^~~~ ]) AT_CLEANUP @@ -134,7 +144,9 @@ CREATE_ERROR_SPS AT_DATA([insert.sps], [INSERT FILE='error.sps' ERROR=STOP. ]) AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl -error.sps:10: error: DISPLAY: AKSDJ is not a variable name. +error.sps:10.9-10.13: error: DISPLAY: AKSDJ is not a variable name. + 10 | DISPLAY AKSDJ. + | ^~~~~ warning: Error encountered while ERROR=STOP is effective. ]) AT_CLEANUP @@ -144,10 +156,14 @@ CREATE_ERROR_SPS AT_DATA([insert.sps], [INSERT FILE='error.sps' ERROR=CONTINUE. ]) AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl -error.sps:10: error: DISPLAY: AKSDJ is not a variable name. +error.sps:10.9-10.13: error: DISPLAY: AKSDJ is not a variable name. + 10 | DISPLAY AKSDJ. + | ^~~~~ ]) AT_CHECK([cat pspp.csv], [0], [dnl -error.sps:10: error: DISPLAY: AKSDJ is not a variable name. +"error.sps:10.9-10.13: error: DISPLAY: AKSDJ is not a variable name. + 10 | DISPLAY AKSDJ. + | ^~~~~" Table: Data List x @@ -171,7 +187,9 @@ LIST. AT_CHECK([pspp -O format=csv insert.sps], [1], [dnl insert.sps:2: error: INSERT: Can't find `nonexistent' in include file search path. -insert.sps:6: error: LIST: LIST is allowed only after the active dataset has been defined. +"insert.sps:6.1-6.4: error: LIST: LIST is allowed only after the active dataset has been defined. + 6 | LIST. + | ^~~~" ]) AT_CLEANUP diff --git a/tests/language/utilities/permissions.at b/tests/language/utilities/permissions.at index 6d2baa20b8..23a1f1298e 100644 --- a/tests/language/utilities/permissions.at +++ b/tests/language/utilities/permissions.at @@ -47,6 +47,8 @@ AT_DATA([pe.sps], [[PERMI|SIONS /FILE='foobar' PERMISSIONS=WRITEABLE. ]]) AT_CHECK([pspp -O format=csv pe.sps], [1], [dnl -pe.sps:1.6: error: PERMISSIONS: Syntax error at `|': expecting STRING. +"pe.sps:1.6: error: PERMISSIONS: Syntax error expecting STRING. + 1 | PERMI|SIONS /FILE='foobar' PERMISSIONS=WRITEABLE. + | ^" ]) AT_CLEANUP diff --git a/tests/output/ascii.at b/tests/output/ascii.at index 1ca7510667..ce000d65fb 100644 --- a/tests/output/ascii.at +++ b/tests/output/ascii.at @@ -615,8 +615,10 @@ END DATA. REGRESSION /VARIABLES= a -ascii.sps:11: warning: REGRESSION: a is not a numeric variable. It will not be -included in the variable list. +ascii.sps:10.13: warning: REGRESSION: a is not a numeric variable. It will not +be included in the variable list. + 10 | /VARIABLES= a + | ^ /DEPENDENT= x y /STATISTICS=COEFF R ANOVA. diff --git a/tests/output/pivot-table-test.c b/tests/output/pivot-table-test.c index 7aef458d24..67edc0481f 100644 --- a/tests/output/pivot-table-test.c +++ b/tests/output/pivot-table-test.c @@ -661,7 +661,7 @@ read_value_option (struct lexer *lexer, const struct pivot_table *pt, return; } - lex_error (lexer, "Expecting valid value option"); + lex_error (lexer, "Syntax error expecting valid value option."); exit (1); } @@ -826,7 +826,7 @@ read_stroke (struct lexer *lexer) if (lex_match_id (lexer, table_stroke_to_string (stroke))) return stroke; - lex_error (lexer, "expecting stroke"); + lex_error (lexer, "Syntax error expecting stroke."); exit (1); } diff --git a/utilities/pspp-convert.c b/utilities/pspp-convert.c index 99a254ba44..a381a98746 100644 --- a/utilities/pspp-convert.c +++ b/utilities/pspp-convert.c @@ -80,7 +80,7 @@ parse_variables_option (const char *arg, struct dictionary *dict, bool ok = parse_variables (lexer, dict, vars, n_vars, 0); if (ok && (lex_token (lexer) != T_STOP && lex_token (lexer) != T_ENDCMD)) { - lex_error (lexer, _("expecting variable name")); + lex_error (lexer, _("Syntax error expecting variable name.")); ok = false; } -- 2.30.2