0cc0b1b3172ffaf40673de96087784b918151eed
[pspp] / src / language / stats / means-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2012, 2013, 2019 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/case.h"
20 #include "data/casegrouper.h"
21 #include "data/casereader.h"
22 #include "data/dataset.h"
23 #include "data/dictionary.h"
24 #include "data/format.h"
25 #include "data/variable.h"
26
27 #include "language/lexer/lexer.h"
28 #include "language/lexer/variable-parser.h"
29
30 #include "libpspp/pool.h"
31
32 #include "means.h"
33
34 /* Parse the /TABLES stanza of the command.  */
35 static bool
36 parse_means_table_syntax (struct lexer *lexer, const struct means *cmd,
37                           struct mtable *table)
38 {
39   memset (table, 0, sizeof *table);
40
41   /* Dependent variable (s) */
42   if (!parse_variables_const_pool (lexer, cmd->pool, cmd->dict,
43                                    &table->dep_vars, &table->n_dep_vars,
44                                    PV_NO_DUPLICATE | PV_NUMERIC))
45     return false;
46
47   /* Factor variable (s) */
48   while (lex_match (lexer, T_BY))
49     {
50       struct layer *layer = pool_zalloc (cmd->pool, sizeof *layer);
51
52       table->layers =
53         pool_nrealloc (cmd->pool, table->layers, table->n_layers + 1,
54                        sizeof *table->layers);
55       table->layers[table->n_layers] = layer;
56       table->n_layers++;
57
58       if (!parse_variables_const_pool
59           (lexer, cmd->pool, cmd->dict,
60            &layer->factor_vars,
61            &layer->n_factor_vars,
62            PV_NO_DUPLICATE))
63         return false;
64     }
65
66   return true;
67 }
68
69 /* Match a variable.
70    If the match succeeds, the variable will be placed in VAR.
71    Returns true if successful */
72 static bool
73 lex_is_variable (struct lexer *lexer, const struct dictionary *dict,
74                  int n)
75 {
76   if (lex_next_token (lexer, n) != T_ID)
77     return false;
78
79   const char *tstr = lex_next_tokcstr (lexer, n);
80   return dict_lookup_var (dict, tstr) != NULL;
81 }
82
83 static const struct cell_spec *
84 match_cell (struct lexer *lexer)
85 {
86   for (size_t i = 0; i < n_MEANS_STATISTICS; ++i)
87     {
88       const struct cell_spec *cs = &cell_spec[i];
89       if (lex_match_id (lexer, cs->keyword))
90         return cs;
91     }
92   return NULL;
93 }
94
95 static void
96 add_statistic (struct means *means, int statistic)
97 {
98   if (means->n_statistics >= means->allocated_statistics)
99     means->statistics = pool_2nrealloc (means->pool, means->statistics,
100                                         &means->allocated_statistics,
101                                         sizeof *means->statistics);
102   means->statistics[means->n_statistics++] = statistic;
103 }
104
105 void
106 means_set_default_statistics (struct means *means)
107 {
108   means->n_statistics = 0;
109   add_statistic (means, MEANS_MEAN);
110   add_statistic (means, MEANS_N);
111   add_statistic (means, MEANS_STDDEV);
112 }
113
114 bool
115 means_parse (struct lexer *lexer, struct means *means)
116 {
117   /* Optional TABLES=. */
118   if (lex_match_id (lexer, "TABLES") && !lex_force_match (lexer, T_EQUALS))
119     return false;
120
121   /* Parse the "tables" */
122   for (;;)
123     {
124       means->table = pool_realloc (means->pool, means->table,
125                                    (means->n_tables + 1) * sizeof *means->table);
126
127       if (!parse_means_table_syntax (lexer, means,
128                                      &means->table[means->n_tables]))
129         return false;
130       means->n_tables++;
131
132       /* Look ahead to see if there are more tables to be parsed */
133       if (lex_next_token (lexer, 0) != T_SLASH
134           || !lex_is_variable (lexer, means->dict, 1))
135         break;
136       lex_match (lexer, T_SLASH);
137     }
138
139   /* /MISSING subcommand */
140   while (lex_token (lexer) != T_ENDCMD)
141     {
142       lex_match (lexer, T_SLASH);
143
144       if (lex_match_id (lexer, "MISSING"))
145         {
146           /* If no MISSING subcommand is specified, each combination of a
147              dependent variable and categorical variables is handled
148              separately. */
149           lex_match (lexer, T_EQUALS);
150           if (lex_match_id (lexer, "INCLUDE"))
151             {
152               /* Use the subcommand "/MISSING=INCLUDE" to include user-missing
153                  values in the analysis. */
154
155               means->ctrl_exclude = MV_SYSTEM;
156               means->dep_exclude = MV_SYSTEM;
157             }
158           else if (lex_match_id (lexer, "DEPENDENT"))
159             /* Use the command "/MISSING=DEPENDENT" to include user-missing
160                values for the categorical variables, while excluding them for
161                the dependent variables.
162
163                Cases are dropped only when user-missing values appear in
164                dependent variables.  User-missing values for categorical
165                variables are treated according to their face value.
166
167                Cases are ALWAYS dropped when System Missing values appear in
168                the categorical variables. */
169             {
170               means->dep_exclude = MV_ANY;
171               means->ctrl_exclude = MV_SYSTEM;
172             }
173           else
174             {
175               lex_error_expecting (lexer, "INCLUDE", "DEPENDENT");
176               return false;
177             }
178         }
179       else if (lex_match_id (lexer, "CELLS"))
180         {
181           lex_match (lexer, T_EQUALS);
182
183           /* The default values become overwritten */
184           means->n_statistics = 0;
185           while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
186             {
187               if (lex_match (lexer, T_ALL))
188                 {
189                   means->n_statistics = 0;
190                   for (int i = 0; i < n_MEANS_STATISTICS; ++i)
191                     add_statistic (means, i);
192                 }
193               else if (lex_match_id (lexer, "NONE"))
194                 means->n_statistics = 0;
195               else if (lex_match_id (lexer, "DEFAULT"))
196                 means_set_default_statistics (means);
197               else
198                 {
199                   const struct cell_spec *cs = match_cell (lexer);
200                   if (cs)
201                     add_statistic (means, cs - cell_spec);
202                   else
203                     {
204                       const char *keywords[n_MEANS_STATISTICS];
205                       for (int i = 0; i < n_MEANS_STATISTICS; ++i)
206                         keywords[i] = cell_spec[i].keyword;
207                       lex_error_expecting_array (lexer, keywords,
208                                                  n_MEANS_STATISTICS);
209                       return false;
210                     }
211                 }
212             }
213         }
214       else
215         {
216           lex_error_expecting (lexer, "MISSING", "CELLS");
217           return false;
218         }
219     }
220   return true;
221 }