work on missing value handling
[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 <math.h>
20 #include <errno.h>
21
22 #include "data/casereader.h"
23 #include "data/casewriter.h"
24 #include "data/data-out.h"
25 #include "data/dataset.h"
26 #include "data/dictionary.h"
27 #include "data/mrset.h"
28 #include "data/subcase.h"
29 #include "data/value-labels.h"
30 #include "language/command.h"
31 #include "language/lexer/format-parser.h"
32 #include "language/lexer/lexer.h"
33 #include "language/lexer/variable-parser.h"
34 #include "libpspp/array.h"
35 #include "libpspp/assertion.h"
36 #include "libpspp/hash-functions.h"
37 #include "libpspp/hmap.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/string-array.h"
41 #include "math/mode.h"
42 #include "math/moments.h"
43 #include "math/percentiles.h"
44 #include "math/sort.h"
45 #include "output/pivot-table.h"
46
47 #include "gl/minmax.h"
48 #include "gl/xalloc.h"
49
50 #include "gettext.h"
51 #define _(msgid) gettext (msgid)
52 #define N_(msgid) (msgid)
53
54 enum ctables_vlabel
55   {
56     CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
57     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
58     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
59     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
60   };
61
62 /* XXX:
63    - unweighted summaries (U*)
64    - lower confidence limits (*.LCL)
65    - upper confidence limits (*.UCL)
66    - standard error (*.SE)
67  */
68 #define SUMMARIES                                                       \
69     /* All variables. */                                                \
70     S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL)            \
71     S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
72     S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
73     S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
74     S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
75     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
76     S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
77     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
78     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
79     S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
80     S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
81     S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
82     S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
83     S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
84     S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
85     S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
86     S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
87     S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
88     S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
89     S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
90     S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
91     S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
92     S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
93                                                                         \
94     /* Scale variables, totals, and subtotals. */                       \
95     S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE)  \
96     S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE)           \
97     S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE)     \
98     S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE)  \
99     S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE)  \
100     S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE)           \
101     S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE)   \
102     S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE)        \
103     S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
104     S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
105     S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE)              \
106     S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE)      \
107     S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
108     S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE)      \
109     S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
110     S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
111     S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
112     S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
113     S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
114     S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
115     S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
116     S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
117     S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
118
119 #if 0         /* Multiple response sets not yet implemented. */
120   S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
121     S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
122     S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
123     S(CTSF_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
124     S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
125     S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
126     S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
127     S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
128     S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
129     S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
130     S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
131     S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
132     S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
133     S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
134     S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
135     S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
136     S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
137     S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
138     S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
139     S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
140     S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
141     S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
142 #endif
143
144 enum ctables_summary_function
145   {
146 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
147     SUMMARIES
148 #undef S
149   };
150
151 enum {
152 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
153   N_CTSF_FUNCTIONS = SUMMARIES
154 #undef S
155 };
156
157 static bool ctables_summary_function_is_count (enum ctables_summary_function);
158
159 enum ctables_domain_type
160   {
161     /* Within a section, where stacked variables divide one section from
162        another. */
163     CTDT_TABLE,                  /* All layers of a whole section. */
164     CTDT_LAYER,                  /* One layer within a section. */
165     CTDT_LAYERROW,               /* Row in one layer within a section. */
166     CTDT_LAYERCOL,               /* Column in one layer within a section. */
167
168     /* Within a subtable, where a subtable pairs an innermost row variable with
169        an innermost column variable within a single layer.  */
170     CTDT_SUBTABLE,               /* Whole subtable. */
171     CTDT_ROW,                    /* Row within a subtable. */
172     CTDT_COL,                    /* Column within a subtable. */
173 #define N_CTDTS 7
174   };
175
176 struct ctables_domain
177   {
178     struct hmap_node node;
179
180     const struct ctables_cell *example;
181
182     double d_valid;             /* Dictionary weight. */
183     double d_count;
184     double d_total;
185     double e_valid;             /* Effective weight */
186     double e_count;
187     double e_total;
188   };
189
190 enum ctables_summary_variant
191   {
192     CSV_CELL,
193     CSV_TOTAL
194 #define N_CSVS 2
195   };
196
197 struct ctables_cell
198   {
199     /* In struct ctables_section's 'cells' hmap.  Indexed by all the values in
200        all the axes (except the scalar variable, if any). */
201     struct hmap_node node;
202
203     /* The domains that contain this cell. */
204     bool contributes_to_domains;
205     struct ctables_domain *domains[N_CTDTS];
206
207     bool hide;
208
209     /* Is at least one value missing, whether included or excluded? */
210     bool is_missing;
211
212     /* Is at least one value missing and excluded? */
213     bool excluded_missing;
214
215     bool postcompute;
216     enum ctables_summary_variant sv;
217
218     struct ctables_cell_axis
219       {
220         struct ctables_cell_value
221           {
222             const struct ctables_category *category;
223             union value value;
224           }
225         *cvs;
226         int leaf;
227       }
228     axes[PIVOT_N_AXES];
229
230     union ctables_summary *summaries;
231   };
232
233 struct ctables
234   {
235     const struct dictionary *dict;
236     struct pivot_table_look *look;
237
238     /* CTABLES has a number of extra formats that we implement via custom
239        currency specifications on an alternate fmt_settings. */
240 #define CTEF_NEGPAREN FMT_CCA
241 #define CTEF_NEQUAL   FMT_CCB
242 #define CTEF_PAREN    FMT_CCC
243 #define CTEF_PCTPAREN FMT_CCD
244     struct fmt_settings ctables_formats;
245
246     /* If this is NULL, zeros are displayed using the normal print format.
247        Otherwise, this string is displayed. */
248     char *zero;
249
250     /* If this is NULL, missing values are displayed using the normal print
251        format.  Otherwise, this string is displayed. */
252     char *missing;
253
254     /* Indexed by variable dictionary index. */
255     enum ctables_vlabel *vlabels;
256
257     struct hmap postcomputes;   /* Contains "struct ctables_postcompute"s. */
258
259     bool mrsets_count_duplicates; /* MRSETS. */
260     bool smissing_listwise;       /* SMISSING. */
261     struct variable *e_weight;    /* WEIGHT. */
262     int hide_threshold;           /* HIDESMALLCOUNTS. */
263
264     struct ctables_table **tables;
265     size_t n_tables;
266   };
267
268 static struct ctables_postcompute *ctables_find_postcompute (struct ctables *,
269                                                              const char *name);
270
271 struct ctables_postcompute
272   {
273     struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
274     char *name;                 /* Name, without leading &. */
275
276     struct msg_location *location; /* Location of definition. */
277     struct ctables_pcexpr *expr;
278     char *label;
279     struct ctables_summary_spec_set *specs;
280     bool hide_source_cats;
281   };
282
283 struct ctables_pcexpr
284   {
285     /* Precedence table:
286
287        ()
288        **
289        -
290        * /
291        - +
292     */
293     enum ctables_postcompute_op
294       {
295         /* Terminals. */
296         CTPO_CONSTANT,          /* 5 */
297         CTPO_CAT_NUMBER,        /* [5] */
298         CTPO_CAT_STRING,        /* ["STRING"] */
299         CTPO_CAT_RANGE,         /* [LO THRU 5] */
300         CTPO_CAT_MISSING,       /* MISSING */
301         CTPO_CAT_OTHERNM,       /* OTHERNM */
302         CTPO_CAT_SUBTOTAL,      /* SUBTOTAL */
303         CTPO_CAT_TOTAL,         /* TOTAL */
304
305         /* Nonterminals. */
306         CTPO_ADD,
307         CTPO_SUB,
308         CTPO_MUL,
309         CTPO_DIV,
310         CTPO_POW,
311         CTPO_NEG,
312       }
313     op;
314
315     union
316       {
317         /* CTPO_CAT_NUMBER. */
318         double number;
319
320         /* CTPO_CAT_STRING. */
321         char *string;
322
323         /* CTPO_CAT_RANGE. */
324         double range[2];
325
326         /* CTPO_CAT_SUBTOTAL. */
327         size_t subtotal_index;
328
329         /* Two elements: CTPO_ADD, CTPO_SUB, CTPO_MUL, CTPO_DIV, CTPO_POW.
330            One element: CTPO_NEG. */
331         struct ctables_pcexpr *subs[2];
332       };
333
334     /* Source location. */
335     struct msg_location *location;
336   };
337
338 static void ctables_pcexpr_destroy (struct ctables_pcexpr *);
339 static struct ctables_pcexpr *ctables_pcexpr_allocate_binary (
340   enum ctables_postcompute_op, struct ctables_pcexpr *sub0,
341   struct ctables_pcexpr *sub1);
342
343 struct ctables_summary_spec_set
344   {
345     struct ctables_summary_spec *specs;
346     size_t n;
347     size_t allocated;
348
349     /* The variable to which the summary specs are applied. */
350     struct variable *var;
351
352     /* Whether the variable to which the summary specs are applied is a scale
353        variable for the purpose of summarization.
354
355        (VALIDN and TOTALN act differently for summarizing scale and categorical
356        variables.) */
357     bool is_scale;
358   };
359
360 static void ctables_summary_spec_set_clone (struct ctables_summary_spec_set *,
361                                             const struct ctables_summary_spec_set *);
362 static void ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *);
363
364 /* A nested sequence of variables, e.g. a > b > c. */
365 struct ctables_nest
366   {
367     struct variable **vars;
368     size_t n;
369     size_t scale_idx;
370     size_t *domains[N_CTDTS];
371     size_t n_domains[N_CTDTS];
372
373     struct ctables_summary_spec_set specs[N_CSVS];
374   };
375
376 /* A stack of nestings, e.g. nest1 + nest2 + ... + nestN. */
377 struct ctables_stack
378   {
379     struct ctables_nest *nests;
380     size_t n;
381   };
382
383 struct ctables_value
384   {
385     struct hmap_node node;
386     union value value;
387     int leaf;
388   };
389
390 struct ctables_occurrence
391   {
392     struct hmap_node node;
393     union value value;
394   };
395
396 struct ctables_section
397   {
398     struct ctables_table *table;
399     struct ctables_nest *nests[PIVOT_N_AXES];
400     struct hmap *occurrences[PIVOT_N_AXES];
401     struct hmap cells;            /* Contains "struct ctable_cell"s. */
402     struct hmap domains[N_CTDTS]; /* Contains "struct ctable_domain"s. */
403   };
404
405 struct ctables_table
406   {
407     struct ctables *ctables;
408     struct ctables_axis *axes[PIVOT_N_AXES];
409     struct ctables_stack stacks[PIVOT_N_AXES];
410     struct ctables_section *sections;
411     size_t n_sections;
412     enum pivot_axis_type summary_axis;
413     struct ctables_summary_spec_set summary_specs;
414
415     const struct variable *clabels_example;
416     struct hmap clabels_values_map;
417     struct ctables_value **clabels_values;
418     size_t n_clabels_values;
419
420     enum pivot_axis_type slabels_axis;
421     bool slabels_visible;
422
423     /* The innermost category labels for axis 'a' appear on axis label_axis[a].
424
425        Most commonly, label_axis[a] == a, and in particular we always have
426        label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
427
428        If ROWLABELS or COLLABELS is specified, then one of
429        label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
430        opposite axis or PIVOT_AXIS_LAYER.  Only one of them will differ.
431     */
432     enum pivot_axis_type label_axis[PIVOT_N_AXES];
433     enum pivot_axis_type clabels_from_axis;
434
435     /* Indexed by variable dictionary index. */
436     struct ctables_categories **categories;
437     size_t n_categories;
438
439     double cilevel;
440
441     char *caption;
442     char *corner;
443     char *title;
444
445     struct ctables_chisq *chisq;
446     struct ctables_pairwise *pairwise;
447   };
448
449 struct ctables_var
450   {
451     bool is_mrset;
452     union
453       {
454         struct variable *var;
455         const struct mrset *mrset;
456       };
457   };
458
459 static const struct fmt_spec *
460 ctables_var_get_print_format (const struct ctables_var *var)
461 {
462   return (var->is_mrset
463           ? var_get_print_format (var->mrset->vars[0])
464           : var_get_print_format (var->var));
465 }
466
467 static const char *
468 ctables_var_name (const struct ctables_var *var)
469 {
470   return var->is_mrset ? var->mrset->name : var_get_name (var->var);
471 }
472
473 struct ctables_categories
474   {
475     size_t n_refs;
476     struct ctables_category *cats;
477     size_t n_cats;
478     bool show_empty;
479   };
480
481 struct ctables_category
482   {
483     enum ctables_category_type
484       {
485         /* Explicit category lists. */
486         CCT_NUMBER,
487         CCT_STRING,
488         CCT_RANGE,
489         CCT_MISSING,
490         CCT_OTHERNM,
491         CCT_POSTCOMPUTE,
492
493         /* Totals and subtotals. */
494         CCT_SUBTOTAL,
495         CCT_TOTAL,
496
497         /* Implicit category lists. */
498         CCT_VALUE,
499         CCT_LABEL,
500         CCT_FUNCTION,
501
502         /* For contributing to TOTALN. */
503         CCT_EXCLUDED_MISSING,
504       }
505     type;
506
507     struct ctables_category *subtotal;
508
509     bool hide;
510
511     union
512       {
513         double number;          /* CCT_NUMBER. */
514         char *string;           /* CCT_STRING. */
515         double range[2];        /* CCT_RANGE. */
516
517         struct
518           {
519             char *total_label;      /* CCT_SUBTOTAL, CCT_TOTAL. */
520             bool hide_subcategories; /* CCT_SUBTOTAL. */
521           };
522
523         const struct ctables_postcompute *pc; /* CCT_POSTCOMPUTE. */
524
525         /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
526         struct
527           {
528             bool include_missing;
529             bool sort_ascending;
530
531             /* CCT_FUNCTION. */
532             enum ctables_summary_function sort_function;
533             struct variable *sort_var;
534             double percentile;
535           };
536       };
537
538     /* Source location.  This is null for CCT_TOTAL, CCT_VALUE, CCT_LABEL,
539        CCT_FUNCTION, CCT_EXCLUDED_MISSING. */
540     struct msg_location *location;
541   };
542
543 static void
544 ctables_category_uninit (struct ctables_category *cat)
545 {
546   if (!cat)
547     return;
548
549   switch (cat->type)
550     {
551     case CCT_NUMBER:
552     case CCT_RANGE:
553     case CCT_MISSING:
554     case CCT_OTHERNM:
555     case CCT_POSTCOMPUTE:
556       break;
557
558     case CCT_STRING:
559       free (cat->string);
560       break;
561
562     case CCT_SUBTOTAL:
563     case CCT_TOTAL:
564       free (cat->total_label);
565       break;
566
567     case CCT_VALUE:
568     case CCT_LABEL:
569     case CCT_FUNCTION:
570       break;
571
572     case CCT_EXCLUDED_MISSING:
573       break;
574     }
575 }
576
577 static bool
578 ctables_category_equal (const struct ctables_category *a,
579                         const struct ctables_category *b)
580 {
581   if (a->type != b->type)
582     return false;
583
584   switch (a->type)
585     {
586     case CCT_NUMBER:
587       return a->number == b->number;
588
589     case CCT_STRING:
590       return strcmp (a->string, b->string);
591
592     case CCT_RANGE:
593       return a->range[0] == b->range[0] && a->range[1] == b->range[1];
594
595     case CCT_MISSING:
596     case CCT_OTHERNM:
597       return true;
598
599     case CCT_POSTCOMPUTE:
600       return a->pc == b->pc;
601
602     case CCT_SUBTOTAL:
603     case CCT_TOTAL:
604       return !strcmp (a->total_label, b->total_label);
605
606     case CCT_VALUE:
607     case CCT_LABEL:
608     case CCT_FUNCTION:
609       return (a->include_missing == b->include_missing
610               && a->sort_ascending == b->sort_ascending
611               && a->sort_function == b->sort_function
612               && a->sort_var == b->sort_var
613               && a->percentile == b->percentile);
614
615     case CCT_EXCLUDED_MISSING:
616       return true;
617     }
618
619   NOT_REACHED ();
620 }
621
622 static void
623 ctables_categories_unref (struct ctables_categories *c)
624 {
625   if (!c)
626     return;
627
628   assert (c->n_refs > 0);
629   if (--c->n_refs)
630     return;
631
632   for (size_t i = 0; i < c->n_cats; i++)
633     ctables_category_uninit (&c->cats[i]);
634   free (c->cats);
635   free (c);
636 }
637
638 static bool
639 ctables_categories_equal (const struct ctables_categories *a,
640                           const struct ctables_categories *b)
641 {
642   if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
643     return false;
644
645   for (size_t i = 0; i < a->n_cats; i++)
646     if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
647       return false;
648
649   return true;
650 }
651
652 /* Chi-square test (SIGTEST). */
653 struct ctables_chisq
654   {
655     double alpha;
656     bool include_mrsets;
657     bool all_visible;
658   };
659
660 /* Pairwise comparison test (COMPARETEST). */
661 struct ctables_pairwise
662   {
663     enum { PROP, MEAN } type;
664     double alpha[2];
665     bool include_mrsets;
666     bool meansvariance_allcats;
667     bool all_visible;
668     enum { BONFERRONI = 1, BH } adjust;
669     bool merge;
670     bool apa_style;
671     bool show_sig;
672   };
673
674 struct ctables_axis
675   {
676     enum ctables_axis_op
677       {
678         /* Terminals. */
679         CTAO_VAR,
680
681         /* Nonterminals. */
682         CTAO_STACK,             /* + */
683         CTAO_NEST,              /* > */
684       }
685     op;
686
687     union
688       {
689         /* Terminals. */
690         struct
691           {
692             struct ctables_var var;
693             bool scale;
694             struct ctables_summary_spec_set specs[N_CSVS];
695           };
696
697         /* Nonterminals. */
698         struct ctables_axis *subs[2];
699       };
700
701     struct msg_location *loc;
702   };
703
704 static void ctables_axis_destroy (struct ctables_axis *);
705
706 enum ctables_format
707   {
708     CTF_COUNT,
709     CTF_PERCENT,
710     CTF_GENERAL
711   };
712
713 enum ctables_function_availability
714   {
715     CTFA_ALL,                /* Any variables. */
716     CTFA_SCALE,              /* Only scale variables, totals, and subtotals. */
717     CTFA_MRSETS,             /* Only multiple-response sets */
718   };
719
720 struct ctables_summary_spec
721   {
722     enum ctables_summary_function function;
723     double percentile;          /* CTSF_PTILE only. */
724     char *label;
725
726     struct fmt_spec format;
727     bool is_ctables_format;       /* Is 'format' one of CTEF_*? */
728
729     size_t axis_idx;
730   };
731
732 static void
733 ctables_summary_spec_clone (struct ctables_summary_spec *dst,
734                             const struct ctables_summary_spec *src)
735 {
736   *dst = *src;
737   dst->label = xstrdup (src->label);
738 }
739
740 static void
741 ctables_summary_spec_uninit (struct ctables_summary_spec *s)
742 {
743   if (s)
744     free (s->label);
745 }
746
747 static void
748 ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
749                                 const struct ctables_summary_spec_set *src)
750 {
751   struct ctables_summary_spec *specs = xnmalloc (src->n, sizeof *specs);
752   for (size_t i = 0; i < src->n; i++)
753     ctables_summary_spec_clone (&specs[i], &src->specs[i]);
754
755   *dst = (struct ctables_summary_spec_set) {
756     .specs = specs,
757     .n = src->n,
758     .allocated = src->n,
759     .var = src->var,
760     .is_scale = src->is_scale,
761   };
762 }
763
764 static void
765 ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
766 {
767   for (size_t i = 0; i < set->n; i++)
768     ctables_summary_spec_uninit (&set->specs[i]);
769   free (set->specs);
770 }
771
772 static bool
773 parse_col_width (struct lexer *lexer, const char *name, double *width)
774 {
775   lex_match (lexer, T_EQUALS);
776   if (lex_match_id (lexer, "DEFAULT"))
777     *width = SYSMIS;
778   else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
779     {
780       *width = lex_number (lexer);
781       lex_get (lexer);
782     }
783   else
784     return false;
785
786   return true;
787 }
788
789 static bool
790 parse_bool (struct lexer *lexer, bool *b)
791 {
792   if (lex_match_id (lexer, "NO"))
793     *b = false;
794   else if (lex_match_id (lexer, "YES"))
795     *b = true;
796   else
797     {
798       lex_error_expecting (lexer, "YES", "NO");
799       return false;
800     }
801   return true;
802 }
803
804 static enum ctables_function_availability
805 ctables_function_availability (enum ctables_summary_function f)
806 {
807   static enum ctables_function_availability availability[] = {
808 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
809     SUMMARIES
810 #undef S
811   };
812
813   return availability[f];
814 }
815
816 static bool
817 ctables_summary_function_is_count (enum ctables_summary_function f)
818 {
819   switch (f)
820     {
821     case CTSF_COUNT:
822     case CTSF_ECOUNT:
823     case CTSF_ROWPCT_COUNT:
824     case CTSF_COLPCT_COUNT:
825     case CTSF_TABLEPCT_COUNT:
826     case CTSF_SUBTABLEPCT_COUNT:
827     case CTSF_LAYERPCT_COUNT:
828     case CTSF_LAYERROWPCT_COUNT:
829     case CTSF_LAYERCOLPCT_COUNT:
830       return true;
831
832     case CTSF_ROWPCT_VALIDN:
833     case CTSF_COLPCT_VALIDN:
834     case CTSF_TABLEPCT_VALIDN:
835     case CTSF_SUBTABLEPCT_VALIDN:
836     case CTSF_LAYERPCT_VALIDN:
837     case CTSF_LAYERROWPCT_VALIDN:
838     case CTSF_LAYERCOLPCT_VALIDN:
839     case CTSF_ROWPCT_TOTALN:
840     case CTSF_COLPCT_TOTALN:
841     case CTSF_TABLEPCT_TOTALN:
842     case CTSF_SUBTABLEPCT_TOTALN:
843     case CTSF_LAYERPCT_TOTALN:
844     case CTSF_LAYERROWPCT_TOTALN:
845     case CTSF_LAYERCOLPCT_TOTALN:
846     case CTSF_MAXIMUM:
847     case CTSF_MEAN:
848     case CTSF_MEDIAN:
849     case CTSF_MINIMUM:
850     case CTSF_MISSING:
851     case CTSF_MODE:
852     case CTSF_PTILE:
853     case CTSF_RANGE:
854     case CTSF_SEMEAN:
855     case CTSF_STDDEV:
856     case CTSF_SUM:
857     case CSTF_TOTALN:
858     case CTSF_ETOTALN:
859     case CTSF_VALIDN:
860     case CTSF_EVALIDN:
861     case CTSF_VARIANCE:
862     case CTSF_ROWPCT_SUM:
863     case CTSF_COLPCT_SUM:
864     case CTSF_TABLEPCT_SUM:
865     case CTSF_SUBTABLEPCT_SUM:
866     case CTSF_LAYERPCT_SUM:
867     case CTSF_LAYERROWPCT_SUM:
868     case CTSF_LAYERCOLPCT_SUM:
869       return false;
870   }
871   NOT_REACHED ();
872 }
873
874
875 static bool
876 parse_ctables_summary_function (struct lexer *lexer,
877                                 enum ctables_summary_function *f)
878 {
879   struct pair
880     {
881       enum ctables_summary_function function;
882       struct substring name;
883     };
884   static struct pair names[] = {
885 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
886     { ENUM, SS_LITERAL_INITIALIZER (NAME) },
887     SUMMARIES
888
889     /* The .COUNT suffix may be omitted. */
890     S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
891     S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
892     S(CTSF_TABLEPCT_COUNT, "TABLEPCT", _, _, _)
893     S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT", _, _, _)
894     S(CTSF_LAYERPCT_COUNT, "LAYERPCT", _, _, _)
895     S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT", _, _, _)
896     S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT", _, _, _)
897 #undef S
898   };
899
900   if (!lex_force_id (lexer))
901     return false;
902
903   for (size_t i = 0; i < sizeof names / sizeof *names; i++)
904     if (ss_equals_case (names[i].name, lex_tokss (lexer)))
905       {
906         *f = names[i].function;
907         lex_get (lexer);
908         return true;
909       }
910
911   lex_error (lexer, _("Expecting summary function name."));
912   return false;
913 }
914
915 static void
916 ctables_axis_destroy (struct ctables_axis *axis)
917 {
918   if (!axis)
919     return;
920
921   switch (axis->op)
922     {
923     case CTAO_VAR:
924       for (size_t i = 0; i < N_CSVS; i++)
925         ctables_summary_spec_set_uninit (&axis->specs[i]);
926       break;
927
928     case CTAO_STACK:
929     case CTAO_NEST:
930       ctables_axis_destroy (axis->subs[0]);
931       ctables_axis_destroy (axis->subs[1]);
932       break;
933     }
934   msg_location_destroy (axis->loc);
935   free (axis);
936 }
937
938 static struct ctables_axis *
939 ctables_axis_new_nonterminal (enum ctables_axis_op op,
940                               struct ctables_axis *sub0,
941                               struct ctables_axis *sub1,
942                               struct lexer *lexer, int start_ofs)
943 {
944   struct ctables_axis *axis = xmalloc (sizeof *axis);
945   *axis = (struct ctables_axis) {
946     .op = op,
947     .subs = { sub0, sub1 },
948     .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
949   };
950   return axis;
951 }
952
953 struct ctables_axis_parse_ctx
954   {
955     struct lexer *lexer;
956     struct dictionary *dict;
957     struct ctables *ct;
958     struct ctables_table *t;
959   };
960
961 static struct fmt_spec
962 ctables_summary_default_format (enum ctables_summary_function function,
963                                 const struct ctables_var *var)
964 {
965   static const enum ctables_format default_formats[] = {
966 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
967     SUMMARIES
968 #undef S
969   };
970   switch (default_formats[function])
971     {
972     case CTF_COUNT:
973       return (struct fmt_spec) { .type = FMT_F, .w = 40 };
974
975     case CTF_PERCENT:
976       return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
977
978     case CTF_GENERAL:
979       return *ctables_var_get_print_format (var);
980
981     default:
982       NOT_REACHED ();
983     }
984 }
985
986 static char *
987 ctables_summary_default_label (enum ctables_summary_function function,
988                                double percentile)
989 {
990   static const char *default_labels[] = {
991 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
992     SUMMARIES
993 #undef S
994   };
995
996   return (function == CTSF_PTILE
997           ? xasprintf (_("Percentile %.2f"), percentile)
998           : xstrdup (gettext (default_labels[function])));
999 }
1000
1001 static const char *
1002 ctables_summary_function_name (enum ctables_summary_function function)
1003 {
1004   static const char *names[] = {
1005 #define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
1006     SUMMARIES
1007 #undef S
1008   };
1009   return names[function];
1010 }
1011
1012 static bool
1013 add_summary_spec (struct ctables_axis *axis,
1014                   enum ctables_summary_function function, double percentile,
1015                   const char *label, const struct fmt_spec *format,
1016                   bool is_ctables_format, const struct msg_location *loc,
1017                   enum ctables_summary_variant sv)
1018 {
1019   if (axis->op == CTAO_VAR)
1020     {
1021       const char *function_name = ctables_summary_function_name (function);
1022       const char *var_name = ctables_var_name (&axis->var);
1023       switch (ctables_function_availability (function))
1024         {
1025         case CTFA_MRSETS:
1026           if (!axis->var.is_mrset)
1027             {
1028               msg_at (SE, loc, _("Summary function %s applies only to multiple "
1029                                  "response sets."), function_name);
1030               msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
1031                       var_name);
1032               return false;
1033             }
1034           break;
1035
1036         case CTFA_SCALE:
1037 #if 0
1038           if (!axis->scale)
1039             {
1040               msg_at (SE, loc,
1041                       _("Summary function %s applies only to scale variables."),
1042                       function_name);
1043               msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
1044                       var_name);
1045               return false;
1046             }
1047 #endif
1048           break;
1049
1050         case CTFA_ALL:
1051           break;
1052         }
1053
1054       struct ctables_summary_spec_set *set = &axis->specs[sv];
1055       if (set->n >= set->allocated)
1056         set->specs = x2nrealloc (set->specs, &set->allocated,
1057                                  sizeof *set->specs);
1058
1059       struct ctables_summary_spec *dst = &set->specs[set->n++];
1060       *dst = (struct ctables_summary_spec) {
1061         .function = function,
1062         .percentile = percentile,
1063         .label = xstrdup (label),
1064         .format = (format ? *format
1065                    : ctables_summary_default_format (function, &axis->var)),
1066         .is_ctables_format = is_ctables_format,
1067       };
1068       return true;
1069     }
1070   else
1071     {
1072       for (size_t i = 0; i < 2; i++)
1073         if (!add_summary_spec (axis->subs[i], function, percentile, label,
1074                                format, is_ctables_format, loc, sv))
1075           return false;
1076       return true;
1077     }
1078 }
1079
1080 static struct ctables_axis *ctables_axis_parse_stack (
1081   struct ctables_axis_parse_ctx *);
1082
1083 static bool
1084 ctables_var_parse (struct lexer *lexer, struct dictionary *dict,
1085                    struct ctables_var *var)
1086 {
1087   if (ss_starts_with (lex_tokss (lexer), ss_cstr ("$")))
1088     {
1089       *var = (struct ctables_var) {
1090         .is_mrset = true,
1091         .mrset = dict_lookup_mrset (dict, lex_tokcstr (lexer))
1092       };
1093       if (!var->mrset)
1094         {
1095           lex_error (lexer, _("'%s' does not name a multiple-response set "
1096                               "in the active file dictionary."),
1097                      lex_tokcstr (lexer));
1098           return false;
1099         }
1100       lex_get (lexer);
1101       return true;
1102     }
1103   else
1104     {
1105       *var = (struct ctables_var) {
1106         .is_mrset = false,
1107         .var = parse_variable (lexer, dict),
1108       };
1109       return var->var != NULL;
1110     }
1111 }
1112
1113 static struct ctables_axis *
1114 ctables_axis_parse_primary (struct ctables_axis_parse_ctx *ctx)
1115 {
1116   if (lex_match (ctx->lexer, T_LPAREN))
1117     {
1118       struct ctables_axis *sub = ctables_axis_parse_stack (ctx);
1119       if (!sub || !lex_force_match (ctx->lexer, T_RPAREN))
1120         {
1121           ctables_axis_destroy (sub);
1122           return NULL;
1123         }
1124       return sub;
1125     }
1126
1127   if (!lex_force_id (ctx->lexer))
1128     return NULL;
1129
1130   int start_ofs = lex_ofs (ctx->lexer);
1131   struct ctables_var var;
1132   if (!ctables_var_parse (ctx->lexer, ctx->dict, &var))
1133     return NULL;
1134
1135   struct ctables_axis *axis = xmalloc (sizeof *axis);
1136   *axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
1137
1138   /* XXX should figure out default measures by reading data */
1139   axis->scale = (var.is_mrset ? false
1140                  : lex_match_phrase (ctx->lexer, "[S]") ? true
1141                  : lex_match_phrase (ctx->lexer, "[C]") ? false
1142                  : var_get_measure (var.var) == MEASURE_SCALE);
1143   axis->loc = lex_ofs_location (ctx->lexer, start_ofs,
1144                                 lex_ofs (ctx->lexer) - 1);
1145   return axis;
1146 }
1147
1148 static bool
1149 has_digit (const char *s)
1150 {
1151   return s[strcspn (s, "0123456789")] != '\0';
1152 }
1153
1154 static bool
1155 parse_ctables_format_specifier (struct lexer *lexer, struct fmt_spec *format,
1156                                 bool *is_ctables_format)
1157 {
1158   char type[FMT_TYPE_LEN_MAX + 1];
1159   if (!parse_abstract_format_specifier__ (lexer, type, &format->w, &format->d))
1160     return false;
1161
1162   if (!strcasecmp (type, "NEGPAREN"))
1163     format->type = CTEF_NEGPAREN;
1164   else if (!strcasecmp (type, "NEQUAL"))
1165     format->type = CTEF_NEQUAL;
1166   else if (!strcasecmp (type, "PAREN"))
1167     format->type = CTEF_PAREN;
1168   else if (!strcasecmp (type, "PCTPAREN"))
1169     format->type = CTEF_PCTPAREN;
1170   else
1171     {
1172       *is_ctables_format = false;
1173       return (parse_format_specifier (lexer, format)
1174               && fmt_check_output (format)
1175               && fmt_check_type_compat (format, VAL_NUMERIC));
1176     }
1177
1178   if (format->w < 2)
1179     {
1180       msg (SE, _("Output format %s requires width 2 or greater."), type);
1181       return false;
1182     }
1183   else if (format->d > format->w - 1)
1184     {
1185       msg (SE, _("Output format %s requires width greater than decimals."),
1186            type);
1187       return false;
1188     }
1189   else
1190     {
1191       *is_ctables_format = true;
1192       return true;
1193     }
1194 }
1195
1196 static struct ctables_axis *
1197 ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
1198 {
1199   struct ctables_axis *sub = ctables_axis_parse_primary (ctx);
1200   if (!sub || !lex_match (ctx->lexer, T_LBRACK))
1201     return sub;
1202
1203   enum ctables_summary_variant sv = CSV_CELL;
1204   for (;;)
1205     {
1206       int start_ofs = lex_ofs (ctx->lexer);
1207
1208       /* Parse function. */
1209       enum ctables_summary_function function;
1210       if (!parse_ctables_summary_function (ctx->lexer, &function))
1211         goto error;
1212
1213       /* Parse percentile. */
1214       double percentile = 0;
1215       if (function == CTSF_PTILE)
1216         {
1217           if (!lex_force_num_range_closed (ctx->lexer, "PTILE", 0, 100))
1218             goto error;
1219           percentile = lex_number (ctx->lexer);
1220           lex_get (ctx->lexer);
1221         }
1222
1223       /* Parse label. */
1224       char *label;
1225       if (lex_is_string (ctx->lexer))
1226         {
1227           label = ss_xstrdup (lex_tokss (ctx->lexer));
1228           lex_get (ctx->lexer);
1229         }
1230       else
1231         label = ctables_summary_default_label (function, percentile);
1232
1233       /* Parse format. */
1234       struct fmt_spec format;
1235       const struct fmt_spec *formatp;
1236       bool is_ctables_format = false;
1237       if (lex_token (ctx->lexer) == T_ID
1238           && has_digit (lex_tokcstr (ctx->lexer)))
1239         {
1240           if (!parse_ctables_format_specifier (ctx->lexer, &format,
1241                                                &is_ctables_format))
1242             {
1243               free (label);
1244               goto error;
1245             }
1246           formatp = &format;
1247         }
1248       else
1249         formatp = NULL;
1250
1251       struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
1252                                                    lex_ofs (ctx->lexer) - 1);
1253       add_summary_spec (sub, function, percentile, label, formatp,
1254                         is_ctables_format, loc, sv);
1255       free (label);
1256       msg_location_destroy (loc);
1257
1258       lex_match (ctx->lexer, T_COMMA);
1259       if (sv == CSV_CELL && lex_match_id (ctx->lexer, "TOTALS"))
1260         {
1261           if (!lex_force_match (ctx->lexer, T_LBRACK))
1262             goto error;
1263           sv = CSV_TOTAL;
1264         }
1265       else if (lex_match (ctx->lexer, T_RBRACK))
1266         {
1267           if (sv == CSV_TOTAL && !lex_force_match (ctx->lexer, T_RBRACK))
1268             goto error;
1269           return sub;
1270         }
1271     }
1272
1273 error:
1274   ctables_axis_destroy (sub);
1275   return NULL;
1276 }
1277
1278 static const struct ctables_axis *
1279 find_scale (const struct ctables_axis *axis)
1280 {
1281   if (!axis)
1282     return NULL;
1283   else if (axis->op == CTAO_VAR)
1284     {
1285       if (axis->scale)
1286         {
1287           assert (!axis->var.is_mrset);
1288           return axis;
1289         }
1290       else
1291         return NULL;
1292     }
1293   else
1294     {
1295       for (size_t i = 0; i < 2; i++)
1296         {
1297           const struct ctables_axis *scale = find_scale (axis->subs[i]);
1298           if (scale)
1299             return scale;
1300         }
1301       return NULL;
1302     }
1303 }
1304
1305 static const struct ctables_axis *
1306 find_categorical_summary_spec (const struct ctables_axis *axis)
1307 {
1308   if (!axis)
1309     return NULL;
1310   else if (axis->op == CTAO_VAR)
1311     return !axis->scale && axis->specs[CSV_CELL].n ? axis : NULL;
1312   else
1313     {
1314       for (size_t i = 0; i < 2; i++)
1315         {
1316           const struct ctables_axis *sum
1317             = find_categorical_summary_spec (axis->subs[i]);
1318           if (sum)
1319             return sum;
1320         }
1321       return NULL;
1322     }
1323 }
1324
1325 static struct ctables_axis *
1326 ctables_axis_parse_nest (struct ctables_axis_parse_ctx *ctx)
1327 {
1328   int start_ofs = lex_ofs (ctx->lexer);
1329   struct ctables_axis *lhs = ctables_axis_parse_postfix (ctx);
1330   if (!lhs)
1331     return NULL;
1332
1333   while (lex_match (ctx->lexer, T_GT))
1334     {
1335       struct ctables_axis *rhs = ctables_axis_parse_postfix (ctx);
1336       if (!rhs)
1337         return NULL;
1338
1339       struct ctables_axis *nest = ctables_axis_new_nonterminal (
1340         CTAO_NEST, lhs, rhs, ctx->lexer, start_ofs);
1341
1342       const struct ctables_axis *outer_scale = find_scale (lhs);
1343       const struct ctables_axis *inner_scale = find_scale (rhs);
1344       if (outer_scale && inner_scale)
1345         {
1346           msg_at (SE, nest->loc, _("Cannot nest scale variables."));
1347           msg_at (SN, outer_scale->loc, _("This is an outer scale variable."));
1348           msg_at (SN, inner_scale->loc, _("This is an inner scale variable."));
1349           ctables_axis_destroy (nest);
1350           return NULL;
1351         }
1352
1353       const struct ctables_axis *outer_sum = find_categorical_summary_spec (lhs);
1354       if (outer_sum)
1355         {
1356           msg_at (SE, nest->loc,
1357                   _("Summaries may only be requested for categorical variables "
1358                     "at the innermost nesting level."));
1359           msg_at (SN, outer_sum->loc,
1360                   _("This outer categorical variable has a summary."));
1361           ctables_axis_destroy (nest);
1362           return NULL;
1363         }
1364
1365       lhs = nest;
1366     }
1367
1368   return lhs;
1369 }
1370
1371 static struct ctables_axis *
1372 ctables_axis_parse_stack (struct ctables_axis_parse_ctx *ctx)
1373 {
1374   int start_ofs = lex_ofs (ctx->lexer);
1375   struct ctables_axis *lhs = ctables_axis_parse_nest (ctx);
1376   if (!lhs)
1377     return NULL;
1378
1379   while (lex_match (ctx->lexer, T_PLUS))
1380     {
1381       struct ctables_axis *rhs = ctables_axis_parse_nest (ctx);
1382       if (!rhs)
1383         return NULL;
1384
1385       lhs = ctables_axis_new_nonterminal (CTAO_STACK, lhs, rhs,
1386                                           ctx->lexer, start_ofs);
1387     }
1388
1389   return lhs;
1390 }
1391
1392 static bool
1393 ctables_axis_parse (struct lexer *lexer, struct dictionary *dict,
1394                     struct ctables *ct, struct ctables_table *t,
1395                     enum pivot_axis_type a)
1396 {
1397   if (lex_token (lexer) == T_BY
1398       || lex_token (lexer) == T_SLASH
1399       || lex_token (lexer) == T_ENDCMD)
1400     return true;
1401
1402   struct ctables_axis_parse_ctx ctx = {
1403     .lexer = lexer,
1404     .dict = dict,
1405     .ct = ct,
1406     .t = t
1407   };
1408   t->axes[a] = ctables_axis_parse_stack (&ctx);
1409   return t->axes[a] != NULL;
1410 }
1411
1412 static void
1413 ctables_chisq_destroy (struct ctables_chisq *chisq)
1414 {
1415   free (chisq);
1416 }
1417
1418 static void
1419 ctables_pairwise_destroy (struct ctables_pairwise *pairwise)
1420 {
1421   free (pairwise);
1422 }
1423
1424 static void
1425 ctables_table_destroy (struct ctables_table *t)
1426 {
1427   if (!t)
1428     return;
1429
1430   for (size_t i = 0; i < t->n_categories; i++)
1431     ctables_categories_unref (t->categories[i]);
1432   free (t->categories);
1433
1434   ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
1435   ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
1436   ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
1437   free (t->caption);
1438   free (t->corner);
1439   free (t->title);
1440   ctables_chisq_destroy (t->chisq);
1441   ctables_pairwise_destroy (t->pairwise);
1442   free (t);
1443 }
1444
1445 static void
1446 ctables_destroy (struct ctables *ct)
1447 {
1448   if (!ct)
1449     return;
1450
1451   pivot_table_look_unref (ct->look);
1452   free (ct->zero);
1453   free (ct->missing);
1454   free (ct->vlabels);
1455   for (size_t i = 0; i < ct->n_tables; i++)
1456     ctables_table_destroy (ct->tables[i]);
1457   free (ct->tables);
1458   free (ct);
1459 }
1460
1461 static struct ctables_category
1462 cct_range (double low, double high)
1463 {
1464   return (struct ctables_category) {
1465     .type = CCT_RANGE,
1466     .range = { low, high }
1467   };
1468 }
1469
1470 static bool
1471 ctables_table_parse_subtotal (struct lexer *lexer, bool hide_subcategories,
1472                               struct ctables_category *cat)
1473 {
1474   char *total_label;
1475   if (lex_match (lexer, T_EQUALS))
1476     {
1477       if (!lex_force_string (lexer))
1478         return false;
1479
1480       total_label = ss_xstrdup (lex_tokss (lexer));
1481       lex_get (lexer);
1482     }
1483   else
1484     total_label = xstrdup (_("Subtotal"));
1485
1486   *cat = (struct ctables_category) {
1487     .type = CCT_SUBTOTAL,
1488     .hide_subcategories = hide_subcategories,
1489     .total_label = total_label
1490   };
1491   return true;
1492 }
1493
1494 static bool
1495 ctables_table_parse_explicit_category (struct lexer *lexer, struct ctables *ct,
1496                                        struct ctables_category *cat)
1497 {
1498   if (lex_match_id (lexer, "OTHERNM"))
1499     *cat = (struct ctables_category) { .type = CCT_OTHERNM };
1500   else if (lex_match_id (lexer, "MISSING"))
1501     *cat = (struct ctables_category) { .type = CCT_MISSING };
1502   else if (lex_match_id (lexer, "SUBTOTAL"))
1503     return ctables_table_parse_subtotal (lexer, false, cat);
1504   else if (lex_match_id (lexer, "HSUBTOTAL"))
1505     return ctables_table_parse_subtotal (lexer, true, cat);
1506   else if (lex_match_id (lexer, "LO"))
1507     {
1508       if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
1509         return false;
1510       *cat = cct_range (-DBL_MAX, lex_number (lexer));
1511       lex_get (lexer);
1512     }
1513   else if (lex_is_number (lexer))
1514     {
1515       double number = lex_number (lexer);
1516       lex_get (lexer);
1517       if (lex_match_id (lexer, "THRU"))
1518         {
1519           if (lex_match_id (lexer, "HI"))
1520             *cat = cct_range (number, DBL_MAX);
1521           else
1522             {
1523               if (!lex_force_num (lexer))
1524                 return false;
1525               *cat = cct_range (number, lex_number (lexer));
1526               lex_get (lexer);
1527             }
1528         }
1529       else
1530         *cat = (struct ctables_category) {
1531           .type = CCT_NUMBER,
1532           .number = number
1533         };
1534     }
1535   else if (lex_is_string (lexer))
1536     {
1537       *cat = (struct ctables_category) {
1538         .type = CCT_STRING,
1539         .string = ss_xstrdup (lex_tokss (lexer)),
1540       };
1541       lex_get (lexer);
1542     }
1543   else if (lex_match (lexer, T_AND))
1544     {
1545       if (!lex_force_id (lexer))
1546         return false;
1547       struct ctables_postcompute *pc = ctables_find_postcompute (
1548         ct, lex_tokcstr (lexer));
1549       if (!pc)
1550         {
1551           struct msg_location *loc = lex_get_location (lexer, -1, 0);
1552           msg_at (SE, loc, _("Unknown postcompute &%s."),
1553                   lex_tokcstr (lexer));
1554           msg_location_destroy (loc);
1555           return false;
1556         }
1557       lex_get (lexer);
1558
1559       *cat = (struct ctables_category) { .type = CCT_POSTCOMPUTE, .pc = pc };
1560     }
1561   else
1562     {
1563       lex_error (lexer, NULL);
1564       return false;
1565     }
1566
1567   return true;
1568 }
1569
1570 static struct ctables_category *
1571 ctables_find_category_for_postcompute (const struct ctables_categories *cats,
1572                                        const struct ctables_pcexpr *e)
1573 {
1574   struct ctables_category *best = NULL;
1575   size_t n_subtotals = 0;
1576   for (size_t i = 0; i < cats->n_cats; i++)
1577     {
1578       struct ctables_category *cat = &cats->cats[i];
1579       switch (e->op)
1580         {
1581         case CTPO_CAT_NUMBER:
1582           if (cat->type == CCT_NUMBER && cat->number == e->number)
1583             best = cat;
1584           break;
1585
1586         case CTPO_CAT_STRING:
1587           if (cat->type == CCT_STRING && !strcmp (cat->string, e->string))
1588             best = cat;
1589           break;
1590
1591         case CTPO_CAT_RANGE:
1592           if (cat->type == CCT_RANGE
1593               && cat->range[0] == e->range[0]
1594               && cat->range[1] == e->range[1])
1595             best = cat;
1596           break;
1597
1598         case CTPO_CAT_MISSING:
1599           if (cat->type == CCT_MISSING)
1600             best = cat;
1601           break;
1602
1603         case CTPO_CAT_OTHERNM:
1604           if (cat->type == CCT_OTHERNM)
1605             best = cat;
1606           break;
1607
1608         case CTPO_CAT_SUBTOTAL:
1609           if (cat->type == CCT_SUBTOTAL)
1610             {
1611               n_subtotals++;
1612               if (e->subtotal_index == n_subtotals)
1613                 return cat;
1614               else if (e->subtotal_index == 0)
1615                 best = cat;
1616             }
1617           break;
1618
1619         case CTPO_CAT_TOTAL:
1620           if (cat->type == CCT_TOTAL)
1621             return cat;
1622           break;
1623
1624         case CTPO_CONSTANT:
1625         case CTPO_ADD:
1626         case CTPO_SUB:
1627         case CTPO_MUL:
1628         case CTPO_DIV:
1629         case CTPO_POW:
1630         case CTPO_NEG:
1631           NOT_REACHED ();
1632         }
1633     }
1634   if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0 && n_subtotals > 1)
1635     return NULL;
1636   return best;
1637 }
1638
1639 static bool
1640 ctables_recursive_check_postcompute (const struct ctables_pcexpr *e,
1641                                      struct ctables_category *pc_cat,
1642                                      const struct ctables_categories *cats,
1643                                      const struct msg_location *cats_location)
1644 {
1645   switch (e->op)
1646     {
1647     case CTPO_CAT_NUMBER:
1648     case CTPO_CAT_STRING:
1649     case CTPO_CAT_RANGE:
1650     case CTPO_CAT_MISSING:
1651     case CTPO_CAT_OTHERNM:
1652     case CTPO_CAT_SUBTOTAL:
1653     case CTPO_CAT_TOTAL:
1654       {
1655         struct ctables_category *cat = ctables_find_category_for_postcompute (
1656           cats, e);
1657         if (!cat)
1658           {
1659             if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0)
1660               {
1661                 size_t n_subtotals = 0;
1662                 for (size_t i = 0; i < cats->n_cats; i++)
1663                   n_subtotals += cats->cats[i].type == CCT_SUBTOTAL;
1664                 if (n_subtotals > 1)
1665                   {
1666                     msg_at (SE, cats_location,
1667                             ngettext ("These categories include %zu instance "
1668                                       "of SUBTOTAL or HSUBTOTAL, so references "
1669                                       "from computed categories must refer to "
1670                                       "subtotals by position.",
1671                                       "These categories include %zu instances "
1672                                       "of SUBTOTAL or HSUBTOTAL, so references "
1673                                       "from computed categories must refer to "
1674                                       "subtotals by position.",
1675                                       n_subtotals),
1676                             n_subtotals);
1677                     msg_at (SN, e->location,
1678                             _("This is the reference that lacks a position."));
1679                     return NULL;
1680                   }
1681               }
1682
1683             msg_at (SE, pc_cat->location,
1684                     _("Computed category &%s references a category not included "
1685                       "in the category list."),
1686                     pc_cat->pc->name);
1687             msg_at (SN, e->location, _("This is the missing category."));
1688             msg_at (SN, cats_location,
1689                     _("To fix the problem, add the missing category to the "
1690                       "list of categories here."));
1691             return false;
1692           }
1693         if (pc_cat->pc->hide_source_cats)
1694           cat->hide = true;
1695         return true;
1696       }
1697
1698     case CTPO_CONSTANT:
1699       return true;
1700
1701     case CTPO_ADD:
1702     case CTPO_SUB:
1703     case CTPO_MUL:
1704     case CTPO_DIV:
1705     case CTPO_POW:
1706     case CTPO_NEG:
1707       for (size_t i = 0; i < 2; i++)
1708         if (e->subs[i] && !ctables_recursive_check_postcompute (
1709               e->subs[i], pc_cat, cats, cats_location))
1710           return false;
1711       return true;
1712
1713     default:
1714       NOT_REACHED ();
1715     }
1716 }
1717
1718 static bool
1719 ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
1720                                 struct ctables *ct, struct ctables_table *t)
1721 {
1722   if (!lex_match_id (lexer, "VARIABLES"))
1723     return false;
1724   lex_match (lexer, T_EQUALS);
1725
1726   struct variable **vars;
1727   size_t n_vars;
1728   if (!parse_variables (lexer, dict, &vars, &n_vars, PV_NO_SCRATCH))
1729     return false;
1730
1731   struct ctables_categories *c = xmalloc (sizeof *c);
1732   *c = (struct ctables_categories) { .n_refs = n_vars, .show_empty = true };
1733   for (size_t i = 0; i < n_vars; i++)
1734     {
1735       struct ctables_categories **cp
1736         = &t->categories[var_get_dict_index (vars[i])];
1737       ctables_categories_unref (*cp);
1738       *cp = c;
1739     }
1740   free (vars);
1741
1742   size_t allocated_cats = 0;
1743   if (lex_match (lexer, T_LBRACK))
1744     {
1745       int cats_start_ofs = lex_ofs (lexer);
1746       do
1747         {
1748           if (c->n_cats >= allocated_cats)
1749             c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1750
1751           int start_ofs = lex_ofs (lexer);
1752           struct ctables_category *cat = &c->cats[c->n_cats];
1753           if (!ctables_table_parse_explicit_category (lexer, ct, cat))
1754             return false;
1755           cat->location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
1756           c->n_cats++;
1757
1758           lex_match (lexer, T_COMMA);
1759         }
1760       while (!lex_match (lexer, T_RBRACK));
1761
1762       struct msg_location *cats_location
1763         = lex_ofs_location (lexer, cats_start_ofs, lex_ofs (lexer) - 1);
1764       for (size_t i = 0; i < c->n_cats; i++)
1765         {
1766           struct ctables_category *cat = &c->cats[i];
1767           if (cat->type == CCT_POSTCOMPUTE
1768               && !ctables_recursive_check_postcompute (cat->pc->expr, cat,
1769                                                        c, cats_location))
1770             return false;
1771         }
1772     }
1773
1774   struct ctables_category cat = {
1775     .type = CCT_VALUE,
1776     .include_missing = false,
1777     .sort_ascending = true,
1778   };
1779   bool show_totals = false;
1780   char *total_label = NULL;
1781   bool totals_before = false;
1782   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
1783     {
1784       if (!c->n_cats && lex_match_id (lexer, "ORDER"))
1785         {
1786           lex_match (lexer, T_EQUALS);
1787           if (lex_match_id (lexer, "A"))
1788             cat.sort_ascending = true;
1789           else if (lex_match_id (lexer, "D"))
1790             cat.sort_ascending = false;
1791           else
1792             {
1793               lex_error_expecting (lexer, "A", "D");
1794               return false;
1795             }
1796         }
1797       else if (!c->n_cats && lex_match_id (lexer, "KEY"))
1798         {
1799           lex_match (lexer, T_EQUALS);
1800           if (lex_match_id (lexer, "VALUE"))
1801             cat.type = CCT_VALUE;
1802           else if (lex_match_id (lexer, "LABEL"))
1803             cat.type = CCT_LABEL;
1804           else
1805             {
1806               cat.type = CCT_FUNCTION;
1807               if (!parse_ctables_summary_function (lexer, &cat.sort_function))
1808                 return false;
1809
1810               if (lex_match (lexer, T_LPAREN))
1811                 {
1812                   cat.sort_var = parse_variable (lexer, dict);
1813                   if (!cat.sort_var)
1814                     return false;
1815
1816                   if (cat.sort_function == CTSF_PTILE)
1817                     {
1818                       lex_match (lexer, T_COMMA);
1819                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
1820                         return false;
1821                       cat.percentile = lex_number (lexer);
1822                       lex_get (lexer);
1823                     }
1824
1825                   if (!lex_force_match (lexer, T_RPAREN))
1826                     return false;
1827                 }
1828               else if (ctables_function_availability (cat.sort_function)
1829                        == CTFA_SCALE)
1830                 {
1831                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
1832                   return false;
1833                 }
1834             }
1835         }
1836       else if (!c->n_cats && lex_match_id (lexer, "MISSING"))
1837         {
1838           lex_match (lexer, T_EQUALS);
1839           if (lex_match_id (lexer, "INCLUDE"))
1840             cat.include_missing = true;
1841           else if (lex_match_id (lexer, "EXCLUDE"))
1842             cat.include_missing = false;
1843           else
1844             {
1845               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1846               return false;
1847             }
1848         }
1849       else if (lex_match_id (lexer, "TOTAL"))
1850         {
1851           lex_match (lexer, T_EQUALS);
1852           if (!parse_bool (lexer, &show_totals))
1853             return false;
1854         }
1855       else if (lex_match_id (lexer, "LABEL"))
1856         {
1857           lex_match (lexer, T_EQUALS);
1858           if (!lex_force_string (lexer))
1859             return false;
1860           free (total_label);
1861           total_label = ss_xstrdup (lex_tokss (lexer));
1862           lex_get (lexer);
1863         }
1864       else if (lex_match_id (lexer, "POSITION"))
1865         {
1866           lex_match (lexer, T_EQUALS);
1867           if (lex_match_id (lexer, "BEFORE"))
1868             totals_before = true;
1869           else if (lex_match_id (lexer, "AFTER"))
1870             totals_before = false;
1871           else
1872             {
1873               lex_error_expecting (lexer, "BEFORE", "AFTER");
1874               return false;
1875             }
1876         }
1877       else if (lex_match_id (lexer, "EMPTY"))
1878         {
1879           lex_match (lexer, T_EQUALS);
1880           if (lex_match_id (lexer, "INCLUDE"))
1881             c->show_empty = true;
1882           else if (lex_match_id (lexer, "EXCLUDE"))
1883             c->show_empty = false;
1884           else
1885             {
1886               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
1887               return false;
1888             }
1889         }
1890       else
1891         {
1892           if (!c->n_cats)
1893             lex_error_expecting (lexer, "ORDER", "KEY", "MISSING",
1894                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
1895           else
1896             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
1897           return false;
1898         }
1899     }
1900
1901   if (!c->n_cats)
1902     {
1903       if (c->n_cats >= allocated_cats)
1904         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1905       c->cats[c->n_cats++] = cat;
1906     }
1907
1908   if (show_totals)
1909     {
1910       if (c->n_cats >= allocated_cats)
1911         c->cats = x2nrealloc (c->cats, &allocated_cats, sizeof *c->cats);
1912
1913       struct ctables_category *totals;
1914       if (totals_before)
1915         {
1916           insert_element (c->cats, c->n_cats, sizeof *c->cats, 0);
1917           totals = &c->cats[0];
1918         }
1919       else
1920         totals = &c->cats[c->n_cats];
1921       c->n_cats++;
1922
1923       *totals = (struct ctables_category) {
1924         .type = CCT_TOTAL,
1925         .total_label = total_label ? total_label : xstrdup (_("Total")),
1926       };
1927     }
1928
1929   struct ctables_category *subtotal = NULL;
1930   for (size_t i = totals_before ? 0 : c->n_cats;
1931        totals_before ? i < c->n_cats : i-- > 0;
1932        totals_before ? i++ : 0)
1933     {
1934       struct ctables_category *cat = &c->cats[i];
1935       switch (cat->type)
1936         {
1937         case CCT_NUMBER:
1938         case CCT_STRING:
1939         case CCT_RANGE:
1940         case CCT_MISSING:
1941         case CCT_OTHERNM:
1942           cat->subtotal = subtotal;
1943           break;
1944
1945         case CCT_POSTCOMPUTE:
1946           break;
1947
1948         case CCT_SUBTOTAL:
1949           subtotal = cat;
1950           break;
1951
1952         case CCT_TOTAL:
1953         case CCT_VALUE:
1954         case CCT_LABEL:
1955         case CCT_FUNCTION:
1956         case CCT_EXCLUDED_MISSING:
1957           break;
1958         }
1959     }
1960
1961   return true;
1962 }
1963
1964 static void
1965 ctables_nest_uninit (struct ctables_nest *nest)
1966 {
1967   if (nest)
1968     free (nest->vars);
1969 }
1970
1971 static void
1972 ctables_stack_uninit (struct ctables_stack *stack)
1973 {
1974   if (stack)
1975     {
1976       for (size_t i = 0; i < stack->n; i++)
1977         ctables_nest_uninit (&stack->nests[i]);
1978       free (stack->nests);
1979     }
1980 }
1981
1982 static struct ctables_stack
1983 nest_fts (struct ctables_stack s0, struct ctables_stack s1)
1984 {
1985   if (!s0.n)
1986     return s1;
1987   else if (!s1.n)
1988     return s0;
1989
1990   struct ctables_stack stack = { .nests = xnmalloc (s0.n, s1.n * sizeof *stack.nests) };
1991   for (size_t i = 0; i < s0.n; i++)
1992     for (size_t j = 0; j < s1.n; j++)
1993       {
1994         const struct ctables_nest *a = &s0.nests[i];
1995         const struct ctables_nest *b = &s1.nests[j];
1996
1997         size_t allocate = a->n + b->n;
1998         struct variable **vars = xnmalloc (allocate, sizeof *vars);
1999         enum pivot_axis_type *axes = xnmalloc (allocate, sizeof *axes);
2000         size_t n = 0;
2001         for (size_t k = 0; k < a->n; k++)
2002           vars[n++] = a->vars[k];
2003         for (size_t k = 0; k < b->n; k++)
2004           vars[n++] = b->vars[k];
2005         assert (n == allocate);
2006
2007         const struct ctables_nest *summary_src;
2008         if (!a->specs[CSV_CELL].var)
2009           summary_src = b;
2010         else if (!b->specs[CSV_CELL].var)
2011           summary_src = a;
2012         else
2013           NOT_REACHED ();
2014
2015         struct ctables_nest *new = &stack.nests[stack.n++];
2016         *new = (struct ctables_nest) {
2017           .vars = vars,
2018           .scale_idx = (a->scale_idx != SIZE_MAX ? a->scale_idx
2019                         : b->scale_idx != SIZE_MAX ? a->n + b->scale_idx
2020                         : SIZE_MAX),
2021           .n = n,
2022         };
2023         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
2024           ctables_summary_spec_set_clone (&new->specs[sv], &summary_src->specs[sv]);
2025       }
2026   ctables_stack_uninit (&s0);
2027   ctables_stack_uninit (&s1);
2028   return stack;
2029 }
2030
2031 static struct ctables_stack
2032 stack_fts (struct ctables_stack s0, struct ctables_stack s1)
2033 {
2034   struct ctables_stack stack = { .nests = xnmalloc (s0.n + s1.n, sizeof *stack.nests) };
2035   for (size_t i = 0; i < s0.n; i++)
2036     stack.nests[stack.n++] = s0.nests[i];
2037   for (size_t i = 0; i < s1.n; i++)
2038     stack.nests[stack.n++] = s1.nests[i];
2039   assert (stack.n == s0.n + s1.n);
2040   free (s0.nests);
2041   free (s1.nests);
2042   return stack;
2043 }
2044
2045 static struct ctables_stack
2046 enumerate_fts (enum pivot_axis_type axis_type, const struct ctables_axis *a)
2047 {
2048   if (!a)
2049     return (struct ctables_stack) { .n = 0 };
2050
2051   switch (a->op)
2052     {
2053     case CTAO_VAR:
2054       assert (!a->var.is_mrset);
2055
2056       struct variable **vars = xmalloc (sizeof *vars);
2057       *vars = a->var.var;
2058
2059       struct ctables_nest *nest = xmalloc (sizeof *nest);
2060       *nest = (struct ctables_nest) {
2061         .vars = vars,
2062         .n = 1,
2063         .scale_idx = a->scale ? 0 : SIZE_MAX,
2064       };
2065       if (a->specs[CSV_CELL].n || a->scale)
2066         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
2067           {
2068             ctables_summary_spec_set_clone (&nest->specs[sv], &a->specs[sv]);
2069             nest->specs[sv].var = a->var.var;
2070             nest->specs[sv].is_scale = a->scale;
2071           }
2072       return (struct ctables_stack) { .nests = nest, .n = 1 };
2073
2074     case CTAO_STACK:
2075       return stack_fts (enumerate_fts (axis_type, a->subs[0]),
2076                         enumerate_fts (axis_type, a->subs[1]));
2077
2078     case CTAO_NEST:
2079       return nest_fts (enumerate_fts (axis_type, a->subs[0]),
2080                        enumerate_fts (axis_type, a->subs[1]));
2081     }
2082
2083   NOT_REACHED ();
2084 }
2085
2086 union ctables_summary
2087   {
2088     /* COUNT, VALIDN, TOTALN. */
2089     double count;
2090
2091     /* MINIMUM, MAXIMUM, RANGE. */
2092     struct
2093       {
2094         double min;
2095         double max;
2096       };
2097
2098     /* MEAN, SEMEAN, STDDEV, SUM, VARIANCE, *.SUM. */
2099     struct moments1 *moments;
2100
2101     /* MEDIAN, MODE, PTILE. */
2102     struct
2103       {
2104         struct casewriter *writer;
2105         double ovalid;
2106         double ovalue;
2107       };
2108
2109     /* XXX multiple response */
2110   };
2111
2112 static void
2113 ctables_summary_init (union ctables_summary *s,
2114                       const struct ctables_summary_spec *ss)
2115 {
2116   switch (ss->function)
2117     {
2118     case CTSF_COUNT:
2119     case CTSF_ECOUNT:
2120     case CTSF_ROWPCT_COUNT:
2121     case CTSF_COLPCT_COUNT:
2122     case CTSF_TABLEPCT_COUNT:
2123     case CTSF_SUBTABLEPCT_COUNT:
2124     case CTSF_LAYERPCT_COUNT:
2125     case CTSF_LAYERROWPCT_COUNT:
2126     case CTSF_LAYERCOLPCT_COUNT:
2127     case CTSF_ROWPCT_VALIDN:
2128     case CTSF_COLPCT_VALIDN:
2129     case CTSF_TABLEPCT_VALIDN:
2130     case CTSF_SUBTABLEPCT_VALIDN:
2131     case CTSF_LAYERPCT_VALIDN:
2132     case CTSF_LAYERROWPCT_VALIDN:
2133     case CTSF_LAYERCOLPCT_VALIDN:
2134     case CTSF_ROWPCT_TOTALN:
2135     case CTSF_COLPCT_TOTALN:
2136     case CTSF_TABLEPCT_TOTALN:
2137     case CTSF_SUBTABLEPCT_TOTALN:
2138     case CTSF_LAYERPCT_TOTALN:
2139     case CTSF_LAYERROWPCT_TOTALN:
2140     case CTSF_LAYERCOLPCT_TOTALN:
2141     case CTSF_MISSING:
2142     case CSTF_TOTALN:
2143     case CTSF_ETOTALN:
2144     case CTSF_VALIDN:
2145     case CTSF_EVALIDN:
2146       s->count = 0;
2147       break;
2148
2149     case CTSF_MAXIMUM:
2150     case CTSF_MINIMUM:
2151     case CTSF_RANGE:
2152       s->min = s->max = SYSMIS;
2153       break;
2154
2155     case CTSF_MEAN:
2156     case CTSF_SEMEAN:
2157     case CTSF_STDDEV:
2158     case CTSF_SUM:
2159     case CTSF_VARIANCE:
2160     case CTSF_ROWPCT_SUM:
2161     case CTSF_COLPCT_SUM:
2162     case CTSF_TABLEPCT_SUM:
2163     case CTSF_SUBTABLEPCT_SUM:
2164     case CTSF_LAYERPCT_SUM:
2165     case CTSF_LAYERROWPCT_SUM:
2166     case CTSF_LAYERCOLPCT_SUM:
2167       s->moments = moments1_create (MOMENT_VARIANCE);
2168       break;
2169
2170     case CTSF_MEDIAN:
2171     case CTSF_MODE:
2172     case CTSF_PTILE:
2173       {
2174         struct caseproto *proto = caseproto_create ();
2175         proto = caseproto_add_width (proto, 0);
2176         proto = caseproto_add_width (proto, 0);
2177
2178         struct subcase ordering;
2179         subcase_init (&ordering, 0, 0, SC_ASCEND);
2180         s->writer = sort_create_writer (&ordering, proto);
2181         subcase_uninit (&ordering);
2182         caseproto_unref (proto);
2183
2184         s->ovalid = 0;
2185         s->ovalue = SYSMIS;
2186       }
2187       break;
2188     }
2189 }
2190
2191 static void UNUSED
2192 ctables_summary_uninit (union ctables_summary *s,
2193                         const struct ctables_summary_spec *ss)
2194 {
2195   switch (ss->function)
2196     {
2197     case CTSF_COUNT:
2198     case CTSF_ECOUNT:
2199     case CTSF_ROWPCT_COUNT:
2200     case CTSF_COLPCT_COUNT:
2201     case CTSF_TABLEPCT_COUNT:
2202     case CTSF_SUBTABLEPCT_COUNT:
2203     case CTSF_LAYERPCT_COUNT:
2204     case CTSF_LAYERROWPCT_COUNT:
2205     case CTSF_LAYERCOLPCT_COUNT:
2206     case CTSF_ROWPCT_VALIDN:
2207     case CTSF_COLPCT_VALIDN:
2208     case CTSF_TABLEPCT_VALIDN:
2209     case CTSF_SUBTABLEPCT_VALIDN:
2210     case CTSF_LAYERPCT_VALIDN:
2211     case CTSF_LAYERROWPCT_VALIDN:
2212     case CTSF_LAYERCOLPCT_VALIDN:
2213     case CTSF_ROWPCT_TOTALN:
2214     case CTSF_COLPCT_TOTALN:
2215     case CTSF_TABLEPCT_TOTALN:
2216     case CTSF_SUBTABLEPCT_TOTALN:
2217     case CTSF_LAYERPCT_TOTALN:
2218     case CTSF_LAYERROWPCT_TOTALN:
2219     case CTSF_LAYERCOLPCT_TOTALN:
2220     case CTSF_MISSING:
2221     case CSTF_TOTALN:
2222     case CTSF_ETOTALN:
2223     case CTSF_VALIDN:
2224     case CTSF_EVALIDN:
2225       break;
2226
2227     case CTSF_MAXIMUM:
2228     case CTSF_MINIMUM:
2229     case CTSF_RANGE:
2230       break;
2231
2232     case CTSF_MEAN:
2233     case CTSF_SEMEAN:
2234     case CTSF_STDDEV:
2235     case CTSF_SUM:
2236     case CTSF_VARIANCE:
2237     case CTSF_ROWPCT_SUM:
2238     case CTSF_COLPCT_SUM:
2239     case CTSF_TABLEPCT_SUM:
2240     case CTSF_SUBTABLEPCT_SUM:
2241     case CTSF_LAYERPCT_SUM:
2242     case CTSF_LAYERROWPCT_SUM:
2243     case CTSF_LAYERCOLPCT_SUM:
2244       moments1_destroy (s->moments);
2245       break;
2246
2247     case CTSF_MEDIAN:
2248     case CTSF_MODE:
2249     case CTSF_PTILE:
2250       casewriter_destroy (s->writer);
2251       break;
2252     }
2253 }
2254
2255 static void
2256 ctables_summary_add (const struct ctables_cell *cell, union ctables_summary *s,
2257                      const struct ctables_summary_spec *ss,
2258                      const struct variable *var, const union value *value,
2259                      bool is_scale, bool is_missing,
2260                      double d_weight, double e_weight)
2261 {
2262   /* To determine whether a case is included in a given table for a particular
2263      kind of summary, consider the following charts for each variable in the
2264      table.  Only if "yes" appears for every variable for the summary is the
2265      case counted.
2266
2267      Categorical variables:                    VALIDN   COUNT   TOTALN
2268        Valid values in included categories       yes     yes      yes
2269        Missing values in included categories     ---     yes      yes
2270        Missing values in excluded categories     ---     ---      yes
2271        Valid values in excluded categories       ---     ---      ---
2272
2273      Scale variables:                          VALIDN   COUNT   TOTALN
2274        Valid value                               yes     yes      yes
2275        Missing value                             ---     yes      yes
2276
2277      Missing values include both user- and system-missing.  (The system-missing
2278      value is always in an excluded category.)
2279   */
2280   switch (ss->function)
2281     {
2282     case CSTF_TOTALN:
2283       s->count += d_weight;
2284       break;
2285
2286     case CTSF_COUNT:
2287       if (is_scale || !cell->excluded_missing)
2288         s->count += d_weight;
2289       break;
2290
2291     case CTSF_VALIDN:
2292       if (is_scale
2293           ? !var_is_value_missing (var, value)
2294           : !is_missing)
2295         s->count += d_weight;
2296       break;
2297
2298     case CTSF_MISSING:
2299       if (is_missing)
2300         s->count += d_weight;
2301       break;
2302
2303     case CTSF_ECOUNT:
2304     case CTSF_ROWPCT_COUNT:
2305     case CTSF_COLPCT_COUNT:
2306     case CTSF_TABLEPCT_COUNT:
2307     case CTSF_SUBTABLEPCT_COUNT:
2308     case CTSF_LAYERPCT_COUNT:
2309     case CTSF_LAYERROWPCT_COUNT:
2310     case CTSF_LAYERCOLPCT_COUNT:
2311     case CTSF_ROWPCT_VALIDN:
2312     case CTSF_COLPCT_VALIDN:
2313     case CTSF_TABLEPCT_VALIDN:
2314     case CTSF_SUBTABLEPCT_VALIDN:
2315     case CTSF_LAYERPCT_VALIDN:
2316     case CTSF_LAYERROWPCT_VALIDN:
2317     case CTSF_LAYERCOLPCT_VALIDN:
2318     case CTSF_ROWPCT_TOTALN:
2319     case CTSF_COLPCT_TOTALN:
2320     case CTSF_TABLEPCT_TOTALN:
2321     case CTSF_SUBTABLEPCT_TOTALN:
2322     case CTSF_LAYERPCT_TOTALN:
2323     case CTSF_LAYERROWPCT_TOTALN:
2324     case CTSF_LAYERCOLPCT_TOTALN:
2325       s->count += d_weight;
2326       break;
2327
2328     case CTSF_EVALIDN:
2329       if (is_scale
2330           ? !var_is_value_missing (var, value)
2331           : !is_missing)
2332         s->count += e_weight;
2333       break;
2334
2335     case CTSF_ETOTALN:
2336       s->count += e_weight;
2337       break;
2338
2339     case CTSF_MAXIMUM:
2340     case CTSF_MINIMUM:
2341     case CTSF_RANGE:
2342       if (!var_is_value_missing (var, value))
2343         {
2344           assert (!var_is_alpha (var)); /* XXX? */
2345           if (s->min == SYSMIS || value->f < s->min)
2346             s->min = value->f;
2347           if (s->max == SYSMIS || value->f > s->max)
2348             s->max = value->f;
2349         }
2350       break;
2351
2352     case CTSF_MEAN:
2353     case CTSF_SEMEAN:
2354     case CTSF_STDDEV:
2355     case CTSF_SUM:
2356     case CTSF_VARIANCE:
2357     case CTSF_ROWPCT_SUM:
2358     case CTSF_COLPCT_SUM:
2359     case CTSF_TABLEPCT_SUM:
2360     case CTSF_SUBTABLEPCT_SUM:
2361     case CTSF_LAYERPCT_SUM:
2362     case CTSF_LAYERROWPCT_SUM:
2363     case CTSF_LAYERCOLPCT_SUM:
2364       if (!var_is_value_missing (var, value))
2365         moments1_add (s->moments, value->f, e_weight);
2366       break;
2367
2368     case CTSF_MEDIAN:
2369     case CTSF_MODE:
2370     case CTSF_PTILE:
2371       if (var_is_value_missing (var, value))
2372         {
2373           s->ovalid += e_weight;
2374
2375           struct ccase *c = case_create (casewriter_get_proto (s->writer));
2376           *case_num_rw_idx (c, 0) = value->f;
2377           *case_num_rw_idx (c, 1) = e_weight;
2378           casewriter_write (s->writer, c);
2379         }
2380       break;
2381     }
2382 }
2383
2384 static enum ctables_domain_type
2385 ctables_function_domain (enum ctables_summary_function function)
2386 {
2387   switch (function)
2388     {
2389     case CTSF_COUNT:
2390     case CTSF_ECOUNT:
2391     case CTSF_MISSING:
2392     case CSTF_TOTALN:
2393     case CTSF_ETOTALN:
2394     case CTSF_VALIDN:
2395     case CTSF_EVALIDN:
2396     case CTSF_MAXIMUM:
2397     case CTSF_MINIMUM:
2398     case CTSF_RANGE:
2399     case CTSF_MEAN:
2400     case CTSF_SEMEAN:
2401     case CTSF_STDDEV:
2402     case CTSF_SUM:
2403     case CTSF_VARIANCE:
2404     case CTSF_MEDIAN:
2405     case CTSF_PTILE:
2406     case CTSF_MODE:
2407       NOT_REACHED ();
2408
2409     case CTSF_COLPCT_COUNT:
2410     case CTSF_COLPCT_SUM:
2411     case CTSF_COLPCT_TOTALN:
2412     case CTSF_COLPCT_VALIDN:
2413       return CTDT_COL;
2414
2415     case CTSF_LAYERCOLPCT_COUNT:
2416     case CTSF_LAYERCOLPCT_SUM:
2417     case CTSF_LAYERCOLPCT_TOTALN:
2418     case CTSF_LAYERCOLPCT_VALIDN:
2419       return CTDT_LAYERCOL;
2420
2421     case CTSF_LAYERPCT_COUNT:
2422     case CTSF_LAYERPCT_SUM:
2423     case CTSF_LAYERPCT_TOTALN:
2424     case CTSF_LAYERPCT_VALIDN:
2425       return CTDT_LAYER;
2426
2427     case CTSF_LAYERROWPCT_COUNT:
2428     case CTSF_LAYERROWPCT_SUM:
2429     case CTSF_LAYERROWPCT_TOTALN:
2430     case CTSF_LAYERROWPCT_VALIDN:
2431       return CTDT_LAYERROW;
2432
2433     case CTSF_ROWPCT_COUNT:
2434     case CTSF_ROWPCT_SUM:
2435     case CTSF_ROWPCT_TOTALN:
2436     case CTSF_ROWPCT_VALIDN:
2437       return CTDT_ROW;
2438
2439     case CTSF_SUBTABLEPCT_COUNT:
2440     case CTSF_SUBTABLEPCT_SUM:
2441     case CTSF_SUBTABLEPCT_TOTALN:
2442     case CTSF_SUBTABLEPCT_VALIDN:
2443       return CTDT_SUBTABLE;
2444
2445     case CTSF_TABLEPCT_COUNT:
2446     case CTSF_TABLEPCT_SUM:
2447     case CTSF_TABLEPCT_TOTALN:
2448     case CTSF_TABLEPCT_VALIDN:
2449       return CTDT_TABLE;
2450     }
2451
2452   NOT_REACHED ();
2453 }
2454
2455 static double
2456 ctables_summary_value (const struct ctables_cell *cell,
2457                        union ctables_summary *s,
2458                        const struct ctables_summary_spec *ss)
2459 {
2460   switch (ss->function)
2461     {
2462     case CTSF_COUNT:
2463     case CTSF_ECOUNT:
2464       return s->count;
2465
2466     case CTSF_ROWPCT_COUNT:
2467     case CTSF_COLPCT_COUNT:
2468     case CTSF_TABLEPCT_COUNT:
2469     case CTSF_SUBTABLEPCT_COUNT:
2470     case CTSF_LAYERPCT_COUNT:
2471     case CTSF_LAYERROWPCT_COUNT:
2472     case CTSF_LAYERCOLPCT_COUNT:
2473       {
2474         enum ctables_domain_type d = ctables_function_domain (ss->function);
2475         return (cell->domains[d]->e_valid
2476                 ? s->count / cell->domains[d]->e_valid * 100
2477                 : SYSMIS);
2478       }
2479
2480     case CTSF_ROWPCT_VALIDN:
2481     case CTSF_COLPCT_VALIDN:
2482     case CTSF_TABLEPCT_VALIDN:
2483     case CTSF_SUBTABLEPCT_VALIDN:
2484     case CTSF_LAYERPCT_VALIDN:
2485     case CTSF_LAYERROWPCT_VALIDN:
2486     case CTSF_LAYERCOLPCT_VALIDN:
2487     case CTSF_ROWPCT_TOTALN:
2488     case CTSF_COLPCT_TOTALN:
2489     case CTSF_TABLEPCT_TOTALN:
2490     case CTSF_SUBTABLEPCT_TOTALN:
2491     case CTSF_LAYERPCT_TOTALN:
2492     case CTSF_LAYERROWPCT_TOTALN:
2493     case CTSF_LAYERCOLPCT_TOTALN:
2494       NOT_REACHED ();
2495
2496     case CTSF_MISSING:
2497       return s->count;
2498
2499     case CSTF_TOTALN:
2500     case CTSF_ETOTALN:
2501       return s->count;
2502
2503     case CTSF_VALIDN:
2504       return s->count;
2505
2506     case CTSF_EVALIDN:
2507       return s->count;
2508
2509     case CTSF_MAXIMUM:
2510       return s->max;
2511
2512     case CTSF_MINIMUM:
2513       return s->min;
2514
2515     case CTSF_RANGE:
2516       return s->max != SYSMIS && s->min != SYSMIS ? s->max - s->min : SYSMIS;
2517
2518     case CTSF_MEAN:
2519       {
2520         double mean;
2521         moments1_calculate (s->moments, NULL, &mean, NULL, NULL, NULL);
2522         return mean;
2523       }
2524
2525     case CTSF_SEMEAN:
2526       {
2527         double weight, variance;
2528         moments1_calculate (s->moments, &weight, NULL, &variance, NULL, NULL);
2529         return calc_semean (variance, weight);
2530       }
2531
2532     case CTSF_STDDEV:
2533       {
2534         double variance;
2535         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2536         return variance != SYSMIS ? sqrt (variance) : SYSMIS;
2537       }
2538
2539     case CTSF_SUM:
2540       {
2541         double weight, mean;
2542         moments1_calculate (s->moments, &weight, &mean, NULL, NULL, NULL);
2543         return weight != SYSMIS && mean != SYSMIS ? weight * mean : SYSMIS;
2544       }
2545
2546     case CTSF_VARIANCE:
2547       {
2548         double variance;
2549         moments1_calculate (s->moments, NULL, NULL, &variance, NULL, NULL);
2550         return variance;
2551       }
2552
2553     case CTSF_ROWPCT_SUM:
2554     case CTSF_COLPCT_SUM:
2555     case CTSF_TABLEPCT_SUM:
2556     case CTSF_SUBTABLEPCT_SUM:
2557     case CTSF_LAYERPCT_SUM:
2558     case CTSF_LAYERROWPCT_SUM:
2559     case CTSF_LAYERCOLPCT_SUM:
2560       NOT_REACHED ();
2561
2562     case CTSF_MEDIAN:
2563     case CTSF_PTILE:
2564       if (s->writer)
2565         {
2566           struct casereader *reader = casewriter_make_reader (s->writer);
2567           s->writer = NULL;
2568
2569           struct percentile *ptile = percentile_create (
2570             ss->function == CTSF_PTILE ? ss->percentile : 0.5, s->ovalid);
2571           struct order_stats *os = &ptile->parent;
2572           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2573           s->ovalue = percentile_calculate (ptile, PC_HAVERAGE);
2574           statistic_destroy (&ptile->parent.parent);
2575         }
2576       return s->ovalue;
2577
2578     case CTSF_MODE:
2579       if (s->writer)
2580         {
2581           struct casereader *reader = casewriter_make_reader (s->writer);
2582           s->writer = NULL;
2583
2584           struct mode *mode = mode_create ();
2585           struct order_stats *os = &mode->parent;
2586           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
2587           s->ovalue = mode->mode;
2588           statistic_destroy (&mode->parent.parent);
2589         }
2590       return s->ovalue;
2591     }
2592
2593   NOT_REACHED ();
2594 }
2595
2596 struct ctables_cell_sort_aux
2597   {
2598     const struct ctables_nest *nest;
2599     enum pivot_axis_type a;
2600   };
2601
2602 static int
2603 ctables_cell_compare_3way (const void *a_, const void *b_, const void *aux_)
2604 {
2605   const struct ctables_cell_sort_aux *aux = aux_;
2606   struct ctables_cell *const *ap = a_;
2607   struct ctables_cell *const *bp = b_;
2608   const struct ctables_cell *a = *ap;
2609   const struct ctables_cell *b = *bp;
2610
2611   const struct ctables_nest *nest = aux->nest;
2612   for (size_t i = 0; i < nest->n; i++)
2613     if (i != nest->scale_idx)
2614       {
2615         const struct variable *var = nest->vars[i];
2616         const struct ctables_cell_value *a_cv = &a->axes[aux->a].cvs[i];
2617         const struct ctables_cell_value *b_cv = &b->axes[aux->a].cvs[i];
2618         if (a_cv->category != b_cv->category)
2619           return a_cv->category > b_cv->category ? 1 : -1;
2620
2621         const union value *a_val = &a_cv->value;
2622         const union value *b_val = &b_cv->value;
2623         switch (a_cv->category->type)
2624           {
2625           case CCT_NUMBER:
2626           case CCT_STRING:
2627           case CCT_SUBTOTAL:
2628           case CCT_TOTAL:
2629           case CCT_POSTCOMPUTE:
2630           case CCT_EXCLUDED_MISSING:
2631             /* Must be equal. */
2632             continue;
2633
2634           case CCT_RANGE:
2635           case CCT_MISSING:
2636           case CCT_OTHERNM:
2637             {
2638               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2639               if (cmp)
2640                 return cmp;
2641             }
2642             break;
2643
2644           case CCT_VALUE:
2645             {
2646               int cmp = value_compare_3way (a_val, b_val, var_get_width (var));
2647               if (cmp)
2648                 return a_cv->category->sort_ascending ? cmp : -cmp;
2649             }
2650             break;
2651
2652           case CCT_LABEL:
2653             {
2654               const char *a_label = var_lookup_value_label (var, a_val);
2655               const char *b_label = var_lookup_value_label (var, b_val);
2656               int cmp = (a_label
2657                          ? (b_label ? strcmp (a_label, b_label) : 1)
2658                          : (b_label ? -1 : value_compare_3way (
2659                               a_val, b_val, var_get_width (var))));
2660               if (cmp)
2661                 return a_cv->category->sort_ascending ? cmp : -cmp;
2662             }
2663             break;
2664
2665           case CCT_FUNCTION:
2666             NOT_REACHED ();
2667           }
2668       }
2669   return 0;
2670 }
2671
2672 /* Algorithm:
2673
2674    For each row:
2675        For each ctables_table:
2676            For each combination of row vars:
2677                For each combination of column vars:
2678                    For each combination of layer vars:
2679                        Add entry
2680    Make a table of row values:
2681        Sort entries by row values
2682        Assign a 0-based index to each actual value
2683        Construct a dimension
2684    Make a table of column values
2685    Make a table of layer values
2686    For each entry:
2687        Fill the table entry using the indexes from before.
2688  */
2689
2690 static struct ctables_domain *
2691 ctables_domain_insert (struct ctables_section *s, struct ctables_cell *cell,
2692                        enum ctables_domain_type domain)
2693 {
2694   size_t hash = 0;
2695   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2696     {
2697       const struct ctables_nest *nest = s->nests[a];
2698       for (size_t i = 0; i < nest->n_domains[domain]; i++)
2699         {
2700           size_t v_idx = nest->domains[domain][i];
2701           hash = value_hash (&cell->axes[a].cvs[v_idx].value,
2702                              var_get_width (nest->vars[v_idx]), hash);
2703         }
2704     }
2705
2706   struct ctables_domain *d;
2707   HMAP_FOR_EACH_WITH_HASH (d, struct ctables_domain, node, hash, &s->domains[domain])
2708     {
2709       const struct ctables_cell *df = d->example;
2710       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2711         {
2712           const struct ctables_nest *nest = s->nests[a];
2713           for (size_t i = 0; i < nest->n_domains[domain]; i++)
2714             {
2715               size_t v_idx = nest->domains[domain][i];
2716               if (!value_equal (&df->axes[a].cvs[v_idx].value,
2717                                 &cell->axes[a].cvs[v_idx].value,
2718                                 var_get_width (nest->vars[v_idx])))
2719                 goto not_equal;
2720             }
2721         }
2722       return d;
2723
2724     not_equal: ;
2725     }
2726
2727   d = xmalloc (sizeof *d);
2728   *d = (struct ctables_domain) { .example = cell };
2729   hmap_insert (&s->domains[domain], &d->node, hash);
2730   return d;
2731 }
2732
2733 static const struct ctables_category *
2734 ctables_categories_match (const struct ctables_categories *c,
2735                           const union value *v, const struct variable *var)
2736 {
2737   if (var_is_numeric (var) && v->f == SYSMIS)
2738     return NULL;
2739
2740   const struct ctables_category *othernm = NULL;
2741   for (size_t i = c->n_cats; i-- > 0; )
2742     {
2743       const struct ctables_category *cat = &c->cats[i];
2744       switch (cat->type)
2745         {
2746         case CCT_NUMBER:
2747           if (cat->number == v->f)
2748             return cat;
2749           break;
2750
2751         case CCT_STRING:
2752           NOT_REACHED ();
2753
2754         case CCT_RANGE:
2755           if ((cat->range[0] == -DBL_MAX || v->f >= cat->range[0])
2756               && (cat->range[1] == DBL_MAX || v->f <= cat->range[1]))
2757             return cat;
2758           break;
2759
2760         case CCT_MISSING:
2761           if (var_is_value_missing (var, v))
2762             return cat;
2763           break;
2764
2765         case CCT_POSTCOMPUTE:
2766           break;
2767
2768         case CCT_OTHERNM:
2769           if (!othernm)
2770             othernm = cat;
2771           break;
2772
2773         case CCT_SUBTOTAL:
2774         case CCT_TOTAL:
2775           break;
2776
2777         case CCT_VALUE:
2778         case CCT_LABEL:
2779         case CCT_FUNCTION:
2780           return (cat->include_missing || !var_is_value_missing (var, v) ? cat
2781                   : NULL);
2782
2783         case CCT_EXCLUDED_MISSING:
2784           break;
2785         }
2786     }
2787
2788   return var_is_value_missing (var, v) ? NULL : othernm;
2789 }
2790
2791 static const struct ctables_category *
2792 ctables_categories_total (const struct ctables_categories *c)
2793 {
2794   const struct ctables_category *first = &c->cats[0];
2795   const struct ctables_category *last = &c->cats[c->n_cats - 1];
2796   return (first->type == CCT_TOTAL ? first
2797           : last->type == CCT_TOTAL ? last
2798           : NULL);
2799 }
2800
2801 static struct ctables_cell *
2802 ctables_cell_insert__ (struct ctables_section *s, const struct ccase *c,
2803                        const struct ctables_category *cats[PIVOT_N_AXES][10])
2804 {
2805   size_t hash = 0;
2806   enum ctables_summary_variant sv = CSV_CELL;
2807   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2808     {
2809       const struct ctables_nest *nest = s->nests[a];
2810       for (size_t i = 0; i < nest->n; i++)
2811         if (i != nest->scale_idx)
2812           {
2813             hash = hash_pointer (cats[a][i], hash);
2814             if (cats[a][i]->type != CCT_TOTAL
2815                 && cats[a][i]->type != CCT_SUBTOTAL
2816                 && cats[a][i]->type != CCT_POSTCOMPUTE)
2817               hash = value_hash (case_data (c, nest->vars[i]),
2818                                  var_get_width (nest->vars[i]), hash);
2819             else
2820               sv = CSV_TOTAL;
2821           }
2822     }
2823
2824   struct ctables_cell *cell;
2825   HMAP_FOR_EACH_WITH_HASH (cell, struct ctables_cell, node, hash, &s->cells)
2826     {
2827       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2828         {
2829           const struct ctables_nest *nest = s->nests[a];
2830           for (size_t i = 0; i < nest->n; i++)
2831             if (i != nest->scale_idx
2832                 && (cats[a][i] != cell->axes[a].cvs[i].category
2833                     || (cats[a][i]->type != CCT_TOTAL
2834                         && cats[a][i]->type != CCT_SUBTOTAL
2835                         && cats[a][i]->type != CCT_POSTCOMPUTE
2836                         && !value_equal (case_data (c, nest->vars[i]),
2837                                          &cell->axes[a].cvs[i].value,
2838                                          var_get_width (nest->vars[i])))))
2839                 goto not_equal;
2840         }
2841
2842       return cell;
2843
2844     not_equal: ;
2845     }
2846
2847   cell = xmalloc (sizeof *cell);
2848   cell->hide = false;
2849   cell->is_missing = false;
2850   cell->excluded_missing = false;
2851   cell->sv = sv;
2852   cell->contributes_to_domains = true;
2853   cell->postcompute = false;
2854   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
2855     {
2856       const struct ctables_nest *nest = s->nests[a];
2857       cell->axes[a].cvs = (nest->n
2858                         ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs)
2859                         : NULL);
2860       for (size_t i = 0; i < nest->n; i++)
2861         {
2862           const struct ctables_category *cat = cats[a][i];
2863           const struct variable *var = nest->vars[i];
2864           const union value *value = case_data (c, var);
2865           if (i != nest->scale_idx)
2866             {
2867               const struct ctables_category *subtotal = cat->subtotal;
2868               if (cat->hide || (subtotal && subtotal->hide_subcategories))
2869                 cell->hide = true;
2870
2871               if (cat->type == CCT_TOTAL
2872                   || cat->type == CCT_SUBTOTAL
2873                   || cat->type == CCT_POSTCOMPUTE)
2874                 cell->contributes_to_domains = false;
2875               else if (var_is_value_missing (var, value))
2876                 cell->is_missing = true;
2877               if (cat->type == CCT_EXCLUDED_MISSING)
2878                 cell->excluded_missing = true;
2879               if (cat->type == CCT_POSTCOMPUTE)
2880                 cell->postcompute = true;
2881             }
2882
2883           cell->axes[a].cvs[i].category = cat;
2884           value_clone (&cell->axes[a].cvs[i].value, value, var_get_width (var));
2885         }
2886     }
2887
2888   const struct ctables_nest *ss = s->nests[s->table->summary_axis];
2889   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2890   cell->summaries = xmalloc (specs->n * sizeof *cell->summaries);
2891   for (size_t i = 0; i < specs->n; i++)
2892     ctables_summary_init (&cell->summaries[i], &specs->specs[i]);
2893   for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2894     cell->domains[dt] = ctables_domain_insert (s, cell, dt);
2895   hmap_insert (&s->cells, &cell->node, hash);
2896   return cell;
2897 }
2898
2899 static void
2900 ctables_cell_add__ (struct ctables_section *s, const struct ccase *c,
2901                     const struct ctables_category *cats[PIVOT_N_AXES][10],
2902                     bool is_missing, double d_weight, double e_weight)
2903 {
2904   struct ctables_cell *cell = ctables_cell_insert__ (s, c, cats);
2905   const struct ctables_nest *ss = s->nests[s->table->summary_axis];
2906
2907   const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
2908   for (size_t i = 0; i < specs->n; i++)
2909     ctables_summary_add (cell, &cell->summaries[i], &specs->specs[i],
2910                          specs->var, case_data (c, specs->var), specs->is_scale,
2911                          is_missing, d_weight, e_weight);
2912   if (cell->contributes_to_domains)
2913     {
2914       for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
2915         {
2916           struct ctables_domain *d = cell->domains[dt];
2917           d->d_total += d_weight;
2918           d->e_total += e_weight;
2919           if (!cell->excluded_missing)
2920             {
2921               d->d_count += d_weight;
2922               d->e_count += e_weight;
2923             }
2924           if (!cell->is_missing)
2925             {
2926               d->d_valid += d_weight;
2927               d->e_valid += e_weight;
2928             }
2929         }
2930     }
2931 }
2932
2933 static void
2934 recurse_totals (struct ctables_section *s, const struct ccase *c,
2935                 const struct ctables_category *cats[PIVOT_N_AXES][10],
2936                 bool is_missing, double d_weight, double e_weight,
2937                 enum pivot_axis_type start_axis, size_t start_nest)
2938 {
2939   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2940     {
2941       const struct ctables_nest *nest = s->nests[a];
2942       for (size_t i = start_nest; i < nest->n; i++)
2943         {
2944           if (i == nest->scale_idx)
2945             continue;
2946
2947           const struct variable *var = nest->vars[i];
2948
2949           const struct ctables_category *total = ctables_categories_total (
2950             s->table->categories[var_get_dict_index (var)]);
2951           if (total)
2952             {
2953               const struct ctables_category *save = cats[a][i];
2954               cats[a][i] = total;
2955               ctables_cell_add__ (s, c, cats, is_missing, d_weight, e_weight);
2956               recurse_totals (s, c, cats, is_missing,
2957                               d_weight, e_weight, a, i + 1);
2958               cats[a][i] = save;
2959             }
2960         }
2961       start_nest = 0;
2962     }
2963 }
2964
2965 static void
2966 recurse_subtotals (struct ctables_section *s, const struct ccase *c,
2967                    const struct ctables_category *cats[PIVOT_N_AXES][10],
2968                    bool is_missing, double d_weight, double e_weight,
2969                    enum pivot_axis_type start_axis, size_t start_nest)
2970 {
2971   for (enum pivot_axis_type a = start_axis; a < PIVOT_N_AXES; a++)
2972     {
2973       const struct ctables_nest *nest = s->nests[a];
2974       for (size_t i = start_nest; i < nest->n; i++)
2975         {
2976           if (i == nest->scale_idx)
2977             continue;
2978
2979           const struct ctables_category *save = cats[a][i];
2980           if (save->subtotal)
2981             {
2982               cats[a][i] = save->subtotal;
2983               ctables_cell_add__ (s, c, cats, is_missing, d_weight, e_weight);
2984               recurse_subtotals (s, c, cats, is_missing,
2985                                  d_weight, e_weight, a, i + 1);
2986               cats[a][i] = save;
2987             }
2988         }
2989       start_nest = 0;
2990     }
2991 }
2992
2993 static void
2994 ctables_add_occurrence (const struct variable *var,
2995                         const union value *value,
2996                         struct hmap *occurrences)
2997 {
2998   int width = var_get_width (var);
2999   unsigned int hash = value_hash (value, width, 0);
3000
3001   struct ctables_occurrence *o;
3002   HMAP_FOR_EACH_WITH_HASH (o, struct ctables_occurrence, node, hash,
3003                            occurrences)
3004     if (value_equal (value, &o->value, width))
3005       return;
3006
3007   o = xmalloc (sizeof *o);
3008   value_clone (&o->value, value, width);
3009   hmap_insert (occurrences, &o->node, hash);
3010 }
3011
3012 static void
3013 ctables_cell_insert (struct ctables_section *s,
3014                      const struct ccase *c,
3015                      double d_weight, double e_weight)
3016 {
3017   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
3018   bool is_missing = false;
3019   bool excluded_missing = false;
3020   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3021     {
3022       const struct ctables_nest *nest = s->nests[a];
3023       for (size_t i = 0; i < nest->n; i++)
3024         {
3025           if (i == nest->scale_idx)
3026             continue;
3027
3028           const struct variable *var = nest->vars[i];
3029           const union value *value = case_data (c, var);
3030
3031           bool var_missing = var_is_value_missing (var, value) != 0;
3032           if (var_missing)
3033             is_missing = true;
3034
3035           cats[a][i] = ctables_categories_match (
3036             s->table->categories[var_get_dict_index (var)], value, var);
3037           if (!cats[a][i])
3038             {
3039               if (!is_missing)
3040                 return;
3041
3042               static const struct ctables_category cct_excluded_missing = {
3043                 .type = CCT_EXCLUDED_MISSING,
3044                 .hide = true,
3045               };
3046               cats[a][i] = &cct_excluded_missing;
3047               excluded_missing = true;
3048             }
3049         }
3050     }
3051
3052   if (!excluded_missing)
3053     for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3054       {
3055         const struct ctables_nest *nest = s->nests[a];
3056         for (size_t i = 0; i < nest->n; i++)
3057           if (i != nest->scale_idx)
3058             {
3059               const struct variable *var = nest->vars[i];
3060               const union value *value = case_data (c, var);
3061               ctables_add_occurrence (var, value, &s->occurrences[a][i]);
3062             }
3063       }
3064
3065   ctables_cell_add__ (s, c, cats, is_missing, d_weight, e_weight);
3066
3067   if (!excluded_missing)
3068     {
3069       recurse_totals (s, c, cats, is_missing, d_weight, e_weight, 0, 0);
3070       recurse_subtotals (s, c, cats, is_missing, d_weight, e_weight, 0, 0);
3071     }
3072 }
3073
3074 struct merge_item
3075   {
3076     const struct ctables_summary_spec_set *set;
3077     size_t ofs;
3078   };
3079
3080 static int
3081 merge_item_compare_3way (const struct merge_item *a, const struct merge_item *b)
3082 {
3083   const struct ctables_summary_spec *as = &a->set->specs[a->ofs];
3084   const struct ctables_summary_spec *bs = &b->set->specs[b->ofs];
3085   if (as->function != bs->function)
3086     return as->function > bs->function ? 1 : -1;
3087   else if (as->percentile != bs->percentile)
3088     return as->percentile < bs->percentile ? 1 : -1;
3089   return strcmp (as->label, bs->label);
3090 }
3091
3092 static struct pivot_value *
3093 ctables_category_create_label (const struct ctables_category *cat,
3094                                const struct variable *var,
3095                                const union value *value)
3096 {
3097   return (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL
3098           ? pivot_value_new_user_text (cat->total_label, SIZE_MAX)
3099           : cat->type == CCT_POSTCOMPUTE && cat->pc->label
3100           ? pivot_value_new_user_text (cat->pc->label, SIZE_MAX)
3101           : pivot_value_new_var_value (var, value));
3102 }
3103
3104 static struct ctables_value *
3105 ctables_value_find__ (struct ctables_table *t, const union value *value,
3106                       int width, unsigned int hash)
3107 {
3108   struct ctables_value *clv;
3109   HMAP_FOR_EACH_WITH_HASH (clv, struct ctables_value, node,
3110                            hash, &t->clabels_values_map)
3111     if (value_equal (value, &clv->value, width))
3112       return clv;
3113   return NULL;
3114 }
3115
3116 static void
3117 ctables_value_insert (struct ctables_table *t, const union value *value,
3118                       int width)
3119 {
3120   unsigned int hash = value_hash (value, width, 0);
3121   struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
3122   if (!clv)
3123     {
3124       clv = xmalloc (sizeof *clv);
3125       value_clone (&clv->value, value, width);
3126       hmap_insert (&t->clabels_values_map, &clv->node, hash);
3127     }
3128 }
3129
3130 static struct ctables_value *
3131 ctables_value_find (struct ctables_table *t,
3132                     const union value *value, int width)
3133 {
3134   return ctables_value_find__ (t, value, width,
3135                                value_hash (value, width, 0));
3136 }
3137
3138 static void
3139 ctables_table_add_section (struct ctables_table *t, enum pivot_axis_type a,
3140                            size_t ix[PIVOT_N_AXES])
3141 {
3142   if (a < PIVOT_N_AXES)
3143     {
3144       size_t limit = MAX (t->stacks[a].n, 1);
3145       for (ix[a] = 0; ix[a] < limit; ix[a]++)
3146         ctables_table_add_section (t, a + 1, ix);
3147     }
3148   else
3149     {
3150       struct ctables_section *s = &t->sections[t->n_sections++];
3151       *s = (struct ctables_section) {
3152         .table = t,
3153         .cells = HMAP_INITIALIZER (s->cells),
3154       };
3155       for (a = 0; a < PIVOT_N_AXES; a++)
3156         if (t->stacks[a].n)
3157           {
3158             struct ctables_nest *nest = &t->stacks[a].nests[ix[a]];
3159             s->nests[a] = nest;
3160             s->occurrences[a] = xnmalloc (nest->n, sizeof *s->occurrences[a]);
3161             for (size_t i = 0; i < nest->n; i++)
3162               hmap_init (&s->occurrences[a][i]);
3163         }
3164       for (size_t i = 0; i < N_CTDTS; i++)
3165         hmap_init (&s->domains[i]);
3166     }
3167 }
3168
3169 static double
3170 ctpo_add (double a, double b)
3171 {
3172   return a + b;
3173 }
3174
3175 static double
3176 ctpo_sub (double a, double b)
3177 {
3178   return a - b;
3179 }
3180
3181 static double
3182 ctpo_mul (double a, double b)
3183 {
3184   return a * b;
3185 }
3186
3187 static double
3188 ctpo_div (double a, double b)
3189 {
3190   return b ? a / b : SYSMIS;
3191 }
3192
3193 static double
3194 ctpo_pow (double a, double b)
3195 {
3196   int save_errno = errno;
3197   errno = 0;
3198   double result = pow (a, b);
3199   if (errno)
3200     result = SYSMIS;
3201   errno = save_errno;
3202   return result;
3203 }
3204
3205 static double
3206 ctpo_neg (double a, double b UNUSED)
3207 {
3208   return -a;
3209 }
3210
3211 struct ctables_pcexpr_evaluate_ctx
3212   {
3213     const struct ctables_cell *cell;
3214     const struct ctables_section *section;
3215     const struct ctables_categories *cats;
3216     enum pivot_axis_type pc_a;
3217     size_t pc_a_idx;
3218   };
3219
3220 static double ctables_pcexpr_evaluate (
3221   const struct ctables_pcexpr_evaluate_ctx *, const struct ctables_pcexpr *);
3222
3223 static double
3224 ctables_pcexpr_evaluate_nonterminal (
3225   const struct ctables_pcexpr_evaluate_ctx *ctx,
3226   const struct ctables_pcexpr *e, size_t n_args,
3227   double evaluate (double, double))
3228 {
3229   double args[2] = { 0, 0 };
3230   for (size_t i = 0; i < n_args; i++)
3231     {
3232       args[i] = ctables_pcexpr_evaluate (ctx, e->subs[i]);
3233       if (!isfinite (args[i]) || args[i] == SYSMIS)
3234         return SYSMIS;
3235     }
3236   return evaluate (args[0], args[1]);
3237 }
3238
3239 static double
3240 ctables_pcexpr_evaluate_category (const struct ctables_pcexpr_evaluate_ctx *ctx,
3241                                   const struct ctables_cell_value *pc_cv)
3242 {
3243   const struct ctables_section *s = ctx->section;
3244
3245   size_t hash = 0;
3246   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3247     {
3248       const struct ctables_nest *nest = s->nests[a];
3249       for (size_t i = 0; i < nest->n; i++)
3250         if (i != nest->scale_idx)
3251           {
3252             const struct ctables_cell_value *cv
3253               = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3254                  : &ctx->cell->axes[a].cvs[i]);
3255             hash = hash_pointer (cv->category, hash);
3256             if (cv->category->type != CCT_TOTAL
3257                 && cv->category->type != CCT_SUBTOTAL
3258                 && cv->category->type != CCT_POSTCOMPUTE)
3259               hash = value_hash (&cv->value,
3260                                  var_get_width (nest->vars[i]), hash);
3261           }
3262     }
3263
3264   struct ctables_cell *tc;
3265   HMAP_FOR_EACH_WITH_HASH (tc, struct ctables_cell, node, hash, &s->cells)
3266     {
3267       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3268         {
3269           const struct ctables_nest *nest = s->nests[a];
3270           for (size_t i = 0; i < nest->n; i++)
3271             if (i != nest->scale_idx)
3272               {
3273                 const struct ctables_cell_value *p_cv
3274                   = (a == ctx->pc_a && i == ctx->pc_a_idx ? pc_cv
3275                      : &ctx->cell->axes[a].cvs[i]);
3276                 const struct ctables_cell_value *t_cv = &tc->axes[a].cvs[i];
3277                 if (p_cv->category != t_cv->category
3278                     || (p_cv->category->type != CCT_TOTAL
3279                         && p_cv->category->type != CCT_SUBTOTAL
3280                         && p_cv->category->type != CCT_POSTCOMPUTE
3281                         && !value_equal (&p_cv->value,
3282                                          &t_cv->value,
3283                                          var_get_width (nest->vars[i]))))
3284                   goto not_equal;
3285               }
3286         }
3287
3288       goto found;
3289
3290     not_equal: ;
3291     }
3292   return 0;
3293
3294 found: ;
3295   const struct ctables_table *t = s->table;
3296   const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
3297   const struct ctables_summary_spec_set *specs = &specs_nest->specs[tc->sv];
3298   size_t j = 0 /* XXX */;
3299   return ctables_summary_value (tc, &tc->summaries[j], &specs->specs[j]);
3300 }
3301
3302 static double
3303 ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
3304                          const struct ctables_pcexpr *e)
3305 {
3306   switch (e->op)
3307     {
3308     case CTPO_CONSTANT:
3309       return e->number;
3310
3311     case CTPO_CAT_RANGE:
3312       {
3313         struct ctables_cell_value cv = {
3314           .category = ctables_find_category_for_postcompute (ctx->cats, e)
3315         };
3316         assert (cv.category != NULL);
3317
3318         struct hmap *occurrences = &ctx->section->occurrences[ctx->pc_a][ctx->pc_a_idx];
3319         const struct ctables_occurrence *o;
3320
3321         double sum = 0.0;
3322         const struct variable *var = ctx->section->nests[ctx->pc_a]->vars[ctx->pc_a_idx];
3323         HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
3324           if (ctables_categories_match (ctx->cats, &o->value, var) == cv.category)
3325             {
3326               cv.value = o->value;
3327               sum += ctables_pcexpr_evaluate_category (ctx, &cv);
3328             }
3329         return sum;
3330       }
3331
3332     case CTPO_CAT_NUMBER:
3333     case CTPO_CAT_STRING:
3334     case CTPO_CAT_MISSING:
3335     case CTPO_CAT_OTHERNM:
3336     case CTPO_CAT_SUBTOTAL:
3337     case CTPO_CAT_TOTAL:
3338       {
3339         struct ctables_cell_value cv = {
3340           .category = ctables_find_category_for_postcompute (ctx->cats, e),
3341           .value = { .f = e->number },
3342         };
3343         assert (cv.category != NULL);
3344         return ctables_pcexpr_evaluate_category (ctx, &cv);
3345       }
3346
3347     case CTPO_ADD:
3348       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_add);
3349
3350     case CTPO_SUB:
3351       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_sub);
3352
3353     case CTPO_MUL:
3354       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_mul);
3355
3356     case CTPO_DIV:
3357       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_div);
3358
3359     case CTPO_POW:
3360       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_pow);
3361
3362     case CTPO_NEG:
3363       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 1, ctpo_neg);
3364     }
3365
3366   NOT_REACHED ();
3367 }
3368
3369 static double
3370 ctables_cell_calculate_postcompute (const struct ctables_section *s,
3371                                     const struct ctables_cell *cell)
3372 {
3373   enum pivot_axis_type pc_a;
3374   size_t pc_a_idx;
3375   const struct ctables_postcompute *pc;
3376   for (pc_a = 0; ; pc_a++)
3377     {
3378       assert (pc_a < PIVOT_N_AXES);
3379       for (pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++)
3380         {
3381           const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx];
3382           if (cv->category->type == CCT_POSTCOMPUTE)
3383             {
3384               pc = cv->category->pc;
3385               goto found;
3386             }
3387         }
3388     }
3389 found: ;
3390
3391   const struct variable *var = s->nests[pc_a]->vars[pc_a_idx];
3392   const struct ctables_categories *cats = s->table->categories[
3393     var_get_dict_index (var)];
3394   struct ctables_pcexpr_evaluate_ctx ctx = {
3395     .cell = cell,
3396     .section = s,
3397     .cats = cats,
3398     .pc_a = pc_a,
3399     .pc_a_idx = pc_a_idx,
3400   };
3401   return ctables_pcexpr_evaluate (&ctx, pc->expr);
3402 }
3403
3404 static void
3405 ctables_table_output (struct ctables *ct, struct ctables_table *t)
3406 {
3407   struct pivot_table *pt = pivot_table_create__ (
3408     (t->title
3409      ? pivot_value_new_user_text (t->title, SIZE_MAX)
3410      : pivot_value_new_text (N_("Custom Tables"))),
3411     "Custom Tables");
3412   if (t->caption)
3413     pivot_table_set_caption (
3414       pt, pivot_value_new_user_text (t->caption, SIZE_MAX));
3415   if (t->corner)
3416     pivot_table_set_caption (
3417       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
3418
3419   bool summary_dimension = (t->summary_axis != t->slabels_axis
3420                             || (!t->slabels_visible
3421                                 && t->summary_specs.n > 1));
3422   if (summary_dimension)
3423     {
3424       struct pivot_dimension *d = pivot_dimension_create (
3425         pt, t->slabels_axis, N_("Statistics"));
3426       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3427       if (!t->slabels_visible)
3428         d->hide_all_labels = true;
3429       for (size_t i = 0; i < specs->n; i++)
3430         pivot_category_create_leaf (
3431           d->root, pivot_value_new_text (specs->specs[i].label));
3432     }
3433
3434   bool categories_dimension = t->clabels_example != NULL;
3435   if (categories_dimension)
3436     {
3437       struct pivot_dimension *d = pivot_dimension_create (
3438         pt, t->label_axis[t->clabels_from_axis],
3439         t->clabels_from_axis == PIVOT_AXIS_ROW
3440         ? N_("Row Categories")
3441         : N_("Column Categories"));
3442       const struct variable *var = t->clabels_example;
3443       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
3444       for (size_t i = 0; i < t->n_clabels_values; i++)
3445         {
3446           const struct ctables_value *value = t->clabels_values[i];
3447           const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
3448           assert (cat != NULL);
3449           pivot_category_create_leaf (d->root, ctables_category_create_label (
3450                                         cat, t->clabels_example, &value->value));
3451         }
3452     }
3453
3454   pivot_table_set_look (pt, ct->look);
3455   struct pivot_dimension *d[PIVOT_N_AXES];
3456   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3457     {
3458       static const char *names[] = {
3459         [PIVOT_AXIS_ROW] = N_("Rows"),
3460         [PIVOT_AXIS_COLUMN] = N_("Columns"),
3461         [PIVOT_AXIS_LAYER] = N_("Layers"),
3462       };
3463       d[a] = (t->axes[a] || a == t->summary_axis
3464               ? pivot_dimension_create (pt, a, names[a])
3465               : NULL);
3466       if (!d[a])
3467         continue;
3468
3469       assert (t->axes[a]);
3470
3471       for (size_t i = 0; i < t->stacks[a].n; i++)
3472         {
3473           struct ctables_nest *nest = &t->stacks[a].nests[i];
3474           struct ctables_section **sections = xnmalloc (t->n_sections,
3475                                                         sizeof *sections);
3476           size_t n_sections = 0;
3477
3478           size_t n_total_cells = 0;
3479           size_t max_depth = 0;
3480           for (size_t j = 0; j < t->n_sections; j++)
3481             if (t->sections[j].nests[a] == nest)
3482               {
3483                 struct ctables_section *s = &t->sections[j];
3484                 sections[n_sections++] = s;
3485                 n_total_cells += s->cells.count;
3486
3487                 size_t depth = s->nests[a]->n;
3488                 max_depth = MAX (depth, max_depth);
3489               }
3490
3491           struct ctables_cell **sorted = xnmalloc (n_total_cells,
3492                                                    sizeof *sorted);
3493           size_t n_sorted = 0;
3494
3495           for (size_t j = 0; j < n_sections; j++)
3496             {
3497               struct ctables_section *s = sections[j];
3498
3499               struct ctables_cell *cell;
3500               HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
3501                 if (!cell->hide)
3502                   sorted[n_sorted++] = cell;
3503               assert (n_sorted <= n_total_cells);
3504             }
3505
3506           struct ctables_cell_sort_aux aux = { .nest = nest, .a = a };
3507           sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux);
3508
3509           struct ctables_level
3510             {
3511               enum ctables_level_type
3512                 {
3513                   CTL_VAR,          /* Variable label for nest->vars[var_idx]. */
3514                   CTL_CATEGORY,     /* Category for nest->vars[var_idx]. */
3515                   CTL_SUMMARY,      /* Summary functions. */
3516                 }
3517                 type;
3518
3519               enum settings_value_show vlabel; /* CTL_VAR only. */
3520               size_t var_idx;
3521             };
3522           struct ctables_level *levels = xnmalloc (1 + 2 * max_depth, sizeof *levels);
3523           size_t n_levels = 0;
3524           for (size_t k = 0; k < nest->n; k++)
3525             {
3526               enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
3527               if (vlabel != CTVL_NONE)
3528                 {
3529                   levels[n_levels++] = (struct ctables_level) {
3530                     .type = CTL_VAR,
3531                     .vlabel = (enum settings_value_show) vlabel,
3532                     .var_idx = k,
3533                   };
3534                 }
3535
3536               if (nest->scale_idx != k
3537                   && (k != nest->n - 1 || t->label_axis[a] == a))
3538                 {
3539                   levels[n_levels++] = (struct ctables_level) {
3540                     .type = CTL_CATEGORY,
3541                     .var_idx = k,
3542                   };
3543                 }
3544             }
3545
3546           if (!summary_dimension && a == t->slabels_axis)
3547             {
3548               levels[n_levels++] = (struct ctables_level) {
3549                 .type = CTL_SUMMARY,
3550                 .var_idx = SIZE_MAX,
3551               };
3552             }
3553
3554           /* Pivot categories:
3555
3556              - variable label for nest->vars[0], if vlabel != CTVL_NONE
3557              - category for nest->vars[0], if nest->scale_idx != 0
3558              - variable label for nest->vars[1], if vlabel != CTVL_NONE
3559              - category for nest->vars[1], if nest->scale_idx != 1
3560              ...
3561              - variable label for nest->vars[n - 1], if vlabel != CTVL_NONE
3562              - category for nest->vars[n - 1], if t->label_axis[a] == a && nest->scale_idx != n - 1.
3563              - summary function, if 'a == t->slabels_axis && a ==
3564              t->summary_axis'.
3565
3566              Additional dimensions:
3567
3568              - If 'a == t->slabels_axis && a != t->summary_axis', add a summary
3569              dimension.
3570              - If 't->label_axis[b] == a' for some 'b != a', add a category
3571              dimension to 'a'.
3572           */
3573
3574
3575           struct pivot_category **groups = xnmalloc (1 + 2 * max_depth, sizeof *groups);
3576           int prev_leaf = 0;
3577           for (size_t j = 0; j < n_sorted; j++)
3578             {
3579               struct ctables_cell *cell = sorted[j];
3580               struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
3581
3582               size_t n_common = 0;
3583               if (j > 0)
3584                 {
3585                   for (; n_common < n_levels; n_common++)
3586                     {
3587                       const struct ctables_level *level = &levels[n_common];
3588                       if (level->type == CTL_CATEGORY)
3589                         {
3590                           size_t var_idx = level->var_idx;
3591                           const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
3592                           if (prev->axes[a].cvs[var_idx].category != c)
3593                             break;
3594                           else if (c->type != CCT_SUBTOTAL
3595                                    && c->type != CCT_TOTAL
3596                                    && c->type != CCT_POSTCOMPUTE
3597                                    && !value_equal (&prev->axes[a].cvs[var_idx].value,
3598                                                     &cell->axes[a].cvs[var_idx].value,
3599                                                     var_get_type (nest->vars[var_idx])))
3600                             break;
3601                         }
3602                     }
3603                 }
3604
3605               for (size_t k = n_common; k < n_levels; k++)
3606                 {
3607                   const struct ctables_level *level = &levels[k];
3608                   struct pivot_category *parent = k ? groups[k - 1] : d[a]->root;
3609                   if (level->type == CTL_SUMMARY)
3610                     {
3611                       assert (k == n_levels - 1);
3612
3613                       const struct ctables_summary_spec_set *specs = &t->summary_specs;
3614                       for (size_t m = 0; m < specs->n; m++)
3615                         {
3616                           int leaf = pivot_category_create_leaf (
3617                             parent, pivot_value_new_text (specs->specs[m].label));
3618                           if (!m)
3619                             prev_leaf = leaf;
3620                         }
3621                     }
3622                   else
3623                     {
3624                       const struct variable *var = nest->vars[level->var_idx];
3625                       struct pivot_value *label;
3626                       if (level->type == CTL_VAR)
3627                         {
3628                           label = pivot_value_new_variable (var);
3629                           label->variable.show = level->vlabel;
3630                         }
3631                       else if (level->type == CTL_CATEGORY)
3632                         {
3633                           const struct ctables_cell_value *cv = &cell->axes[a].cvs[level->var_idx];
3634                           label = ctables_category_create_label (cv->category,
3635                                                                  var, &cv->value);
3636                         }
3637                       else
3638                         NOT_REACHED ();
3639
3640                       if (k == n_levels - 1)
3641                         prev_leaf = pivot_category_create_leaf (parent, label);
3642                       else
3643                         groups[k] = pivot_category_create_group__ (parent, label);
3644                     }
3645                 }
3646
3647               cell->axes[a].leaf = prev_leaf;
3648             }
3649           free (sorted);
3650           free (groups);
3651         }
3652     }
3653
3654   for (size_t i = 0; i < t->n_sections; i++)
3655     {
3656       struct ctables_section *s = &t->sections[i];
3657
3658       struct ctables_cell *cell;
3659       HMAP_FOR_EACH (cell, struct ctables_cell, node, &s->cells)
3660         {
3661           if (cell->hide)
3662             continue;
3663
3664           const struct ctables_nest *specs_nest = s->nests[t->summary_axis];
3665           const struct ctables_summary_spec_set *specs = &specs_nest->specs[cell->sv];
3666           for (size_t j = 0; j < specs->n; j++)
3667             {
3668               size_t dindexes[5];
3669               size_t n_dindexes = 0;
3670
3671               if (summary_dimension)
3672                 dindexes[n_dindexes++] = specs->specs[j].axis_idx;
3673
3674               if (categories_dimension)
3675                 {
3676                   const struct ctables_nest *clabels_nest = s->nests[t->clabels_from_axis];
3677                   const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
3678                   const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
3679                   const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
3680                   if (!ctv)
3681                     continue;
3682                   dindexes[n_dindexes++] = ctv->leaf;
3683                 }
3684
3685               for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3686                 if (d[a])
3687                   {
3688                     int leaf = cell->axes[a].leaf;
3689                     if (a == t->summary_axis && !summary_dimension)
3690                       leaf += j;
3691                     dindexes[n_dindexes++] = leaf;
3692                   }
3693
3694               const struct ctables_summary_spec *ss = &specs->specs[j];
3695
3696               double d = (cell->postcompute
3697                           ? ctables_cell_calculate_postcompute (s, cell)
3698                           : ctables_summary_value (cell, &cell->summaries[j], ss));
3699               struct pivot_value *value;
3700               if (ct->hide_threshold != 0
3701                   && d < ct->hide_threshold
3702                   && (cell->postcompute
3703                       ? false /* XXX */
3704                       : ctables_summary_function_is_count (ss->function)))
3705                 {
3706                   value = pivot_value_new_user_text_nocopy (
3707                     xasprintf ("<%d", ct->hide_threshold));
3708                 }
3709               else if (d == 0 && ct->zero)
3710                 value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
3711               else if (d == SYSMIS && ct->missing)
3712                 value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
3713               else if (specs->specs[j].is_ctables_format)
3714                 {
3715                   char *s = data_out_stretchy (&(union value) { .f = d },
3716                                                "UTF-8",
3717                                                &specs->specs[j].format,
3718                                                &ct->ctables_formats, NULL);
3719                   value = pivot_value_new_user_text_nocopy (s);
3720                 }
3721               else
3722                 {
3723                   value = pivot_value_new_number (d);
3724                   value->numeric.format = specs->specs[j].format;
3725                 }
3726               pivot_table_put (pt, dindexes, n_dindexes, value);
3727             }
3728         }
3729     }
3730
3731   pivot_table_submit (pt);
3732 }
3733
3734 static bool
3735 ctables_check_label_position (struct ctables_table *t, enum pivot_axis_type a)
3736 {
3737   enum pivot_axis_type label_pos = t->label_axis[a];
3738   if (label_pos == a)
3739     return true;
3740
3741   t->clabels_from_axis = a;
3742
3743   const char *subcommand_name = a == PIVOT_AXIS_ROW ? "ROWLABELS" : "COLLABELS";
3744   const char *pos_name = label_pos == PIVOT_AXIS_LAYER ? "LAYER" : "OPPOSITE";
3745
3746   const struct ctables_stack *stack = &t->stacks[a];
3747   if (!stack->n)
3748     return true;
3749
3750   const struct ctables_nest *n0 = &stack->nests[0];
3751   assert (n0->n > 0);
3752   const struct variable *v0 = n0->vars[n0->n - 1];
3753   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
3754   t->clabels_example = v0;
3755
3756   for (size_t i = 0; i < c0->n_cats; i++)
3757     if (c0->cats[i].type == CCT_FUNCTION)
3758       {
3759         msg (SE, _("%s=%s is not allowed with sorting based "
3760                    "on a summary function."),
3761              subcommand_name, pos_name);
3762         return false;
3763       }
3764   if (n0->n - 1 == n0->scale_idx)
3765     {
3766       msg (SE, _("%s=%s requires the variables to be moved to be categorical, "
3767                  "but %s is a scale variable."),
3768            subcommand_name, pos_name, var_get_name (v0));
3769       return false;
3770     }
3771
3772   for (size_t i = 1; i < stack->n; i++)
3773     {
3774       const struct ctables_nest *ni = &stack->nests[i];
3775       assert (ni->n > 0);
3776       const struct variable *vi = ni->vars[ni->n - 1];
3777       struct ctables_categories *ci = t->categories[var_get_dict_index (vi)];
3778
3779       if (ni->n - 1 == ni->scale_idx)
3780         {
3781           msg (SE, _("%s=%s requires the variables to be moved to be "
3782                      "categorical, but %s is a scale variable."),
3783                subcommand_name, pos_name, var_get_name (vi));
3784           return false;
3785         }
3786       if (var_get_width (v0) != var_get_width (vi))
3787         {
3788           msg (SE, _("%s=%s requires the variables to be "
3789                      "moved to have the same width, but %s has "
3790                      "width %d and %s has width %d."),
3791                subcommand_name, pos_name,
3792                var_get_name (v0), var_get_width (v0),
3793                var_get_name (vi), var_get_width (vi));
3794           return false;
3795         }
3796       if (!val_labs_equal (var_get_value_labels (v0),
3797                            var_get_value_labels (vi)))
3798         {
3799           msg (SE, _("%s=%s requires the variables to be "
3800                      "moved to have the same value labels, but %s "
3801                      "and %s have different value labels."),
3802                subcommand_name, pos_name,
3803                var_get_name (v0), var_get_name (vi));
3804           return false;
3805         }
3806       if (!ctables_categories_equal (c0, ci))
3807         {
3808           msg (SE, _("%s=%s requires the variables to be "
3809                      "moved to have the same category "
3810                      "specifications, but %s and %s have different "
3811                      "category specifications."),
3812                subcommand_name, pos_name,
3813                var_get_name (v0), var_get_name (vi));
3814           return false;
3815         }
3816     }
3817
3818   return true;
3819 }
3820
3821 static bool
3822 ctables_prepare_table (struct ctables_table *t)
3823 {
3824   for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
3825     if (t->axes[a])
3826       {
3827         t->stacks[a] = enumerate_fts (a, t->axes[a]);
3828
3829         for (size_t j = 0; j < t->stacks[a].n; j++)
3830           {
3831             struct ctables_nest *nest = &t->stacks[a].nests[j];
3832             for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
3833               {
3834                 nest->domains[dt] = xmalloc (nest->n * sizeof *nest->domains[dt]);
3835                 nest->n_domains[dt] = 0;
3836
3837                 for (size_t k = 0; k < nest->n; k++)
3838                   {
3839                     if (k == nest->scale_idx)
3840                       continue;
3841
3842                     switch (dt)
3843                       {
3844                       case CTDT_TABLE:
3845                         continue;
3846
3847                       case CTDT_LAYER:
3848                         if (a != PIVOT_AXIS_LAYER)
3849                           continue;
3850                         break;
3851
3852                       case CTDT_SUBTABLE:
3853                       case CTDT_ROW:
3854                       case CTDT_COL:
3855                         if (dt == CTDT_SUBTABLE ? a != PIVOT_AXIS_LAYER
3856                             : dt == CTDT_ROW ? a == PIVOT_AXIS_COLUMN
3857                             : a == PIVOT_AXIS_ROW)
3858                           {
3859                             if (k == nest->n - 1
3860                                 || (nest->scale_idx == nest->n - 1
3861                                     && k == nest->n - 2))
3862                               continue;
3863                           }
3864                         break;
3865
3866                       case CTDT_LAYERROW:
3867                         if (a == PIVOT_AXIS_COLUMN)
3868                           continue;
3869                         break;
3870
3871                       case CTDT_LAYERCOL:
3872                         if (a == PIVOT_AXIS_ROW)
3873                           continue;
3874                         break;
3875                       }
3876
3877                     nest->domains[dt][nest->n_domains[dt]++] = k;
3878                   }
3879               }
3880           }
3881       }
3882     else
3883       {
3884         struct ctables_nest *nest = xmalloc (sizeof *nest);
3885         *nest = (struct ctables_nest) { .n = 0 };
3886         t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
3887       }
3888
3889   struct ctables_stack *stack = &t->stacks[t->summary_axis];
3890   for (size_t i = 0; i < stack->n; i++)
3891     {
3892       struct ctables_nest *nest = &stack->nests[i];
3893       if (!nest->specs[CSV_CELL].n)
3894         {
3895           struct ctables_summary_spec_set *specs = &nest->specs[CSV_CELL];
3896           specs->specs = xmalloc (sizeof *specs->specs);
3897           specs->n = 1;
3898
3899           enum ctables_summary_function function
3900             = specs->is_scale ? CTSF_MEAN : CTSF_COUNT;
3901           struct ctables_var var = { .is_mrset = false, .var = specs->var };
3902
3903           *specs->specs = (struct ctables_summary_spec) {
3904             .function = function,
3905             .format = ctables_summary_default_format (function, &var),
3906             .label = ctables_summary_default_label (function, 0),
3907           };
3908           if (!specs->var)
3909             specs->var = nest->vars[0];
3910
3911           ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3912                                           &nest->specs[CSV_CELL]);
3913         }
3914       else if (!nest->specs[CSV_TOTAL].n)
3915         ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
3916                                         &nest->specs[CSV_CELL]);
3917     }
3918
3919   struct ctables_summary_spec_set *merged = &t->summary_specs;
3920   struct merge_item *items = xnmalloc (2 * stack->n, sizeof *items);
3921   size_t n_left = 0;
3922   for (size_t j = 0; j < stack->n; j++)
3923     {
3924       const struct ctables_nest *nest = &stack->nests[j];
3925       if (nest->n)
3926         for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3927           items[n_left++] = (struct merge_item) { .set = &nest->specs[sv] };
3928     }
3929
3930   while (n_left > 0)
3931     {
3932       struct merge_item min = items[0];
3933       for (size_t j = 1; j < n_left; j++)
3934         if (merge_item_compare_3way (&items[j], &min) < 0)
3935           min = items[j];
3936
3937       if (merged->n >= merged->allocated)
3938         merged->specs = x2nrealloc (merged->specs, &merged->allocated,
3939                                     sizeof *merged->specs);
3940       merged->specs[merged->n++] = min.set->specs[min.ofs];
3941
3942       for (size_t j = 0; j < n_left; )
3943         {
3944           if (merge_item_compare_3way (&items[j], &min) == 0)
3945             {
3946               struct merge_item *item = &items[j];
3947               item->set->specs[item->ofs].axis_idx = merged->n - 1;
3948               if (++item->ofs >= item->set->n)
3949                 {
3950                   items[j] = items[--n_left];
3951                   continue;
3952                 }
3953             }
3954           j++;
3955         }
3956     }
3957
3958 #if 0
3959   for (size_t j = 0; j < merged->n; j++)
3960     printf ("%s\n", ctables_summary_function_name (merged->specs[j].function));
3961
3962   for (size_t j = 0; j < stack->n; j++)
3963     {
3964       const struct ctables_nest *nest = &stack->nests[j];
3965       for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
3966         {
3967           const struct ctables_summary_spec_set *specs = &nest->specs[sv];
3968           for (size_t k = 0; k < specs->n; k++)
3969             printf ("(%s, %zu) ", ctables_summary_function_name (specs->specs[k].function),
3970                     specs->specs[k].axis_idx);
3971           printf ("\n");
3972         }
3973     }
3974 #endif
3975
3976   return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
3977           && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
3978 }
3979
3980 static void
3981 ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
3982                                enum pivot_axis_type a)
3983 {
3984   struct ctables_stack *stack = &t->stacks[a];
3985   for (size_t i = 0; i < stack->n; i++)
3986     {
3987       const struct ctables_nest *nest = &stack->nests[i];
3988       const struct variable *var = nest->vars[nest->n - 1];
3989       const union value *value = case_data (c, var);
3990
3991       if (var_is_numeric (var) && value->f == SYSMIS)
3992         continue;
3993
3994       if (ctables_categories_match (t->categories [var_get_dict_index (var)],
3995                                     value, var))
3996         ctables_value_insert (t, value, var_get_width (var));
3997     }
3998 }
3999
4000 static int
4001 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
4002 {
4003   const struct ctables_value *const *ap = a_;
4004   const struct ctables_value *const *bp = b_;
4005   const struct ctables_value *a = *ap;
4006   const struct ctables_value *b = *bp;
4007   const int *width = width_;
4008   return value_compare_3way (&a->value, &b->value, *width);
4009 }
4010
4011 static void
4012 ctables_sort_clabels_values (struct ctables_table *t)
4013 {
4014   const struct variable *v0 = t->clabels_example;
4015   int width = var_get_width (v0);
4016
4017   struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
4018   if (c0->show_empty)
4019     {
4020       const struct val_labs *val_labs = var_get_value_labels (v0);
4021       for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4022            vl = val_labs_next (val_labs, vl))
4023         if (ctables_categories_match (c0, &vl->value, v0))
4024           ctables_value_insert (t, &vl->value, width);
4025     }
4026
4027   size_t n = hmap_count (&t->clabels_values_map);
4028   t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
4029
4030   struct ctables_value *clv;
4031   size_t i = 0;
4032   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
4033     t->clabels_values[i++] = clv;
4034   t->n_clabels_values = n;
4035   assert (i == n);
4036
4037   sort (t->clabels_values, n, sizeof *t->clabels_values,
4038         compare_clabels_values_3way, &width);
4039
4040   for (size_t i = 0; i < n; i++)
4041     t->clabels_values[i]->leaf = i;
4042 }
4043
4044 static void
4045 ctables_add_category_occurrences (const struct variable *var,
4046                                   struct hmap *occurrences,
4047                                   const struct ctables_categories *cats)
4048 {
4049   const struct val_labs *val_labs = var_get_value_labels (var);
4050
4051   for (size_t i = 0; i < cats->n_cats; i++)
4052     {
4053       const struct ctables_category *c = &cats->cats[i];
4054       switch (c->type)
4055         {
4056         case CCT_NUMBER:
4057           ctables_add_occurrence (var, &(const union value) { .f = c->number },
4058                                   occurrences);
4059           break;
4060
4061         case CCT_STRING:
4062           abort ();             /* XXX */
4063
4064         case CCT_RANGE:
4065           assert (var_is_numeric (var));
4066           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4067                vl = val_labs_next (val_labs, vl))
4068             if (vl->value.f >= c->range[0] && vl->value.f <= c->range[1])
4069               ctables_add_occurrence (var, &vl->value, occurrences);
4070           break;
4071
4072         case CCT_MISSING:
4073           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4074                vl = val_labs_next (val_labs, vl))
4075             if (var_is_value_missing (var, &vl->value))
4076               ctables_add_occurrence (var, &vl->value, occurrences);
4077           break;
4078
4079         case CCT_OTHERNM:
4080           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4081                vl = val_labs_next (val_labs, vl))
4082             ctables_add_occurrence (var, &vl->value, occurrences);
4083           break;
4084
4085         case CCT_POSTCOMPUTE:
4086           break;
4087
4088         case CCT_SUBTOTAL:
4089         case CCT_TOTAL:
4090           break;
4091
4092         case CCT_VALUE:
4093         case CCT_LABEL:
4094         case CCT_FUNCTION:
4095           for (const struct val_lab *vl = val_labs_first (val_labs); vl;
4096                vl = val_labs_next (val_labs, vl))
4097             if (c->include_missing || !var_is_value_missing (var, &vl->value))
4098               ctables_add_occurrence (var, &vl->value, occurrences);
4099           break;
4100
4101         case CCT_EXCLUDED_MISSING:
4102           break;
4103         }
4104     }
4105 }
4106
4107 static void
4108 ctables_section_recurse_add_empty_categories (
4109   struct ctables_section *s,
4110   const struct ctables_category *cats[PIVOT_N_AXES][10], struct ccase *c,
4111   enum pivot_axis_type a, size_t a_idx)
4112 {
4113   if (a >= PIVOT_N_AXES)
4114     ctables_cell_insert__ (s, c, cats);
4115   else if (!s->nests[a] || a_idx >= s->nests[a]->n)
4116     ctables_section_recurse_add_empty_categories (s, cats, c, a + 1, 0);
4117   else
4118     {
4119       const struct variable *var = s->nests[a]->vars[a_idx];
4120       const struct ctables_categories *categories = s->table->categories[
4121         var_get_dict_index (var)];
4122       int width = var_get_width (var);
4123       const struct hmap *occurrences = &s->occurrences[a][a_idx];
4124       const struct ctables_occurrence *o;
4125       HMAP_FOR_EACH (o, struct ctables_occurrence, node, occurrences)
4126         {
4127           union value *value = case_data_rw (c, var);
4128           value_destroy (value, width);
4129           value_clone (value, &o->value, width);
4130           cats[a][a_idx] = ctables_categories_match (categories, value, var);
4131           assert (cats[a][a_idx] != NULL);
4132           ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4133         }
4134
4135       for (size_t i = 0; i < categories->n_cats; i++)
4136         {
4137           const struct ctables_category *cat = &categories->cats[i];
4138           if (cat->type == CCT_POSTCOMPUTE)
4139             {
4140               cats[a][a_idx] = cat;
4141               ctables_section_recurse_add_empty_categories (s, cats, c, a, a_idx + 1);
4142             }
4143         }
4144     }
4145 }
4146
4147 static void
4148 ctables_section_add_empty_categories (struct ctables_section *s)
4149 {
4150   bool show_empty = false;
4151   for (size_t a = 0; a < PIVOT_N_AXES; a++)
4152     if (s->nests[a])
4153       for (size_t k = 0; k < s->nests[a]->n; k++)
4154         if (k != s->nests[a]->scale_idx)
4155           {
4156             const struct variable *var = s->nests[a]->vars[k];
4157             const struct ctables_categories *cats = s->table->categories[
4158               var_get_dict_index (var)];
4159             if (cats->show_empty)
4160               {
4161                 show_empty = true;
4162                 ctables_add_category_occurrences (var, &s->occurrences[a][k], cats);
4163               }
4164           }
4165   if (!show_empty)
4166     return;
4167
4168   const struct ctables_category *cats[PIVOT_N_AXES][10]; /* XXX */
4169   struct ccase *c = case_create (dict_get_proto (s->table->ctables->dict));
4170   ctables_section_recurse_add_empty_categories (s, cats, c, 0, 0);
4171   case_unref (c);
4172 }
4173
4174 static bool
4175 ctables_execute (struct dataset *ds, struct ctables *ct)
4176 {
4177   for (size_t i = 0; i < ct->n_tables; i++)
4178     {
4179       struct ctables_table *t = ct->tables[i];
4180       t->sections = xnmalloc (MAX (1, t->stacks[PIVOT_AXIS_ROW].n) *
4181                               MAX (1, t->stacks[PIVOT_AXIS_COLUMN].n) *
4182                               MAX (1, t->stacks[PIVOT_AXIS_LAYER].n),
4183                               sizeof *t->sections);
4184       size_t ix[PIVOT_N_AXES];
4185       ctables_table_add_section (t, 0, ix);
4186     }
4187
4188   struct casereader *input = proc_open (ds);
4189   bool warn_on_invalid = true;
4190   for (struct ccase *c = casereader_read (input); c;
4191        case_unref (c), c = casereader_read (input))
4192     {
4193       double d_weight = dict_get_case_weight (dataset_dict (ds), c,
4194                                               &warn_on_invalid);
4195       double e_weight = (ct->e_weight
4196                          ? var_force_valid_weight (ct->e_weight,
4197                                                    case_num (c, ct->e_weight),
4198                                                    &warn_on_invalid)
4199                          : d_weight);
4200
4201       for (size_t i = 0; i < ct->n_tables; i++)
4202         {
4203           struct ctables_table *t = ct->tables[i];
4204
4205           for (size_t j = 0; j < t->n_sections; j++)
4206             ctables_cell_insert (&t->sections[j], c, d_weight, e_weight);
4207
4208           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
4209             if (t->label_axis[a] != a)
4210               ctables_insert_clabels_values (t, c, a);
4211         }
4212     }
4213   casereader_destroy (input);
4214
4215   for (size_t i = 0; i < ct->n_tables; i++)
4216     {
4217       struct ctables_table *t = ct->tables[i];
4218
4219       if (t->clabels_example)
4220         ctables_sort_clabels_values (t);
4221
4222       for (size_t j = 0; j < t->n_sections; j++)
4223         ctables_section_add_empty_categories (&t->sections[j]);
4224
4225       ctables_table_output (ct, ct->tables[i]);
4226     }
4227   return proc_commit (ds);
4228 }
4229 \f
4230 /* Postcomputes. */
4231
4232 typedef struct ctables_pcexpr *parse_recursively_func (struct lexer *);
4233
4234 static void
4235 ctables_pcexpr_destroy (struct ctables_pcexpr *e)
4236 {
4237   if (e)
4238     {
4239       switch (e->op)
4240         {
4241         case CTPO_CAT_STRING:
4242           free (e->string);
4243           break;
4244
4245         case CTPO_ADD:
4246         case CTPO_SUB:
4247         case CTPO_MUL:
4248         case CTPO_DIV:
4249         case CTPO_POW:
4250         case CTPO_NEG:
4251           for (size_t i = 0; i < 2; i++)
4252             ctables_pcexpr_destroy (e->subs[i]);
4253           break;
4254
4255         case CTPO_CONSTANT:
4256         case CTPO_CAT_NUMBER:
4257         case CTPO_CAT_RANGE:
4258         case CTPO_CAT_MISSING:
4259         case CTPO_CAT_OTHERNM:
4260         case CTPO_CAT_SUBTOTAL:
4261         case CTPO_CAT_TOTAL:
4262           break;
4263         }
4264
4265       msg_location_destroy (e->location);
4266       free (e);
4267     }
4268 }
4269
4270 static struct ctables_pcexpr *
4271 ctables_pcexpr_allocate_binary (enum ctables_postcompute_op op,
4272                                 struct ctables_pcexpr *sub0,
4273                                 struct ctables_pcexpr *sub1)
4274 {
4275   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4276   *e = (struct ctables_pcexpr) {
4277     .op = op,
4278     .subs = { sub0, sub1 },
4279     .location = msg_location_merged (sub0->location, sub1->location),
4280   };
4281   return e;
4282 }
4283
4284 /* How to parse an operator. */
4285 struct operator
4286   {
4287     enum token_type token;
4288     enum ctables_postcompute_op op;
4289   };
4290
4291 static const struct operator *
4292 match_operator (struct lexer *lexer, const struct operator ops[], size_t n_ops)
4293 {
4294   for (const struct operator *op = ops; op < ops + n_ops; op++)
4295     if (lex_token (lexer) == op->token)
4296       {
4297         if (op->token != T_NEG_NUM)
4298           lex_get (lexer);
4299
4300         return op;
4301       }
4302
4303   return NULL;
4304 }
4305
4306 static struct ctables_pcexpr *
4307 parse_binary_operators__ (struct lexer *lexer,
4308                           const struct operator ops[], size_t n_ops,
4309                           parse_recursively_func *parse_next_level,
4310                           const char *chain_warning,
4311                           struct ctables_pcexpr *lhs)
4312 {
4313   for (int op_count = 0; ; op_count++)
4314     {
4315       const struct operator *op = match_operator (lexer, ops, n_ops);
4316       if (!op)
4317         {
4318           if (op_count > 1 && chain_warning)
4319             msg_at (SW, lhs->location, "%s", chain_warning);
4320
4321           return lhs;
4322         }
4323
4324       struct ctables_pcexpr *rhs = parse_next_level (lexer);
4325       if (!rhs)
4326         {
4327           ctables_pcexpr_destroy (lhs);
4328           return NULL;
4329         }
4330
4331       lhs = ctables_pcexpr_allocate_binary (op->op, lhs, rhs);
4332     }
4333 }
4334
4335 static struct ctables_pcexpr *
4336 parse_binary_operators (struct lexer *lexer,
4337                         const struct operator ops[], size_t n_ops,
4338                         parse_recursively_func *parse_next_level,
4339                         const char *chain_warning)
4340 {
4341   struct ctables_pcexpr *lhs = parse_next_level (lexer);
4342   if (!lhs)
4343     return NULL;
4344
4345   return parse_binary_operators__ (lexer, ops, n_ops, parse_next_level,
4346                                    chain_warning, lhs);
4347 }
4348
4349 static struct ctables_pcexpr *parse_add (struct lexer *);
4350
4351 static struct ctables_pcexpr
4352 ctpo_cat_range (double low, double high)
4353 {
4354   return (struct ctables_pcexpr) {
4355     .op = CTPO_CAT_RANGE,
4356     .range = { low, high },
4357   };
4358 }
4359
4360 static struct ctables_pcexpr *
4361 parse_primary (struct lexer *lexer)
4362 {
4363   int start_ofs = lex_ofs (lexer);
4364   struct ctables_pcexpr e;
4365   if (lex_is_number (lexer))
4366     {
4367       e = (struct ctables_pcexpr) { .op = CTPO_CONSTANT,
4368                                     .number = lex_number (lexer) };
4369       lex_get (lexer);
4370     }
4371   else if (lex_match_id (lexer, "MISSING"))
4372     e = (struct ctables_pcexpr) { .op = CTPO_CAT_MISSING };
4373   else if (lex_match_id (lexer, "OTHERNM"))
4374     e = (struct ctables_pcexpr) { .op = CTPO_CAT_OTHERNM };
4375   else if (lex_match_id (lexer, "TOTAL"))
4376     e = (struct ctables_pcexpr) { .op = CTPO_CAT_TOTAL };
4377   else if (lex_match_id (lexer, "SUBTOTAL"))
4378     {
4379       size_t subtotal_index = 0;
4380       if (lex_match (lexer, T_LBRACK))
4381         {
4382           if (!lex_force_int_range (lexer, "SUBTOTAL", 1, LONG_MAX))
4383             return NULL;
4384           subtotal_index = lex_integer (lexer);
4385           lex_get (lexer);
4386           if (!lex_force_match (lexer, T_RBRACK))
4387             return NULL;
4388         }
4389       e = (struct ctables_pcexpr) { .op = CTPO_CAT_SUBTOTAL,
4390                                     .subtotal_index = subtotal_index };
4391     }
4392   else if (lex_match (lexer, T_LBRACK))
4393     {
4394       if (lex_match_id (lexer, "LO"))
4395         {
4396           if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer))
4397             return false;
4398           e = ctpo_cat_range (-DBL_MAX, lex_number (lexer));
4399           lex_get (lexer);
4400         }
4401       else if (lex_is_number (lexer))
4402         {
4403           double number = lex_number (lexer);
4404           lex_get (lexer);
4405           if (lex_match_id (lexer, "THRU"))
4406             {
4407               if (lex_match_id (lexer, "HI"))
4408                 e = ctpo_cat_range (number, DBL_MAX);
4409               else
4410                 {
4411                   if (!lex_force_num (lexer))
4412                     return false;
4413                   e = ctpo_cat_range (number, lex_number (lexer));
4414                   lex_get (lexer);
4415                 }
4416             }
4417           else
4418             e = (struct ctables_pcexpr) { .op = CTPO_CAT_NUMBER,
4419                                           .number = number };
4420         }
4421       else if (lex_is_string (lexer))
4422         {
4423           e = (struct ctables_pcexpr) {
4424             .op = CTPO_CAT_STRING,
4425             .string = ss_xstrdup (lex_tokss (lexer)),
4426           };
4427           lex_get (lexer);
4428         }
4429       else
4430         {
4431           lex_error (lexer, NULL);
4432           return NULL;
4433         }
4434
4435       if (!lex_force_match (lexer, T_RBRACK))
4436         {
4437           if (e.op == CTPO_CAT_STRING)
4438             free (e.string);
4439           return NULL;
4440         }
4441     }
4442   else if (lex_match (lexer, T_LPAREN))
4443     {
4444       struct ctables_pcexpr *ep = parse_add (lexer);
4445       if (!ep)
4446         return NULL;
4447       if (!lex_force_match (lexer, T_RPAREN))
4448         {
4449           ctables_pcexpr_destroy (ep);
4450           return NULL;
4451         }
4452       return ep;
4453     }
4454   else
4455     {
4456       lex_error (lexer, NULL);
4457       return NULL;
4458     }
4459
4460   e.location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
4461   return xmemdup (&e, sizeof e);
4462 }
4463
4464 static struct ctables_pcexpr *
4465 ctables_pcexpr_allocate_neg (struct ctables_pcexpr *sub,
4466                              struct lexer *lexer, int start_ofs)
4467 {
4468   struct ctables_pcexpr *e = xmalloc (sizeof *e);
4469   *e = (struct ctables_pcexpr) {
4470     .op = CTPO_NEG,
4471     .subs = { sub },
4472     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
4473   };
4474   return e;
4475 }
4476
4477 static struct ctables_pcexpr *
4478 parse_exp (struct lexer *lexer)
4479 {
4480   static const struct operator op = { T_EXP, CTPO_POW };
4481
4482   const char *chain_warning =
4483     _("The exponentiation operator (`**') is left-associative: "
4484       "`a**b**c' equals `(a**b)**c', not `a**(b**c)'.  "
4485       "To disable this warning, insert parentheses.");
4486
4487   if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
4488     return parse_binary_operators (lexer, &op, 1,
4489                                    parse_primary, chain_warning);
4490
4491   /* Special case for situations like "-5**6", which must be parsed as
4492      -(5**6). */
4493
4494   int start_ofs = lex_ofs (lexer);
4495   struct ctables_pcexpr *lhs = xmalloc (sizeof *lhs);
4496   *lhs = (struct ctables_pcexpr) {
4497     .op = CTPO_CONSTANT,
4498     .number = -lex_tokval (lexer),
4499     .location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer)),
4500   };
4501   lex_get (lexer);
4502
4503   struct ctables_pcexpr *node = parse_binary_operators__ (
4504     lexer, &op, 1, parse_primary, chain_warning, lhs);
4505   if (!node)
4506     return NULL;
4507
4508   return ctables_pcexpr_allocate_neg (node, lexer, start_ofs);
4509 }
4510
4511 /* Parses the unary minus level. */
4512 static struct ctables_pcexpr *
4513 parse_neg (struct lexer *lexer)
4514 {
4515   int start_ofs = lex_ofs (lexer);
4516   if (!lex_match (lexer, T_DASH))
4517     return parse_exp (lexer);
4518
4519   struct ctables_pcexpr *inner = parse_neg (lexer);
4520   if (!inner)
4521     return NULL;
4522
4523   return ctables_pcexpr_allocate_neg (inner, lexer, start_ofs);
4524 }
4525
4526 /* Parses the multiplication and division level. */
4527 static struct ctables_pcexpr *
4528 parse_mul (struct lexer *lexer)
4529 {
4530   static const struct operator ops[] =
4531     {
4532       { T_ASTERISK, CTPO_MUL },
4533       { T_SLASH, CTPO_DIV },
4534     };
4535
4536   return parse_binary_operators (lexer, ops, sizeof ops / sizeof *ops,
4537                                  parse_neg, NULL);
4538 }
4539
4540 /* Parses the addition and subtraction level. */
4541 static struct ctables_pcexpr *
4542 parse_add (struct lexer *lexer)
4543 {
4544   static const struct operator ops[] =
4545     {
4546       { T_PLUS, CTPO_ADD },
4547       { T_DASH, CTPO_SUB },
4548       { T_NEG_NUM, CTPO_ADD },
4549     };
4550
4551   return parse_binary_operators (lexer, ops, sizeof ops / sizeof *ops,
4552                                  parse_mul, NULL);
4553 }
4554
4555 static struct ctables_postcompute *
4556 ctables_find_postcompute (struct ctables *ct, const char *name)
4557 {
4558   struct ctables_postcompute *pc;
4559   HMAP_FOR_EACH_WITH_HASH (pc, struct ctables_postcompute, hmap_node,
4560                            utf8_hash_case_string (name, 0), &ct->postcomputes)
4561     if (!utf8_strcasecmp (pc->name, name))
4562       return pc;
4563   return NULL;
4564 }
4565
4566 static bool
4567 ctables_parse_pcompute (struct lexer *lexer, struct ctables *ct)
4568 {
4569   int pcompute_start = lex_ofs (lexer) - 1;
4570
4571   if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer))
4572     return false;
4573
4574   char *name = ss_xstrdup (lex_tokss (lexer));
4575
4576   lex_get (lexer);
4577   if (!lex_force_match (lexer, T_EQUALS)
4578       || !lex_force_match_id (lexer, "EXPR")
4579       || !lex_force_match (lexer, T_LPAREN))
4580     {
4581       free (name);
4582       return false;
4583     }
4584
4585   int expr_start = lex_ofs (lexer);
4586   struct ctables_pcexpr *expr = parse_add (lexer);
4587   int expr_end = lex_ofs (lexer) - 1;
4588   if (!expr || !lex_force_match (lexer, T_RPAREN))
4589     {
4590       free (name);
4591       return false;
4592     }
4593   int pcompute_end = lex_ofs (lexer) - 1;
4594
4595   struct msg_location *location = lex_ofs_location (lexer, pcompute_start,
4596                                                     pcompute_end);
4597
4598   struct ctables_postcompute *pc = ctables_find_postcompute (ct, name);
4599   if (pc)
4600     {
4601       msg_at (SW, location, _("New definition of &%s will override the "
4602                               "previous definition."),
4603               pc->name);
4604       msg_at (SN, pc->location, _("This is the previous definition."));
4605
4606       ctables_pcexpr_destroy (pc->expr);
4607       msg_location_destroy (pc->location);
4608       free (name);
4609     }
4610   else
4611     {
4612       pc = xmalloc (sizeof *pc);
4613       *pc = (struct ctables_postcompute) { .name = name };
4614       hmap_insert (&ct->postcomputes, &pc->hmap_node,
4615                    utf8_hash_case_string (pc->name, 0));
4616     }
4617   pc->expr = expr;
4618   pc->location = location;
4619   if (!pc->label)
4620     pc->label = lex_ofs_representation (lexer, expr_start, expr_end);
4621   return true;
4622 }
4623
4624 static bool
4625 ctables_parse_pproperties_format (struct lexer *lexer,
4626                                   struct ctables_summary_spec_set *sss)
4627 {
4628   *sss = (struct ctables_summary_spec_set) { .n = 0 };
4629
4630   while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH
4631          && !(lex_token (lexer) == T_ID
4632               && (lex_id_match (ss_cstr ("LABEL"), lex_tokss (lexer))
4633                   || lex_id_match (ss_cstr ("HIDESOURCECATS"),
4634                                    lex_tokss (lexer)))))
4635     {
4636       /* Parse function. */
4637       enum ctables_summary_function function;
4638       if (!parse_ctables_summary_function (lexer, &function))
4639         goto error;
4640
4641       /* Parse percentile. */
4642       double percentile = 0;
4643       if (function == CTSF_PTILE)
4644         {
4645           if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
4646             goto error;
4647           percentile = lex_number (lexer);
4648           lex_get (lexer);
4649         }
4650
4651       /* Parse format. */
4652       struct fmt_spec format;
4653       if (!parse_format_specifier (lexer, &format)
4654           || !fmt_check_output (&format)
4655           || !fmt_check_type_compat (&format, VAL_NUMERIC))
4656         goto error;
4657
4658       if (sss->n >= sss->allocated)
4659         sss->specs = x2nrealloc (sss->specs, &sss->allocated,
4660                                  sizeof *sss->specs);
4661       sss->specs[sss->n++] = (struct ctables_summary_spec) {
4662         .function = function,
4663         .percentile = percentile,
4664         .format = format,
4665       };
4666     }
4667   return true;
4668
4669 error:
4670   ctables_summary_spec_set_uninit (sss);
4671   return false;
4672 }
4673
4674 static bool
4675 ctables_parse_pproperties (struct lexer *lexer, struct ctables *ct)
4676 {
4677   struct ctables_postcompute **pcs = NULL;
4678   size_t n_pcs = 0;
4679   size_t allocated_pcs = 0;
4680
4681   while (lex_match (lexer, T_AND))
4682     {
4683       if (!lex_force_id (lexer))
4684         goto error;
4685       struct ctables_postcompute *pc
4686         = ctables_find_postcompute (ct, lex_tokcstr (lexer));
4687       if (!pc)
4688         {
4689           msg (SE, _("Unknown computed category &%s."), lex_tokcstr (lexer));
4690           goto error;
4691         }
4692       lex_get (lexer);
4693
4694       if (n_pcs >= allocated_pcs)
4695         pcs = x2nrealloc (pcs, &allocated_pcs, sizeof *pcs);
4696       pcs[n_pcs++] = pc;
4697     }
4698
4699   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
4700     {
4701       if (lex_match_id (lexer, "LABEL"))
4702         {
4703           lex_match (lexer, T_EQUALS);
4704           if (!lex_force_string (lexer))
4705             goto error;
4706
4707           for (size_t i = 0; i < n_pcs; i++)
4708             {
4709               free (pcs[i]->label);
4710               pcs[i]->label = ss_xstrdup (lex_tokss (lexer));
4711             }
4712
4713           lex_get (lexer);
4714         }
4715       else if (lex_match_id (lexer, "FORMAT"))
4716         {
4717           lex_match (lexer, T_EQUALS);
4718
4719           struct ctables_summary_spec_set sss;
4720           if (!ctables_parse_pproperties_format (lexer, &sss))
4721             goto error;
4722
4723           for (size_t i = 0; i < n_pcs; i++)
4724             {
4725               if (pcs[i]->specs)
4726                 ctables_summary_spec_set_uninit (pcs[i]->specs);
4727               else
4728                 pcs[i]->specs = xmalloc (sizeof *pcs[i]->specs);
4729               ctables_summary_spec_set_clone (pcs[i]->specs, &sss);
4730             }
4731           ctables_summary_spec_set_uninit (&sss);
4732         }
4733       else if (lex_match_id (lexer, "HIDESOURCECATS"))
4734         {
4735           lex_match (lexer, T_EQUALS);
4736           bool hide_source_cats;
4737           if (!parse_bool (lexer, &hide_source_cats))
4738             goto error;
4739           for (size_t i = 0; i < n_pcs; i++)
4740             pcs[i]->hide_source_cats = hide_source_cats;
4741         }
4742       else
4743         {
4744           lex_error_expecting (lexer, "LABEL", "FORMAT", "HIDESOURCECATS");
4745           goto error;
4746         }
4747     }
4748   free (pcs);
4749   return true;
4750
4751 error:
4752   free (pcs);
4753   return false;
4754 }
4755
4756 int
4757 cmd_ctables (struct lexer *lexer, struct dataset *ds)
4758 {
4759   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
4760   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
4761   enum settings_value_show tvars = settings_get_show_variables ();
4762   for (size_t i = 0; i < n_vars; i++)
4763     vlabels[i] = (enum ctables_vlabel) tvars;
4764
4765   struct pivot_table_look *look = pivot_table_look_unshare (
4766     pivot_table_look_ref (pivot_table_look_get_default ()));
4767   look->omit_empty = false;
4768
4769   struct ctables *ct = xmalloc (sizeof *ct);
4770   *ct = (struct ctables) {
4771     .dict = dataset_dict (ds),
4772     .look = look,
4773     .ctables_formats = FMT_SETTINGS_INIT,
4774     .vlabels = vlabels,
4775     .postcomputes = HMAP_INITIALIZER (ct->postcomputes),
4776   };
4777
4778   struct ctf
4779     {
4780       enum fmt_type type;
4781       const char *dot_string;
4782       const char *comma_string;
4783     };
4784   static const struct ctf ctfs[4] = {
4785     { CTEF_NEGPAREN, "(,,,)",   "(...)" },
4786     { CTEF_NEQUAL,   "-,N=,,",  "-.N=.." },
4787     { CTEF_PAREN,    "-,(,),",  "-.(.)." },
4788     { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
4789   };
4790   bool is_dot = settings_get_fmt_settings ()->decimal == '.';
4791   for (size_t i = 0; i < 4; i++)
4792     {
4793       const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
4794       fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
4795                            fmt_number_style_from_string (s));
4796     }
4797
4798   if (!lex_force_match (lexer, T_SLASH))
4799     goto error;
4800
4801   while (!lex_match_id (lexer, "TABLE"))
4802     {
4803       if (lex_match_id (lexer, "FORMAT"))
4804         {
4805           double widths[2] = { SYSMIS, SYSMIS };
4806           double units_per_inch = 72.0;
4807
4808           while (lex_token (lexer) != T_SLASH)
4809             {
4810               if (lex_match_id (lexer, "MINCOLWIDTH"))
4811                 {
4812                   if (!parse_col_width (lexer, "MINCOLWIDTH", &widths[0]))
4813                     goto error;
4814                 }
4815               else if (lex_match_id (lexer, "MAXCOLWIDTH"))
4816                 {
4817                   if (!parse_col_width (lexer, "MAXCOLWIDTH", &widths[1]))
4818                     goto error;
4819                 }
4820               else if (lex_match_id (lexer, "UNITS"))
4821                 {
4822                   lex_match (lexer, T_EQUALS);
4823                   if (lex_match_id (lexer, "POINTS"))
4824                     units_per_inch = 72.0;
4825                   else if (lex_match_id (lexer, "INCHES"))
4826                     units_per_inch = 1.0;
4827                   else if (lex_match_id (lexer, "CM"))
4828                     units_per_inch = 2.54;
4829                   else
4830                     {
4831                       lex_error_expecting (lexer, "POINTS", "INCHES", "CM");
4832                       goto error;
4833                     }
4834                 }
4835               else if (lex_match_id (lexer, "EMPTY"))
4836                 {
4837                   free (ct->zero);
4838                   ct->zero = NULL;
4839
4840                   lex_match (lexer, T_EQUALS);
4841                   if (lex_match_id (lexer, "ZERO"))
4842                     {
4843                       /* Nothing to do. */
4844                     }
4845                   else if (lex_match_id (lexer, "BLANK"))
4846                     ct->zero = xstrdup ("");
4847                   else if (lex_force_string (lexer))
4848                     {
4849                       ct->zero = ss_xstrdup (lex_tokss (lexer));
4850                       lex_get (lexer);
4851                     }
4852                   else
4853                     goto error;
4854                 }
4855               else if (lex_match_id (lexer, "MISSING"))
4856                 {
4857                   lex_match (lexer, T_EQUALS);
4858                   if (!lex_force_string (lexer))
4859                     goto error;
4860
4861                   free (ct->missing);
4862                   ct->missing = (strcmp (lex_tokcstr (lexer), ".")
4863                                  ? ss_xstrdup (lex_tokss (lexer))
4864                                  : NULL);
4865                   lex_get (lexer);
4866                 }
4867               else
4868                 {
4869                   lex_error_expecting (lexer, "MINCOLWIDTH", "MAXCOLWIDTH",
4870                                        "UNITS", "EMPTY", "MISSING");
4871                   goto error;
4872                 }
4873             }
4874
4875           if (widths[0] != SYSMIS && widths[1] != SYSMIS
4876               && widths[0] > widths[1])
4877             {
4878               msg (SE, _("MINCOLWIDTH must not be greater than MAXCOLWIDTH."));
4879               goto error;
4880             }
4881
4882           for (size_t i = 0; i < 2; i++)
4883             if (widths[i] != SYSMIS)
4884               {
4885                 int *wr = ct->look->width_ranges[TABLE_HORZ];
4886                 wr[i] = widths[i] / units_per_inch * 96.0;
4887                 if (wr[0] > wr[1])
4888                   wr[!i] = wr[i];
4889               }
4890         }
4891       else if (lex_match_id (lexer, "VLABELS"))
4892         {
4893           if (!lex_force_match_id (lexer, "VARIABLES"))
4894             goto error;
4895           lex_match (lexer, T_EQUALS);
4896
4897           struct variable **vars;
4898           size_t n_vars;
4899           if (!parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
4900                                 PV_NO_SCRATCH))
4901             goto error;
4902
4903           if (!lex_force_match_id (lexer, "DISPLAY"))
4904             {
4905               free (vars);
4906               goto error;
4907             }
4908           lex_match (lexer, T_EQUALS);
4909
4910           enum ctables_vlabel vlabel;
4911           if (lex_match_id (lexer, "DEFAULT"))
4912             vlabel = (enum ctables_vlabel) settings_get_show_variables ();
4913           else if (lex_match_id (lexer, "NAME"))
4914             vlabel = CTVL_NAME;
4915           else if (lex_match_id (lexer, "LABEL"))
4916             vlabel = CTVL_LABEL;
4917           else if (lex_match_id (lexer, "BOTH"))
4918             vlabel = CTVL_BOTH;
4919           else if (lex_match_id (lexer, "NONE"))
4920             vlabel = CTVL_NONE;
4921           else
4922             {
4923               lex_error_expecting (lexer, "DEFAULT", "NAME", "LABEL",
4924                                    "BOTH", "NONE");
4925               free (vars);
4926               goto error;
4927             }
4928
4929           for (size_t i = 0; i < n_vars; i++)
4930             ct->vlabels[var_get_dict_index (vars[i])] = vlabel;
4931           free (vars);
4932         }
4933       else if (lex_match_id (lexer, "MRSETS"))
4934         {
4935           if (!lex_force_match_id (lexer, "COUNTDUPLICATES"))
4936             goto error;
4937           lex_match (lexer, T_EQUALS);
4938           if (!parse_bool (lexer, &ct->mrsets_count_duplicates))
4939             goto error;
4940         }
4941       else if (lex_match_id (lexer, "SMISSING"))
4942         {
4943           if (lex_match_id (lexer, "VARIABLE"))
4944             ct->smissing_listwise = false;
4945           else if (lex_match_id (lexer, "LISTWISE"))
4946             ct->smissing_listwise = true;
4947           else
4948             {
4949               lex_error_expecting (lexer, "VARIABLE", "LISTWISE");
4950               goto error;
4951             }
4952         }
4953       else if (lex_match_id (lexer, "PCOMPUTE"))
4954         {
4955           if (!ctables_parse_pcompute (lexer, ct))
4956             goto error;
4957         }
4958       else if (lex_match_id (lexer, "PPROPERTIES"))
4959         {
4960           if (!ctables_parse_pproperties (lexer, ct))
4961             goto error;
4962         }
4963       else if (lex_match_id (lexer, "WEIGHT"))
4964         {
4965           if (!lex_force_match_id (lexer, "VARIABLE"))
4966             goto error;
4967           lex_match (lexer, T_EQUALS);
4968           ct->e_weight = parse_variable (lexer, dataset_dict (ds));
4969           if (!ct->e_weight)
4970             goto error;
4971         }
4972       else if (lex_match_id (lexer, " HIDESMALLCOUNTS"))
4973         {
4974           if (lex_match_id (lexer, "COUNT"))
4975             {
4976               lex_match (lexer, T_EQUALS);
4977               if (!lex_force_int_range (lexer, "HIDESMALLCOUNTS COUNT",
4978                                         2, INT_MAX))
4979                 goto error;
4980               ct->hide_threshold = lex_integer (lexer);
4981               lex_get (lexer);
4982             }
4983           else if (ct->hide_threshold == 0)
4984             ct->hide_threshold = 5;
4985         }
4986       else
4987         {
4988           lex_error_expecting (lexer, "FORMAT", "VLABELS", "MRSETS",
4989                                "SMISSING", "PCOMPUTE", "PPROPERTIES",
4990                                "WEIGHT", "HIDESMALLCOUNTS", "TABLE");
4991           goto error;
4992         }
4993
4994       if (!lex_force_match (lexer, T_SLASH))
4995         goto error;
4996     }
4997
4998   size_t allocated_tables = 0;
4999   do
5000     {
5001       if (ct->n_tables >= allocated_tables)
5002         ct->tables = x2nrealloc (ct->tables, &allocated_tables,
5003                                  sizeof *ct->tables);
5004
5005       struct ctables_category *cat = xmalloc (sizeof *cat);
5006       *cat = (struct ctables_category) {
5007         .type = CCT_VALUE,
5008         .include_missing = false,
5009         .sort_ascending = true,
5010       };
5011
5012       struct ctables_categories *c = xmalloc (sizeof *c);
5013       size_t n_vars = dict_get_n_vars (dataset_dict (ds));
5014       *c = (struct ctables_categories) {
5015         .n_refs = n_vars,
5016         .cats = cat,
5017         .n_cats = 1,
5018         .show_empty = true,
5019       };
5020
5021       struct ctables_categories **categories = xnmalloc (n_vars,
5022                                                          sizeof *categories);
5023       for (size_t i = 0; i < n_vars; i++)
5024         categories[i] = c;
5025
5026       struct ctables_table *t = xmalloc (sizeof *t);
5027       *t = (struct ctables_table) {
5028         .ctables = ct,
5029         .slabels_axis = PIVOT_AXIS_COLUMN,
5030         .slabels_visible = true,
5031         .clabels_values_map = HMAP_INITIALIZER (t->clabels_values_map),
5032         .label_axis = {
5033           [PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW,
5034           [PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN,
5035           [PIVOT_AXIS_LAYER] = PIVOT_AXIS_LAYER,
5036         },
5037         .clabels_from_axis = PIVOT_AXIS_LAYER,
5038         .categories = categories,
5039         .n_categories = n_vars,
5040         .cilevel = 95,
5041       };
5042       ct->tables[ct->n_tables++] = t;
5043
5044       lex_match (lexer, T_EQUALS);
5045       if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW))
5046         goto error;
5047       if (lex_match (lexer, T_BY))
5048         {
5049           if (!ctables_axis_parse (lexer, dataset_dict (ds),
5050                                    ct, t, PIVOT_AXIS_COLUMN))
5051             goto error;
5052
5053           if (lex_match (lexer, T_BY))
5054             {
5055               if (!ctables_axis_parse (lexer, dataset_dict (ds),
5056                                        ct, t, PIVOT_AXIS_LAYER))
5057                 goto error;
5058             }
5059         }
5060
5061       if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN]
5062           && !t->axes[PIVOT_AXIS_LAYER])
5063         {
5064           lex_error (lexer, _("At least one variable must be specified."));
5065           goto error;
5066         }
5067
5068       const struct ctables_axis *scales[PIVOT_N_AXES];
5069       size_t n_scales = 0;
5070       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5071         {
5072           scales[a] = find_scale (t->axes[a]);
5073           if (scales[a])
5074             n_scales++;
5075         }
5076       if (n_scales > 1)
5077         {
5078           msg (SE, _("Scale variables may appear only on one axis."));
5079           if (scales[PIVOT_AXIS_ROW])
5080             msg_at (SN, scales[PIVOT_AXIS_ROW]->loc,
5081                     _("This scale variable appears on the rows axis."));
5082           if (scales[PIVOT_AXIS_COLUMN])
5083             msg_at (SN, scales[PIVOT_AXIS_COLUMN]->loc,
5084                     _("This scale variable appears on the columns axis."));
5085           if (scales[PIVOT_AXIS_LAYER])
5086             msg_at (SN, scales[PIVOT_AXIS_LAYER]->loc,
5087                     _("This scale variable appears on the layer axis."));
5088           goto error;
5089         }
5090
5091       const struct ctables_axis *summaries[PIVOT_N_AXES];
5092       size_t n_summaries = 0;
5093       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5094         {
5095           summaries[a] = (scales[a]
5096                           ? scales[a]
5097                           : find_categorical_summary_spec (t->axes[a]));
5098           if (summaries[a])
5099             n_summaries++;
5100         }
5101       if (n_summaries > 1)
5102         {
5103           msg (SE, _("Summaries may appear only on one axis."));
5104           if (summaries[PIVOT_AXIS_ROW])
5105             msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
5106                     _("This variable on the rows axis has a summary."));
5107           if (summaries[PIVOT_AXIS_COLUMN])
5108             msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
5109                     _("This variable on the columns axis has a summary."));
5110           if (summaries[PIVOT_AXIS_LAYER])
5111             msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
5112                     _("This variable on the layers axis has a summary."));
5113           goto error;
5114         }
5115       for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
5116         if (n_summaries ? summaries[a] : t->axes[a])
5117           {
5118             t->summary_axis = a;
5119             break;
5120           }
5121
5122       if (lex_token (lexer) == T_ENDCMD)
5123         {
5124           if (!ctables_prepare_table (t))
5125             goto error;
5126           break;
5127         }
5128       if (!lex_force_match (lexer, T_SLASH))
5129         break;
5130
5131       while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
5132         {
5133           if (lex_match_id (lexer, "SLABELS"))
5134             {
5135               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5136                 {
5137                   if (lex_match_id (lexer, "POSITION"))
5138                     {
5139                       lex_match (lexer, T_EQUALS);
5140                       if (lex_match_id (lexer, "COLUMN"))
5141                         t->slabels_axis = PIVOT_AXIS_COLUMN;
5142                       else if (lex_match_id (lexer, "ROW"))
5143                         t->slabels_axis = PIVOT_AXIS_ROW;
5144                       else if (lex_match_id (lexer, "LAYER"))
5145                         t->slabels_axis = PIVOT_AXIS_LAYER;
5146                       else
5147                         {
5148                           lex_error_expecting (lexer, "COLUMN", "ROW", "LAYER");
5149                           goto error;
5150                         }
5151                     }
5152                   else if (lex_match_id (lexer, "VISIBLE"))
5153                     {
5154                       lex_match (lexer, T_EQUALS);
5155                       if (!parse_bool (lexer, &t->slabels_visible))
5156                         goto error;
5157                     }
5158                   else
5159                     {
5160                       lex_error_expecting (lexer, "POSITION", "VISIBLE");
5161                       goto error;
5162                     }
5163                 }
5164             }
5165           else if (lex_match_id (lexer, "CLABELS"))
5166             {
5167               while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
5168                 {
5169                   if (lex_match_id (lexer, "AUTO"))
5170                     {
5171                       t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
5172                       t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
5173                     }
5174                   else if (lex_match_id (lexer, "ROWLABELS"))
5175                     {
5176                       lex_match (lexer, T_EQUALS);
5177                       if (lex_match_id (lexer, "OPPOSITE"))
5178                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
5179                       else if (lex_match_id (lexer, "LAYER"))
5180                         t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
5181                       else
5182                         {
5183                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5184                           goto error;
5185                         }
5186                     }
5187                   else if (lex_match_id (lexer, "COLLABELS"))
5188                     {
5189                       lex_match (lexer, T_EQUALS);
5190                       if (lex_match_id (lexer, "OPPOSITE"))
5191                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
5192                       else if (lex_match_id (lexer, "LAYER"))
5193                         t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
5194                       else
5195                         {
5196                           lex_error_expecting (lexer, "OPPOSITE", "LAYER");
5197                           goto error;
5198                         }
5199                     }
5200                   else
5201                     {
5202                       lex_error_expecting (lexer, "AUTO", "ROWLABELS",
5203                                            "COLLABELS");
5204                       goto error;
5205                     }
5206                 }
5207             }
5208           else if (lex_match_id (lexer, "CRITERIA"))
5209             {
5210               if (!lex_force_match_id (lexer, "CILEVEL"))
5211                 goto error;
5212               lex_match (lexer, T_EQUALS);
5213
5214               if (!lex_force_num_range_halfopen (lexer, "CILEVEL", 0, 100))
5215                 goto error;
5216               t->cilevel = lex_number (lexer);
5217               lex_get (lexer);
5218             }
5219           else if (lex_match_id (lexer, "CATEGORIES"))
5220             {
5221               if (!ctables_table_parse_categories (lexer, dataset_dict (ds),
5222                                                    ct, t))
5223                 goto error;
5224             }
5225           else if (lex_match_id (lexer, "TITLES"))
5226             {
5227               do
5228                 {
5229                   char **textp;
5230                   if (lex_match_id (lexer, "CAPTION"))
5231                     textp = &t->caption;
5232                   else if (lex_match_id (lexer, "CORNER"))
5233                     textp = &t->corner;
5234                   else if (lex_match_id (lexer, "TITLE"))
5235                     textp = &t->title;
5236                   else
5237                     {
5238                       lex_error_expecting (lexer, "CAPTION", "CORNER", "TITLE");
5239                       goto error;
5240                     }
5241                   lex_match (lexer, T_EQUALS);
5242
5243                   struct string s = DS_EMPTY_INITIALIZER;
5244                   while (lex_is_string (lexer))
5245                     {
5246                       if (!ds_is_empty (&s))
5247                         ds_put_byte (&s, ' ');
5248                       ds_put_substring (&s, lex_tokss (lexer));
5249                       lex_get (lexer);
5250                     }
5251                   free (*textp);
5252                   *textp = ds_steal_cstr (&s);
5253                 }
5254               while (lex_token (lexer) != T_SLASH
5255                      && lex_token (lexer) != T_ENDCMD);
5256             }
5257           else if (lex_match_id (lexer, "SIGTEST"))
5258             {
5259               if (!t->chisq)
5260                 {
5261                   t->chisq = xmalloc (sizeof *t->chisq);
5262                   *t->chisq = (struct ctables_chisq) {
5263                     .alpha = .05,
5264                     .include_mrsets = true,
5265                     .all_visible = true,
5266                   };
5267                 }
5268
5269               do
5270                 {
5271                   if (lex_match_id (lexer, "TYPE"))
5272                     {
5273                       lex_match (lexer, T_EQUALS);
5274                       if (!lex_force_match_id (lexer, "CHISQUARE"))
5275                         goto error;
5276                     }
5277                   else if (lex_match_id (lexer, "ALPHA"))
5278                     {
5279                       lex_match (lexer, T_EQUALS);
5280                       if (!lex_force_num_range_halfopen (lexer, "ALPHA", 0, 1))
5281                         goto error;
5282                       t->chisq->alpha = lex_number (lexer);
5283                       lex_get (lexer);
5284                     }
5285                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5286                     {
5287                       lex_match (lexer, T_EQUALS);
5288                       if (parse_bool (lexer, &t->chisq->include_mrsets))
5289                         goto error;
5290                     }
5291                   else if (lex_match_id (lexer, "CATEGORIES"))
5292                     {
5293                       lex_match (lexer, T_EQUALS);
5294                       if (lex_match_id (lexer, "ALLVISIBLE"))
5295                         t->chisq->all_visible = true;
5296                       else if (lex_match_id (lexer, "SUBTOTALS"))
5297                         t->chisq->all_visible = false;
5298                       else
5299                         {
5300                           lex_error_expecting (lexer,
5301                                                "ALLVISIBLE", "SUBTOTALS");
5302                           goto error;
5303                         }
5304                     }
5305                   else
5306                     {
5307                       lex_error_expecting (lexer, "TYPE", "ALPHA",
5308                                            "INCLUDEMRSETS", "CATEGORIES");
5309                       goto error;
5310                     }
5311                 }
5312               while (lex_token (lexer) != T_SLASH
5313                      && lex_token (lexer) != T_ENDCMD);
5314             }
5315           else if (lex_match_id (lexer, "COMPARETEST"))
5316             {
5317               if (!t->pairwise)
5318                 {
5319                   t->pairwise = xmalloc (sizeof *t->pairwise);
5320                   *t->pairwise = (struct ctables_pairwise) {
5321                     .type = PROP,
5322                     .alpha = { .05, .05 },
5323                     .adjust = BONFERRONI,
5324                     .include_mrsets = true,
5325                     .meansvariance_allcats = true,
5326                     .all_visible = true,
5327                     .merge = false,
5328                     .apa_style = true,
5329                     .show_sig = false,
5330                   };
5331                 }
5332
5333               do
5334                 {
5335                   if (lex_match_id (lexer, "TYPE"))
5336                     {
5337                       lex_match (lexer, T_EQUALS);
5338                       if (lex_match_id (lexer, "PROP"))
5339                         t->pairwise->type = PROP;
5340                       else if (lex_match_id (lexer, "MEAN"))
5341                         t->pairwise->type = MEAN;
5342                       else
5343                         {
5344                           lex_error_expecting (lexer, "PROP", "MEAN");
5345                           goto error;
5346                         }
5347                     }
5348                   else if (lex_match_id (lexer, "ALPHA"))
5349                     {
5350                       lex_match (lexer, T_EQUALS);
5351
5352                       if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5353                         goto error;
5354                       double a0 = lex_number (lexer);
5355                       lex_get (lexer);
5356
5357                       lex_match (lexer, T_COMMA);
5358                       if (lex_is_number (lexer))
5359                         {
5360                           if (!lex_force_num_range_open (lexer, "ALPHA", 0, 1))
5361                             goto error;
5362                           double a1 = lex_number (lexer);
5363                           lex_get (lexer);
5364
5365                           t->pairwise->alpha[0] = MIN (a0, a1);
5366                           t->pairwise->alpha[1] = MAX (a0, a1);
5367                         }
5368                       else
5369                         t->pairwise->alpha[0] = t->pairwise->alpha[1] = a0;
5370                     }
5371                   else if (lex_match_id (lexer, "ADJUST"))
5372                     {
5373                       lex_match (lexer, T_EQUALS);
5374                       if (lex_match_id (lexer, "BONFERRONI"))
5375                         t->pairwise->adjust = BONFERRONI;
5376                       else if (lex_match_id (lexer, "BH"))
5377                         t->pairwise->adjust = BH;
5378                       else if (lex_match_id (lexer, "NONE"))
5379                         t->pairwise->adjust = 0;
5380                       else
5381                         {
5382                           lex_error_expecting (lexer, "BONFERRONI", "BH",
5383                                                "NONE");
5384                           goto error;
5385                         }
5386                     }
5387                   else if (lex_match_id (lexer, "INCLUDEMRSETS"))
5388                     {
5389                       lex_match (lexer, T_EQUALS);
5390                       if (!parse_bool (lexer, &t->pairwise->include_mrsets))
5391                         goto error;
5392                     }
5393                   else if (lex_match_id (lexer, "MEANSVARIANCE"))
5394                     {
5395                       lex_match (lexer, T_EQUALS);
5396                       if (lex_match_id (lexer, "ALLCATS"))
5397                         t->pairwise->meansvariance_allcats = true;
5398                       else if (lex_match_id (lexer, "TESTEDCATS"))
5399                         t->pairwise->meansvariance_allcats = false;
5400                       else
5401                         {
5402                           lex_error_expecting (lexer, "ALLCATS", "TESTEDCATS");
5403                           goto error;
5404                         }
5405                     }
5406                   else if (lex_match_id (lexer, "CATEGORIES"))
5407                     {
5408                       lex_match (lexer, T_EQUALS);
5409                       if (lex_match_id (lexer, "ALLVISIBLE"))
5410                         t->pairwise->all_visible = true;
5411                       else if (lex_match_id (lexer, "SUBTOTALS"))
5412                         t->pairwise->all_visible = false;
5413                       else
5414                         {
5415                           lex_error_expecting (lexer, "ALLVISIBLE",
5416                                                "SUBTOTALS");
5417                           goto error;
5418                         }
5419                     }
5420                   else if (lex_match_id (lexer, "MERGE"))
5421                     {
5422                       lex_match (lexer, T_EQUALS);
5423                       if (!parse_bool (lexer, &t->pairwise->merge))
5424                         goto error;
5425                     }
5426                   else if (lex_match_id (lexer, "STYLE"))
5427                     {
5428                       lex_match (lexer, T_EQUALS);
5429                       if (lex_match_id (lexer, "APA"))
5430                         t->pairwise->apa_style = true;
5431                       else if (lex_match_id (lexer, "SIMPLE"))
5432                         t->pairwise->apa_style = false;
5433                       else
5434                         {
5435                           lex_error_expecting (lexer, "APA", "SIMPLE");
5436                           goto error;
5437                         }
5438                     }
5439                   else if (lex_match_id (lexer, "SHOWSIG"))
5440                     {
5441                       lex_match (lexer, T_EQUALS);
5442                       if (!parse_bool (lexer, &t->pairwise->show_sig))
5443                         goto error;
5444                     }
5445                   else
5446                     {
5447                       lex_error_expecting (lexer, "TYPE", "ALPHA", "ADJUST",
5448                                            "INCLUDEMRSETS", "MEANSVARIANCE",
5449                                            "CATEGORIES", "MERGE", "STYLE",
5450                                            "SHOWSIG");
5451                       goto error;
5452                     }
5453                 }
5454               while (lex_token (lexer) != T_SLASH
5455                      && lex_token (lexer) != T_ENDCMD);
5456             }
5457           else
5458             {
5459               lex_error_expecting (lexer, "TABLE", "SLABELS", "CLABELS",
5460                                    "CRITERIA", "CATEGORIES", "TITLES",
5461                                    "SIGTEST", "COMPARETEST");
5462               goto error;
5463             }
5464
5465           if (!lex_match (lexer, T_SLASH))
5466             break;
5467         }
5468
5469       if (t->label_axis[PIVOT_AXIS_ROW] != PIVOT_AXIS_ROW
5470           && t->label_axis[PIVOT_AXIS_COLUMN] != PIVOT_AXIS_COLUMN)
5471         {
5472           msg (SE, _("ROWLABELS and COLLABELS may not both be specified."));
5473           goto error;
5474         }
5475
5476       if (!ctables_prepare_table (t))
5477         goto error;
5478     }
5479   while (lex_token (lexer) != T_ENDCMD);
5480
5481   bool ok = ctables_execute (ds, ct);
5482   ctables_destroy (ct);
5483   return ok ? CMD_SUCCESS : CMD_FAILURE;
5484
5485 error:
5486   ctables_destroy (ct);
5487   return CMD_FAILURE;
5488 }
5489