}
}
- lex_error (lexer, _("Expecting summary function name."));
+ lex_error (lexer, _("Syntax error expecting summary function name."));
return false;
}
};
};
- /* 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;
};
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;
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"))
}
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;
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;
}
}
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;
}
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;
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++)
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;
}
}
}
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])
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
= 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);
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"))
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;
}
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;
}
if (lex_token (lexer) == T_ENDCMD)
{
- if (!ctables_prepare_table (t))
+ if (!ctables_prepare_table (t, lexer))
goto error;
break;
}
}
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;
"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"))
{
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
{
}
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);
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;
}
}
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);