X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Fctables.c;h=565c8ce1db10cbd512683973ee3c90968f3f24d2;hb=f982df09b0eb59a54faaef4e54b864ad8c9e8d70;hp=d746a3356f8ce50b851f7d98b1c25dda989b752b;hpb=cfe0d592966e82229ea2892bd323f22ddd1b15a4;p=pspp diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index d746a3356f..565c8ce1db 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; } @@ -890,7 +890,8 @@ ctables_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict) } else { - lex_error (lexer, NULL); + lex_error (lexer, + _("Syntax error expecting number or string or range.")); return NULL; } @@ -920,7 +921,7 @@ ctables_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict) } else { - lex_error (lexer, NULL); + lex_error (lexer, _("Syntax error in postcompute expression.")); return NULL; } @@ -1288,9 +1289,20 @@ parse_ctables_format_specifier (struct lexer *lexer, struct fmt_spec *format, else { *is_ctables_format = false; - return (parse_format_specifier (lexer, format) - && fmt_check_output (format) - && fmt_check_type_compat (format, VAL_NUMERIC)); + if (!parse_format_specifier (lexer, format)) + return false; + + char *error = fmt_check_output__ (format); + if (!error) + error = fmt_check_type_compat__ (format, NULL, VAL_NUMERIC); + if (error) + { + lex_next_error (lexer, -1, -1, "%s", error); + free (error); + return false; + } + + return true; } lex_get (lexer); @@ -1533,7 +1545,6 @@ struct ctables_categories size_t n_refs; struct ctables_category *cats; size_t n_cats; - bool show_empty; }; struct ctables_category @@ -1602,8 +1613,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; }; @@ -1723,7 +1733,7 @@ static bool ctables_categories_equal (const struct ctables_categories *a, const struct ctables_categories *b) { - if (a->n_cats != b->n_cats || a->show_empty != b->show_empty) + if (a->n_cats != b->n_cats) return false; for (size_t i = 0; i < a->n_cats; i++) @@ -1873,7 +1883,7 @@ ctables_table_parse_explicit_category (struct lexer *lexer, } else { - lex_error (lexer, NULL); + lex_error (lexer, _("Syntax error expecting category specification.")); return false; } @@ -2975,6 +2985,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; @@ -2983,6 +2994,7 @@ struct ctables_table /* Indexed by variable dictionary index. */ struct ctables_categories **categories; size_t n_categories; + bool *show_empty; double cilevel; @@ -3492,8 +3504,9 @@ ctables_sort_clabels_values (struct ctables_table *t) const struct variable *v0 = t->clabels_example; int width = var_get_width (v0); - struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)]; - if (c0->show_empty) + size_t i0 = var_get_dict_index (v0); + struct ctables_categories *c0 = t->categories[i0]; + if (t->show_empty[i0]) { const struct val_labs *val_labs = var_get_value_labels (v0); for (const struct val_lab *vl = val_labs_first (val_labs); vl; @@ -3942,6 +3955,7 @@ ctables_table_destroy (struct ctables_table *t) for (size_t i = 0; i < t->n_categories; i++) ctables_categories_unref (t->categories[i]); free (t->categories); + free (t->show_empty); for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) { @@ -4051,20 +4065,16 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))); struct ctables_categories *c = xmalloc (sizeof *c); - *c = (struct ctables_categories) { .n_refs = n_vars, .show_empty = true }; - for (size_t i = 0; i < n_vars; i++) - { - struct ctables_categories **cp - = &t->categories[var_get_dict_index (vars[i])]; - ctables_categories_unref (*cp); - *cp = c; - } + *c = (struct ctables_categories) { .n_refs = 1 }; + + bool set_categories = false; size_t allocated_cats = 0; int cats_start_ofs = -1; int cats_end_ofs = -1; if (lex_match (lexer, T_LBRACK)) { + set_categories = true; cats_start_ofs = lex_ofs (lexer); do { @@ -4092,10 +4102,13 @@ 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")) { + set_categories = true; lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "A")) cat.sort_ascending = true; @@ -4109,7 +4122,8 @@ 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; + set_categories = true; + key_start_ofs = lex_ofs (lexer) - 1; lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "VALUE")) cat.type = CCT_VALUE; @@ -4146,14 +4160,19 @@ 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; } } else if (!c->n_cats && lex_match_id (lexer, "MISSING")) { + set_categories = true; lex_match (lexer, T_EQUALS); if (lex_match_id (lexer, "INCLUDE")) cat.include_missing = true; @@ -4167,6 +4186,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, } else if (lex_match_id (lexer, "TOTAL")) { + set_categories = true; lex_match (lexer, T_EQUALS); if (!parse_bool (lexer, &show_totals)) goto error; @@ -4196,15 +4216,20 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, else if (lex_match_id (lexer, "EMPTY")) { lex_match (lexer, T_EQUALS); + + bool show_empty; if (lex_match_id (lexer, "INCLUDE")) - c->show_empty = true; + show_empty = true; else if (lex_match_id (lexer, "EXCLUDE")) - c->show_empty = false; + show_empty = false; else { lex_error_expecting (lexer, "INCLUDE", "EXCLUDE"); goto error; } + + for (size_t i = 0; i < n_vars; i++) + t->show_empty[var_get_dict_index (vars[i])] = show_empty; } else { @@ -4219,6 +4244,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; @@ -4371,10 +4399,22 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict, } } + if (set_categories) + for (size_t i = 0; i < n_vars; i++) + { + struct ctables_categories **cp + = &t->categories[var_get_dict_index (vars[i])]; + ctables_categories_unref (*cp); + *cp = c; + c->n_refs++; + } + + ctables_categories_unref (c); free (vars); return true; error: + ctables_categories_unref (c); free (vars); return false; } @@ -4893,15 +4933,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 +4958,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 +4990,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 +5099,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 +5336,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 @@ -5443,9 +5491,9 @@ ctables_section_add_empty_categories (struct ctables_section *s) if (k != s->nests[a]->scale_idx) { const struct variable *var = s->nests[a]->vars[k]; - const struct ctables_categories *cats = s->table->categories[ - var_get_dict_index (var)]; - if (cats->show_empty) + size_t idx = var_get_dict_index (var); + const struct ctables_categories *cats = s->table->categories[idx]; + if (s->table->show_empty[idx]) { show_empty = true; ctables_add_category_occurrences (var, &s->occurrences[a][k], cats); @@ -5598,14 +5646,7 @@ ctables_execute (struct dataset *ds, struct casereader *input, while (casegrouper_get_next_group (grouper, &group)) { if (splitting) - { - struct ccase *c = casereader_peek (group, 0); - if (c != NULL) - { - output_split_file_values (ds, c); - case_unref (c); - } - } + output_split_file_values_peek (ds, group); bool warn_on_invalid = true; for (struct ccase *c = casereader_read (group); c; @@ -5682,9 +5723,7 @@ ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict, char *name = ss_xstrdup (lex_tokss (lexer)); lex_get (lexer); - if (!lex_force_match (lexer, T_EQUALS) - || !lex_force_match_id (lexer, "EXPR") - || !lex_force_match (lexer, T_LPAREN)) + if (!lex_force_match_phrase (lexer, "=EXPR(")) { free (name); return false; @@ -5800,7 +5839,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 +6057,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 +6128,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 +6243,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; } @@ -6227,7 +6279,6 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) .n_refs = n_vars, .cats = cat, .n_cats = 1, - .show_empty = true, }; struct ctables_categories **categories = xnmalloc (n_vars, @@ -6235,6 +6286,9 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) for (size_t i = 0; i < n_vars; i++) categories[i] = c; + bool *show_empty = xmalloc (n_vars); + memset (show_empty, true, n_vars); + struct ctables_table *t = xmalloc (sizeof *t); *t = (struct ctables_table) { .ctables = ct, @@ -6250,6 +6304,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) .clabels_to_axis = PIVOT_AXIS_LAYER, .categories = categories, .n_categories = n_vars, + .show_empty = show_empty, .cilevel = 95, }; ct->tables[ct->n_tables++] = t; @@ -6343,7 +6398,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 +6441,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 +6479,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")) { @@ -6446,11 +6520,11 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) do { char **textp; - if (lex_match_id (lexer, "CAPTION")) + if (lex_match_id (lexer, "CAPTIONS")) textp = &t->caption; - else if (lex_match_id (lexer, "CORNER")) + else if (lex_match_id (lexer, "CORNERS")) textp = &t->corner; - else if (lex_match_id (lexer, "TITLE")) + else if (lex_match_id (lexer, "TITLES")) textp = &t->title; else { @@ -6463,7 +6537,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) while (lex_is_string (lexer)) { if (!ds_is_empty (&s)) - ds_put_byte (&s, ' '); + ds_put_byte (&s, '\n'); put_title_text (&s, lex_tokss (lexer), now, lexer, dataset_dict (ds), expr_start, expr_end); @@ -6540,7 +6614,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 +6764,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 +6782,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);