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