+
+
+static double
+calc_mom1 (double acc, double x, double w)
+{
+ return acc + x * w;
+}
+
+static double
+calc_mom0 (double acc, double x UNUSED, double w)
+{
+ return acc + w;
+}
+
+static double
+pre_low_extreme (void)
+{
+ return -DBL_MAX;
+}
+
+static double
+calc_max (double acc, double x, double w UNUSED)
+{
+ return (acc > x) ? acc : x;
+}
+
+static double
+pre_high_extreme (void)
+{
+ return DBL_MAX;
+}
+
+static double
+calc_min (double acc, double x, double w UNUSED)
+{
+ return (acc < x) ? acc : x;
+}
+
+static double
+post_normalise (double acc, double cc)
+{
+ return acc / cc;
+}
+
+static double
+post_percentage (double acc, double ccc)
+{
+ return acc / ccc * 100.0;
+}
+
+
+const struct ag_func ag_func[] =
+ {
+ {"COUNT", N_("Count"), 0, 0, NULL, calc_mom0, 0, 0},
+ {"PCT", N_("Percentage"), 0, 0, NULL, calc_mom0, 0, post_percentage},
+ {"CUFREQ", N_("Cumulative Count"), 0, 1, NULL, calc_mom0, 0, 0},
+ {"CUPCT", N_("Cumulative Percent"), 0, 1, NULL, calc_mom0, 0, post_percentage},
+
+ {"MEAN", N_("Mean"), 1, 0, NULL, calc_mom1, post_normalise, 0},
+ {"SUM", N_("Sum"), 1, 0, NULL, calc_mom1, 0, 0},
+ {"MAXIMUM", N_("Maximum"), 1, 0, pre_low_extreme, calc_max, 0, 0},
+ {"MINIMUM", N_("Minimum"), 1, 0, pre_high_extreme, calc_min, 0, 0},
+ };
+
+const int N_AG_FUNCS = sizeof (ag_func) / sizeof (ag_func[0]);
+
+static bool
+parse_function (struct lexer *lexer, struct graph *graph)
+{
+ int i;
+ for (i = 0 ; i < N_AG_FUNCS; ++i)
+ {
+ if (lex_match_id (lexer, ag_func[i].name))
+ {
+ graph->agr = i;
+ break;
+ }
+ }
+ if (i == N_AG_FUNCS)
+ {
+ goto error;
+ }
+
+ graph->n_dep_vars = ag_func[i].arity;
+ if (ag_func[i].arity > 0)
+ {
+ int v;
+ if (!lex_force_match (lexer, T_LPAREN))
+ goto error;
+
+ graph->dep_vars = xzalloc (sizeof (graph->dep_vars) * graph->n_dep_vars);
+ for (v = 0; v < ag_func[i].arity; ++v)
+ {
+ graph->dep_vars[v] = parse_variable (lexer, graph->dict);
+ }
+
+ if (!lex_force_match (lexer, T_RPAREN))
+ goto error;
+ }
+
+ if (!lex_force_match (lexer, T_BY))
+ goto error;
+
+ graph->by_var[0] = parse_variable (lexer, graph->dict);
+ if (!graph->by_var[0])
+ {
+ goto error;
+ }
+ subcase_add_var (&graph->ordering, graph->by_var[0], SC_ASCEND);
+ graph->n_by_vars++;
+
+ if (lex_match (lexer, T_BY))
+ {
+ graph->by_var[1] = parse_variable (lexer, graph->dict);
+ if (!graph->by_var[1])
+ {
+ goto error;
+ }
+ subcase_add_var (&graph->ordering, graph->by_var[1], SC_ASCEND);
+ graph->n_by_vars++;
+ }
+
+ return true;
+
+ error:
+ lex_error (lexer, NULL);
+ return false;
+}
+
+