From 6dc31f9aba2c0e6a9e2f03b7f72534399198a150 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 10 Dec 2021 17:50:11 -0800 Subject: [PATCH] starting to look like it works need to pause and resume loop and do if --- src/data/dataset.c | 210 +++++++++++++++-------------- src/data/dataset.h | 7 +- src/data/transformations.c | 138 ++++++------------- src/data/transformations.h | 40 +++--- src/language/command.c | 3 - src/language/command.def | 5 - src/language/command.h | 6 - src/language/control/do-if.c | 23 ++-- src/language/control/loop.c | 51 +++++-- src/language/data-io/data-list.c | 14 +- src/language/data-io/inpt-pgm.c | 195 +++++++++++++-------------- src/language/data-io/print-space.c | 12 +- src/language/data-io/print.c | 27 +++- src/language/data-io/save.c | 12 +- src/language/stats/autorecode.c | 11 +- src/language/stats/descriptives.c | 9 +- src/language/stats/quick-cluster.c | 7 +- src/language/stats/rank.c | 8 +- src/language/stats/regression.c | 7 +- src/language/xforms/compute.c | 41 ++++-- src/language/xforms/count.c | 12 +- src/language/xforms/fail.c | 6 +- src/language/xforms/recode.c | 14 +- src/language/xforms/sample.c | 11 +- src/language/xforms/select-if.c | 11 +- 25 files changed, 471 insertions(+), 409 deletions(-) diff --git a/src/data/dataset.c b/src/data/dataset.c index 2ffc4eb423..32c73fab65 100644 --- a/src/data/dataset.c +++ b/src/data/dataset.c @@ -64,20 +64,22 @@ struct dataset { 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; @@ -143,13 +145,13 @@ dataset_create_finish__ (struct dataset *ds, struct session *session) 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; @@ -170,10 +172,11 @@ dataset_clone (struct dataset *old, const char *name) 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); @@ -200,7 +203,10 @@ dataset_destroy (struct dataset *ds) 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); @@ -386,9 +392,8 @@ proc_execute (struct dataset *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; @@ -525,8 +530,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_) /* 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; @@ -546,10 +550,10 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_) 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; } @@ -667,29 +671,16 @@ lagged_case (const struct dataset *ds, int n_before) return NULL; } -/* 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); } @@ -699,7 +690,7 @@ add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *fr bool proc_in_temporary_transformations (const struct dataset *ds) { - return ds->temporary_trns_chain != NULL; + return ds->temporary; } /* Marks the start of temporary transformations. @@ -714,7 +705,7 @@ proc_start_temporary_transformations (struct dataset *ds) 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); } } @@ -732,10 +723,9 @@ proc_make_temporary_transformations_permanent (struct dataset *ds) { 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; @@ -758,10 +748,9 @@ proc_cancel_temporary_transformations (struct dataset *ds) 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 @@ -775,15 +764,33 @@ proc_cancel_all_transformations (struct dataset *ds) { 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) { @@ -799,19 +806,18 @@ 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; } @@ -848,25 +854,6 @@ dataset_end_of_command (struct dataset *ds) return true; } -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 @@ -891,22 +878,30 @@ case_limit_trns_free (void *cases_remaining_) free (cases_remaining); return true; } - -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); } } + /* FILTER transformation. */ static enum trns_result filter_trns_proc (void *filter_var_, @@ -919,6 +914,23 @@ 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) diff --git a/src/data/dataset.h b/src/data/dataset.h index fec342ef62..1fe535536f 100644 --- a/src/data/dataset.h +++ b/src/data/dataset.h @@ -79,14 +79,11 @@ void dataset_set_display (struct dataset *, enum dataset_display); /* 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); diff --git a/src/data/transformations.c b/src/data/transformations.c index 4501b90f0b..999638c527 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -25,135 +25,75 @@ #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; diff --git a/src/data/transformations.h b/src/data/transformations.h index 2091499782..dd8c29d0c8 100644 --- a/src/data/transformations.h +++ b/src/data/transformations.h @@ -21,7 +21,8 @@ #include #include "data/case.h" -/* trns_proc_func return values. */ +/* One transformation. */ + enum trns_result { TRNS_CONTINUE, /* Continue to next transformation. */ @@ -34,38 +35,39 @@ enum trns_result 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); }; - -/* 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); + +/* 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 */ diff --git a/src/language/command.c b/src/language/command.c index 522d53eaa2..15b7651967 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -55,9 +55,6 @@ cmd_result_is_valid (enum cmd_result result) 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: diff --git a/src/language/command.def b/src/language/command.def index 253885857e..53a23a2c90 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -93,10 +93,6 @@ DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WRITE FORMATS", cmd_write_form 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) @@ -154,7 +150,6 @@ DEF_CMD (S_DATA, 0, "USE", cmd_use) /* 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. */ diff --git a/src/language/command.h b/src/language/command.h index 766a637b0b..f38ed5cdb9 100644 --- a/src/language/command.h +++ b/src/language/command.h @@ -27,12 +27,6 @@ enum cmd_result 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. */ diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index b45694804a..efe4667753 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -37,8 +37,7 @@ struct clause { 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. */ @@ -48,8 +47,7 @@ struct do_if_trns 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, @@ -77,7 +75,7 @@ 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); @@ -96,7 +94,7 @@ static void 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. */ @@ -133,7 +131,7 @@ cmd_do_if (struct lexer *lexer, struct dataset *ds) } 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; } @@ -158,8 +156,7 @@ do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num) 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; } @@ -177,9 +174,15 @@ do_if_trns_free (void *do_if_) 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, +}; diff --git a/src/language/control/loop.c b/src/language/control/loop.c index 604af45569..f081c761c7 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -51,12 +51,12 @@ struct loop_trns 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 **); @@ -83,6 +83,7 @@ cmd_loop (struct lexer *lexer, struct dataset *ds) lex_end_of_command (lexer); proc_push_transformations (ds); + in_loop++; for (;;) { if (lex_token (lexer) == T_STOP) @@ -100,18 +101,37 @@ cmd_loop (struct lexer *lexer, struct dataset *ds) 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; } @@ -221,15 +241,14 @@ loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num) 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; @@ -263,8 +282,14 @@ loop_trns_free (void *loop_) 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, +}; diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index a340f207f1..b1a7717340 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -67,8 +67,7 @@ static bool parse_fixed (struct lexer *, struct dictionary *, 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) @@ -295,7 +294,7 @@ 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); @@ -303,7 +302,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds) fh_unref (fh); free (encoding); - return CMD_DATA_LIST; + return CMD_SUCCESS; error: data_parser_destroy (parser); @@ -544,4 +543,9 @@ data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) return retval; } - + +static const struct trns_class data_list_trns_class = { + .name = "DATA LIST", + .execute = data_list_trns_proc, + .destroy = data_list_trns_free, +}; diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 6ce75f6a4d..55b19cbf5e 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -49,8 +49,10 @@ struct input_program_pgm { 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. */ @@ -59,14 +61,16 @@ struct input_program_pgm }; 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. */ @@ -78,68 +82,48 @@ in_input_program (void) /* 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) { @@ -154,10 +138,6 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds) 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)); @@ -171,28 +151,6 @@ cmd_input_program (struct lexer *lexer, struct dataset *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. */ @@ -200,27 +158,52 @@ static struct ccase * 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 @@ -229,7 +212,7 @@ destroy_input_program (struct input_program_pgm *pgm) 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); @@ -238,11 +221,9 @@ destroy_input_program (struct input_program_pgm *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); } @@ -255,24 +236,28 @@ static const struct casereader_class input_program_casereader_class = }; 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 { @@ -336,7 +321,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds) 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); @@ -382,15 +367,22 @@ reread_trns_free (void *t_) 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. */ @@ -400,3 +392,8 @@ end_file_trns_proc (void *trns_ UNUSED, struct ccase **c UNUSED, { return TRNS_END_FILE; } + +static const struct trns_class end_file_trns_class = { + .name = "END FILE", + .execute = end_file_trns_proc, +}; diff --git a/src/language/data-io/print-space.c b/src/language/data-io/print-space.c index 11b9dcb79b..b908927bdf 100644 --- a/src/language/data-io/print-space.c +++ b/src/language/data-io/print-space.c @@ -41,8 +41,7 @@ struct print_space_trns 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) @@ -100,8 +99,7 @@ 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; @@ -154,3 +152,9 @@ print_space_trns_free (void *trns_) 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, +}; diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 26bb2e12cd..657d53c350 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -96,13 +96,16 @@ enum which_formats 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_); /* Basic parsing. */ @@ -239,11 +242,9 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds, 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); @@ -685,3 +686,15 @@ print_trns_free (void *trns_) 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, +}; + diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index 190de124c3..d903dd3eb5 100644 --- a/src/language/data-io/save.c +++ b/src/language/data-io/save.c @@ -99,8 +99,7 @@ struct output_trns 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, @@ -140,7 +139,7 @@ parse_output_trns (struct lexer *lexer, struct dataset *ds, enum writer_type wri return CMD_CASCADING_FAILURE; } - add_transformation (ds, output_trns_proc, output_trns_free, t); + add_transformation (ds, &output_trns_class, t); return CMD_SUCCESS; } @@ -382,3 +381,10 @@ output_trns_free (void *trns_) free (t); return ok; } + +static const struct trns_class output_trns_class = { + .name = "XSAVE/XEXPORT", + .execute = output_trns_proc, + .destroy = output_trns_free, +}; + diff --git a/src/language/stats/autorecode.c b/src/language/stats/autorecode.c index a5fef75268..2d569a0436 100644 --- a/src/language/stats/autorecode.c +++ b/src/language/stats/autorecode.c @@ -96,8 +96,7 @@ struct autorecode_pgm 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 *); @@ -450,7 +449,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) /* 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]); @@ -582,3 +581,9 @@ autorecode_trns_free (void *arc_) arc_free (arc); return true; } + +static const struct trns_class autorecode_trns_class = { + .name = "AUTORECODE", + .execute = autorecode_trns_proc, + .destroy = autorecode_trns_free, +}; diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 1fcc309749..95c57740b2 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -711,6 +711,12 @@ descriptives_trns_free (void *trns_) 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) @@ -766,8 +772,7 @@ 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); } /* Statistical calculation. */ diff --git a/src/language/stats/quick-cluster.c b/src/language/stats/quick-cluster.c index 3aff0e8a46..be04af929f 100644 --- a/src/language/stats/quick-cluster.c +++ b/src/language/stats/quick-cluster.c @@ -1076,7 +1076,12 @@ cmd_quick_cluster (struct lexer *lexer, struct dataset *ds) 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); diff --git a/src/language/stats/rank.c b/src/language/stats/rank.c index 597c08fe3e..7e76d68aba 100644 --- a/src/language/stats/rank.c +++ b/src/language/stats/rank.c @@ -961,6 +961,12 @@ rank_trns_free (void *trns_) 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) { @@ -1116,7 +1122,7 @@ 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); diff --git a/src/language/stats/regression.c b/src/language/stats/regression.c index a65dd75767..b4448dd9e5 100644 --- a/src/language/stats/regression.c +++ b/src/language/stats/regression.c @@ -449,7 +449,12 @@ cmd_regression (struct lexer *lexer, struct dataset *ds) 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); } diff --git a/src/language/xforms/compute.c b/src/language/xforms/compute.c index ca8f200d4f..083d7d219f 100644 --- a/src/language/xforms/compute.c +++ b/src/language/xforms/compute.c @@ -85,8 +85,8 @@ static struct expression *parse_rvalue (struct lexer *lexer, 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 *); /* COMPUTE. */ @@ -109,7 +109,7 @@ cmd_compute (struct lexer *lexer, struct dataset *ds) 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); @@ -129,6 +129,7 @@ compute_num (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; + printf ("compute\n"); if (compute->test == NULL || expr_evaluate_num (compute->test, *c, case_num) == 1.0) { @@ -265,7 +266,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds) 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); @@ -279,15 +280,35 @@ cmd_if (struct lexer *lexer, struct dataset *ds) /* 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 diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 4dfc68bd89..1a1422b31f 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -88,13 +88,13 @@ struct count_trns 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_); int cmd_count (struct lexer *lexer, struct dataset *ds) @@ -185,7 +185,7 @@ 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: @@ -369,3 +369,9 @@ count_trns_free (void *trns_) pool_destroy (trns->pool); return true; } + +static const struct trns_class count_trns_class = { + .name = "COUNT", + .execute = count_trns_proc, + .destroy = count_trns_free, +}; diff --git a/src/language/xforms/fail.c b/src/language/xforms/fail.c index ec94fe25a5..f90b19673e 100644 --- a/src/language/xforms/fail.c +++ b/src/language/xforms/fail.c @@ -38,6 +38,10 @@ trns_fail (void *x UNUSED, struct ccase **c UNUSED, 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; } diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index b359661bdf..4d491dd9be 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -128,8 +128,9 @@ static void set_map_out_str (struct map_out *, struct pool *, 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; /* Parser. */ @@ -173,8 +174,7 @@ cmd_recode (struct lexer *lexer, struct dataset *ds) 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)); @@ -747,3 +747,9 @@ recode_trns_free (void *trns_) pool_destroy (trns->pool); return true; } + +static const struct trns_class recode_trns_class = { + .name = "RECODE", + .execute = recode_trns_proc, + .destroy = recode_trns_free, +}; diff --git a/src/language/xforms/sample.c b/src/language/xforms/sample.c index 072cd68e22..665cd4468e 100644 --- a/src/language/xforms/sample.c +++ b/src/language/xforms/sample.c @@ -51,8 +51,7 @@ struct sample_trns 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) @@ -101,7 +100,7 @@ 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; } @@ -146,3 +145,9 @@ sample_trns_free (void *t_) free (t); return true; } + +static const struct trns_class sample_trns_class = { + .name = "SAMPLE", + .execute = sample_trns_proc, + .destroy = sample_trns_free, +}; diff --git a/src/language/xforms/select-if.c b/src/language/xforms/select-if.c index 313b5fc4fc..deb13047e9 100644 --- a/src/language/xforms/select-if.c +++ b/src/language/xforms/select-if.c @@ -40,8 +40,7 @@ struct select_if_trns 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 @@ -63,7 +62,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds) 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; } @@ -88,6 +87,12 @@ select_if_free (void *t_) 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) -- 2.30.2