This simplifies parsing code that needs an integer in a particular range.
int
cmd_n_of_cases (struct lexer *lexer, struct dataset *ds)
{
- /* Value for N. */
- int x;
-
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "N OF CASES", 1, LONG_MAX))
return CMD_FAILURE;
- x = lex_integer (lexer);
+ long n = lex_integer (lexer);
lex_get (lexer);
if (!lex_match_id (lexer, "ESTIMATED"))
- dict_set_case_limit (dataset_dict (ds), x);
+ dict_set_case_limit (dataset_dict (ds), n);
return CMD_SUCCESS;
}
if (lex_next_token (lexer, 1) == T_TO)
{
- long int a, b;
- long int i;
-
if (!lex_is_integer (lexer))
{
msg (SE, _("Ranges may only have integer bounds."));
return false;
}
- a = lex_integer (lexer);
+ long a = lex_integer (lexer);
lex_get (lexer);
lex_get (lexer);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, NULL, a, LONG_MAX))
return false;
- b = lex_integer (lexer);
+ long b = lex_integer (lexer);
if (b < a)
{
msg (SE, _("%ld TO %ld is an invalid range."), a, b);
}
lex_get (lexer);
- for (i = a; i <= b; i++)
+ for (long i = a; i <= b; i++)
add_replacement (dv, xasprintf ("%ld", i), &allocated);
}
else
{
lex_match (lexer, T_EQUALS);
lex_match (lexer, T_LPAREN);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "RECORDS", 0, INT_MAX))
goto error;
-
- int records = lex_integer (lexer);
- if (records < 0)
- {
- msg (SE, _("The %s value must be non-negative."), "RECORDS");
- goto error;
- }
- data_parser_set_records (parser, records);
+ data_parser_set_records (parser, lex_integer (lexer));
lex_get (lexer);
lex_match (lexer, T_RPAREN);
}
else if (lex_match_id (lexer, "SKIP"))
{
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "SKIP", 0, INT_MAX))
goto error;
- int skip = lex_integer (lexer);
- if (skip < 0)
- {
- msg (SE, _("The %s value must be non-negative."), "SKIP");
- goto error;
- }
- data_parser_set_skip (parser, skip);
+ data_parser_set_skip (parser, lex_integer (lexer));
lex_get (lexer);
}
else if (lex_match_id (lexer, "END"))
}
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "LRECL", 1, (1UL << 31) - 1))
goto exit;
lrecl = lex_integer (lexer);
lex_get (lexer);
}
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "TABWIDTH", 1, INT_MAX))
goto exit;
tabwidth = lex_integer (lexer);
lex_get (lexer);
msg (SE, _("The specified file mode requires LRECL. "
"Assuming %zu-character records."),
properties.record_width);
- else if (lrecl < 1 || lrecl >= (1UL << 31))
- msg (SE, _("Record length (%d) must be between 1 and %lu bytes. "
- "Assuming %zu-character records."),
- lrecl, (1UL << 31) - 1, properties.record_width);
else
properties.record_width = lrecl;
}
if (lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
{
psql.str_width = lex_integer (lexer);
lex_get (lexer);
else if (lex_match_id (lexer, "BSIZE"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "BSIZE", 1, INT_MAX))
{
psql.bsize = lex_integer (lexer);
lex_get (lexer);
if (lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
{
opts->asw = lex_integer (lexer);
lex_get (lexer);
}
else if (lex_match_id (lexer, "INDEX"))
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "INDEX", 1, INT_MAX))
goto error;
-
opts->sheet_index = lex_integer (lexer);
- if (opts->sheet_index <= 0)
- {
- msg (SE, _("The sheet index must be greater than or equal to 1"));
- goto error;
- }
lex_get (lexer);
}
else
else if (lex_match_id (lexer, "FIRSTCASE"))
{
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "FIRSTCASE", 1, INT_MAX))
goto error;
- if (lex_integer (lexer) < 1)
- {
- msg (SE, _("Value of %s must be 1 or greater."), "FIRSTCASE");
- goto error;
- }
data_parser_set_skip (parser, lex_integer (lexer) - 1);
lex_get (lexer);
}
if (!set_type (parser, "FIXCASE", DP_FIXED, &has_type))
goto error;
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "FIXCASE", 1, INT_MAX))
goto error;
- if (lex_integer (lexer) < 1)
- {
- msg (SE, _("Value of %s must be 1 or greater."), "FIXCASE");
- goto error;
- }
data_parser_set_records (parser, lex_integer (lexer));
lex_get (lexer);
}
while (type == DP_FIXED && lex_match (lexer, T_SLASH))
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, NULL, record,
+ data_parser_get_records (parser)))
goto error;
- if (lex_integer (lexer) < record)
- {
- msg (SE, _("The record number specified, %ld, is at or "
- "before the previous record, %d. Data "
- "fields must be listed in order of "
- "increasing record number."),
- lex_integer (lexer), record);
- goto error;
- }
- if (lex_integer (lexer) > data_parser_get_records (parser))
- {
- msg (SE, _("The record number specified, %ld, exceeds "
- "the number of records per case specified "
- "on FIXCASE, %d."),
- lex_integer (lexer), data_parser_get_records (parser));
- goto error;
- }
record = lex_integer (lexer);
lex_get (lexer);
}
{
lex_match (lexer, T_EQUALS);
- if (! lex_force_int (lexer))
+ if (! lex_force_int_range (lexer, "N", 0, INT_MAX))
goto error;
mformat.n = lex_integer (lexer);
- if (mformat.n < 0)
- {
- msg (SE, _("%s must not be negative."), "N");
- goto error;
- }
lex_get (lexer);
}
else if (lex_match_id (lexer, "FORMAT"))
{
if (lex_is_number (lexer))
{
- double orignum = lex_number (lexer);
- long n = (lex_is_integer (lexer)?lex_integer (lexer):*record);
- bool out_of_range = orignum > INT_MAX || orignum < INT_MIN;
- if (n <= *record || out_of_range)
- {
- msg (SE, _("The record number specified, %.0f, is at or "
- "before the previous record, %d. Data "
- "fields must be listed in order of "
- "increasing record number."),
- orignum, *record);
- return false;
- }
- *record = n;
+ if (!lex_force_int_range (lexer, NULL, *record + 1, INT_MAX))
+ return false;
+ *record = lex_integer (lexer);
lex_get (lexer);
}
else
{
lex_match (lexer, T_EQUALS);
lex_match (lexer, T_LPAREN);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "RECORDS", 0, INT_MAX))
goto error;
trns->record_cnt = lex_integer (lexer);
lex_get (lexer);
&& lex_match_id (lexer, "VERSION"))
{
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "VERSION", 2, 3))
goto error;
sysfile_opts.version = lex_integer (lexer);
lex_get (lexer);
else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "DIGITS"))
{
lex_match (lexer, T_EQUALS);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "DIGITS", 1, INT_MAX))
goto error;
porfile_opts.digits = lex_integer (lexer);
lex_get (lexer);
if (lex_match (lexer, T_LBRACK))
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, NULL, 1, 65535))
goto error;
- if (lex_integer (lexer) < 1 || lex_integer (lexer) > 65535)
- {
- msg (SE, _("Attribute array index must be between 1 and 65535."));
- goto error;
- }
*index = lex_integer (lexer);
lex_get (lexer);
if (!lex_force_match (lexer, T_RBRACK))
if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
return CMD_FAILURE;
- if (!lex_force_match (lexer, T_LPAREN) || !lex_force_int (lexer))
+ if (!lex_force_match (lexer, T_LPAREN)
+ || !lex_force_int_range (lexer, NULL, 1, INT_MAX))
{
free (v);
return CMD_FAILURE;
return CMD_FAILURE;
}
- if (width < 0)
- {
- msg (SE, _("Variable display width must be a positive integer."));
- free (v);
- return CMD_FAILURE;
- }
width = MIN (width, 2 * MAX_STRING);
for(i = 0 ; i < nv ; ++i)
{
if (lex_is_integer (lexer) && var_cnt == 0)
{
+ if (!lex_force_int_range (lexer, NULL, 1, INT_MAX))
+ goto fail;
var_cnt = lex_integer (lexer);
lex_get (lexer);
- if (var_cnt <= 0)
- {
- msg (SE, _("Vectors must have at least one element."));
- goto fail;
- }
}
else if (lex_token (lexer) == T_ID && !seen_format)
{
}
}
+/* If the current token is an integer in the range MIN...MAX (inclusive), 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
+lex_force_int_range (struct lexer *lexer, const char *name, long min, long max)
+{
+ bool is_integer = lex_is_integer (lexer);
+ bool too_small = is_integer && lex_integer (lexer) < min;
+ bool too_big = is_integer && lex_integer (lexer) > max;
+ if (is_integer && !too_small && !too_big)
+ return true;
+
+ if (min > 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);
+ else
+ lex_error (lexer, _("Integer expected."));
+ }
+ else if (min == max)
+ {
+ if (name)
+ lex_error (lexer, _("Expected %ld for %s."), min, name);
+ else
+ lex_error (lexer, _("Expected %ld."), min);
+ }
+ else if (min + 1 == max)
+ {
+ if (name)
+ lex_error (lexer, _("Expected %ld or %ld for %s."), min, min + 1, name);
+ else
+ lex_error (lexer, _("Expected %ld or %ld."), min, min + 1);
+ }
+ else
+ {
+ bool report_lower_bound = (min > INT_MIN / 2) || too_small;
+ bool report_upper_bound = (max < INT_MAX / 2) || too_big;
+
+ if (report_lower_bound && report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected integer between %ld and %ld for %s."),
+ min, max, name);
+ else
+ lex_error (lexer, _("Expected integer between %ld and %ld."),
+ min, max);
+ }
+ else if (report_lower_bound)
+ {
+ if (min == 0)
+ {
+ if (name)
+ lex_error (lexer, _("Expected non-negative integer for %s."),
+ name);
+ else
+ lex_error (lexer, _("Expected non-negative integer."));
+ }
+ else if (min == 1)
+ {
+ if (name)
+ lex_error (lexer, _("Expected positive integer for %s."),
+ name);
+ else
+ lex_error (lexer, _("Expected positive integer."));
+ }
+ }
+ else if (report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected integer less than or equal to %ld for %s."),
+ max, name);
+ else
+ lex_error (lexer, _("Expected integer less than or equal to %ld."),
+ max);
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Integer expected for %s."), name);
+ else
+ lex_error (lexer, _("Integer expected."));
+ }
+ }
+ return false;
+}
+
/* If the current token is a number, does nothing and returns true.
Otherwise, reports an error and returns false. */
bool
ds_put_cstr (&s, ": ");
ds_put_vformat (&s, format, args);
}
- ds_put_byte (&s, '.');
+ if (ds_last (&s) != '.')
+ ds_put_byte (&s, '.');
struct msg m = {
.category = MSG_C_SYNTAX,
bool lex_force_match (struct lexer *, enum token_type) WARN_UNUSED_RESULT;
bool lex_force_match_id (struct lexer *, const char *) WARN_UNUSED_RESULT;
bool lex_force_int (struct lexer *) WARN_UNUSED_RESULT;
+bool lex_force_int_range (struct lexer *, const char *name,
+ long min, long max) WARN_UNUSED_RESULT;
bool lex_force_num (struct lexer *) WARN_UNUSED_RESULT;
bool lex_force_id (struct lexer *) WARN_UNUSED_RESULT;
bool lex_force_string (struct lexer *) WARN_UNUSED_RESULT;
for (;;)
{
size_t orig_nv = proc->n_variables;
- size_t i;
-
- long min, max;
if (!parse_variables_const (lexer, dataset_dict (ds),
&proc->variables, &proc->n_variables,
if (!lex_force_int (lexer))
goto error;
- min = lex_integer (lexer);
+ long min = lex_integer (lexer);
lex_get (lexer);
lex_match (lexer, T_COMMA);
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, NULL, min, LONG_MAX))
goto error;
- max = lex_integer (lexer);
- if (max < min)
- {
- msg (SE, _("Maximum value (%ld) less than minimum value (%ld)."),
- max, min);
- goto error;
- }
+ long max = lex_integer (lexer);
lex_get (lexer);
if (!lex_force_match (lexer, T_RPAREN))
goto error;
- for (i = orig_nv; i < proc->n_variables; i++)
+ for (size_t i = orig_nv; i < proc->n_variables; i++)
{
const struct variable *var = proc->variables[i];
struct var_range *vr = xmalloc (sizeof *vr);
int extr = 5;
if (lex_match (lexer, T_LPAREN))
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "EXTREME", 0, INT_MAX))
goto error;
extr = lex_integer (lexer);
- if (extr < 0)
- {
- msg (MW, _("%s may not be negative. Using default value (%g)."), "EXTREME", 5.0);
- extr = 5;
- }
-
lex_get (lexer);
if (! lex_force_match (lexer, T_RPAREN))
goto error;
else if (lex_match_id (lexer, "ITERATE"))
{
if (lex_force_match (lexer, T_LPAREN)
- && lex_force_int (lexer))
+ && lex_force_int_range (lexer, "ITERATE", 0, INT_MAX))
{
n_iterations = lex_integer (lexer);
lex_get (lexer);
else if (lex_match_id (lexer, "LIMIT"))
{
if (!lex_force_match (lexer, T_LPAREN)
- || !lex_force_int (lexer))
+ || !lex_force_int_range (lexer, "LIMIT", 0, INT_MAX))
goto error;
frq.max_categories = lex_integer (lexer);
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "NTILES", 0, INT_MAX))
{
- int i;
int n = lex_integer (lexer);
lex_get (lexer);
- for (i = 0; i < n + 1; ++i)
+ for (int i = 0; i < n + 1; ++i)
{
frq.percentiles =
xrealloc (frq.percentiles,
hi_scale = FRQ_FREQ;
if (lex_match (lexer, T_LPAREN))
{
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "FREQ", 1, INT_MAX))
{
hi_freq = lex_integer (lexer);
- if (hi_freq <= 0)
- {
- lex_error (lexer, _("Histogram frequency must be greater than zero."));
- }
lex_get (lexer);
if (! lex_force_match (lexer, T_RPAREN))
goto error;
hi_scale = FRQ_PERCENT;
if (lex_match (lexer, T_LPAREN))
{
- if (lex_force_int (lexer))
+ if (lex_force_int_range (lexer, "PERCENT", 1, INT_MAX))
{
hi_pcnt = lex_integer (lexer);
- if (hi_pcnt <= 0)
- {
- lex_error (lexer, _("Histogram percentage must be greater than zero."));
- }
lex_get (lexer);
if (! lex_force_match (lexer, T_RPAREN))
goto error;
goto error;
}
- if (! lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "SSTYPE", 1, 3))
{
lex_error (lexer, NULL);
goto error;
}
glm.ss_type = lex_integer (lexer);
- if (1 > glm.ss_type || 3 < glm.ss_type)
- {
- msg (ME, _("Only types 1, 2 & 3 sums of squares are currently implemented"));
- goto error;
- }
-
lex_get (lexer);
if (! lex_force_match (lexer, T_RPAREN))
{
if (lex_force_match (lexer, T_LPAREN))
{
- if (! lex_force_int (lexer))
+ if (! lex_force_int_range (lexer, "ITERATE", 0, INT_MAX))
{
lex_error (lexer, NULL);
goto error;
if (lex_match_id (lexer, "CLUSTERS"))
{
if (lex_force_match (lexer, T_LPAREN) &&
- lex_force_int (lexer))
+ lex_force_int_range (lexer, "CLUSTERS", 1, INT_MAX))
{
qc->ngroups = lex_integer (lexer);
- if (qc->ngroups <= 0)
- {
- lex_error (lexer, _("The number of clusters must be positive"));
- return false;
- }
lex_get (lexer);
if (!lex_force_match (lexer, T_RPAREN))
return false;
else if (lex_match_id (lexer, "MXITER"))
{
if (lex_force_match (lexer, T_LPAREN) &&
- lex_force_int (lexer))
+ lex_force_int_range (lexer, "MXITER", 1, INT_MAX))
{
qc->maxiter = lex_integer (lexer);
- if (qc->maxiter <= 0)
- {
- lex_error (lexer, _("The number of iterations must be positive"));
- return false;
- }
lex_get (lexer);
if (!lex_force_match (lexer, T_RPAREN))
return false;
if (!lex_force_match (lexer, T_LPAREN))
return false;
- if (! lex_force_int (lexer))
+ if (! lex_force_int_range (lexer, "NTILES", 1, INT_MAX))
return false;
cmd->k_ntiles = lex_integer (lexer);
if (settings_get_testing_mode () && lex_match (lexer, T_SLASH))
{
if (!lex_force_match_id (lexer, "BUFFERS") || !lex_match (lexer, T_EQUALS)
- || !lex_force_int (lexer))
+ || !lex_force_int_range (lexer, "BUFFERS", 2, INT_MAX))
goto done;
min_buffers = max_buffers = lex_integer (lexer);
- if (max_buffers < 2)
- {
- msg (SE, _("Buffer limit must be at least 2."));
- goto done;
- }
lex_get (lexer);
}
#include "output/journal.h"
#include "output/pivot-table.h"
+#include "gl/minmax.h"
#include "gl/xalloc.h"
#include "gettext.h"
settings_set_epoch (-1);
else if (lex_is_integer (lexer))
{
- int new_epoch = lex_integer (lexer);
+ if (!lex_force_int_range (lexer, "EPOCH", 1500, INT_MAX))
+ return false;
+ settings_set_epoch (lex_integer (lexer));
lex_get (lexer);
- if (new_epoch < 1500)
- {
- msg (SE, _("%s must be 1500 or later."), "EPOCH");
- return false;
- }
- settings_set_epoch (new_epoch);
}
else
{
static bool
parse_FUZZBITS (struct lexer *lexer)
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "FUZZITS", 0, 20))
return false;
- int fuzzbits = lex_integer (lexer);
+ settings_set_fuzzbits (lex_integer (lexer));
lex_get (lexer);
-
- if (fuzzbits >= 0 && fuzzbits <= 20)
- settings_set_fuzzbits (fuzzbits);
- else
- msg (SE, _("%s must be between 0 and 20."), "FUZZBITS");
return true;
}
page_length = -1;
else
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "LENGTH", 1, INT_MAX))
return false;
- if (lex_integer (lexer) < 1)
- {
- msg (SE, _("%s must be at least %d."), "LENGTH", 1);
- return false;
- }
page_length = lex_integer (lexer);
lex_get (lexer);
}
settings_set_viewwidth (131);
else
{
- if (!lex_force_int (lexer))
- return 0;
- if (lex_integer (lexer) < 40)
- {
- msg (SE, _("%s must be at least %d."), "WIDTH", 40);
- return 0;
- }
+ if (!lex_force_int_range (lexer, "WIDTH", 40, INT_MAX))
+ return false;
settings_set_viewwidth (lex_integer (lexer));
lex_get (lexer);
}
- return 1;
+ return true;
}
static bool
parse_WORKSPACE (struct lexer *lexer)
{
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "WORKSPACE",
+ settings_get_testing_mode () ? 1 : 1024,
+ INT_MAX))
return false;
int workspace = lex_integer (lexer);
lex_get (lexer);
-
- if (workspace < 1024 && !settings_get_testing_mode ())
- msg (SE, _("%s must be at least 1MB"), "WORKSPACE");
- else if (workspace <= 0)
- msg (SE, _("%s must be positive"), "WORKSPACE");
- else
- settings_set_workspace (workspace * 1024L);
+ settings_set_workspace (MIN (workspace, INT_MAX / 1024) * 1024);
return true;
}
\f
lex_get (lexer);
if (!lex_force_match_id (lexer, "FROM"))
return CMD_FAILURE;
- if (!lex_force_int (lexer))
+ if (!lex_force_int_range (lexer, "FROM", a + 1, INT_MAX))
return CMD_FAILURE;
b = lex_integer (lexer);
- if (a >= b)
- {
- msg (SE, _("Cannot sample %d observations from a population of "
- "%d."),
- a, b);
- return CMD_FAILURE;
- }
-
frac = 0;
}
lex_get (lexer);
])
AT_CHECK([pspp -O format=csv data-list.sps], [1], [dnl
-data-list.sps:1: error: DATA LIST: The SKIP value must be non-negative.
+data-list.sps:1.41-1.42: error: DATA LIST: Syntax error at `-1': Expected non-negative integer for SKIP.
data-list.sps:3: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
])
])
AT_CHECK([pspp -O format=csv data-list.sps], [1], [dnl
-data-list.sps:1: error: DATA LIST: The RECORDS value must be non-negative.
+data-list.sps:1.44-1.45: error: DATA LIST: Syntax error at `-1': Expected non-negative integer for RECORDS.
data-list.sps:3: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
])
printf "DATA LIST/5555555555555555." > lexer.sps
AT_CHECK([pspp -O format=csv lexer.sps], [1], [dnl
-"lexer.sps:1: error: DATA LIST: The record number specified, 5555555555555555, is at or before the previous record, 0. Data fields must be listed in order of increasing record number."
+lexer.sps:1.11-1.27: error: DATA LIST: Syntax error at `5555555555555555.': Expected integer between 1 and 2147483647.
])
AT_CLEANUP
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:19.11: error: RANK: Syntax error at `d': expecting integer.
+rank.sps:19.11: error: RANK: Syntax error at `d': Expected positive integer for NTILES.
rank.sps:25: error: RANK: Variable x already exists.