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 n0, int n1,
+static void lex_source_error_valist (struct lex_source *, int ofs0, int ofs1,
const char *format, va_list)
PRINTF_FORMAT (4, 0);
static const struct lex_token *lex_source_next__ (const struct lex_source *,
va_list args;
va_start (args, format);
- lex_next_error_valist (lexer, 0, 0, format, args);
+ lex_ofs_error_valist (lexer, lex_ofs (lexer), lex_ofs (lexer), format, args);
va_end (args);
}
void
lex_error_valist (struct lexer *lexer, const char *format, va_list args)
{
- lex_next_error_valist (lexer, 0, 0, format, args);
+ lex_ofs_error_valist (lexer, lex_ofs (lexer), lex_ofs (lexer), format, 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_next_error (struct lexer *lexer, int n0, int n1, const char *format, ...)
{
va_list args;
va_start (args, format);
- lex_next_error_valist (lexer, n0, n1, format, args);
+ int ofs = lex_ofs (lexer);
+ lex_ofs_error_valist (lexer, 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_error_valist (lexer, ofs0, ofs1, format, args);
va_end (args);
}
sbc, spec);
}
-/* 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 with offsets OFS0
+ through OFS1, inclusive, within the current command in LEXER, adding message
+ MESSAGE (if non-null) with the given ARGS. */
void
-lex_next_error_valist (struct lexer *lexer, int n0, int n1,
- const char *format, va_list args)
+lex_ofs_error_valist (struct lexer *lexer, 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, n0, n1, format, args);
+ lex_source_error_valist (src, ofs0, ofs1, format, args);
else
{
struct string s;
}
static struct msg_location *
-lex_source_get_location (const struct lex_source *src, int n0, int n1)
+lex_source_get_location (const struct lex_source *src, int ofs0, int ofs1)
{
return lex_token_location_rw (src,
- lex_source_next__ (src, n0),
- lex_source_next__ (src, n1));
+ lex_source_ofs__ (src, ofs0),
+ lex_source_ofs__ (src, ofs1));
}
/* Returns the name of the syntax file from which the current command is drawn.
}
static bool
-lex_source_contains_macro_call (struct lex_source *src, int n0, int n1)
+lex_source_contains_macro_call (struct lex_source *src, int ofs0, int ofs1)
{
- for (int i = n0; i <= n1; i++)
- if (lex_source_next__ (src, i)->macro_rep)
+ for (int i = ofs0; i <= ofs1; i++)
+ if (lex_source_ofs__ (src, i)->macro_rep)
return true;
return false;
}
The caller must not modify or free the returned string. */
static struct substring
-lex_source_get_macro_call (struct lex_source *src, int n0, int n1)
+lex_source_get_macro_call (struct lex_source *src, int ofs0, int ofs1)
{
- if (!lex_source_contains_macro_call (src, n0, n1))
+ if (!lex_source_contains_macro_call (src, ofs0, ofs1))
return ss_empty ();
- const struct lex_token *token0 = lex_source_next__ (src, n0);
- const struct lex_token *token1 = lex_source_next__ (src, MAX (n0, n1));
+ const struct lex_token *token0 = lex_source_ofs__ (src, ofs0);
+ const struct lex_token *token1 = lex_source_ofs__ (src, MAX (ofs0, ofs1));
size_t start = token0->token_pos;
size_t end = token1->token_pos + token1->token_len;
}
static void
-lex_source_error_valist (struct lex_source *src, int n0, int n1,
+lex_source_error_valist (struct lex_source *src, int ofs0, int ofs1,
const char *format, va_list args)
{
const struct lex_token *token;
ds_init_empty (&s);
- token = lex_source_next__ (src, n0);
+ token = lex_source_ofs__ (src, ofs0);
if (token->token.type == T_ENDCMD)
ds_put_cstr (&s, _("Syntax error at end of command"));
else
{
/* Get the syntax that caused the error. */
- char *raw_syntax = lex_source_syntax__ (src, n0 + src->parse_ofs,
- n1 + src->parse_ofs);
+ 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, n0, n1),
+ str_ellipsize (lex_source_get_macro_call (src, ofs0, ofs1),
call, sizeof call);
if (syntax[0])
*m = (struct msg) {
.category = MSG_C_SYNTAX,
.severity = MSG_S_ERROR,
- .location = lex_source_get_location (src, n0, n1),
+ .location = lex_source_get_location (src, ofs0, ofs1),
.text = ds_steal_cstr (&s),
};
msg_emit (m);
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);
int lex_end_of_command (struct lexer *);
void lex_error_expecting (struct lexer *, ...) SENTINEL(0);
void lex_error_valist (struct lexer *, const char *, va_list)
PRINTF_FORMAT (2, 0);
-void lex_next_error_valist (struct lexer *lexer, int n0, int n1,
- const char *format, va_list)
+void lex_ofs_error_valist (struct lexer *lexer, int ofs0, int ofs1,
+ const char *format, va_list)
PRINTF_FORMAT (4, 0);
/* Error handling. */
axes[PIVOT_N_AXES];
union ctables_summary *summaries;
-
- //char *name;
};
struct ctables
return false;
struct substring name = lex_tokss (lexer);
+ if (ss_ends_with_case (name, ss_cstr (".LCL"))
+ || ss_ends_with_case (name, ss_cstr (".UCL"))
+ || ss_ends_with_case (name, ss_cstr (".SE")))
+ {
+ lex_error (lexer, _("Support for LCL, UCL, and SE summary functions "
+ "is not yet implemented."));
+ return false;
+ }
+
bool u = ss_match_byte (&name, 'U') || ss_match_byte (&name, 'u');
bool e = !u && (ss_match_byte (&name, 'E') || ss_match_byte (&name, 'e'));
if (!lex_force_id (ctx->lexer))
return NULL;
+ if (lex_tokcstr (ctx->lexer)[0] == '$')
+ {
+ lex_error (ctx->lexer,
+ _("Multiple response set support not implemented."));
+ return NULL;
+ }
+
int start_ofs = lex_ofs (ctx->lexer);
struct variable *var = parse_variable (ctx->lexer, ctx->dict);
if (!var)
}
else if (!c->n_cats && lex_match_id (lexer, "KEY"))
{
+ int 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;
}
+
+ lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
+ _("Data-dependent sorting is not implemented."));
+ goto error;
}
}
else if (!c->n_cats && lex_match_id (lexer, "MISSING"))
cell->sv = sv;
cell->omit_areas = 0;
cell->postcompute = false;
- //struct string name = DS_EMPTY_INITIALIZER;
for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
{
const struct ctables_nest *nest = s->nests[a];
cell->axes[a].cvs[i].category = cat;
value_clone (&cell->axes[a].cvs[i].value, value, var_get_width (var));
-
-#if 0
- if (i != nest->scale_idx)
- {
- if (!ds_is_empty (&name))
- ds_put_cstr (&name, ", ");
- char *value_s = data_out (value, var_get_encoding (var),
- var_get_print_format (var),
- settings_get_fmt_settings ());
- if (cat->type == CCT_TOTAL
- || cat->type == CCT_SUBTOTAL
- || cat->type == CCT_POSTCOMPUTE)
- ds_put_format (&name, "%s=total", var_get_name (var));
- else
- ds_put_format (&name, "%s=%s", var_get_name (var),
- value_s + strspn (value_s, " "));
- free (value_s);
- }
-#endif
}
}
- //cell->name = ds_steal_cstr (&name);
const struct ctables_nest *ss = s->nests[s->table->summary_axis];
const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
-#if 0
- if (a == PIVOT_AXIS_ROW)
- {
- size_t ids[N_CTATS];
- memset (ids, 0, sizeof ids);
- for (size_t j = 0; j < n_sorted; j++)
- {
- struct ctables_cell *cell = sorted[j];
- for (enum ctables_area_type at = 0; at < N_CTATS; at++)
- {
- struct ctables_area *area = cell->areas[at];
- if (!area->sequence)
- area->sequence = ++ids[at];
- }
- }
- }
-#endif
-
-#if 0
- for (size_t j = 0; j < n_sorted; j++)
- {
- printf ("%s (%s): %f/%f = %.1f%%\n", sorted[j]->name, sorted[j]->contributes_to_areas ? "y" : "n", sorted[j]->summaries[0].count, sorted[j]->areas[CTAT_COL]->e_count, sorted[j]->summaries[0].count / sorted[j]->areas[CTAT_COL]->e_count * 100.0);
- }
- printf ("\n");
-#endif
-
struct ctables_level
{
enum ctables_level_type
}
free (items);
-#if 0
- for (size_t j = 0; j < merged->n; j++)
- printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
-
- for (size_t j = 0; j < stack->n; j++)
- {
- const struct ctables_nest *nest = &stack->nests[j];
- for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
- {
- const struct ctables_summary_spec_set *specs = &nest->specs[sv];
- for (size_t k = 0; k < specs->n; k++)
- printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
- specs->specs[k].axis_idx);
- printf ("\n");
- }
- }
-#endif
-
size_t allocated_sum_vars = 0;
enumerate_sum_vars (t->axes[t->summary_axis],
&t->sum_vars, &t->n_sum_vars, &allocated_sum_vars);
}
else if (lex_match_id (lexer, "SIGTEST"))
{
+ int start_ofs = lex_ofs (lexer) - 1;
if (!t->chisq)
{
t->chisq = xmalloc (sizeof *t->chisq);
}
while (lex_token (lexer) != T_SLASH
&& lex_token (lexer) != T_ENDCMD);
+
+ lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
+ _("Support for SIGTEST not yet implemented."));
+ goto error;
}
else if (lex_match_id (lexer, "COMPARETEST"))
{
+ int start_ofs = lex_ofs (lexer);
if (!t->pairwise)
{
t->pairwise = xmalloc (sizeof *t->pairwise);
}
while (lex_token (lexer) != T_SLASH
&& lex_token (lexer) != T_ENDCMD);
+
+ lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
+ _("Support for COMPARETEST not yet implemented."));
+ goto error;
}
else
{
&& !memcmp (ss.string, prefix.string, prefix.length));
}
+/* Returns true if SS starts with PREFIX in any case, false otherwise. */
+bool
+ss_starts_with_case (struct substring ss, struct substring prefix)
+{
+ return (ss.length >= prefix.length
+ && !memcasecmp (ss.string, prefix.string, prefix.length));
+}
+
/* Returns true if SS ends with SUFFIX, false otherwise. */
bool
ss_ends_with (struct substring ss, struct substring suffix)
suffix.length));
}
+/* Returns true if SS ends with SUFFIX in any case, false otherwise. */
+bool
+ss_ends_with_case (struct substring ss, struct substring suffix)
+{
+ return (ss.length >= suffix.length
+ && !memcasecmp (&ss.string[ss.length - suffix.length], suffix.string,
+ suffix.length));
+}
+
/* Returns the number of contiguous bytes at the beginning
of SS that are in SKIP_SET. */
size_t
int ss_first (struct substring);
int ss_last (struct substring);
bool ss_starts_with (struct substring, struct substring prefix);
+bool ss_starts_with_case (struct substring, struct substring prefix);
bool ss_ends_with (struct substring, struct substring suffix);
+bool ss_ends_with_case (struct substring, struct substring suffix);
size_t ss_span (struct substring, struct substring skip_set);
size_t ss_cspan (struct substring, struct substring stop_set);
size_t ss_find_byte (struct substring, char);
AT_BANNER([CTABLES])
-dnl Features not yet tested:
-dnl - Summary functions:
-dnl * WEIGHT and adjustment weights.
-dnl * details of missing value handling in summaries.
-dnl
-dnl Not for v1:
+dnl Features not yet implemented:
dnl - Multiple response sets
dnl - MRSETS subcommand.
dnl - CATEGORIES: Special case for explicit category specifications and multiple dichotomy sets.
dnl - Summary functions:
dnl * .LCL and .UCL suffixes.
dnl * .SE suffixes.
-dnl - Summary functions:
-dnl * )CILEVEL in summary label specification
dnl - CATEGORIES:
dnl * Data-dependent sorting.
CTABLES /TABLE.
CTABLES /TABLE qn113 [COUNT] BY qn114 [COUNT] BY qn116 [COUNT].
+
+CTABLES /TABLE qn1 /CATEGORIES VARIABLES=qn1 KEY=PTILE(qn1, 50).
+
+CTABLES /TABLE $mrset.
+
+CTABLES /TABLE qn113 /SIGTEST TYPE=CHISQUARE.
+CTABLES /TABLE qn113 /COMPARETEST TYPE=PROP.
+
+CTABLES /TABLE qn113 [COUNT.UCL].
]])
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
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:10.74-10.86: error: CTABLES: Syntax error at `KEY=MEAN(qn1)': Data-
+dependent sorting is not implemented.
ctables.sps:12: error: CTABLES: ROWLABELS=OPPOSITE requires the variables to be
moved to be categorical, but qnd1 is a scale variable.
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:27.16-27.21: error: CTABLES: Syntax error at `$mrset': Multiple
+response set support not implemented.
+
+ctables.sps:29.23-29.44: error: CTABLES: Syntax error at `SIGTEST
+TYPE=CHISQUARE': Support for SIGTEST not yet implemented.
+
+ctables.sps:30.35-30.43: error: CTABLES: Syntax error at `TYPE=PROP': Support
+for COMPARETEST not yet implemented.
+
+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.
]])
AT_CLEANUP