From 962a26d84037059eaacc4a94a9866440a5aff68c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 31 Jul 2022 21:18:37 -0700 Subject: [PATCH] Bug fixes. --- src/language/stats/ctables.c | 236 ++++++------ tests/language/stats/ctables.at | 618 +++++++++++++++++++++++++++++++- 2 files changed, 732 insertions(+), 122 deletions(-) diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index e043105ccb..3b7dc24d10 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -795,7 +795,7 @@ enum ctables_function_availability { CTFA_ALL, /* Any variables. */ CTFA_SCALE, /* Only scale variables, totals, and subtotals. */ - CTFA_MRSETS, /* Only multiple-response sets */ + //CTFA_MRSETS, /* Only multiple-response sets */ }; struct ctables_summary_spec @@ -1165,16 +1165,17 @@ add_summary_spec (struct ctables_axis *axis, const char *var_name = var_get_name (axis->var); switch (ctables_function_availability (function)) { +#if 0 case CTFA_MRSETS: msg_at (SE, loc, _("Summary function %s applies only to multiple " "response sets."), function_name); msg_at (SN, axis->loc, _("'%s' is not a multiple response set."), var_name); return false; +#endif case CTFA_SCALE: -#if 0 - if (!axis->scale) + if (!axis->scale && sv != CSV_TOTAL) { msg_at (SE, loc, _("Summary function %s applies only to scale variables."), @@ -1183,7 +1184,6 @@ add_summary_spec (struct ctables_axis *axis, var_name); return false; } -#endif break; case CTFA_ALL: @@ -1245,7 +1245,6 @@ ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx) struct ctables_axis *axis = xmalloc (sizeof *axis); *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var }; - /* XXX should figure out default measures by reading data */ axis->scale = (lex_match_phrase (ctx->lexer, "[S]") ? true : lex_match_phrase (ctx->lexer, "[C]") ? false : var_get_measure (var) == MEASURE_SCALE); @@ -1293,15 +1292,17 @@ parse_ctables_format_specifier (struct lexer *lexer, struct fmt_spec *format, && fmt_check_type_compat (format, VAL_NUMERIC)); } + lex_get (lexer); if (format->w < 2) { - msg (SE, _("Output format %s requires width 2 or greater."), type); + lex_next_error (lexer, -1, -1, + _("Output format %s requires width 2 or greater."), type); return false; } else if (format->d > format->w - 1) { - msg (SE, _("Output format %s requires width greater than decimals."), - type); + lex_next_error (lexer, -1, -1, _("Output format %s requires width " + "greater than decimals."), type); return false; } else @@ -1897,11 +1898,13 @@ ctables_recursive_check_postcompute (struct dictionary *dict, ngettext ("These categories include %zu instance " "of SUBTOTAL or HSUBTOTAL, so references " "from computed categories must refer to " - "subtotals by position.", + "subtotals by position, " + "e.g. SUBTOTAL[1].", "These categories include %zu instances " "of SUBTOTAL or HSUBTOTAL, so references " "from computed categories must refer to " - "subtotals by position.", + "subtotals by position, " + "e.g. SUBTOTAL[1].", n_subtotals), n_subtotals); msg_at (SN, e->location, @@ -1915,9 +1918,17 @@ ctables_recursive_check_postcompute (struct dictionary *dict, "in the category list."), pc_cat->pc->name); msg_at (SN, e->location, _("This is the missing category.")); - msg_at (SN, cats_location, - _("To fix the problem, add the missing category to the " - "list of categories here.")); + if (e->op == CTPO_CAT_SUBTOTAL) + msg_at (SN, cats_location, + _("To fix the problem, add subtotals to the " + "list of categories here.")); + else if (e->op == CTPO_CAT_TOTAL) + msg (SN, _("To fix the problem, add TOTAL=YES to the variable's " + "CATEGORIES specification.")); + else + msg_at (SN, cats_location, + _("To fix the problem, add the missing category to the " + "list of categories here.")); return false; } if (pc_cat->pc->hide_source_cats) @@ -2001,9 +2012,11 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, } size_t allocated_cats = 0; + int cats_start_ofs = -1; + int cats_end_ofs = -1; if (lex_match (lexer, T_LBRACK)) { - int cats_start_ofs = lex_ofs (lexer); + cats_start_ofs = lex_ofs (lexer); do { if (c->n_cats >= allocated_cats) @@ -2019,94 +2032,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, lex_match (lexer, T_COMMA); } while (!lex_match (lexer, T_RBRACK)); - - struct msg_location *cats_location - = lex_ofs_location (lexer, cats_start_ofs, lex_ofs (lexer) - 1); - for (size_t i = 0; i < c->n_cats; i++) - { - struct ctables_category *cat = &c->cats[i]; - switch (cat->type) - { - case CCT_POSTCOMPUTE: - cat->parse_format = parse_strings ? common_format->type : FMT_F; - if (!ctables_recursive_check_postcompute (dict, cat->pc->expr, - cat, c, cats_location)) - return false; - break; - - case CCT_NUMBER: - case CCT_NRANGE: - for (size_t j = 0; j < n_vars; j++) - if (var_is_alpha (vars[j])) - { - msg_at (SE, cat->location, - _("This category specification may be applied " - "only to numeric variables, but this " - "subcommand tries to apply it to string " - "variable %s."), - var_get_name (vars[j])); - return false; - } - break; - - case CCT_STRING: - if (parse_strings) - { - double n; - if (!parse_category_string (cat->location, cat->string, dict, - common_format->type, &n)) - return false; - - ss_dealloc (&cat->string); - - cat->type = CCT_NUMBER; - cat->number = n; - } - else if (!all_strings (vars, n_vars, cat)) - return false; - break; - - case CCT_SRANGE: - if (parse_strings) - { - double n[2]; - - if (!cat->srange[0].string) - n[0] = -DBL_MAX; - else if (!parse_category_string (cat->location, - cat->srange[0], dict, - common_format->type, &n[0])) - return false; - - if (!cat->srange[1].string) - n[1] = DBL_MAX; - else if (!parse_category_string (cat->location, - cat->srange[1], dict, - common_format->type, &n[1])) - return false; - - ss_dealloc (&cat->srange[0]); - ss_dealloc (&cat->srange[1]); - - cat->type = CCT_NRANGE; - cat->nrange[0] = n[0]; - cat->nrange[1] = n[1]; - } - else if (!all_strings (vars, n_vars, cat)) - return false; - break; - - case CCT_MISSING: - case CCT_OTHERNM: - case CCT_SUBTOTAL: - case CCT_TOTAL: - case CCT_VALUE: - case CCT_LABEL: - case CCT_FUNCTION: - case CCT_EXCLUDED_MISSING: - break; - } - } + cats_end_ofs = lex_ofs (lexer) - 1; } struct ctables_category cat = { @@ -2297,6 +2223,97 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, } } + if (cats_start_ofs != -1) + { + struct msg_location *cats_location + = lex_ofs_location (lexer, cats_start_ofs, cats_end_ofs); + for (size_t i = 0; i < c->n_cats; i++) + { + struct ctables_category *cat = &c->cats[i]; + switch (cat->type) + { + case CCT_POSTCOMPUTE: + cat->parse_format = parse_strings ? common_format->type : FMT_F; + if (!ctables_recursive_check_postcompute (dict, cat->pc->expr, + cat, c, cats_location)) + return false; + break; + + case CCT_NUMBER: + case CCT_NRANGE: + for (size_t j = 0; j < n_vars; j++) + if (var_is_alpha (vars[j])) + { + msg_at (SE, cat->location, + _("This category specification may be applied " + "only to numeric variables, but this " + "subcommand tries to apply it to string " + "variable %s."), + var_get_name (vars[j])); + return false; + } + break; + + case CCT_STRING: + if (parse_strings) + { + double n; + if (!parse_category_string (cat->location, cat->string, dict, + common_format->type, &n)) + return false; + + ss_dealloc (&cat->string); + + cat->type = CCT_NUMBER; + cat->number = n; + } + else if (!all_strings (vars, n_vars, cat)) + return false; + break; + + case CCT_SRANGE: + if (parse_strings) + { + double n[2]; + + if (!cat->srange[0].string) + n[0] = -DBL_MAX; + else if (!parse_category_string (cat->location, + cat->srange[0], dict, + common_format->type, &n[0])) + return false; + + if (!cat->srange[1].string) + n[1] = DBL_MAX; + else if (!parse_category_string (cat->location, + cat->srange[1], dict, + common_format->type, &n[1])) + return false; + + ss_dealloc (&cat->srange[0]); + ss_dealloc (&cat->srange[1]); + + cat->type = CCT_NRANGE; + cat->nrange[0] = n[0]; + cat->nrange[1] = n[1]; + } + else if (!all_strings (vars, n_vars, cat)) + return false; + break; + + case CCT_MISSING: + case CCT_OTHERNM: + case CCT_SUBTOTAL: + case CCT_TOTAL: + case CCT_VALUE: + case CCT_LABEL: + case CCT_FUNCTION: + case CCT_EXCLUDED_MISSING: + break; + } + } + } + return true; } @@ -5575,7 +5592,7 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict) { if (lex_match_id (lexer, "LO")) { - if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer)) + if (!lex_force_match_id (lexer, "THRU") || !lex_force_num (lexer)) return false; e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer)); lex_get (lexer); @@ -5756,7 +5773,12 @@ ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict, { int pcompute_start = lex_ofs (lexer) - 1; - if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer)) + if (!lex_match (lexer, T_AND)) + { + lex_error_expecting (lexer, "&"); + return false; + } + if (!lex_force_id (lexer)) return false; char *name = ss_xstrdup (lex_tokss (lexer)); @@ -6414,7 +6436,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) break; } if (!lex_force_match (lexer, T_SLASH)) - break; + goto error; while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD) { @@ -6460,7 +6482,6 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "ROWLABELS")) { lex_match (lexer, T_EQUALS); - t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN; if (lex_match_id (lexer, "OPPOSITE")) t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN; else if (lex_match_id (lexer, "LAYER")) @@ -6474,7 +6495,6 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "COLLABELS")) { lex_match (lexer, T_EQUALS); - t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW; if (lex_match_id (lexer, "OPPOSITE")) t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW; else if (lex_match_id (lexer, "LAYER")) @@ -6574,7 +6594,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "INCLUDEMRSETS")) { lex_match (lexer, T_EQUALS); - if (parse_bool (lexer, &t->chisq->include_mrsets)) + if (!parse_bool (lexer, &t->chisq->include_mrsets)) goto error; } else if (lex_match_id (lexer, "CATEGORIES")) diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 23a41edc60..1ea40840f0 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -93,29 +93,614 @@ CTABLES /WEIGHT VARIABLE=qns3a /HIDESMALLCOUNTS /HIDESMALLCOUNTS COUNT=10 - /TABLE qnd1 + /TABLE qnsa1 /SLABELS POSITION=COLUMN VISIBLE=YES /SLABELS VISIBLE=NO POSITION=ROW /SLABELS POSITION=LAYER /CLABELS AUTO /CLABELS ROWLABELS=OPPOSITE - /CLABELS ROWLABELS=LAYER - /CLABELS COLLABELS=OPPOSITE - /CLABELS COLLABELS=LAYER /CRITERIA CILEVEL=50 /CATEGORIES VARIABLES=qn1 qn17 ORDER=A KEY=VALUE MISSING=INCLUDE TOTAL=YES LABEL="xyzzy" POSITION=BEFORE EMPTY=INCLUDE. +CTABLES /TABLE qnsa1 /CLABELS ROWLABELS=LAYER. +CTABLES /TABLE qnsa1 /CLABELS COLLABELS=OPPOSITE. +CTABLES /TABLE qnsa1 /CLABELS COLLABELS=LAYER. ]]) AT_CHECK([pspp ctables.sps -O box=unicode -O width=80], [0], [dnl - Custom Tables -Mean -╭───────────────────────────────┬──╮ -│qnd1 D1. AGE: What is your age?│49│ -╰───────────────────────────────┴──╯ + Custom Tables +Count +╭───────────────────┬────┬────╮ +│ │ RDD│CELL│ +├───────────────────┼────┼────┤ +│Sa1. SAMPLE SOURCE:│5392│1607│ +╰───────────────────┴────┴────╯ + + Custom Tables +RDD +╭───────────────────┬─────╮ +│ │Count│ +├───────────────────┼─────┤ +│Sa1. SAMPLE SOURCE:│ 5392│ +╰───────────────────┴─────╯ + + Custom Tables +╭────────────────────────┬─────╮ +│ │Count│ +├────────────────────────┼─────┤ +│Sa1. SAMPLE SOURCE: RDD │ 5392│ +│ CELL│ 1607│ +╰────────────────────────┴─────╯ + + Custom Tables +╭────────────────────────┬─────╮ +│ │Count│ +├────────────────────────┼─────┤ +│Sa1. SAMPLE SOURCE: RDD │ 5392│ +│ CELL│ 1607│ +╰────────────────────────┴─────╯ ]) AT_CLEANUP +AT_SETUP([CTABLES parsing - negative]) +AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .]) +AT_DATA([ctables.sps], +[[GET 'nhtsa.sav'. +CTABLES. +CTABLES /FORMAT MINCOLWIDTH='foo'. +CTABLES /TABLE qn1 [**]. +CTABLES /TABLE qn1 [NOTAFUNCTION]. +CTABLES /TABLE (qn1. +CTABLES /TABLE **. +CTABLES /TABLE NOTAVAR. +STRING string(A8). +CTABLES /TABLE string[S]. +CTABLES /TABLE qn1 [PTILE 101]. +CTABLES /TABLE qn1 [MEAN F0.1]. +CTABLES /TABLE qn1 [MEAN NEGPAREN1.2]. +CTABLES /TABLE qn1 [MEAN NEGPAREN3.4]. +CTABLES /TABLE qn1 [MEAN TOTALS]. +CTABLES /TABLE qn1 [MEAN TOTALS[STDDEV]%]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [SUBTOTAL=x]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [LO **]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [LO THRU x]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [1 THRU **]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 ['x' THRU **]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&**]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&x]. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=PTILE(qn1, 101). +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=MEAN(qn1. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=MEAN. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 MISSING=**. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 TOTAL=**. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 LABEL=**. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 POSITION=**. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 EMPTY=**. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 **. +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 [1,2,3] **. +CTABLES /PCOMPUTE &k=EXPR(SUBTOTAL[0]). +CTABLES /PCOMPUTE &k=EXPR(SUBTOTAL[1**]). +CTABLES /PCOMPUTE &k=EXPR([LO **]). +CTABLES /PCOMPUTE &k=EXPR([LO THRU **]). +CTABLES /PCOMPUTE &k=EXPR([1 THRU **]). +CTABLES /PCOMPUTE &k=EXPR([1**]). +CTABLES /PCOMPUTE &k=EXPR((1x)). +CTABLES /PCOMPUTE **k. +CTABLES /PCOMPUTE &1. +CTABLES /PCOMPUTE &k**. +CTABLES /PCOMPUTE &k=**. +CTABLES /PCOMPUTE &k=EXPR**. +CTABLES /PCOMPUTE &k=EXPR(1x). +CTABLES /PCOMPUTE &k=EXPR(1) /PCOMPUTE &k=EXPR(2). +CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k FORMAT=NOTAFUNCTION. +CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k FORMAT=PTILE **. +CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k LABEL=**. +CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k HIDESOURCECATS=**. +CTABLES /PCOMPUTE &k=EXPR(1) /PPROPERTIES &k **. +CTABLES /FORMAT EMPTY=**. +CTABLES /FORMAT MISSING=**. +CTABLES /FORMAT **. +CTABLES /FORMAT MINCOLWIDTH=20 MAXCOLWIDTH=10/. +CTABLES /VLABELS **. +CTABLES /VLABELS VARIABLES=NOTAVAR. +CTABLES /VLABELS VARIABLES=qn1 **. +CTABLES /VLABELS VARIABLES=qn1 DISPLAY=**. +CTABLES /MRSETS **. +CTABLES /MRSETS COUNTDUPLICATES=**. +CTABLES /SMISSING **. +CTABLES /WEIGHT **. +CTABLES /WEIGHT VARIABLE=NOTAVAR. +CTABLES /HIDESMALLCOUNTS COUNT=1. +CTABLES /QUUX. +CTABLES /HIDESMALLCOUNTS COUNT=2. +CTABLES /TABLE qn1**. +CTABLES /TABLE qn1 /SLABELS POSITION=**. +CTABLES /TABLE qn1 /SLABELS VISIBLE=**. +CTABLES /TABLE qn1 /SLABELS **. +CTABLES /TABLE qn1 /CLABELS ROWLABELS=**. +CTABLES /TABLE qn1 /CLABELS COLLABELS=**. +CTABLES /TABLE qn1 /CLABELS **. +CTABLES /TABLE qn1 /CRITERIA **. +CTABLES /TABLE qn1 /CRITERIA CILEVEL=101. +CTABLES /TABLE qn1 /TITLES **. +CTABLES /TABLE qn1 /SIGTEST TYPE=**. +CTABLES /TABLE qn1 /SIGTEST ALPHA=**. +CTABLES /TABLE qn1 /SIGTEST INCLUDEMRSETS=**. +CTABLES /TABLE qn1 /SIGTEST CATEGORIES=**. +CTABLES /TABLE qn1 /SIGTEST **. +CTABLES /TABLE qn1 /COMPARETEST TYPE=**. +CTABLES /TABLE qn1 /COMPARETEST ALPHA=**. +CTABLES /TABLE qn1 /COMPARETEST ALPHA=0,5. +CTABLES /TABLE qn1 /COMPARETEST ADJUST=**. +CTABLES /TABLE qn1 /COMPARETEST INCLUDEMRSETS=**. +CTABLES /TABLE qn1 /COMPARETEST MEANSVARIANCE=**. +CTABLES /TABLE qn1 /COMPARETEST CATEGORIES=**. +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 /CLABELS ROWLABELS=OPPOSITE /CLABELS COLLABELS=OPPOSITE. +CTABLES /TABLE qn20 > qnd1. +CTABLES /TABLE qn1 [ROWPCT] > qnsa1. +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:3.29-3.33: error: CTABLES: Syntax error at `'foo'': Expected non- +negative number for MINCOLWIDTH. + +ctables.sps:4.21-4.22: error: CTABLES: Syntax error at `**': expecting +identifier. + +ctables.sps:5.21-5.32: error: CTABLES: Syntax error at `NOTAFUNCTION': Expecting +summary function name. + +ctables.sps:6.20: error: CTABLES: Syntax error at end of command: expecting `@:}@'. + +ctables.sps:7.16-7.17: error: CTABLES: Syntax error at `**': expecting +identifier. + +ctables.sps:8: error: CTABLES: NOTAVAR is not a variable name. + +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: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:14.26-14.36: error: CTABLES: Syntax error at `NEGPAREN3.4': Output +format NEGPAREN requires width greater than decimals. + +ctables.sps:15.21-15.24: error: CTABLES: Summary function MEAN applies only to +scale variables. + 15 | CTABLES /TABLE qn1 [MEAN TOTALS]. + | ^~~~ + +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:16.21-16.24: error: CTABLES: Summary function MEAN applies only to +scale variables. + 16 | CTABLES /TABLE qn1 [MEAN TOTALS[STDDEV]%]. + | ^~~~ + +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:17.56: error: CTABLES: Syntax error at `x': expecting string. + +ctables.sps:18.50-18.51: error: CTABLES: Syntax error at `**': expecting THRU. + +ctables.sps:19.55: error: CTABLES: Syntax error at `x': expecting number. + +ctables.sps:20.54-20.55: error: CTABLES: Syntax error at `**': expecting number. + +ctables.sps:21.56-21.57: error: CTABLES: Syntax error at `**': expecting string. + +ctables.sps:22.48-22.49: error: CTABLES: Syntax error at `**': expecting +identifier. + +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:25.58: error: CTABLES: Syntax error at end of command: expecting +`@:}@'. + +ctables.sps:26.54: error: CTABLES: Syntax error at end of command: expecting +`@{:@'. + +ctables.sps:27.54-27.55: error: CTABLES: Syntax error at `**': expecting INCLUDE +or EXCLUDE. + +ctables.sps:28.52-28.53: error: CTABLES: Syntax error at `**': expecting YES or +NO. + +ctables.sps:29.52-29.53: error: CTABLES: Syntax error at `**': expecting string. + +ctables.sps:30.55-30.56: error: CTABLES: Syntax error at `**': expecting BEFORE +or AFTER. + +ctables.sps:31.52-31.53: error: CTABLES: Syntax error at `**': expecting INCLUDE +or EXCLUDE. + +ctables.sps:32.46-32.47: error: CTABLES: Syntax error at `**': expecting ORDER, +KEY, MISSING, TOTAL, LABEL, POSITION, or EMPTY. + +ctables.sps:33.54-33.55: error: CTABLES: Syntax error at `**': expecting TOTAL, +LABEL, POSITION, or EMPTY. + +ctables.sps:34.36: error: CTABLES: Syntax error at `0': Expected positive +integer for SUBTOTAL. + +ctables.sps:35.37-35.38: error: CTABLES: Syntax error at `**': expecting `@:>@'. + +ctables.sps:36.31-36.32: error: CTABLES: Syntax error at `**': expecting THRU. + +ctables.sps:37.36-37.37: error: CTABLES: Syntax error at `**': expecting number. + +ctables.sps:38.35-38.36: error: CTABLES: Syntax error at `**': expecting number. + +ctables.sps:39.29-39.30: error: CTABLES: Syntax error at `**': expecting `@:>@'. + +ctables.sps:40.29: error: CTABLES: Syntax error at `x': expecting `@:}@'. + +ctables.sps:41.19-41.20: error: CTABLES: Syntax error at `**': expecting &. + +ctables.sps:42.20: error: CTABLES: Syntax error at `1': expecting identifier. + +ctables.sps:43.21-43.22: error: CTABLES: Syntax error at `**': expecting `='. + +ctables.sps:44.22-44.23: error: CTABLES: Syntax error at `**': expecting EXPR. + +ctables.sps:45.26-45.27: error: CTABLES: Syntax error at `**': expecting `('. + +ctables.sps:46.28: error: CTABLES: Syntax error at `x': expecting `)'. + +ctables.sps:47.31-47.49: warning: CTABLES: New definition of &k will override +the previous definition. + 47 | CTABLES /PCOMPUTE &k=EXPR(1) /PCOMPUTE &k=EXPR(2). + | ^~~~~~~~~~~~~~~~~~~ + +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:48.53-48.64: error: CTABLES: Syntax error at `NOTAFUNCTION': +Expecting summary function name. + +ctables.sps:49.59-49.60: error: CTABLES: Syntax error at `**': Expected number +between 0 and 100 for PTILE. + +ctables.sps:50.52-50.53: error: CTABLES: Syntax error at `**': expecting string. + +ctables.sps:51.61-51.62: error: CTABLES: Syntax error at `**': expecting YES or +NO. + +ctables.sps:52.46-52.47: error: CTABLES: Syntax error at `**': expecting LABEL, +FORMAT, or HIDESOURCECATS. + +ctables.sps:53.23-53.24: error: CTABLES: Syntax error at `**': expecting string. + +ctables.sps:54.25-54.26: error: CTABLES: Syntax error at `**': expecting string. + +ctables.sps:55.17-55.18: error: CTABLES: Syntax error at `**': expecting +MINCOLWIDTH, MAXCOLWIDTH, UNITS, EMPTY, or MISSING. + +ctables.sps:56: error: CTABLES: MINCOLWIDTH must not be greater than +MAXCOLWIDTH. + +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 +FORMAT, VLABELS, MRSETS, SMISSING, PCOMPUTE, PPROPERTIES, WEIGHT, +HIDESMALLCOUNTS, or 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 at `**': expecting YES or +NO. + +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 at `**': expecting TYPE, +ALPHA, INCLUDEMRSETS, or CATEGORIES. + +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 at `**': Expected number +in (0,1) for ALPHA. + +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 at `**': expecting +BONFERRONI, BH, or NONE. + +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 at `**': expecting ALLCATS +or TESTEDCATS. + +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 at `**': expecting YES or +NO. + +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 at `**': expecting YES or +NO. + +ctables.sps:94.33-94.34: error: CTABLES: Syntax error at `**': expecting TYPE, +ALPHA, ADJUST, INCLUDEMRSETS, MEANSVARIANCE, CATEGORIES, MERGE, STYLE, or +SHOWSIG. + +ctables.sps:95.22-95.23: error: CTABLES: Syntax error at `**': expecting TABLE, +SLABELS, CLABELS, CRITERIA, CATEGORIES, TITLES, SIGTEST, or COMPARETEST. + +ctables.sps:96: error: CTABLES: ROWLABELS and COLLABELS may not both be +specified. + +ctables.sps:97.16-97.26: error: CTABLES: Cannot nest scale variables. + 97 | CTABLES /TABLE qn20 > qnd1. + | ^~~~~~~~~~~ + +ctables.sps:97.16-97.19: note: CTABLES: This is an outer scale variable. + 97 | CTABLES /TABLE qn20 > qnd1. + | ^~~~ + +ctables.sps:97.23-97.26: note: CTABLES: This is an inner scale variable. + 97 | CTABLES /TABLE qn20 > qnd1. + | ^~~~ + +ctables.sps:98.16-98.35: error: CTABLES: Summaries may only be requested for +categorical variables at the innermost nesting level. + 98 | CTABLES /TABLE qn1 [ROWPCT] > qnsa1. + | ^~~~~~~~~~~~~~~~~~~~ + +ctables.sps:98.16-98.18: note: CTABLES: This outer categorical variable has a +summary. + 98 | CTABLES /TABLE qn1 [ROWPCT] > qnsa1. + | ^~~ + +ctables.sps:100.52-100.56: error: CTABLES: Failed to parse category +specification as format DATETIME: Day (123) must be between 1 and 31.. + 100 | CTABLES /TABLE qn1 /CATEGORIES VARIABLES=datetime ['123']. + | ^~~~~ +]]) +AT_CLEANUP + +AT_SETUP([CTABLES parsing - more negative]) +AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .]) +AT_DATA([ctables.sps], +[[GET 'nhtsa.sav'. +CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. +CTABLES /PCOMPUTE &pc=EXPR(TOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc]. +CTABLES /PCOMPUTE &pc=EXPR(SUBTOTAL) /TABLE qn1 /CATEGORIES VARIABLES=qn1 [&pc, SUBTOTAL, SUBTOTAL]. + +STRING string(A8). +CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 ['string']. +CTABLES /TABLE string /CATEGORIES VARIABLES=string [1]. + +CTABLES /TABLE qn1 /CLABELS ROWLABELS=OPPOSITE /CATEGORIES VARIABLES=qn1 KEY=MEAN(qn1). + +CTABLES /TABLE qnd1 /CLABELS ROWLABELS=OPPOSITE. +CTABLES /TABLE qn1 + string /CLABELS ROWLABELS=OPPOSITE. +CTABLES /TABLE qn1 + qnsa1 /CLABELS ROWLABELS=OPPOSITE. +CTABLES /TABLE qn105ba + qn105bb /CLABELS ROWLABELS=OPPOSITE /CATEGORIES VARIABLES=qn105ba [1,2,3]. + +CTABLES /PCOMPUTE &x=EXPR(1**2**3). +CTABLES /PCOMPUTE &x=EXPR([**]). +CTABLES /PCOMPUTE &x=EXPR(**). + +CTABLES /TABLE. + +CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. +]]) +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]. + | +^~~ + +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]. + | ^~~~~~~~ + +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.28-3.32: note: CTABLES: This is the missing category. + 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: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: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. + 8 | CTABLES /TABLE string /CATEGORIES VARIABLES=string [1]. + | ^ + +ctables.sps:10: error: CTABLES: ROWLABELS=OPPOSITE is not allowed with sorting +based on a summary function. + +ctables.sps:12: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be +moved to be categorical, but qnd1 is a scale variable. + +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: 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: ROWLABELS=OPPOSITE requires the variables to be +moved to have the same category specifications, but QN105BA and QN105BB have +different category specifications. + +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:18.28-18.29: error: CTABLES: Syntax error at `**'. + +ctables.sps:19.27-19.28: error: CTABLES: Syntax error at `**'. + +ctables.sps:21.15: error: CTABLES: Syntax error at end of command: At least one +variable must be specified. + +ctables.sps:23: error: CTABLES: Summaries may appear only on one axis. + +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. + 23 | CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT]. + | ^~~~~ + +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]. + | ^~~~~ +]]) +AT_CLEANUP + AT_SETUP([CTABLES one categorical variable]) AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .]) AT_DATA([ctables.sps], @@ -1014,17 +1599,22 @@ END DATA. MISSING VALUES x (1, 2) y (2, 3). VARIABLE LEVEL ALL (NOMINAL). -CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, VALIDN, TOTALN]] +CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, + TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=ALL TOTAL=YES. -CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, VALIDN, TOTALN]] +CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, + TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=ALL TOTAL=YES MISSING=INCLUDE. -CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, + TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=ALL TOTAL=YES /SLABELS POSITION=ROW. -CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, + TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=ALL TOTAL=YES MISSING=INCLUDE /SLABELS POSITION=ROW. -CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, + TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=x [1, 2, 3, 4] TOTAL=YES /CATEGORIES VARIABLES=y [1, 3, 4, 5] TOTAL=YES /SLABELS POSITION=ROW. -- 2.30.2