and are finally passed to the procedure. */
struct casereader *source;
struct caseinit *caseinit;
- struct trns_chain *permanent_trns_chain;
+ struct trns_chain permanent_trns_chain;
struct dictionary *permanent_dict;
struct casewriter *sink;
- struct trns_chain *temporary_trns_chain;
+ struct trns_chain temporary_trns_chain;
+ bool temporary;
struct dictionary *dict;
+ /* Stack of transformation chains for DO IF and LOOP and INPUT PROGRAM. */
+ struct trns_chain *stack;
+ size_t n_stack;
+ size_t allocated_stack;
+
/* If true, cases are discarded instead of being written to
sink. */
bool discard_output;
- /* The transformation chain that the next transformation will be
- added to. */
- struct trns_chain *cur_trns_chain;
-
/* The case map used to compact a case, if necessary;
otherwise a null pointer. */
struct case_map *compactor;
struct dataset *
dataset_create (struct session *session, const char *name)
{
- struct dataset *ds = XZALLOC (struct dataset);
- ds->name = xstrdup (name);
- ds->display = DATASET_FRONT;
- ds->dict = dict_create (get_default_encoding ());
-
- ds->caseinit = caseinit_create ();
-
+ struct dataset *ds = XMALLOC (struct dataset);
+ *ds = (struct dataset) {
+ .name = xstrdup (name),
+ .display = DATASET_FRONT,
+ .dict = dict_create (get_default_encoding ()),
+ .caseinit = caseinit_create (),
+ };
dataset_create_finish__ (ds, session);
return ds;
struct dataset *new;
assert (old->proc_state == PROC_COMMITTED);
- assert (trns_chain_is_empty (old->permanent_trns_chain));
+ assert (!old->permanent_trns_chain.n);
assert (old->permanent_dict == NULL);
assert (old->sink == NULL);
- assert (old->temporary_trns_chain == NULL);
+ assert (!old->temporary);
+ assert (!old->temporary_trns_chain.n);
new = xzalloc (sizeof *new);
new->name = xstrdup (name);
dict_unref (ds->dict);
dict_unref (ds->permanent_dict);
caseinit_destroy (ds->caseinit);
- trns_chain_destroy (ds->permanent_trns_chain);
+ trns_chain_uninit (&ds->permanent_trns_chain);
+ for (size_t i = 0; i < ds->n_stack; i++)
+ trns_chain_uninit (&ds->stack[i]);
+ free (ds->stack);
dataset_transformations_changed__ (ds, false);
free (ds->name);
free (ds);
{
bool ok;
- if ((ds->temporary_trns_chain == NULL
- || trns_chain_is_empty (ds->temporary_trns_chain))
- && trns_chain_is_empty (ds->permanent_trns_chain))
+ if ((!ds->temporary || !ds->temporary_trns_chain.n)
+ && !ds->permanent_trns_chain.n)
{
ds->n_lag = 0;
ds->discard_output = false;
/* Execute permanent transformations. */
case_nr = ds->cases_written + 1;
- retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE,
- &c, case_nr);
+ retval = trns_chain_execute (&ds->permanent_trns_chain, case_nr, &c);
caseinit_update_left_vars (ds->caseinit, c);
if (retval != TRNS_CONTINUE)
continue;
case_map_execute (ds->compactor, case_ref (c)));
/* Execute temporary transformations. */
- if (ds->temporary_trns_chain != NULL)
+ if (ds->temporary_trns_chain.n)
{
- retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE,
- &c, ds->cases_written);
+ retval = trns_chain_execute (&ds->temporary_trns_chain,
+ ds->cases_written, &c);
if (retval != TRNS_CONTINUE)
continue;
}
return NULL;
}
\f
-/* Returns the current set of permanent transformations,
- and clears the permanent transformations.
- For use by INPUT PROGRAM. */
-struct trns_chain *
-proc_capture_transformations (struct dataset *ds)
-{
- struct trns_chain *chain;
-
- assert (ds->temporary_trns_chain == NULL);
- chain = ds->permanent_trns_chain;
- ds->cur_trns_chain = ds->permanent_trns_chain = trns_chain_create ();
- dataset_transformations_changed__ (ds, false);
-
- return chain;
-}
-
-/* Adds a transformation that processes a case with PROC and
- frees itself with FREE to the current set of transformations.
- The functions are passed AUX as auxiliary data. */
+/* Adds TRNS to the current set of transformations. */
void
-add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *free, void *aux)
-{
- trns_chain_append (ds->cur_trns_chain, NULL, proc, free, aux);
+add_transformation (struct dataset *ds,
+ const struct trns_class *class, void *aux)
+{
+ struct trns_chain *chain = (ds->n_stack > 0 ? &ds->stack[ds->n_stack - 1]
+ : ds->temporary ? &ds->temporary_trns_chain
+ : &ds->permanent_trns_chain);
+ struct transformation t = { .class = class, .aux = aux };
+ trns_chain_append (chain, &t);
dataset_transformations_changed__ (ds, true);
}
bool
proc_in_temporary_transformations (const struct dataset *ds)
{
- return ds->temporary_trns_chain != NULL;
+ return ds->temporary;
}
/* Marks the start of temporary transformations.
ds->permanent_dict = dict_clone (ds->dict);
- ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create ();
+ ds->temporary = true;
dataset_transformations_changed__ (ds, true);
}
}
{
if (proc_in_temporary_transformations (ds))
{
- trns_chain_splice (ds->permanent_trns_chain, ds->temporary_trns_chain);
- ds->temporary_trns_chain = NULL;
+ trns_chain_splice (&ds->permanent_trns_chain, &ds->temporary_trns_chain);
- ds->cur_trns_chain = ds->permanent_trns_chain;
+ ds->temporary = false;
dict_unref (ds->permanent_dict);
ds->permanent_dict = NULL;
ds->dict = ds->permanent_dict;
ds->permanent_dict = NULL;
- trns_chain_destroy (ds->temporary_trns_chain);
- ds->temporary_trns_chain = NULL;
- dataset_transformations_changed__ (
- ds, !trns_chain_is_empty (ds->permanent_trns_chain));
+ trns_chain_clear (&ds->temporary_trns_chain);
+
+ dataset_transformations_changed__ (ds, ds->permanent_trns_chain.n != 0);
return true;
}
else
{
bool ok;
assert (ds->proc_state == PROC_COMMITTED);
- ok = trns_chain_destroy (ds->permanent_trns_chain);
- ok = trns_chain_destroy (ds->temporary_trns_chain) && ok;
- ds->permanent_trns_chain = ds->cur_trns_chain = trns_chain_create ();
- ds->temporary_trns_chain = NULL;
+ ok = trns_chain_clear (&ds->permanent_trns_chain);
+ ok = trns_chain_clear (&ds->temporary_trns_chain) && ok;
+ ds->temporary = false;
+ for (size_t i = 0; i < ds->n_stack; i++)
+ ok = trns_chain_uninit (&ds->stack[i]) && ok;
+ ds->n_stack = 0;
dataset_transformations_changed__ (ds, false);
return ok;
}
+void
+proc_push_transformations (struct dataset *ds)
+{
+ if (ds->n_stack >= ds->allocated_stack)
+ ds->stack = x2nrealloc (ds->stack, &ds->allocated_stack,
+ sizeof *ds->stack);
+ trns_chain_init (&ds->stack[ds->n_stack++]);
+}
+
+void
+proc_pop_transformations (struct dataset *ds, struct trns_chain *chain)
+{
+ assert (ds->n_stack > 0);
+ *chain = ds->stack[--ds->n_stack];
+}
+
static enum trns_result
store_case_num (void *var_, struct ccase **cc, casenumber case_num)
{
struct variable *
add_permanent_ordering_transformation (struct dataset *ds)
{
- struct variable *temp_var;
+ struct variable *temp_var = dict_create_var_assert (ds->dict, "$ORDER", 0);
+ struct variable *order_var
+ = (proc_in_temporary_transformations (ds)
+ ? dict_clone_var_in_place_assert (ds->permanent_dict, temp_var)
+ : temp_var);
- temp_var = dict_create_var_assert (ds->dict, "$ORDER", 0);
- if (proc_in_temporary_transformations (ds))
- {
- struct variable *perm_var;
-
- perm_var = dict_clone_var_in_place_assert (ds->permanent_dict, temp_var);
- trns_chain_append (ds->permanent_trns_chain, NULL, store_case_num,
- NULL, perm_var);
- }
- else
- add_transformation (ds, store_case_num, NULL, temp_var);
+ static const struct trns_class trns_class = {
+ .name = "ordering",
+ .execute = store_case_num
+ };
+ const struct transformation t = { .class = &trns_class, .aux = order_var };
+ trns_chain_append (&ds->permanent_trns_chain, &t);
return temp_var;
}
return true;
}
\f
-static trns_proc_func case_limit_trns_proc;
-static trns_free_func case_limit_trns_free;
-
-/* Adds a transformation that limits the number of cases that may
- pass through, if DS->DICT has a case limit. */
-static void
-add_case_limit_trns (struct dataset *ds)
-{
- casenumber case_limit = dict_get_case_limit (ds->dict);
- if (case_limit != 0)
- {
- casenumber *cases_remaining = xmalloc (sizeof *cases_remaining);
- *cases_remaining = case_limit;
- add_transformation (ds, case_limit_trns_proc, case_limit_trns_free,
- cases_remaining);
- dict_set_case_limit (ds->dict, 0);
- }
-}
-
/* Limits the maximum number of cases processed to
*CASES_REMAINING. */
static enum trns_result
free (cases_remaining);
return true;
}
-\f
-static trns_proc_func filter_trns_proc;
-/* Adds a temporary transformation to filter data according to
- the variable specified on FILTER, if any. */
+/* Adds a transformation that limits the number of cases that may
+ pass through, if DS->DICT has a case limit. */
static void
-add_filter_trns (struct dataset *ds)
+add_case_limit_trns (struct dataset *ds)
{
- struct variable *filter_var = dict_get_filter (ds->dict);
- if (filter_var != NULL)
+ casenumber case_limit = dict_get_case_limit (ds->dict);
+ if (case_limit != 0)
{
- proc_start_temporary_transformations (ds);
- add_transformation (ds, filter_trns_proc, NULL, filter_var);
+ casenumber *cases_remaining = xmalloc (sizeof *cases_remaining);
+ *cases_remaining = case_limit;
+
+ static const struct trns_class trns_class = {
+ .name = "case limit",
+ .execute = case_limit_trns_proc,
+ .destroy = case_limit_trns_free,
+ };
+ add_transformation (ds, &trns_class, cases_remaining);
+
+ dict_set_case_limit (ds->dict, 0);
}
}
+\f
/* FILTER transformation. */
static enum trns_result
filter_trns_proc (void *filter_var_,
? TRNS_CONTINUE : TRNS_DROP_CASE);
}
+/* Adds a temporary transformation to filter data according to
+ the variable specified on FILTER, if any. */
+static void
+add_filter_trns (struct dataset *ds)
+{
+ struct variable *filter_var = dict_get_filter (ds->dict);
+ if (filter_var != NULL)
+ {
+ proc_start_temporary_transformations (ds);
+
+ static const struct trns_class trns_class = {
+ .name = "FILTER",
+ .execute = filter_trns_proc,
+ };
+ add_transformation (ds, &trns_class, filter_var);
+ }
+}
void
dataset_need_lag (struct dataset *ds, int n_before)
\f
/* Transformations. */
-void add_transformation (struct dataset *ds,
- trns_proc_func *, trns_free_func *, void *);
+void add_transformation (struct dataset *ds, const struct trns_class *, void *);
bool proc_cancel_all_transformations (struct dataset *ds);
-struct trns_chain *proc_capture_transformations (struct dataset *ds);
void proc_push_transformations (struct dataset *);
-void proc_pop_transformations (struct dataset *, struct transformation **,
- size_t *n);
+void proc_pop_transformations (struct dataset *, struct trns_chain *);
void proc_start_temporary_transformations (struct dataset *ds);
bool proc_in_temporary_transformations (const struct dataset *ds);
#include "gl/xalloc.h"
-/* A single transformation. */
-struct transformation
- {
- /* Offset to add to EXECUTE's return value, if it returns a
- transformation index. Normally 0 but set to the starting
- index of a spliced chain after splicing. */
- int idx_ofs;
- trns_proc_func *execute; /* Executes the transformation. */
- trns_free_func *free; /* Garbage collector proc. */
- void *aux; /* Auxiliary data. */
- };
-
-/* A chain of transformations. */
-struct trns_chain
- {
- struct transformation *trns; /* Array of transformations. */
- size_t n_trns; /* Number of transformations. */
- size_t allocated_trns; /* Allocated capacity. */
- };
-
-/* Allocates and returns a new transformation chain. */
-struct trns_chain *
-trns_chain_create (void)
+void
+trns_chain_init (struct trns_chain *chain)
{
- struct trns_chain *chain = xmalloc (sizeof *chain);
- chain->trns = NULL;
- chain->n_trns = 0;
- chain->allocated_trns = 0;
- return chain;
+ *chain = (struct trns_chain) TRNS_CHAIN_INIT;
}
-/* Destroys CHAIN. */
bool
-trns_chain_destroy (struct trns_chain *chain)
+trns_chain_uninit (struct trns_chain *chain)
{
- if (!chain)
- return true;
-
- for (size_t i = 0; i < chain->n_trns; i++)
+ bool ok = true;
+ for (size_t i = 0; i < chain->n; i++)
{
- struct transformation *trns = &chain->trns[i];
- if (trns->free)
- ok = trns->free (trns->aux) && ok;
+ struct transformation *xform = &chain->xforms[i];
+ if (xform->class->destroy)
+ ok = xform->class->destroy (xform->aux) && ok;
}
- free (chain->trns);
- free (chain);
+ free (chain->xforms);
return ok;
}
-/* Returns true if CHAIN contains any transformations,
- false otherwise. */
bool
-trns_chain_is_empty (const struct trns_chain *chain)
+trns_chain_clear (struct trns_chain *chain)
{
- return chain->n_trns == 0;
+ bool ok = trns_chain_uninit (chain);
+ trns_chain_init (chain);
+ return ok;
}
-/* Adds a transformation to CHAIN with execute function EXECUTE, free function
- FREE, and auxiliary data AUX. */
void
-trns_chain_append (struct trns_chain *chain, trns_proc_func *execute,
- trns_free_func *free, void *aux)
+trns_chain_append (struct trns_chain *chain, const struct transformation *t)
{
- struct transformation *trns;
+ if (chain->n >= chain->allocated)
+ chain->xforms = x2nrealloc (chain->xforms, &chain->allocated,
+ sizeof *chain->xforms);
- if (chain->n_trns == chain->allocated_trns)
- chain->trns = x2nrealloc (chain->trns, &chain->allocated_trns,
- sizeof *chain->trns);
-
- trns = &chain->trns[chain->n_trns++];
- trns->idx_ofs = 0;
- trns->execute = execute;
- trns->free = free;
- trns->aux = aux;
+ chain->xforms[chain->n++] = *t;
}
-/* Appends the transformations in SRC to those in DST, and destroys SRC. */
void
trns_chain_splice (struct trns_chain *dst, struct trns_chain *src)
{
- if (dst->n_trns + src->n_trns > dst->allocated_trns)
+ if (dst->n + src->n >= dst->allocated)
{
- dst->allocated_trns = dst->n_trns + src->n_trns;
- dst->trns = xnrealloc (dst->trns, dst->allocated_trns, sizeof *dst->trns);
+ dst->allocated = dst->n + src->n;
+ dst->xforms = xrealloc (dst->xforms,
+ dst->allocated * sizeof *dst->xforms);
}
- for (size_t i = 0; i < src->n_trns; i++)
- {
- struct transformation *d = &dst->trns[i + dst->n_trns];
- const struct transformation *s = &src->trns[i];
- *d = *s;
- d->idx_ofs += src->n_trns;
- }
- dst->n_trns += src->n_trns;
-
- src->n_trns = 0;
- trns_chain_destroy (src);
+ memcpy (&dst->xforms[dst->n], src->xforms, src->n * sizeof *src->xforms);
+ dst->n += src->n;
+ src->n = 0;
}
-/* Returns the index that a transformation execution function may
- return to "jump" to the next transformation to be added. */
-size_t
-trns_chain_next (struct trns_chain *chain)
-{
- return chain->n_trns;
-}
-
-/* Executes the given CHAIN of transformations on *C,
- passing CASE_NR as the case number.
- *C may be replaced by a new case.
- Returns the result code that caused the transformations to
- terminate, or TRNS_CONTINUE if the transformations finished
- due to "falling off the end" of the set of transformations. */
+/* Executes the N transformations in XFORMS against case *C passing CASE_NR as
+ the case number. The transformations may replace *C by a new case. Returns
+ the result code that caused the transformations to terminate, or
+ TRNS_CONTINUE if the transformations finished due to "falling off the end"
+ of the set of transformations. */
enum trns_result
-trns_chain_execute (const struct trns_chain *chain, enum trns_result start,
- struct ccase **c, casenumber case_nr)
+trns_chain_execute (const struct trns_chain *chain,
+ casenumber case_nr, struct ccase **c)
{
- size_t i;
-
- for (i = start < 0 ? 0 : start; i < chain->n_trns;)
+ for (size_t i = 0; i < chain->n; i++)
{
- struct transformation *trns = &chain->trns[i];
- int retval = trns->execute (trns->aux, c, case_nr);
- if (retval == TRNS_CONTINUE)
- i++;
- else if (retval >= 0)
- i = retval + trns->idx_ofs;
- else
- return retval == TRNS_END_CASE ? i + 1 : retval;
+ const struct transformation *trns = &chain->xforms[i];
+ printf ("%s\n", trns->class->name);
+ int retval = trns->class->execute (trns->aux, c, case_nr);
+ if (retval != TRNS_CONTINUE)
+ return retval;
}
return TRNS_CONTINUE;
#include <stddef.h>
#include "data/case.h"
-/* trns_proc_func return values. */
+/* One transformation. */
+
enum trns_result
{
TRNS_CONTINUE, /* Continue to next transformation. */
struct ccase;
-typedef enum trns_result trns_proc_func (void *, struct ccase **, casenumber);
-typedef bool trns_free_func (void *);
struct trns_class
{
- int (*execute) (void *aux, struct ccase **, casenumber);
+ const char *name; /* For debugging. */
+ enum trns_result (*execute) (void *aux, struct ccase **, casenumber);
bool (*destroy) (void *aux);
};
-\f
-/* Transformation chains. */
struct transformation
{
const struct trns_class *class;
void *aux;
};
-enum trns_result transformations_execute (const struct transformation *,
- size_t n,
- struct ccase **, casenumber case_num);
-void transformations_destroy (struct transformation *, size_t n);
+\f
+/* A chain of transformations. */
-struct trns_builder *trns_builder_create (void);
-void trns_builder_append (struct trns_builder *, trns_proc_func *, trns_free_func *, void *);
-struct trns_chain *trns_builder_finish (struct trns_builder *);
-void trns_builder_destroy (struct trns_chain *);
+struct trns_chain
+ {
+ struct transformation *xforms;
+ size_t n;
+ size_t allocated;
+ };
-bool trns_chain_is_empty (const struct trns_chain *);
+#define TRNS_CHAIN_INIT { .n = 0 }
-size_t trns_chain_next (struct trns_chain *);
-enum trns_result trns_chain_execute (const struct trns_chain *,
- enum trns_result, struct ccase **,
- casenumber case_nr);
+void trns_chain_init (struct trns_chain *);
+bool trns_chain_uninit (struct trns_chain *);
+
+bool trns_chain_clear (struct trns_chain *);
+void trns_chain_append (struct trns_chain *, const struct transformation *);
void trns_chain_splice (struct trns_chain *, struct trns_chain *);
+enum trns_result trns_chain_execute (const struct trns_chain *,
+ casenumber case_num, struct ccase **);
+
#endif /* transformations.h */
case CMD_SUCCESS:
case CMD_EOF:
case CMD_FINISH:
- case CMD_DATA_LIST:
- case CMD_END_CASE:
- case CMD_END_FILE:
case CMD_FAILURE:
case CMD_NOT_IMPLEMENTED:
case CMD_CASCADING_FAILURE:
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "BREAK", cmd_break)
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "COMPUTE", cmd_compute)
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DO IF", cmd_do_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ELSE IF", cmd_else_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ELSE", cmd_else)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "END IF", cmd_end_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "END LOOP", cmd_end_loop)
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "IF", cmd_if)
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "LOOP", cmd_loop)
DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "NUMERIC", cmd_numeric)
/* Commands valid only with INPUT PROGRAM. */
DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "END CASE", cmd_end_case)
DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "END FILE", cmd_end_file)
-DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "END INPUT PROGRAM", cmd_end_input_program)
DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "REREAD", cmd_reread)
/* Commands for testing PSPP. */
CMD_EOF = 2, /* End of input. */
CMD_FINISH = 3, /* FINISH was executed. */
- /* Successful return values returned by specific commands to let INPUT
- PROGRAM function properly. */
- CMD_DATA_LIST,
- CMD_END_CASE,
- CMD_END_FILE,
-
/* Various kinds of failures. */
CMD_FAILURE = -1, /* Not executed at all. */
CMD_NOT_IMPLEMENTED = -2, /* Command not implemented. */
{
struct msg_location *location;
struct expression *condition; /* Test expression; NULL for ELSE clause. */
- struct transformation *xforms;
- size_t n_xforms;
+ struct trns_chain xforms;
};
/* DO IF transformation. */
size_t n_clauses; /* Number of clauses. */
};
-static trns_proc_func do_if_trns_proc;
-static trns_free_func do_if_trns_free;
+static const struct trns_class do_if_trns_class;
static void
start_clause (struct lexer *lexer, struct dataset *ds,
sizeof *do_if->clauses);
struct clause *clause = &do_if->clauses[do_if->n_clauses++];
- *clause = (struct clause) { .n_xforms = 0 };
+ *clause = (struct clause) { .location = NULL };
if (condition)
{
clause->condition = expr_parse_bool (lexer, ds);
finish_clause (struct dataset *ds, struct do_if_trns *do_if)
{
struct clause *clause = &do_if->clauses[do_if->n_clauses - 1];
- proc_pop_transformations (ds, &clause->xforms, &clause->n_xforms);
+ proc_pop_transformations (ds, &clause->xforms);
}
/* Parse DO IF. */
}
finish_clause (ds, do_if);
- add_transformation (ds, do_if_trns_proc, do_if_trns_free, do_if);
+ add_transformation (ds, &do_if_trns_class, do_if);
return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
return TRNS_CONTINUE;
}
- return transformations_execute (clause->xforms, clause->n_xforms,
- c, case_num);
+ return trns_chain_execute (&clause->xforms, case_num, c);
}
return TRNS_CONTINUE;
}
msg_location_destroy (clause->location);
expr_free (clause->condition);
- transformations_destroy (clause->xforms, clause->n_xforms);
+ trns_chain_uninit (&clause->xforms);
}
free (do_if->clauses);
free (do_if);
return true;
}
+
+static const struct trns_class do_if_trns_class = {
+ .name = "DO IF",
+ .execute = do_if_trns_proc,
+ .destroy = do_if_trns_free,
+};
struct expression *end_loop_condition;
/* Inner transformations. */
- struct transformation *xforms;
- size_t n_xforms;
+ struct trns_chain xforms;
};
-static trns_proc_func loop_trns_proc;
-static trns_free_func loop_trns_free;
+static struct trns_class loop_trns_class;
+
+static int in_loop;
static bool parse_if_clause (struct lexer *, struct dataset *,
struct expression **);
lex_end_of_command (lexer);
proc_push_transformations (ds);
+ in_loop++;
for (;;)
{
if (lex_token (lexer) == T_STOP)
else
cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED);
}
- proc_pop_transformations (ds, &loop->xforms, &loop->n_xforms);
+ in_loop--;
+ proc_pop_transformations (ds, &loop->xforms);
+ printf ("%zu loop transvformations\n", loop->xforms.n);
- add_transformation (ds, loop_trns_proc, loop_trns_free, loop);
+ add_transformation (ds, &loop_trns_class, loop);
return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
+static enum trns_result
+break_trns_proc (void *aux UNUSED, struct ccase **c UNUSED,
+ casenumber case_num UNUSED)
+{
+ return TRNS_BREAK;
+}
+
/* Parses BREAK. */
int
-cmd_break (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
+cmd_break (struct lexer *lexer UNUSED, struct dataset *ds)
{
- //add_transformation (ds, break_trns_proc, NULL, NULL);
+ if (!in_loop)
+ {
+ msg (SE, _("BREAK cannot appear outside LOOP...END LOOP."));
+ return CMD_FAILURE;
+ }
+
+ static const struct trns_class trns_class = {
+ .name = "BREAK",
+ .execute = break_trns_proc
+ };
+ add_transformation (ds, &trns_class, NULL);
return CMD_SUCCESS;
}
else
cur = by = last = 0.0;
- int max_pass = loop->index_var ? settings_get_mxloops () : -1;
- for (int i = 0; max_pass < 0 || i < max_pass; i++)
+ for (int i = 0; loop->index_var || i < settings_get_mxloops (); i++)
{
+ printf ("loop %g %g %g\n", cur, by, last);
if (loop->loop_condition
&& expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
break;
- enum trns_result r = transformations_execute (
- loop->xforms, loop->n_xforms, c, case_num);
+ enum trns_result r = trns_chain_execute (&loop->xforms, case_num, c);
if (r != TRNS_CONTINUE)
return r == TRNS_BREAK ? TRNS_CONTINUE : r;
expr_free (loop->loop_condition);
expr_free (loop->end_loop_condition);
- transformations_destroy (loop->xforms, loop->n_xforms);
+ trns_chain_uninit (&loop->xforms);
free (loop);
return true;
}
+
+static struct trns_class loop_trns_class = {
+ .name = "LOOP",
+ .execute = loop_trns_proc,
+ .destroy = loop_trns_free,
+};
static bool parse_free (struct lexer *, struct dictionary *,
struct pool *, struct data_parser *);
-static trns_free_func data_list_trns_free;
-static trns_proc_func data_list_trns_proc;
+static const struct trns_class data_list_trns_class;
int
cmd_data_list (struct lexer *lexer, struct dataset *ds)
trns->parser = parser;
trns->reader = reader;
trns->end = end;
- add_transformation (ds, data_list_trns_proc, data_list_trns_free, trns);
+ add_transformation (ds, &data_list_trns_class, trns);
}
else
data_parser_make_active_file (parser, ds, reader, dict, NULL, NULL);
fh_unref (fh);
free (encoding);
- return CMD_DATA_LIST;
+ return CMD_SUCCESS;
error:
data_parser_destroy (parser);
return retval;
}
-\f
+
+static const struct trns_class data_list_trns_class = {
+ .name = "DATA LIST",
+ .execute = data_list_trns_proc,
+ .destroy = data_list_trns_free,
+};
{
struct session *session;
struct dataset *ds;
- struct trns_chain *trns_chain;
- enum trns_result restart;
+
+ struct trns_chain xforms;
+ size_t idx;
+ bool eof;
casenumber case_nr; /* Incremented by END CASE transformation. */
};
static void destroy_input_program (struct input_program_pgm *);
-static trns_proc_func end_case_trns_proc;
-static trns_proc_func reread_trns_proc;
-static trns_proc_func end_file_trns_proc;
-static trns_free_func reread_trns_free;
+static const struct trns_class end_case_trns_class;
+static const struct trns_class reread_trns_class;
+static const struct trns_class end_file_trns_class;
static const struct casereader_class input_program_casereader_class;
static bool inside_input_program;
+static bool saw_END_CASE;
+static bool saw_END_FILE;
+static bool saw_DATA_LIST;
/* Returns true if we're parsing the inside of a INPUT
PROGRAM...END INPUT PROGRAM construct, false otherwise. */
/* Emits an END CASE transformation for INP. */
static void
-emit_END_CASE (struct dataset *ds, struct input_program_pgm *inp)
+emit_END_CASE (struct dataset *ds)
{
- add_transformation (ds, end_case_trns_proc, NULL, inp);
+ add_transformation (ds, &end_case_trns_class, NULL);
}
int
cmd_input_program (struct lexer *lexer, struct dataset *ds)
{
- struct input_program_pgm *inp;
- bool saw_END_CASE = false;
- bool saw_END_FILE = false;
- bool saw_DATA_LIST = false;
-
if (!lex_match (lexer, T_ENDCMD))
return lex_end_of_command (lexer);
- inp = xmalloc (sizeof *inp);
- inp->session = session_create (dataset_session (ds));
- inp->ds = dataset_create (inp->session, "INPUT PROGRAM");
- inp->trns_chain = NULL;
- inp->init = NULL;
- inp->proto = NULL;
+ struct session *session = session_create (dataset_session (ds));
+ struct dataset *inp_ds = dataset_create (session, "INPUT PROGRAM");
+
+ struct input_program_pgm *inp = xmalloc (sizeof *inp);
+ *inp = (struct input_program_pgm) { .session = session, .ds = inp_ds };
+ proc_push_transformations (inp->ds);
inside_input_program = true;
+ saw_END_CASE = saw_END_FILE = saw_DATA_LIST = false;
while (!lex_match_phrase (lexer, "END INPUT PROGRAM"))
{
enum cmd_result result;
result = cmd_parse_in_state (lexer, inp->ds, CMD_STATE_INPUT_PROGRAM);
- switch (result)
+ if (result != CMD_FAILURE
+ && cmd_result_is_failure (result)
+ && lex_get_error_mode (lexer) != LEX_ERROR_TERMINAL)
{
- case CMD_DATA_LIST:
- saw_DATA_LIST = true;
- break;
-
- case CMD_END_CASE:
- emit_END_CASE (inp->ds, inp);
- saw_END_CASE = true;
- break;
-
- case CMD_END_FILE:
- saw_END_FILE = true;
- break;
-
- case CMD_FAILURE:
- break;
+ proc_pop_transformations (ds, &inp->xforms);
- default:
- if (cmd_result_is_failure (result)
- && lex_get_error_mode (lexer) != LEX_ERROR_TERMINAL)
- {
- if (result == CMD_EOF)
- msg (SE, _("Unexpected end-of-file within %s."), "INPUT PROGRAM");
- inside_input_program = false;
- destroy_input_program (inp);
- return result;
- }
+ if (result == CMD_EOF)
+ msg (SE, _("Unexpected end-of-file within %s."), "INPUT PROGRAM");
+ inside_input_program = false;
+ destroy_input_program (inp);
+ return result;
}
}
if (!saw_END_CASE)
- emit_END_CASE (inp->ds, inp);
+ emit_END_CASE (inp->ds);
inside_input_program = false;
+ proc_pop_transformations (inp->ds, &inp->xforms);
if (!saw_DATA_LIST && !saw_END_FILE)
{
return CMD_FAILURE;
}
- inp->trns_chain = proc_capture_transformations (inp->ds);
-
- inp->restart = TRNS_CONTINUE;
-
/* Figure out how to initialize each input case. */
inp->init = caseinit_create ();
caseinit_mark_for_init (inp->init, dataset_dict (inp->ds));
return CMD_SUCCESS;
}
-int
-cmd_end_input_program (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
-{
- /* Inside INPUT PROGRAM, this should get caught at the top of the loop in
- cmd_input_program().
-
- Outside of INPUT PROGRAM, the command parser should reject this
- command. */
- NOT_REACHED ();
-}
-
-/* Returns true if STATE is valid given the transformations that
- are allowed within INPUT PROGRAM. */
-static bool
-is_valid_state (enum trns_result state)
-{
- return (state == TRNS_CONTINUE
- || state == TRNS_ERROR
- || state == TRNS_END_FILE
- || state >= 0);
-}
-
/* Reads and returns one case.
Returns the case if successful, null at end of file or if an
I/O error occurred. */
input_program_casereader_read (struct casereader *reader UNUSED, void *inp_)
{
struct input_program_pgm *inp = inp_;
+
+ if (inp->eof || !inp->xforms.n)
+ return NULL;
+
struct ccase *c = case_create (inp->proto);
+ caseinit_init_vars (inp->init, c);
- do
+ printf ("%s:%d\n", __FILE__, __LINE__);
+ for (size_t i = inp->idx < inp->xforms.n ? inp->idx : 0; ; i++)
{
- assert (is_valid_state (inp->restart));
- if (inp->restart == TRNS_ERROR || inp->restart == TRNS_END_FILE)
+ printf ("%s:%d %zu\n", __FILE__, __LINE__, i);
+ if (i >= inp->xforms.n)
+ {
+ i = 0;
+ c = case_unshare (c);
+ caseinit_update_left_vars (inp->init, c);
+ caseinit_init_vars (inp->init, c);
+ }
+
+ const struct transformation *trns = &inp->xforms.xforms[i];
+ switch (trns->class->execute (trns->aux, &c, inp->case_nr))
{
+ case TRNS_END_CASE:
+ printf ("END CASE\n");
+ inp->case_nr++;
+ inp->idx = i + 1;
+ return c;
+
+ case TRNS_ERROR:
+ printf ("ERROR\n");
+ casereader_force_error (reader);
+ /* Fall through. */
+ case TRNS_END_FILE:
+ printf ("END FILE\n");
+ inp->eof = true;
case_unref (c);
return NULL;
- }
- c = case_unshare (c);
- caseinit_init_vars (inp->init, c);
- inp->restart = trns_chain_execute (inp->trns_chain, inp->restart,
- &c, inp->case_nr);
- assert (is_valid_state (inp->restart));
- caseinit_update_left_vars (inp->init, c);
- }
- while (inp->restart < 0);
+ case TRNS_CONTINUE:
+ printf ("CONTINUE\n");
+ break;
- return c;
+ default:
+ NOT_REACHED ();
+ }
+ }
}
static void
if (pgm != NULL)
{
session_destroy (pgm->session);
- trns_chain_destroy (pgm->trns_chain);
+ trns_chain_uninit (&pgm->xforms);
caseinit_destroy (pgm->init);
caseproto_unref (pgm->proto);
free (pgm);
/* Destroys the casereader. */
static void
-input_program_casereader_destroy (struct casereader *reader, void *inp_)
+input_program_casereader_destroy (struct casereader *reader UNUSED, void *inp_)
{
struct input_program_pgm *inp = inp_;
- if (inp->restart == TRNS_ERROR)
- casereader_force_error (reader);
destroy_input_program (inp);
}
};
\f
int
-cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED)
+cmd_end_case (struct lexer *lexer UNUSED, struct dataset *ds)
{
assert (in_input_program ());
- if (lex_token (lexer) == T_ENDCMD)
- return CMD_END_CASE;
+ emit_END_CASE (ds);
+ saw_END_CASE = true;
return CMD_SUCCESS;
}
/* Outputs the current case */
-enum trns_result
-end_case_trns_proc (void *inp_, struct ccase **c UNUSED,
+static enum trns_result
+end_case_trns_proc (void *aux UNUSED, struct ccase **c UNUSED,
casenumber case_nr UNUSED)
{
- struct input_program_pgm *inp = inp_;
- inp->case_nr++;
+ printf ("%s:%d\n", __FILE__, __LINE__);
return TRNS_END_CASE;
}
+static const struct trns_class end_case_trns_class = {
+ .name = "END CASE",
+ .execute = end_case_trns_proc,
+};
+
/* REREAD transformation. */
struct reread_trns
{
t = xmalloc (sizeof *t);
t->reader = dfm_open_reader (fh, lexer, encoding);
t->column = e;
- add_transformation (ds, reread_trns_proc, reread_trns_free, t);
+ add_transformation (ds, &reread_trns_class, t);
fh_unref (fh);
free (encoding);
return true;
}
+static const struct trns_class reread_trns_class = {
+ .name = "REREAD",
+ .execute = reread_trns_proc,
+ .destroy = reread_trns_free,
+};
+
/* Parses END FILE command. */
int
cmd_end_file (struct lexer *lexer UNUSED, struct dataset *ds)
{
assert (in_input_program ());
- add_transformation (ds, end_file_trns_proc, NULL, NULL);
+ add_transformation (ds, &end_file_trns_class, NULL);
+ saw_END_FILE = true;
- return CMD_END_FILE;
+ return CMD_SUCCESS;
}
/* Executes an END FILE transformation. */
{
return TRNS_END_FILE;
}
+
+static const struct trns_class end_file_trns_class = {
+ .name = "END FILE",
+ .execute = end_file_trns_proc,
+};
struct expression *expr; /* Number of lines; NULL means 1. */
};
-static trns_proc_func print_space_trns_proc;
-static trns_free_func print_space_trns_free;
+static const struct trns_class print_space_class;
int
cmd_print_space (struct lexer *lexer, struct dataset *ds)
trns->writer = writer;
trns->expr = expr;
- add_transformation (ds,
- print_space_trns_proc, print_space_trns_free, trns);
+ add_transformation (ds, &print_space_class, trns);
fh_unref (handle);
return CMD_SUCCESS;
free (trns);
return ok;
}
+
+static const struct trns_class print_space_class = {
+ .name = "PRINT SPACE",
+ .execute = print_space_trns_proc,
+ .destroy = print_space_trns_free,
+};
WRITE
};
+static const struct trns_class print_binary_trns_class;
+static const struct trns_class print_text_trns_class;
+
static int internal_cmd_print (struct lexer *, struct dataset *ds,
enum which_formats, bool eject);
-static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
-static trns_free_func print_trns_free;
static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
struct dictionary *dict, enum which_formats);
static void dump_table (struct print_trns *);
+
+static bool print_trns_free (void *trns_);
\f
/* Basic parsing. */
dump_table (trns);
/* Put the transformation in the queue. */
- add_transformation (ds,
- (binary
- ? print_binary_trns_proc
- : print_text_trns_proc),
- print_trns_free, trns);
+ add_transformation (ds, (binary
+ ? &print_binary_trns_class
+ : &print_text_trns_class), trns);
pool_destroy (tmp_pool);
fh_unref (fh);
return ok;
}
+static const struct trns_class print_binary_trns_class = {
+ .name = "PRINT",
+ .execute = print_binary_trns_proc,
+ .destroy = print_trns_free,
+};
+
+static const struct trns_class print_text_trns_class = {
+ .name = "PRINT",
+ .execute = print_text_trns_proc,
+ .destroy = print_trns_free,
+};
+
struct casewriter *writer; /* Writer. */
};
-static trns_proc_func output_trns_proc;
-static trns_free_func output_trns_free;
+static const struct trns_class output_trns_class;
static struct casewriter *parse_write_command (struct lexer *,
struct dataset *,
enum writer_type,
return CMD_CASCADING_FAILURE;
}
- add_transformation (ds, output_trns_proc, output_trns_free, t);
+ add_transformation (ds, &output_trns_class, t);
return CMD_SUCCESS;
}
free (t);
return ok;
}
+
+static const struct trns_class output_trns_class = {
+ .name = "XSAVE/XEXPORT",
+ .execute = output_trns_proc,
+ .destroy = output_trns_free,
+};
+
bool blank_valid;
};
-static trns_proc_func autorecode_trns_proc;
-static trns_free_func autorecode_trns_free;
+static const struct trns_class autorecode_trns_class;
static int compare_arc_items (const void *, const void *, const void *aux);
static void arc_free (struct autorecode_pgm *);
/* Free array. */
free (items);
}
- add_transformation (ds, autorecode_trns_proc, autorecode_trns_free, arc);
+ add_transformation (ds, &autorecode_trns_class, arc);
for (size_t i = 0; i < n_dsts; i++)
free (dst_names[i]);
arc_free (arc);
return true;
}
+
+static const struct trns_class autorecode_trns_class = {
+ .name = "AUTORECODE",
+ .execute = autorecode_trns_proc,
+ .destroy = autorecode_trns_free,
+};
return ok;
}
+static const struct trns_class descriptives_trns_class = {
+ .name = "DESCRIPTIVES (Z scores)",
+ .execute = descriptives_trns_proc,
+ .destroy = descriptives_trns_free,
+};
+
/* Sets up a transformation to calculate Z scores. */
static void
setup_z_trns (struct dsc_proc *dsc, struct dataset *ds)
}
}
- add_transformation (ds,
- descriptives_trns_proc, descriptives_trns_free, t);
+ add_transformation (ds, &descriptives_trns_class, t);
}
\f
/* Statistical calculation. */
std->distance = dict_create_var_assert (qc.dict, qc.var_distance, 0);
}
- add_transformation (qc.dataset, save_trans_func, save_trans_destroy, std);
+ static const struct trns_class trns_class = {
+ .name = "QUICK CLUSTER",
+ .execute = save_trans_func,
+ .destroy = save_trans_destroy,
+ };
+ add_transformation (qc.dataset, &trns_class, std);
}
free (qc.var_distance);
return true;
}
+static const struct trns_class rank_trns_class = {
+ .name = "RANK",
+ .execute = rank_trns_proc,
+ .destroy = rank_trns_free,
+};
+
static bool
rank_cmd (struct dataset *ds, const struct rank *cmd)
{
}
free (outputs);
- add_transformation (ds, rank_trns_proc, rank_trns_free, trns);
+ add_transformation (ds, &rank_trns_class, trns);
/* Delete our sort key, which we don't need anymore. */
dict_delete_var (d, order_var);
memcpy (save_trans_data->ws, &workspace, sizeof (workspace));
save_trans_data->n_dep_vars = regression.n_dep_vars;
- add_transformation (ds, save_trans_func, save_trans_free, save_trans_data);
+ static const struct trns_class trns_class = {
+ .name = "REGRESSION",
+ .execute = save_trans_func,
+ .destroy = save_trans_free,
+ };
+ add_transformation (ds, &trns_class, save_trans_data);
}
struct dataset *);
static struct compute_trns *compute_trns_create (void);
-static trns_proc_func *get_proc_func (const struct lvalue *);
-static trns_free_func compute_trns_free;
+static bool compute_trns_free (void *compute_);
+static const struct trns_class *get_trns_class (const struct lvalue *);
\f
/* COMPUTE. */
if (compute->rvalue == NULL)
goto fail;
- add_transformation (ds, get_proc_func (lvalue), compute_trns_free, compute);
+ add_transformation (ds, get_trns_class (lvalue), compute);
lvalue_finalize (lvalue, compute, dict);
{
struct compute_trns *compute = compute_;
+ printf ("compute\n");
if (compute->test == NULL
|| expr_evaluate_num (compute->test, *c, case_num) == 1.0)
{
if (compute->rvalue == NULL)
goto fail;
- add_transformation (ds, get_proc_func (lvalue), compute_trns_free, compute);
+ add_transformation (ds, get_trns_class (lvalue), compute);
lvalue_finalize (lvalue, compute, dict);
\f
/* Code common to COMPUTE and IF. */
-static trns_proc_func *
-get_proc_func (const struct lvalue *lvalue)
+static const struct trns_class *
+get_trns_class (const struct lvalue *lvalue)
{
+ static const struct trns_class classes[2][2] = {
+ [false][false] = {
+ .name = "COMPUTE",
+ .execute = compute_str,
+ .destroy = compute_trns_free
+ },
+ [false][true] = {
+ .name = "COMPUTE",
+ .execute = compute_str_vec,
+ .destroy = compute_trns_free
+ },
+ [true][false] = {
+ .name = "COMPUTE",
+ .execute = compute_num,
+ .destroy = compute_trns_free
+ },
+ [true][true] = {
+ .name = "COMPUTE",
+ .execute = compute_num_vec,
+ .destroy = compute_trns_free
+ },
+ };
+
bool is_numeric = lvalue_get_type (lvalue) == VAL_NUMERIC;
bool is_vector = lvalue_is_vector (lvalue);
-
- return (is_numeric
- ? (is_vector ? compute_num_vec : compute_num)
- : (is_vector ? compute_str_vec : compute_str));
+ return &classes[is_numeric][is_vector];
}
/* Parses and returns an rvalue expression of the same type as
struct pool *pool;
};
-static trns_proc_func count_trns_proc;
-static trns_free_func count_trns_free;
+static const struct trns_class count_trns_class;
static bool parse_numeric_criteria (struct lexer *, struct pool *, struct criteria *);
static bool parse_string_criteria (struct lexer *, struct pool *,
struct criteria *,
const char *dict_encoding);
+static bool count_trns_free (void *trns_);
\f
int
cmd_count (struct lexer *lexer, struct dataset *ds)
dv->var = dict_create_var_assert (dataset_dict (ds), dv->name, 0);
}
- add_transformation (ds, count_trns_proc, count_trns_free, trns);
+ add_transformation (ds, &count_trns_class, trns);
return CMD_SUCCESS;
fail:
pool_destroy (trns->pool);
return true;
}
+
+static const struct trns_class count_trns_class = {
+ .name = "COUNT",
+ .execute = count_trns_proc,
+ .destroy = count_trns_free,
+};
int
cmd_debug_xform_fail (struct lexer *lexer UNUSED, struct dataset *ds)
{
- add_transformation (ds, trns_fail, NULL, NULL);
+ static const struct trns_class fail_trns_class = {
+ .name = "DEBUG XFORM FAIL",
+ .execute = trns_fail
+ };
+ add_transformation (ds, &fail_trns_class, NULL);
return CMD_SUCCESS;
}
static bool enlarge_dst_widths (struct recode_trns *);
static void create_dst_vars (struct recode_trns *, struct dictionary *);
-static trns_proc_func recode_trns_proc;
-static trns_free_func recode_trns_free;
+static bool recode_trns_free (void *trns_);
+
+static const struct trns_class recode_trns_class;
\f
/* Parser. */
create_dst_vars (trns, dict);
/* Done. */
- add_transformation (ds,
- recode_trns_proc, recode_trns_free, trns);
+ add_transformation (ds, &recode_trns_class, trns);
}
while (lex_match (lexer, T_SLASH));
pool_destroy (trns->pool);
return true;
}
+
+static const struct trns_class recode_trns_class = {
+ .name = "RECODE",
+ .execute = recode_trns_proc,
+ .destroy = recode_trns_free,
+};
unsigned frac; /* TYPE_FRACTION: a fraction of UINT_MAX. */
};
-static trns_proc_func sample_trns_proc;
-static trns_free_func sample_trns_free;
+static const struct trns_class sample_trns_class;
int
cmd_sample (struct lexer *lexer, struct dataset *ds)
trns->N = b;
trns->m = trns->t = 0;
trns->frac = frac;
- add_transformation (ds, sample_trns_proc, sample_trns_free, trns);
+ add_transformation (ds, &sample_trns_class, trns);
return CMD_SUCCESS;
}
free (t);
return true;
}
+
+static const struct trns_class sample_trns_class = {
+ .name = "SAMPLE",
+ .execute = sample_trns_proc,
+ .destroy = sample_trns_free,
+};
struct expression *e; /* Test expression. */
};
-static trns_proc_func select_if_proc;
-static trns_free_func select_if_free;
+static const struct trns_class select_if_trns_class;
/* Parses the SELECT IF transformation. */
int
t = xmalloc (sizeof *t);
t->e = e;
- add_transformation (ds, select_if_proc, select_if_free, t);
+ add_transformation (ds, &select_if_trns_class, t);
return CMD_SUCCESS;
}
return true;
}
+static const struct trns_class select_if_trns_class = {
+ .name = "SELECT IF",
+ .execute = select_if_proc,
+ .destroy = select_if_free,
+};
+
/* Parses the FILTER command. */
int
cmd_filter (struct lexer *lexer, struct dataset *ds)