7a18ac5f134e4768f1cc6fdb939d5c16b4f95ee6
[pspp] / src / language / stats / ctables.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2021 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/casereader.h"
20 #include "data/dataset.h"
21 #include "data/dictionary.h"
22 #include "data/mrset.h"
23 #include "language/command.h"
24 #include "language/lexer/format-parser.h"
25 #include "language/lexer/lexer.h"
26 #include "language/lexer/variable-parser.h"
27 #include "libpspp/array.h"
28 #include "libpspp/assertion.h"
29 #include "libpspp/hmap.h"
30 #include "libpspp/message.h"
31 #include "libpspp/string-array.h"
32 #include "output/pivot-table.h"
33
34 #include "gl/minmax.h"
35 #include "gl/xalloc.h"
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) (msgid)
40
41 enum ctables_vlabel
42   {
43     CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
44     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
45     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
46     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
47   };
48
49 /* XXX:
50    - unweighted summaries (U*)
51    - lower confidence limits (*.LCL)
52    - upper confidence limits (*.UCL)
53    - standard error (*.SE)
54  */
55 #define SUMMARIES                                                       \
56     /* All variables. */                                                \
57     S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL)            \
58     S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
59     S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
60     S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
61     S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
62     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
63     S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
64     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
65     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
66     S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
67     S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
68     S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
69     S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
70     S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
71     S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
72     S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
73     S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
74     S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
75     S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
76     S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
77     S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
78     S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
79     S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
80                                                                         \
81     /* Scale variables, totals, and subtotals. */                       \
82     S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE)  \
83     S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE)           \
84     S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE)     \
85     S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE)  \
86     S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE)  \
87     S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE)           \
88     S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE)   \
89     S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE)        \
90     S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
91     S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
92     S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE)              \
93     S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE)      \
94     S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
95     S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE)      \
96     S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
97     S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
98     S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
99     S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
100     S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
101     S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
102     S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
103     S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
104     S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
105                                                                         \
106     /* Multiple response sets. */                                       \
107   S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
108     S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
109     S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
110     S(CTSF_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
111     S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
112     S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
113     S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
114     S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
115     S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
116     S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
117     S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
118     S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
119     S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
120     S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
121     S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
122     S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
123     S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
124     S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
125     S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
126     S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
127     S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
128     S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
129
130 enum ctables_summary_function
131   {
132 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
133     SUMMARIES
134 #undef S
135   };
136
137 enum {
138 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
139   N_CTSF_FUNCTIONS = SUMMARIES
140 #undef S
141 };
142
143 struct ctables
144   {
145     struct pivot_table_look *look;
146
147     /* If this is NULL, zeros are displayed using the normal print format.
148        Otherwise, this string is displayed. */
149     char *zero;
150
151     /* If this is NULL, missing values are displayed using the normal print
152        format.  Otherwise, this string is displayed. */
153     char *missing;
154
155     /* Indexed by variable dictionary index. */
156     enum ctables_vlabel *vlabels;
157
158     bool mrsets_count_duplicates; /* MRSETS. */
159     bool smissing_listwise;       /* SMISSING. */
160     struct variable *base_weight; /* WEIGHT. */
161     int hide_threshold;           /* HIDESMALLCOUNTS. */
162
163     struct ctables_table *tables;
164     size_t n_tables;
165   };
166
167 struct ctables_postcompute
168   {
169     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
170     const char *name;           /* Name, without leading &. */
171
172     struct ctables_postcompute_expr *expr;
173     char *label;
174     /* XXX FORMAT */
175     bool hide_source_cats;
176   };
177
178 struct ctables_postcompute_expr
179   {
180     enum ctables_postcompute_op
181       {
182         /* Terminals. */
183         CTPO_CAT_NUMBER,
184         CTPO_CAT_STRING,
185         CTPO_CAT_RANGE,
186         CTPO_CAT_MISSING,
187         /* XXX OTHERNM */
188         /* XXX SUBTOTAL and HSUBTOTAL */
189
190         /* Nonterminals. */
191         CTPO_ADD,
192         CTPO_SUB,
193         CTPO_MUL,
194         CTPO_DIV,
195         CTPO_POW,
196       }
197     op;
198
199     union
200       {
201         /* CTPO_CAT_NUMBER, CTPO_NUMBER. */
202         double number;
203
204         /* CTPO_CAT_RANGE.
205
206            XXX what about string ranges? */
207         double range[2];
208
209         /* CTPO_ADD, CTPO_SUB, CTPO_MUL, CTPO_DIV, CTPO_POW. */
210         struct ctables_postcompute_expr *subs[2];
211       };
212   };
213
214 enum ctables_label_position
215   {
216     CTLP_NORMAL,
217     CTLP_OPPOSITE,
218     CTLP_LAYER,
219   };
220
221 struct ctables_table
222   {
223     struct ctables_axis *axes[PIVOT_N_AXES];
224
225     enum pivot_axis_type slabels_position;
226     bool slabels_visible;
227
228     enum ctables_label_position row_labels;
229     enum ctables_label_position col_labels;
230
231     /* Indexed by variable dictionary index. */
232     struct ctables_categories **categories;
233     size_t n_categories;
234
235     double cilevel;
236
237     char *caption;
238     char *corner;
239     char *title;
240
241     struct ctables_chisq *chisq;
242     struct ctables_pairwise *pairwise;
243
244     struct ctables_freqtab **fts;
245     size_t n_fts;
246   };
247
248 struct ctables_var
249   {
250     bool is_mrset;
251     union
252       {
253         struct variable *var;
254         const struct mrset *mrset;
255       };
256   };
257
258 static const struct fmt_spec *
259 ctables_var_get_print_format (const struct ctables_var *var)
260 {
261   return (var->is_mrset
262           ? var_get_print_format (var->mrset->vars[0])
263           : var_get_print_format (var->var));
264 }
265
266 static const char *
267 ctables_var_name (const struct ctables_var *var)
268 {
269   return var->is_mrset ? var->mrset->name : var_get_name (var->var);
270 }
271
272 struct ctables_categories
273   {
274     size_t n_refs;
275
276     /* Explicit categories. */
277     struct ctables_cat_value *values;
278     size_t n_values;
279
280     /* Implicit categories. */
281     bool sort_ascending;
282     bool include_missing;
283     enum { CTCS_VALUE, CTCS_LABEL, CTCS_FUNCTION } key;
284     enum ctables_summary_function sort_func;
285     struct variable *sort_func_var;
286     double percentile;
287
288     /* Totals. */
289     bool show_totals;
290     bool totals_before;
291     char *total_label;
292
293     /* Empty categories. */
294     bool show_empty;
295   };
296
297 struct ctables_cat_value
298   {
299     enum ctables_cat_value_type
300       {
301         CCVT_NUMBER,
302         CCVT_STRING,
303         CCVT_RANGE,
304         CCVT_MISSING,
305         CCVT_OTHERNM,
306         CCVT_SUBTOTAL,
307         CCVT_HSUBTOTAL,
308       }
309     type;
310
311     union
312       {
313         double number;          /* CCVT_NUMBER. */
314         char *string;           /* CCVT_STRING. */
315         double range[2];        /* CCVT_RANGE. */
316         char *subtotal_label;   /* CCVT_SUBTOTAL, CCVT_HSUBTOTAL. */
317       };
318   };
319
320 static void
321 ctables_cat_value_uninit (struct ctables_cat_value *cv)
322 {
323   if (!cv)
324     return;
325
326   switch (cv->type)
327     {
328     case CCVT_NUMBER:
329     case CCVT_RANGE:
330     case CCVT_MISSING:
331     case CCVT_OTHERNM:
332       break;
333
334     case CCVT_STRING:
335       free (cv->string);
336       break;
337
338     case CCVT_SUBTOTAL:
339     case CCVT_HSUBTOTAL:
340       free (cv->subtotal_label);
341     }
342 }
343
344 static void
345 ctables_categories_unref (struct ctables_categories *c)
346 {
347   if (!c)
348     return;
349
350   assert (c->n_refs > 0);
351   if (--c->n_refs)
352     return;
353
354   for (size_t i = 0; i < c->n_values; i++)
355     ctables_cat_value_uninit (&c->values[i]);
356   free (c->values);
357   free (c->total_label);
358   free (c);
359 }
360
361 /* Chi-square test (SIGTEST). */
362 struct ctables_chisq
363   {
364     double alpha;
365     bool include_mrsets;
366     bool all_visible;
367   };
368
369 /* Pairwise comparison test (COMPARETEST). */
370 struct ctables_pairwise
371   {
372     enum { PROP, MEAN } type;
373     double alpha[2];
374     bool include_mrsets;
375     bool meansvariance_allcats;
376     bool all_visible;
377     enum { BONFERRONI = 1, BH } adjust;
378     bool merge;
379     bool apa_style;
380     bool show_sig;
381   };
382
383 struct ctables_axis
384   {
385     enum ctables_axis_op
386       {
387         /* Terminals. */
388         CTAO_VAR,
389
390         /* Nonterminals. */
391         CTAO_STACK,             /* + */
392         CTAO_NEST,              /* > */
393       }
394     op;
395
396     union
397       {
398         /* Terminals. */
399         struct
400           {
401             struct ctables_var var;
402             bool scale;
403             struct ctables_summary *summaries;
404             size_t n_summaries;
405             size_t allocated_summaries;
406           };
407
408         /* Nonterminals. */
409         struct ctables_axis *subs[2];
410       };
411
412     struct msg_location *loc;
413   };
414
415 static void ctables_axis_destroy (struct ctables_axis *);
416
417 enum ctables_format
418   {
419     CTF_COUNT,
420     CTF_PERCENT,
421     CTF_GENERAL
422   };
423
424 enum ctables_function_availability
425   {
426     CTFA_ALL,                /* Any variables. */
427     CTFA_SCALE,              /* Only scale variables, totals, and subtotals. */
428     CTFA_MRSETS,             /* Only multiple-response sets */
429   };
430
431 struct ctables_summary
432   {
433     enum ctables_summary_function function;
434     double percentile;          /* CTSF_PTILE only. */
435     char *label;
436     struct fmt_spec format;     /* XXX extra CTABLES formats */
437   };
438
439 static void
440 ctables_summary_uninit (struct ctables_summary *s)
441 {
442   if (s)
443     free (s->label);
444 }
445
446 static bool
447 parse_col_width (struct lexer *lexer, const char *name, double *width)
448 {
449   lex_match (lexer, T_EQUALS);
450   if (lex_match_id (lexer, "DEFAULT"))
451     *width = SYSMIS;
452   else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
453     {
454       *width = lex_number (lexer);
455       lex_get (lexer);
456     }
457   else
458     return false;
459
460   return true;
461 }
462
463 static bool
464 parse_bool (struct lexer *lexer, bool *b)
465 {
466   if (lex_match_id (lexer, "NO"))
467     *b = false;
468   else if (lex_match_id (lexer, "YES"))
469     *b = true;
470   else
471     {
472       lex_error_expecting (lexer, "YES", "NO");
473       return false;
474     }
475   return true;
476 }
477
478 static enum ctables_function_availability
479 ctables_function_availability (enum ctables_summary_function f)
480 {
481   static enum ctables_function_availability availability[] = {
482 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
483     SUMMARIES
484 #undef S
485   };
486
487   return availability[f];
488 }
489
490 static bool
491 parse_ctables_summary_function (struct lexer *lexer,
492                                 enum ctables_summary_function *f)
493 {
494   struct pair
495     {
496       enum ctables_summary_function function;
497       struct substring name;
498     };
499   static struct pair names[] = {
500 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
501     { ENUM, SS_LITERAL_INITIALIZER (NAME) },
502     SUMMARIES
503
504     /* The .COUNT suffix may be omitted. */
505     S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
506     S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
507     S(CTSF_TABLEPCT_COUNT, "TABLEPCT", _, _, _)
508     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT", _, _, _)
509     S(CTSF_LAYERPCT_COUNT, "LAYERPCT", _, _, _)
510     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT", _, _, _)
511     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT", _, _, _)
512 #undef S
513   };
514
515   if (!lex_force_id (lexer))
516     return false;
517
518   for (size_t i = 0; i < sizeof names / sizeof *names; i++)
519     if (ss_equals_case (names[i].name, lex_tokss (lexer)))
520       {
521         *f = names[i].function;
522         lex_get (lexer);
523         return true;
524       }
525
526   lex_error (lexer, _("Expecting summary function name."));
527   return false;
528 }
529
530 static void
531 ctables_axis_destroy (struct ctables_axis *axis)
532 {
533   if (!axis)
534     return;
535
536   switch (axis->op)
537     {
538     case CTAO_VAR:
539       for (size_t i = 0; i < axis->n_summaries; i++)
540         ctables_summary_uninit (&axis->summaries[i]);
541       free (axis->summaries);
542       break;
543
544     case CTAO_STACK:
545     case CTAO_NEST:
546       ctables_axis_destroy (axis->subs[0]);
547       ctables_axis_destroy (axis->subs[1]);
548       break;
549     }
550   msg_location_destroy (axis->loc);
551   free (axis);
552 }
553
554 static struct ctables_axis *
555 ctables_axis_new_nonterminal (enum ctables_axis_op op,
556                               struct ctables_axis *sub0,
557                               struct ctables_axis *sub1,
558                               struct lexer *lexer, int start_ofs)
559 {
560   struct ctables_axis *axis = xmalloc (sizeof *axis);
561   *axis = (struct ctables_axis) {
562     .op = op,
563     .subs = { sub0, sub1 },
564     .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
565   };
566   return axis;
567 }
568
569 struct ctables_axis_parse_ctx
570   {
571     struct lexer *lexer;
572     struct dictionary *dict;
573     struct ctables *ct;
574     struct ctables_table *t;
575   };
576
577 static struct fmt_spec
578 ctables_summary_default_format (enum ctables_summary_function function,
579                                 const struct ctables_var *var)
580 {
581   static const enum ctables_format default_formats[] = {
582 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
583     SUMMARIES
584 #undef S
585   };
586   switch (default_formats[function])
587     {
588     case CTF_COUNT:
589       return (struct fmt_spec) { .type = FMT_F, .w = 40 };
590
591     case CTF_PERCENT:
592       return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
593
594     case CTF_GENERAL:
595       return *ctables_var_get_print_format (var);
596
597     default:
598       NOT_REACHED ();
599     }
600 }
601
602 static const char *
603 ctables_summary_function_name (enum ctables_summary_function function)
604 {
605   static const char *names[] = {
606 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
607     SUMMARIES
608 #undef S
609   };
610   return names[function];
611 }
612
613 static bool
614 add_summary (struct ctables_axis *axis,
615              enum ctables_summary_function function, double percentile,
616              const char *label, const struct fmt_spec *format,
617              const struct msg_location *loc)
618 {
619   if (axis->op == CTAO_VAR)
620     {
621       if (axis->n_summaries >= axis->allocated_summaries)
622         axis->summaries = x2nrealloc (axis->summaries,
623                                       &axis->allocated_summaries,
624                                       sizeof *axis->summaries);
625
626       const char *function_name = ctables_summary_function_name (function);
627       const char *var_name = ctables_var_name (&axis->var);
628       switch (ctables_function_availability (function))
629         {
630         case CTFA_MRSETS:
631           if (!axis->var.is_mrset)
632             {
633               msg_at (SE, loc, _("Summary function %s applies only to multiple "
634                                  "response sets."), function_name);
635               msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
636                       var_name);
637               return false;
638             }
639           break;
640
641         case CTFA_SCALE:
642           if (!axis->scale)
643             {
644               msg_at (SE, loc,
645                       _("Summary function %s applies only to scale variables."),
646                       function_name);
647               msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
648                       var_name);
649               return false;
650             }
651           break;
652
653         case CTFA_ALL:
654           break;
655         }
656
657       struct ctables_summary *dst = &axis->summaries[axis->n_summaries++];
658       *dst = (struct ctables_summary) {
659         .function = function,
660         .percentile = percentile,
661         .label = xstrdup (label),
662         .format = (format ? *format
663                    : ctables_summary_default_format (function, &axis->var)),
664       };
665       return true;
666     }
667   else
668     {
669       for (size_t i = 0; i < 2; i++)
670         if (!add_summary (axis->subs[i], function, percentile, label, format,
671                           loc))
672           return false;
673       return true;
674     }
675 }
676
677 static struct ctables_axis *ctables_axis_parse_stack (
678   struct ctables_axis_parse_ctx *);
679
680 static bool
681 ctables_var_parse (struct lexer *lexer, struct dictionary *dict,
682                    struct ctables_var *var)
683 {
684   if (ss_starts_with (lex_tokss (lexer), ss_cstr ("$")))
685     {
686       *var = (struct ctables_var) {
687         .is_mrset = true,
688         .mrset = dict_lookup_mrset (dict, lex_tokcstr (lexer))
689       };
690       if (!var->mrset)
691         {
692           lex_error (lexer, _("'%s' does not name a multiple-response set "
693                               "in the active file dictionary."),
694                      lex_tokcstr (lexer));
695           return false;
696         }
697       lex_get (lexer);
698       return true;
699     }
700   else
701     {
702       *var = (struct ctables_var) {
703         .is_mrset = false,
704         .var = parse_variable (lexer, dict),
705       };
706       return var->var != NULL;
707     }
708 }
709
710 static struct ctables_axis *
711 ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx)
712 {
713   if (lex_match (ctx->lexer, T_LPAREN))
714     {
715       struct ctables_axis *sub = ctables_axis_parse_stack (ctx);
716       if (!sub || !lex_force_match (ctx->lexer, T_RPAREN))
717         {
718           ctables_axis_destroy (sub);
719           return NULL;
720         }
721       return sub;
722     }
723
724   if (!lex_force_id (ctx->lexer))
725     return NULL;
726
727   int start_ofs = lex_ofs (ctx->lexer);
728   struct ctables_var var;
729   if (!ctables_var_parse (ctx->lexer, ctx->dict, &var))
730     return NULL;
731
732   struct ctables_axis *axis = xmalloc (sizeof *axis);
733   *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
734
735   /* XXX should figure out default measures by reading data */
736   axis->scale = (var.is_mrset ? false
737                  : lex_match_phrase (ctx->lexer, "[S]") ? true
738                  : lex_match_phrase (ctx->lexer, "[C]") ? false
739                  : var_get_measure (var.var) == MEASURE_SCALE);
740   axis->loc = lex_ofs_location (ctx->lexer, start_ofs,
741                                 lex_ofs (ctx->lexer) - 1);
742   return axis;
743 }
744
745 static struct ctables_axis *
746 ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
747 {
748   struct ctables_axis *sub = ctables_axis_parse_primary (ctx);
749   if (!sub || !lex_match (ctx->lexer, T_LBRACK))
750     return sub;
751
752   do
753     {
754       int start_ofs = lex_ofs (ctx->lexer);
755
756       /* Parse function. */
757       enum ctables_summary_function function;
758       if (!parse_ctables_summary_function (ctx->lexer, &function))
759         goto error;
760
761       /* Parse percentile. */
762       double percentile = 0;
763       if (function == CTSF_PTILE)
764         {
765           if (!lex_force_num_range_closed (ctx->lexer, "PTILE", 0, 100))
766             goto error;
767           percentile = lex_number (ctx->lexer);
768           lex_get (ctx->lexer);
769         }
770
771       /* Parse label. */
772       char *label;
773       if (lex_is_string (ctx->lexer))
774         {
775           label = ss_xstrdup (lex_tokss (ctx->lexer));
776           lex_get (ctx->lexer);
777         }
778       else if (function == CTSF_PTILE)
779         label = xasprintf (_("Percentile %.2f"), percentile);
780       else
781         {
782           static const char *default_labels[] = {
783 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
784             SUMMARIES
785 #undef S
786           };
787           label = xstrdup (gettext (default_labels[function]));
788         }
789
790       /* Parse format. */
791       struct fmt_spec format;
792       const struct fmt_spec *formatp;
793       if (lex_token (ctx->lexer) == T_ID)
794         {
795           if (!parse_format_specifier (ctx->lexer, &format)
796               || !fmt_check_output (&format)
797               || !fmt_check_type_compat (&format, VAL_NUMERIC))
798             {
799               free (label);
800               goto error;
801             }
802           formatp = &format;
803         }
804       else
805         formatp = NULL;
806
807       struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
808                                                    lex_ofs (ctx->lexer) - 1);
809       add_summary (sub, function, percentile, label, formatp, loc);
810       free (label);
811       msg_location_destroy (loc);
812
813       lex_match (ctx->lexer, T_COMMA);
814     }
815   while (!lex_match (ctx->lexer, T_RBRACK));
816
817   return sub;
818
819 error:
820   ctables_axis_destroy (sub);
821   return NULL;
822 }
823
824 static const struct ctables_axis *
825 find_scale (const struct ctables_axis *axis)
826 {
827   if (!axis)
828     return NULL;
829   else if (axis->op == CTAO_VAR)
830     {
831       if (axis->scale)
832         {
833           assert (!axis->var.is_mrset);
834           return axis;
835         }
836       else
837         return NULL;
838     }
839   else
840     {
841       for (size_t i = 0; i < 2; i++)
842         {
843           const struct ctables_axis *scale = find_scale (axis->subs[i]);
844           if (scale)
845             return scale;
846         }
847       return NULL;
848     }
849 }
850
851 static const struct ctables_axis *
852 find_categorical_summary (const struct ctables_axis *axis)
853 {
854   if (!axis)
855     return NULL;
856   else if (axis->op == CTAO_VAR)
857     return !axis->scale && axis->n_summaries ? axis : NULL;
858   else
859     {
860       for (size_t i = 0; i < 2; i++)
861         {
862           const struct ctables_axis *sum
863             = find_categorical_summary (axis->subs[i]);
864           if (sum)
865             return sum;
866         }
867       return NULL;
868     }
869 }
870
871 static struct ctables_axis *
872 ctables_axis_parse_nest (struct ctables_axis_parse_ctx *ctx)
873 {
874   int start_ofs = lex_ofs (ctx->lexer);
875   struct ctables_axis *lhs = ctables_axis_parse_postfix (ctx);
876   if (!lhs)
877     return NULL;
878
879   while (lex_match (ctx->lexer, T_GT))
880     {
881       struct ctables_axis *rhs = ctables_axis_parse_postfix (ctx);
882       if (!rhs)
883         return NULL;
884
885       struct ctables_axis *nest = ctables_axis_new_nonterminal (
886         CTAO_NEST, lhs, rhs, ctx->lexer, start_ofs);
887
888       const struct ctables_axis *outer_scale = find_scale (lhs);
889       const struct ctables_axis *inner_scale = find_scale (rhs);
890       if (outer_scale && inner_scale)
891         {
892           msg_at (SE, nest->loc, _("Cannot nest scale variables."));
893           msg_at (SN, outer_scale->loc, _("This is an outer scale variable."));
894           msg_at (SN, inner_scale->loc, _("This is an inner scale variable."));
895           ctables_axis_destroy (nest);
896           return NULL;
897         }
898
899       const struct ctables_axis *outer_sum = find_categorical_summary (lhs);
900       if (outer_sum)
901         {
902           msg_at (SE, nest->loc,
903                   _("Summaries may only be requested for categorical variables "
904                     "at the innermost nesting level."));
905           msg_at (SN, outer_sum->loc,
906                   _("This outer categorical variable has a summary."));
907           ctables_axis_destroy (nest);
908           return NULL;
909         }
910
911       lhs = nest;
912     }
913
914   return lhs;
915 }
916
917 static struct ctables_axis *
918 ctables_axis_parse_stack (struct ctables_axis_parse_ctx *ctx)
919 {
920   int start_ofs = lex_ofs (ctx->lexer);
921   struct ctables_axis *lhs = ctables_axis_parse_nest (ctx);
922   if (!lhs)
923     return NULL;
924
925   while (lex_match (ctx->lexer, T_PLUS))
926     {
927       struct ctables_axis *rhs = ctables_axis_parse_nest (ctx);
928       if (!rhs)
929         return NULL;
930
931       lhs = ctables_axis_new_nonterminal (CTAO_STACK, lhs, rhs,
932                                           ctx->lexer, start_ofs);
933     }
934
935   return lhs;
936 }
937
938 static bool
939 ctables_axis_parse (struct lexer *lexer, struct dictionary *dict,
940                     struct ctables *ct, struct ctables_table *t,
941                     enum pivot_axis_type a)
942 {
943   if (lex_token (lexer) == T_BY
944       || lex_token (lexer) == T_SLASH
945       || lex_token (lexer) == T_ENDCMD)
946     return true;
947
948   struct ctables_axis_parse_ctx ctx = {
949     .lexer = lexer,
950     .dict = dict,
951     .ct = ct,
952     .t = t
953   };
954   t->axes[a] = ctables_axis_parse_stack (&ctx);
955   return t->axes[a] != NULL;
956 }
957
958 static void
959 ctables_chisq_destroy (struct ctables_chisq *chisq)
960 {
961   free (chisq);
962 }
963
964 static void
965 ctables_pairwise_destroy (struct ctables_pairwise *pairwise)
966 {
967   free (pairwise);
968 }
969
970 static void
971 ctables_table_uninit (struct ctables_table *t)
972 {
973   if (!t)
974     return;
975
976   for (size_t i = 0; i < t->n_categories; i++)
977     ctables_categories_unref (t->categories[i]);
978   free (t->categories);
979
980   ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
981   ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
982   ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
983   free (t->caption);
984   free (t->corner);
985   free (t->title);
986   ctables_chisq_destroy (t->chisq);
987   ctables_pairwise_destroy (t->pairwise);
988 }
989
990 static void
991 ctables_destroy (struct ctables *ct)
992 {
993   if (!ct)
994     return;
995
996   pivot_table_look_unref (ct->look);
997   free (ct->zero);
998   free (ct->missing);
999   free (ct->vlabels);
1000   for (size_t i = 0; i < ct->n_tables; i++)
1001     ctables_table_uninit (&ct->tables[i]);
1002   free (ct->tables);
1003   free (ct);
1004 }
1005
1006 static struct ctables_cat_value
1007 ccvt_range (double low, double high)
1008 {
1009   return (struct ctables_cat_value) {
1010     .type = CCVT_RANGE,
1011     .range = { low, high }
1012   };
1013 }
1014
1015 static bool
1016 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
1017                                 struct ctables_table *t)
1018 {
1019   if (!lex_match_id (lexer, "VARIABLES"))
1020     return false;
1021   lex_match (lexer, T_EQUALS);
1022
1023   struct variable **vars;
1024   size_t n_vars;
1025   if (!parse_variables (lexer, dict, &vars, &n_vars, PV_NO_SCRATCH))
1026     return false;
1027
1028   struct ctables_categories *c = xmalloc (sizeof *c);
1029   *c = (struct ctables_categories) { .n_refs = n_vars };
1030   for (size_t i = 0; i < n_vars; i++)
1031     {
1032       struct ctables_categories **cp
1033         = &t->categories[var_get_dict_index (vars[i])];
1034       ctables_categories_unref (*cp);
1035       *cp = c;
1036     }
1037   free (vars);
1038
1039   if (lex_match (lexer, T_LBRACK))
1040     {
1041       size_t allocated_values = 0;
1042       do
1043         {
1044           if (c->n_values >= allocated_values)
1045             c->values = x2nrealloc (c->values, &allocated_values,
1046                                     sizeof *c->values);
1047
1048           struct ctables_cat_value *v = &c->values[c->n_values];
1049           if (lex_match_id (lexer, "OTHERNM"))
1050             v->type = CCVT_OTHERNM;
1051           else if (lex_match_id (lexer, "MISSING"))
1052             v->type = CCVT_MISSING;
1053           else if (lex_match_id (lexer, "SUBTOTAL"))
1054             *v = (struct ctables_cat_value)
1055               { .type = CCVT_SUBTOTAL, .subtotal_label = NULL };
1056           else if (lex_match_id (lexer, "HSUBTOTAL"))
1057             *v = (struct ctables_cat_value)
1058               { .type = CCVT_HSUBTOTAL, .subtotal_label = NULL };
1059           else if (lex_match_id (lexer, "LO"))
1060             {
1061               if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
1062                 return false;
1063               *v = ccvt_range (-DBL_MAX, lex_number (lexer));
1064               lex_get (lexer);
1065             }
1066           else if (lex_is_number (lexer))
1067             {
1068               double number = lex_number (lexer);
1069               lex_get (lexer);
1070               if (lex_match_id (lexer, "THRU"))
1071                 {
1072                   v->type = CCVT_RANGE;
1073                   v->range[0] = number;
1074                   if (lex_match_id (lexer, "HI"))
1075                     *v = ccvt_range (number, DBL_MAX);
1076                   else
1077                     {
1078                       if (!lex_force_num (lexer))
1079                         return false;
1080                       *v = ccvt_range (number, lex_number (lexer));
1081                       lex_get (lexer);
1082                     }
1083                 }
1084               else
1085                 *v = (struct ctables_cat_value) {
1086                   .type = CCVT_NUMBER,
1087                   .number = number
1088                 };
1089             }
1090           else if (lex_is_string (lexer))
1091             {
1092               *v = (struct ctables_cat_value) {
1093                 .type = CCVT_STRING,
1094                 .string = ss_xstrdup (lex_tokss (lexer)),
1095               };
1096               lex_get (lexer);
1097             }
1098           else
1099             {
1100               lex_error (lexer, NULL);
1101               return false;
1102             }
1103
1104           if ((v->type == CCVT_SUBTOTAL || v->type == CCVT_HSUBTOTAL)
1105               && lex_match (lexer, T_EQUALS))
1106             {
1107               if (!lex_force_string (lexer))
1108                 return false;
1109
1110               v->subtotal_label = ss_xstrdup (lex_tokss (lexer));
1111               lex_get (lexer);
1112             }
1113
1114           c->n_values++;
1115           lex_match (lexer, T_COMMA);
1116         }
1117       while (!lex_match (lexer, T_RBRACK));
1118     }
1119
1120   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
1121     {
1122       if (!c->n_values && lex_match_id (lexer, "ORDER"))
1123         {
1124           lex_match (lexer, T_EQUALS);
1125           if (lex_match_id (lexer, "A"))
1126             c->sort_ascending = true;
1127           else if (lex_match_id (lexer, "D"))
1128             c->sort_ascending = false;
1129           else
1130             {
1131               lex_error_expecting (lexer, "A", "D");
1132               return false;
1133             }
1134         }
1135       else if (!c->n_values && lex_match_id (lexer, "KEY"))
1136         {
1137           lex_match (lexer, T_EQUALS);
1138           if (lex_match_id (lexer, "VALUE"))
1139             c->key = CTCS_VALUE;
1140           else if (lex_match_id (lexer, "LABEL"))
1141             c->key = CTCS_LABEL;
1142           else
1143             {
1144               c->key = CTCS_FUNCTION;
1145               if (!parse_ctables_summary_function (lexer, &c->sort_func))
1146                 return false;
1147
1148               if (lex_match (lexer, T_LPAREN))
1149                 {
1150                   c->sort_func_var = parse_variable (lexer, dict);
1151                   if (!c->sort_func_var)
1152                     return false;
1153
1154                   if (c->sort_func == CTSF_PTILE)
1155                     {
1156                       lex_match (lexer, T_COMMA);
1157                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
1158                         return false;
1159                       c->percentile = lex_number (lexer);
1160                       lex_get (lexer);
1161                     }
1162
1163                   if (!lex_force_match (lexer, T_RPAREN))
1164                     return false;
1165                 }
1166               else if (ctables_function_availability (c->sort_func)
1167                        == CTFA_SCALE)
1168                 {
1169                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
1170                   return false;
1171                 }
1172             }
1173         }
1174       else if (!c->n_values && lex_match_id (lexer, "MISSING"))
1175         {
1176           lex_match (lexer, T_EQUALS);
1177           if (lex_match_id (lexer, "INCLUDE"))
1178             c->include_missing = true;
1179           else if (lex_match_id (lexer, "EXCLUDE"))
1180             c->include_missing = false;
1181           else
1182             {
1183               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1184               return false;
1185             }
1186         }
1187       else if (lex_match_id (lexer, "TOTAL"))
1188         {
1189           lex_match (lexer, T_EQUALS);
1190           if (!parse_bool (lexer, &c->show_totals))
1191             return false;
1192         }
1193       else if (lex_match_id (lexer, "LABEL"))
1194         {
1195           lex_match (lexer, T_EQUALS);
1196           if (!lex_force_string (lexer))
1197             return false;
1198           free (c->total_label);
1199           c->total_label = ss_xstrdup (lex_tokss (lexer));
1200           lex_get (lexer);
1201         }
1202       else if (lex_match_id (lexer, "POSITION"))
1203         {
1204           lex_match (lexer, T_EQUALS);
1205           if (lex_match_id (lexer, "BEFORE"))
1206             c->totals_before = true;
1207           else if (lex_match_id (lexer, "AFTER"))
1208             c->totals_before = false;
1209           else
1210             {
1211               lex_error_expecting (lexer, "BEFORE", "AFTER");
1212               return false;
1213             }
1214         }
1215       else if (lex_match_id (lexer, "EMPTY"))
1216         {
1217           lex_match (lexer, T_EQUALS);
1218           if (lex_match_id (lexer, "INCLUDE"))
1219             c->show_empty = true;
1220           else if (lex_match_id (lexer, "EXCLUDE"))
1221             c->show_empty = false;
1222           else
1223             {
1224               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1225               return false;
1226             }
1227         }
1228       else
1229         {
1230           if (!c->n_values)
1231             lex_error_expecting (lexer, "ORDER", "KEY", "MISSING",
1232                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
1233           else
1234             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
1235           return false;
1236         }
1237     }
1238   return true;
1239 }
1240
1241 struct var_array
1242   {
1243     struct variable **vars;
1244     size_t n;
1245   };
1246
1247 static void
1248 var_array_uninit (struct var_array *va)
1249 {
1250   if (va)
1251     free (va->vars);
1252 }
1253
1254 struct var_array2
1255   {
1256     struct var_array *vas;
1257     size_t n;
1258   };
1259
1260 static void
1261 var_array2_uninit (struct var_array2 *vaa)
1262 {
1263   if (vaa)
1264     {
1265       for (size_t i = 0; i < vaa->n; i++)
1266         var_array_uninit (&vaa->vas[i]);
1267       free (vaa->vas);
1268     }
1269 }
1270
1271 static struct var_array2
1272 nest_fts (struct var_array2 va0, struct var_array2 va1)
1273 {
1274   if (!va0.n)
1275     return va1;
1276   else if (!va1.n)
1277     return va0;
1278
1279   struct var_array2 vaa = { .vas = xnmalloc (va0.n, va1.n * sizeof *vaa.vas) };
1280   for (size_t i = 0; i < va0.n; i++)
1281     for (size_t j = 0; j < va1.n; j++)
1282       {
1283         size_t allocate = va0.vas[i].n + va1.vas[j].n;
1284         struct variable **vars = xnmalloc (allocate, sizeof *vars);
1285         size_t n = 0;
1286         for (size_t k = 0; k < va0.vas[i].n; k++)
1287           vars[n++] = va0.vas[i].vars[k];
1288         for (size_t k = 0; k < va1.vas[j].n; k++)
1289           vars[n++] = va1.vas[j].vars[k];
1290         assert (n == allocate);
1291
1292         vaa.vas[vaa.n++] = (struct var_array) { .vars = vars, n = n };
1293       }
1294   var_array2_uninit (&va0);
1295   var_array2_uninit (&va1);
1296   return vaa;
1297 }
1298
1299 static struct var_array2
1300 stack_fts (struct var_array2 va0, struct var_array2 va1)
1301 {
1302   struct var_array2 vaa = { .vas = xnmalloc (va0.n + va1.n, sizeof *vaa.vas) };
1303   for (size_t i = 0; i < va0.n; i++)
1304     vaa.vas[vaa.n++] = va0.vas[i];
1305   for (size_t i = 0; i < va1.n; i++)
1306     vaa.vas[vaa.n++] = va1.vas[i];
1307   assert (vaa.n == va0.n + va1.n);
1308   free (va0.vas);
1309   free (va1.vas);
1310   return vaa;
1311 }
1312
1313 static struct var_array2
1314 enumerate_fts (const struct ctables_axis *a)
1315 {
1316   if (!a)
1317     return (struct var_array2) { .n = 0 };
1318
1319   switch (a->op)
1320     {
1321     case CTAO_VAR:
1322       assert (!a->var.is_mrset);
1323       struct variable **v = xmalloc (sizeof *v);
1324       *v = a->var.var;
1325       struct var_array *va = xmalloc (sizeof *va);
1326       *va = (struct var_array) { .vars = v, .n = 1 };
1327       return (struct var_array2) { .vas = va, .n = 1 };
1328
1329     case CTAO_STACK:
1330       return stack_fts (enumerate_fts (a->subs[0]),
1331                         enumerate_fts (a->subs[1]));
1332
1333     case CTAO_NEST:
1334       return nest_fts (enumerate_fts (a->subs[0]),
1335                        enumerate_fts (a->subs[1]));
1336     }
1337
1338   NOT_REACHED ();
1339 }
1340
1341 struct ctables_freq
1342   {
1343     struct hmap_node node;      /* Element in hash table. */
1344     double count;
1345     union value values[];      /* The value. */
1346   };
1347
1348 static struct ctables_freq *
1349 ctables_freq_allocate (size_t n_values)
1350 {
1351   struct ctables_freq *f;
1352   return xmalloc (sizeof *f + n_values * sizeof *f->values);
1353 }
1354
1355 struct ctables_freqtab
1356   {
1357     struct var_array vars;
1358     struct hmap data;           /* Contains "struct ctables_freq"s. */
1359     struct ctables_freq **sorted;
1360   };
1361
1362 static int
1363 ctables_freq_compare_3way (const void *a_, const void *b_, const void *vars_)
1364 {
1365   const struct var_array *vars = vars_;
1366   struct ctables_freq *const *a = a_;
1367   struct ctables_freq *const *b = b_;
1368
1369   for (size_t i = 0; i < vars->n; i++)
1370     {
1371       int cmp = value_compare_3way (&(*a)->values[i], &(*b)->values[i],
1372                                     var_get_width (vars->vars[i]));
1373       if (cmp)
1374         return cmp;
1375     }
1376   return 0;
1377 }
1378
1379 static bool
1380 ctables_execute (struct dataset *ds, struct ctables *ct)
1381 {
1382   for (size_t i = 0; i < ct->n_tables; i++)
1383     {
1384       size_t allocated_fts = 0;
1385
1386       struct ctables_table *t = &ct->tables[i];
1387       struct var_array2 vaa = enumerate_fts (t->axes[PIVOT_AXIS_ROW]);
1388       vaa = nest_fts (vaa, enumerate_fts (t->axes[PIVOT_AXIS_COLUMN]));
1389       vaa = nest_fts (vaa, enumerate_fts (t->axes[PIVOT_AXIS_LAYER]));
1390       for (size_t i = 0; i < vaa.n; i++)
1391         {
1392           for (size_t j = 0; j < vaa.vas[i].n; j++)
1393             {
1394               if (j)
1395                 fputs (", ", stdout);
1396               fputs (var_get_name (vaa.vas[i].vars[j]), stdout);
1397             }
1398           putchar ('\n');
1399         }
1400
1401       for (size_t j = 0; j < vaa.n; j++)
1402         {
1403           struct ctables_freqtab *ft = xmalloc (sizeof *ft);
1404           *ft = (struct ctables_freqtab) {
1405             .vars = vaa.vas[j],
1406             .data = HMAP_INITIALIZER (ft->data),
1407           };
1408
1409           if (t->n_fts >= allocated_fts)
1410             t->fts = x2nrealloc (t->fts, &allocated_fts, sizeof *t->fts);
1411           t->fts[t->n_fts++] = ft;
1412         }
1413
1414       free (vaa.vas);
1415     }
1416
1417   struct casereader *input = casereader_create_filter_weight (proc_open (ds),
1418                                                               dataset_dict (ds),
1419                                                               NULL, NULL);
1420   bool warn_on_invalid = true;
1421   for (struct ccase *c = casereader_read (input); c;
1422        case_unref (c), c = casereader_read (input))
1423     {
1424       double weight = dict_get_case_weight (dataset_dict (ds), c,
1425                                             &warn_on_invalid);
1426
1427       for (size_t i = 0; i < ct->n_tables; i++)
1428         {
1429           struct ctables_table *t = &ct->tables[i];
1430
1431           for (size_t j = 0; j < t->n_fts; j++)
1432             {
1433               struct ctables_freqtab *ft = t->fts[j];
1434
1435               for (size_t k = 0; k < ft->vars.n; k++)
1436                 {
1437                   const struct variable *var = ft->vars.vars[k];
1438                   switch (var_is_value_missing (var, case_data (c, var)))
1439                     {
1440                     case MV_SYSTEM:
1441                       goto next_ft;
1442
1443                     case MV_USER:
1444                       if (!t->categories[var_get_dict_index (var)]
1445                           || !t->categories[var_get_dict_index (var)]->include_missing)
1446                         goto next_ft;
1447                       break;
1448                     }
1449                 }
1450               size_t hash = 0;
1451               for (size_t k = 0; k < ft->vars.n; k++)
1452                 {
1453                   const struct variable *var = ft->vars.vars[k];
1454                   hash = value_hash (case_data (c, var), var_get_width (var), hash);
1455                 }
1456
1457               struct ctables_freq *f;
1458               HMAP_FOR_EACH_WITH_HASH (f, struct ctables_freq, node, hash, &ft->data)
1459                 {
1460                   for (size_t k = 0; k < ft->vars.n; k++)
1461                     {
1462                       const struct variable *var = ft->vars.vars[k];
1463                       if (!value_equal (case_data (c, var), &f->values[k],
1464                                         var_get_width (var)))
1465                         goto next_hash_node;
1466                     }
1467
1468                   f->count += weight;
1469                   goto next_ft;
1470
1471                 next_hash_node: ;
1472                 }
1473
1474               f = ctables_freq_allocate (ft->vars.n);
1475               f->count = weight;
1476               for (size_t k = 0; k < ft->vars.n; k++)
1477                 {
1478                   const struct variable *var = ft->vars.vars[k];
1479                   value_clone (&f->values[k], case_data (c, var),
1480                                var_get_width (var));
1481                 }
1482               hmap_insert (&ft->data, &f->node, hash);
1483
1484             next_ft: ;
1485             }
1486         }
1487     }
1488   casereader_destroy (input);
1489
1490   for (size_t i = 0; i < ct->n_tables; i++)
1491     {
1492       struct ctables_table *t = &ct->tables[i];
1493
1494       struct pivot_table *pt = pivot_table_create (N_("Custom Tables"));
1495       struct pivot_dimension *d = pivot_dimension_create (
1496         pt, PIVOT_AXIS_ROW, N_("Rows"));
1497       for (size_t j = 0; j < t->n_fts; j++)
1498         {
1499           struct ctables_freqtab *ft = t->fts[j];
1500           ft->sorted = xnmalloc (ft->data.count, sizeof *ft->sorted);
1501
1502           struct ctables_freq *f;
1503           size_t n = 0;
1504           HMAP_FOR_EACH (f, struct ctables_freq, node, &ft->data)
1505             ft->sorted[n++] = f;
1506           assert (n == ft->data.count);
1507           sort (ft->sorted, n, sizeof *ft->sorted,
1508                 ctables_freq_compare_3way, &ft->vars);
1509
1510           struct pivot_category **groups = xnmalloc (ft->vars.n,
1511                                                      sizeof *groups);
1512           for (size_t k = 0; k < n; k++)
1513             {
1514               struct ctables_freq *prev = k > 0 ? ft->sorted[k - 1] : NULL;
1515               struct ctables_freq *f = ft->sorted[k];
1516
1517               size_t n_common = 0;
1518               if (prev)
1519                 for (; n_common + 1 < ft->vars.n; n_common++)
1520                   if (!value_equal (&prev->values[n_common],
1521                                     &f->values[n_common],
1522                                     var_get_type (ft->vars.vars[n_common])))
1523                     break;
1524
1525               for (size_t m = n_common; m < ft->vars.n; m++)
1526                 {
1527                   struct pivot_category *parent = m > 0 ? groups[m - 1] : d->root;
1528                   const struct variable *var = ft->vars.vars[m];
1529                   enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (var)];
1530
1531                   if (vlabel != CTVL_NONE)
1532                     parent = pivot_category_create_group__ (
1533                       parent, pivot_value_new_variable (ft->vars.vars[m]));
1534
1535                   if (m + 1 < ft->vars.n)
1536                     parent = pivot_category_create_group__ (
1537                       parent,
1538                       pivot_value_new_var_value (ft->vars.vars[m], &f->values[m]));
1539                   groups[m] = parent;
1540
1541                   if (m == ft->vars.n - 1)
1542                     {
1543                       int leaf = pivot_category_create_leaf (
1544                         parent,
1545                         pivot_value_new_var_value (ft->vars.vars[ft->vars.n - 1],
1546                                                    &f->values[ft->vars.n - 1]));
1547                       pivot_table_put1 (pt, leaf, pivot_value_new_number (f->count));
1548                     }
1549                 }
1550             }
1551           free (groups);
1552         }
1553       pivot_table_submit (pt);
1554     }
1555
1556   for (size_t i = 0; i < ct->n_tables; i++)
1557     {
1558       struct ctables_table *t = &ct->tables[i];
1559
1560       for (size_t j = 0; j < t->n_fts; j++)
1561         {
1562           struct ctables_freqtab *ft = t->fts[j];
1563           struct ctables_freq *f, *next;
1564           HMAP_FOR_EACH_SAFE (f, next, struct ctables_freq, node, &ft->data)
1565             {
1566               hmap_delete (&ft->data, &f->node);
1567               for (size_t k = 0; k < ft->vars.n; k++)
1568                 {
1569                   const struct variable *var = ft->vars.vars[k];
1570                   value_destroy (&f->values[k], var_get_width (var));
1571                 }
1572               free (f);
1573             }
1574           hmap_destroy (&ft->data);
1575           free (ft->sorted);
1576           var_array_uninit (&ft->vars);
1577           free (ft);
1578         }
1579       free (t->fts);
1580     }
1581
1582   return proc_commit (ds);
1583 }
1584
1585 int
1586 cmd_ctables (struct lexer *lexer, struct dataset *ds)
1587 {
1588   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
1589   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
1590   enum settings_value_show tvars = settings_get_show_variables ();
1591   for (size_t i = 0; i < n_vars; i++)
1592     vlabels[i] = (enum ctables_vlabel) tvars;
1593
1594   struct ctables *ct = xmalloc (sizeof *ct);
1595   *ct = (struct ctables) {
1596     .look = pivot_table_look_unshare (pivot_table_look_ref (
1597                                         pivot_table_look_get_default ())),
1598     .vlabels = vlabels,
1599     .hide_threshold = 5,
1600   };
1601
1602   if (!lex_force_match (lexer, T_SLASH))
1603     goto error;
1604
1605   while (!lex_match_id (lexer, "TABLE"))
1606     {
1607       if (lex_match_id (lexer, "FORMAT"))
1608         {
1609           double widths[2] = { SYSMIS, SYSMIS };
1610           double units_per_inch = 72.0;
1611
1612           while (lex_token (lexer) != T_SLASH)
1613             {
1614               if (lex_match_id (lexer, "MINCOLWIDTH"))
1615                 {
1616                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
1617                     goto error;
1618                 }
1619               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
1620                 {
1621                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
1622                     goto error;
1623                 }
1624               else if (lex_match_id (lexer, "UNITS"))
1625                 {
1626                   lex_match (lexer, T_EQUALS);
1627                   if (lex_match_id (lexer, "POINTS"))
1628                     units_per_inch = 72.0;
1629                   else if (lex_match_id (lexer, "INCHES"))
1630                     units_per_inch = 1.0;
1631                   else if (lex_match_id (lexer, "CM"))
1632                     units_per_inch = 2.54;
1633                   else
1634                     {
1635                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
1636                       goto error;
1637                     }
1638                 }
1639               else if (lex_match_id (lexer, "EMPTY"))
1640                 {
1641                   free (ct->zero);
1642                   ct->zero = NULL;
1643
1644                   lex_match (lexer, T_EQUALS);
1645                   if (lex_match_id (lexer, "ZERO"))
1646                     {
1647                       /* Nothing to do. */
1648                     }
1649                   else if (lex_match_id (lexer, "BLANK"))
1650                     ct->zero = xstrdup ("");
1651                   else if (lex_force_string (lexer))
1652                     {
1653                       ct->zero = ss_xstrdup (lex_tokss (lexer));
1654                       lex_get (lexer);
1655                     }
1656                   else
1657                     goto error;
1658                 }
1659               else if (lex_match_id (lexer, "MISSING"))
1660                 {
1661                   lex_match (lexer, T_EQUALS);
1662                   if (!lex_force_string (lexer))
1663                     goto error;
1664
1665                   free (ct->missing);
1666                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
1667                                  ? ss_xstrdup (lex_tokss (lexer))
1668                                  : NULL);
1669                   lex_get (lexer);
1670                 }
1671               else
1672                 {
1673                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
1674                                        "UNITS", "EMPTY", "MISSING");
1675                   goto error;
1676                 }
1677             }
1678
1679           if (widths[0] != SYSMIS && widths[1] != SYSMIS
1680               && widths[0] > widths[1])
1681             {
1682               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
1683               goto error;
1684             }
1685
1686           for (size_t i = 0; i < 2; i++)
1687             if (widths[i] != SYSMIS)
1688               {
1689                 int *wr = ct->look->width_ranges[TABLE_HORZ];
1690                 wr[i] = widths[i] / units_per_inch * 96.0;
1691                 if (wr[0] > wr[1])
1692                   wr[!i] = wr[i];
1693               }
1694         }
1695       else if (lex_match_id (lexer, "VLABELS"))
1696         {
1697           if (!lex_force_match_id (lexer, "VARIABLES"))
1698             goto error;
1699           lex_match (lexer, T_EQUALS);
1700
1701           struct variable **vars;
1702           size_t n_vars;
1703           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
1704                                 PV_NO_SCRATCH))
1705             goto error;
1706
1707           if (!lex_force_match_id (lexer, "DISPLAY"))
1708             {
1709               free (vars);
1710               goto error;
1711             }
1712           lex_match (lexer, T_EQUALS);
1713
1714           enum ctables_vlabel vlabel;
1715           if (lex_match_id (lexer, "DEFAULT"))
1716             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
1717           else if (lex_match_id (lexer, "NAME"))
1718             vlabel = CTVL_NAME;
1719           else if (lex_match_id (lexer, "LABEL"))
1720             vlabel = CTVL_LABEL;
1721           else if (lex_match_id (lexer, "BOTH"))
1722             vlabel = CTVL_BOTH;
1723           else if (lex_match_id (lexer, "NONE"))
1724             vlabel = CTVL_NONE;
1725           else
1726             {
1727               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
1728                                    "BOTH", "NONE");
1729               free (vars);
1730               goto error;
1731             }
1732
1733           for (size_t i = 0; i < n_vars; i++)
1734             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
1735           free (vars);
1736         }
1737       else if (lex_match_id (lexer, "MRSETS"))
1738         {
1739           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
1740             goto error;
1741           lex_match (lexer, T_EQUALS);
1742           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
1743             goto error;
1744         }
1745       else if (lex_match_id (lexer, "SMISSING"))
1746         {
1747           if (lex_match_id (lexer, "VARIABLE"))
1748             ct->smissing_listwise = false;
1749           else if (lex_match_id (lexer, "LISTWISE"))
1750             ct->smissing_listwise = true;
1751           else
1752             {
1753               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
1754               goto error;
1755             }
1756         }
1757       /* XXX PCOMPUTE */
1758       else if (lex_match_id (lexer, "WEIGHT"))
1759         {
1760           if (!lex_force_match_id (lexer, "VARIABLE"))
1761             goto error;
1762           lex_match (lexer, T_EQUALS);
1763           ct->base_weight = parse_variable (lexer, dataset_dict (ds));
1764           if (!ct->base_weight)
1765             goto error;
1766         }
1767       else if (lex_match_id (lexer, "HIDESMALLCOUNTS"))
1768         {
1769           if (!lex_force_match_id (lexer, "COUNT"))
1770             goto error;
1771           lex_match (lexer, T_EQUALS);
1772           if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT", 2, INT_MAX))
1773             goto error;
1774           ct->hide_threshold = lex_integer (lexer);
1775           lex_get (lexer);
1776         }
1777       else
1778         {
1779           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
1780                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
1781                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
1782           goto error;
1783         }
1784
1785       if (!lex_force_match (lexer, T_SLASH))
1786         goto error;
1787     }
1788
1789   size_t allocated_tables = 0;
1790   do
1791     {
1792       if (ct->n_tables >= allocated_tables)
1793         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
1794                                  sizeof *ct->tables);
1795
1796       struct ctables_table *t = &ct->tables[ct->n_tables++];
1797       *t = (struct ctables_table) {
1798         .slabels_position = PIVOT_AXIS_COLUMN,
1799         .slabels_visible = true,
1800         .row_labels = CTLP_NORMAL,
1801         .col_labels = CTLP_NORMAL,
1802         .categories = xcalloc (dict_get_n_vars (dataset_dict (ds)),
1803                                sizeof *t->categories),
1804         .n_categories = dict_get_n_vars (dataset_dict (ds)),
1805         .cilevel = 95,
1806       };
1807
1808       lex_match (lexer, T_EQUALS);
1809       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
1810         goto error;
1811       if (lex_match (lexer, T_BY))
1812         {
1813           if (!ctables_axis_parse (lexer, dataset_dict (ds),
1814                                    ct, t, PIVOT_AXIS_COLUMN))
1815             goto error;
1816
1817           if (lex_match (lexer, T_BY))
1818             {
1819               if (!ctables_axis_parse (lexer, dataset_dict (ds),
1820                                        ct, t, PIVOT_AXIS_LAYER))
1821                 goto error;
1822             }
1823         }
1824
1825       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
1826           && !t->axes[PIVOT_AXIS_LAYER])
1827         {
1828           lex_error (lexer, _("At least one variable must be specified."));
1829           goto error;
1830         }
1831
1832       const struct ctables_axis *scales[PIVOT_N_AXES];
1833       size_t n_scales = 0;
1834       for (size_t i = 0; i < 3; i++)
1835         {
1836           scales[i] = find_scale (t->axes[i]);
1837           if (scales[i])
1838             n_scales++;
1839         }
1840       if (n_scales > 1)
1841         {
1842           msg (SE, _("Scale variables may appear only on one dimension."));
1843           if (scales[PIVOT_AXIS_ROW])
1844             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
1845                     _("This scale variable appears in the rows dimension."));
1846           if (scales[PIVOT_AXIS_COLUMN])
1847             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
1848                     _("This scale variable appears in the columns dimension."));
1849           if (scales[PIVOT_AXIS_LAYER])
1850             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
1851                     _("This scale variable appears in the layer dimension."));
1852           goto error;
1853         }
1854
1855       if (lex_token (lexer) == T_ENDCMD)
1856         break;
1857       if (!lex_force_match (lexer, T_SLASH))
1858         break;
1859
1860       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
1861         {
1862           if (lex_match_id (lexer, "SLABELS"))
1863             {
1864               while (lex_token (lexer) != T_SLASH)
1865                 {
1866                   if (lex_match_id (lexer, "POSITION"))
1867                     {
1868                       lex_match (lexer, T_EQUALS);
1869                       if (lex_match_id (lexer, "COLUMN"))
1870                         t->slabels_position = PIVOT_AXIS_COLUMN;
1871                       else if (lex_match_id (lexer, "ROW"))
1872                         t->slabels_position = PIVOT_AXIS_ROW;
1873                       else if (lex_match_id (lexer, "LAYER"))
1874                         t->slabels_position = PIVOT_AXIS_LAYER;
1875                       else
1876                         {
1877                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
1878                           goto error;
1879                         }
1880                     }
1881                   else if (lex_match_id (lexer, "VISIBLE"))
1882                     {
1883                       lex_match (lexer, T_EQUALS);
1884                       if (!parse_bool (lexer, &t->slabels_visible))
1885                         goto error;
1886                     }
1887                   else
1888                     {
1889                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
1890                       goto error;
1891                     }
1892                 }
1893             }
1894           else if (lex_match_id (lexer, "CLABELS"))
1895             {
1896               while (lex_token (lexer) != T_SLASH)
1897                 {
1898                   if (lex_match_id (lexer, "AUTO"))
1899                     t->row_labels = t->col_labels = CTLP_NORMAL;
1900                   else if (lex_match_id (lexer, "ROWLABELS"))
1901                     {
1902                       lex_match (lexer, T_EQUALS);
1903                       if (lex_match_id (lexer, "OPPOSITE"))
1904                         t->row_labels = CTLP_OPPOSITE;
1905                       else if (lex_match_id (lexer, "LAYER"))
1906                         t->row_labels = CTLP_LAYER;
1907                       else
1908                         {
1909                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
1910                           goto error;
1911                         }
1912                     }
1913                   else if (lex_match_id (lexer, "COLLABELS"))
1914                     {
1915                       lex_match (lexer, T_EQUALS);
1916                       if (lex_match_id (lexer, "OPPOSITE"))
1917                         t->col_labels = CTLP_OPPOSITE;
1918                       else if (lex_match_id (lexer, "LAYER"))
1919                         t->col_labels = CTLP_LAYER;
1920                       else
1921                         {
1922                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
1923                           goto error;
1924                         }
1925                     }
1926                   else
1927                     {
1928                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
1929                                            "COLLABELS");
1930                       goto error;
1931                     }
1932                 }
1933             }
1934           else if (lex_match_id (lexer, "CRITERIA"))
1935             {
1936               if (!lex_force_match_id (lexer, "CILEVEL"))
1937                 goto error;
1938               lex_match (lexer, T_EQUALS);
1939
1940               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
1941                 goto error;
1942               t->cilevel = lex_number (lexer);
1943               lex_get (lexer);
1944             }
1945           else if (lex_match_id (lexer, "CATEGORIES"))
1946             {
1947               if (!ctables_table_parse_categories (lexer, dataset_dict (ds), t))
1948                 goto error;
1949             }
1950           else if (lex_match_id (lexer, "TITLES"))
1951             {
1952               do
1953                 {
1954                   char **textp;
1955                   if (lex_match_id (lexer, "CAPTION"))
1956                     textp = &t->caption;
1957                   else if (lex_match_id (lexer, "CORNER"))
1958                     textp = &t->corner;
1959                   else if (lex_match_id (lexer, "TITLE"))
1960                     textp = &t->title;
1961                   else
1962                     {
1963                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
1964                       goto error;
1965                     }
1966                   lex_match (lexer, T_EQUALS);
1967
1968                   struct string s = DS_EMPTY_INITIALIZER;
1969                   while (lex_is_string (lexer))
1970                     {
1971                       if (!ds_is_empty (&s))
1972                         ds_put_byte (&s, ' ');
1973                       ds_put_substring (&s, lex_tokss (lexer));
1974                       lex_get (lexer);
1975                     }
1976                   free (*textp);
1977                   *textp = ds_steal_cstr (&s);
1978                 }
1979               while (lex_token (lexer) != T_SLASH
1980                      && lex_token (lexer) != T_ENDCMD);
1981             }
1982           else if (lex_match_id (lexer, "SIGTEST"))
1983             {
1984               if (!t->chisq)
1985                 {
1986                   t->chisq = xmalloc (sizeof *t->chisq);
1987                   *t->chisq = (struct ctables_chisq) {
1988                     .alpha = .05,
1989                     .include_mrsets = true,
1990                     .all_visible = true,
1991                   };
1992                 }
1993
1994               do
1995                 {
1996                   if (lex_match_id (lexer, "TYPE"))
1997                     {
1998                       lex_match (lexer, T_EQUALS);
1999                       if (!lex_force_match_id (lexer, "CHISQUARE"))
2000                         goto error;
2001                     }
2002                   else if (lex_match_id (lexer, "ALPHA"))
2003                     {
2004                       lex_match (lexer, T_EQUALS);
2005                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
2006                         goto error;
2007                       t->chisq->alpha = lex_number (lexer);
2008                       lex_get (lexer);
2009                     }
2010                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
2011                     {
2012                       lex_match (lexer, T_EQUALS);
2013                       if (parse_bool (lexer, &t->chisq->include_mrsets))
2014                         goto error;
2015                     }
2016                   else if (lex_match_id (lexer, "CATEGORIES"))
2017                     {
2018                       lex_match (lexer, T_EQUALS);
2019                       if (lex_match_id (lexer, "ALLVISIBLE"))
2020                         t->chisq->all_visible = true;
2021                       else if (lex_match_id (lexer, "SUBTOTALS"))
2022                         t->chisq->all_visible = false;
2023                       else
2024                         {
2025                           lex_error_expecting (lexer,
2026                                                "ALLVISIBLE", "SUBTOTALS");
2027                           goto error;
2028                         }
2029                     }
2030                   else
2031                     {
2032                       lex_error_expecting (lexer, "TYPE", "ALPHA",
2033                                            "INCLUDEMRSETS", "CATEGORIES");
2034                       goto error;
2035                     }
2036                 }
2037               while (lex_token (lexer) != T_SLASH
2038                      && lex_token (lexer) != T_ENDCMD);
2039             }
2040           else if (lex_match_id (lexer, "COMPARETEST"))
2041             {
2042               if (!t->pairwise)
2043                 {
2044                   t->pairwise = xmalloc (sizeof *t->pairwise);
2045                   *t->pairwise = (struct ctables_pairwise) {
2046                     .type = PROP,
2047                     .alpha = { .05, .05 },
2048                     .adjust = BONFERRONI,
2049                     .include_mrsets = true,
2050                     .meansvariance_allcats = true,
2051                     .all_visible = true,
2052                     .merge = false,
2053                     .apa_style = true,
2054                     .show_sig = false,
2055                   };
2056                 }
2057
2058               do
2059                 {
2060                   if (lex_match_id (lexer, "TYPE"))
2061                     {
2062                       lex_match (lexer, T_EQUALS);
2063                       if (lex_match_id (lexer, "PROP"))
2064                         t->pairwise->type = PROP;
2065                       else if (lex_match_id (lexer, "MEAN"))
2066                         t->pairwise->type = MEAN;
2067                       else
2068                         {
2069                           lex_error_expecting (lexer, "PROP", "MEAN");
2070                           goto error;
2071                         }
2072                     }
2073                   else if (lex_match_id (lexer, "ALPHA"))
2074                     {
2075                       lex_match (lexer, T_EQUALS);
2076
2077                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
2078                         goto error;
2079                       double a0 = lex_number (lexer);
2080                       lex_get (lexer);
2081
2082                       lex_match (lexer, T_COMMA);
2083                       if (lex_is_number (lexer))
2084                         {
2085                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
2086                             goto error;
2087                           double a1 = lex_number (lexer);
2088                           lex_get (lexer);
2089
2090                           t->pairwise->alpha[0] = MIN (a0, a1);
2091                           t->pairwise->alpha[1] = MAX (a0, a1);
2092                         }
2093                       else
2094                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
2095                     }
2096                   else if (lex_match_id (lexer, "ADJUST"))
2097                     {
2098                       lex_match (lexer, T_EQUALS);
2099                       if (lex_match_id (lexer, "BONFERRONI"))
2100                         t->pairwise->adjust = BONFERRONI;
2101                       else if (lex_match_id (lexer, "BH"))
2102                         t->pairwise->adjust = BH;
2103                       else if (lex_match_id (lexer, "NONE"))
2104                         t->pairwise->adjust = 0;
2105                       else
2106                         {
2107                           lex_error_expecting (lexer, "BONFERRONI", "BH",
2108                                                "NONE");
2109                           goto error;
2110                         }
2111                     }
2112                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
2113                     {
2114                       lex_match (lexer, T_EQUALS);
2115                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
2116                         goto error;
2117                     }
2118                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
2119                     {
2120                       lex_match (lexer, T_EQUALS);
2121                       if (lex_match_id (lexer, "ALLCATS"))
2122                         t->pairwise->meansvariance_allcats = true;
2123                       else if (lex_match_id (lexer, "TESTEDCATS"))
2124                         t->pairwise->meansvariance_allcats = false;
2125                       else
2126                         {
2127                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
2128                           goto error;
2129                         }
2130                     }
2131                   else if (lex_match_id (lexer, "CATEGORIES"))
2132                     {
2133                       lex_match (lexer, T_EQUALS);
2134                       if (lex_match_id (lexer, "ALLVISIBLE"))
2135                         t->pairwise->all_visible = true;
2136                       else if (lex_match_id (lexer, "SUBTOTALS"))
2137                         t->pairwise->all_visible = false;
2138                       else
2139                         {
2140                           lex_error_expecting (lexer, "ALLVISIBLE",
2141                                                "SUBTOTALS");
2142                           goto error;
2143                         }
2144                     }
2145                   else if (lex_match_id (lexer, "MERGE"))
2146                     {
2147                       lex_match (lexer, T_EQUALS);
2148                       if (!parse_bool (lexer, &t->pairwise->merge))
2149                         goto error;
2150                     }
2151                   else if (lex_match_id (lexer, "STYLE"))
2152                     {
2153                       lex_match (lexer, T_EQUALS);
2154                       if (lex_match_id (lexer, "APA"))
2155                         t->pairwise->apa_style = true;
2156                       else if (lex_match_id (lexer, "SIMPLE"))
2157                         t->pairwise->apa_style = false;
2158                       else
2159                         {
2160                           lex_error_expecting (lexer, "APA", "SIMPLE");
2161                           goto error;
2162                         }
2163                     }
2164                   else if (lex_match_id (lexer, "SHOWSIG"))
2165                     {
2166                       lex_match (lexer, T_EQUALS);
2167                       if (!parse_bool (lexer, &t->pairwise->show_sig))
2168                         goto error;
2169                     }
2170                   else
2171                     {
2172                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
2173                                            "INCLUDEMRSETS", "MEANSVARIANCE",
2174                                            "CATEGORIES", "MERGE", "STYLE",
2175                                            "SHOWSIG");
2176                       goto error;
2177                     }
2178                 }
2179               while (lex_token (lexer) != T_SLASH
2180                      && lex_token (lexer) != T_ENDCMD);
2181             }
2182           else
2183             {
2184               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
2185                                    "CRITERIA", "CATEGORIES", "TITLES",
2186                                    "SIGTEST", "COMPARETEST");
2187               goto error;
2188             }
2189         }
2190
2191       if (t->row_labels != CTLP_NORMAL && t->col_labels != CTLP_NORMAL)
2192         {
2193           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
2194           goto error;
2195         }
2196
2197     }
2198   while (lex_token (lexer) != T_ENDCMD);
2199
2200   bool ok = ctables_execute (ds, ct);
2201   ctables_destroy (ct);
2202   return ok ? CMD_SUCCESS : CMD_FAILURE;
2203
2204 error:
2205   ctables_destroy (ct);
2206   return CMD_FAILURE;
2207 }
2208