starting to look like it works
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 11 Dec 2021 01:50:11 +0000 (17:50 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 11 Dec 2021 01:50:11 +0000 (17:50 -0800)
need to pause and resume loop and do if

25 files changed:
src/data/dataset.c
src/data/dataset.h
src/data/transformations.c
src/data/transformations.h
src/language/command.c
src/language/command.def
src/language/command.h
src/language/control/do-if.c
src/language/control/loop.c
src/language/data-io/data-list.c
src/language/data-io/inpt-pgm.c
src/language/data-io/print-space.c
src/language/data-io/print.c
src/language/data-io/save.c
src/language/stats/autorecode.c
src/language/stats/descriptives.c
src/language/stats/quick-cluster.c
src/language/stats/rank.c
src/language/stats/regression.c
src/language/xforms/compute.c
src/language/xforms/count.c
src/language/xforms/fail.c
src/language/xforms/recode.c
src/language/xforms/sample.c
src/language/xforms/select-if.c

index 2ffc4eb423b263976a6dec17ba325b1698e717b1..32c73fab65b1dfed413efedd828f2cbaf7cd833e 100644 (file)
@@ -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;
 }
 \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);
 }
 
@@ -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;
 }
 \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
@@ -891,22 +878,30 @@ case_limit_trns_free (void *cases_remaining_)
   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_,
@@ -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)
index fec342ef623e335c7d72ce75205d5ba2336ec19d..1fe535536f6cee4bd5d9da065d0e4a0bb7c9dedd 100644 (file)
@@ -79,14 +79,11 @@ void dataset_set_display (struct dataset *, enum dataset_display);
 \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);
index 4501b90f0b6e38a54932344e4e977c1bb211c1ac..999638c52715e00544838351e8b2709ac702a8c7 100644 (file)
 
 #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;
index 209149978261c831c0615b8736c890c7da89e9d5..dd8c29d0c873c2b048d9953c47b3e2d3d86a9212 100644 (file)
@@ -21,7 +21,8 @@
 #include <stddef.h>
 #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);
   };
-\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 */
index 522d53eaa2d34217a20371c0664d6709dda723f8..15b76519678145bd468101037671849f4652c554 100644 (file)
@@ -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:
index 253885857e008c1be3765a4dad487422e450d900..53a23a2c9008066916784fd77c87e2f1ea67c5d4 100644 (file)
@@ -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. */
index 766a637b0ba5ce694fa0d556a0160f32f53efeed..f38ed5cdb9275d6d938884145a80ab315cfc8341 100644 (file)
@@ -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. */
index b45694804ae35dc2c728c187661b0a3b5f873dc2..efe4667753a387fcb9e0de66d98bf0694f1c0896 100644 (file)
@@ -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,
+};
index 604af4556940bb2156c0048ce641b17d0cd73579..f081c761c78f01e2b596194eb9810930567fd166 100644 (file)
@@ -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,
+};
index a340f207f10a1ebd121c4b504e3450cc80102806..b1a771734023307584015003f1a7f665b0928daf 100644 (file)
@@ -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;
 }
-\f
+
+static const struct trns_class data_list_trns_class = {
+  .name = "DATA LIST",
+  .execute = data_list_trns_proc,
+  .destroy = data_list_trns_free,
+};
index 6ce75f6a4dafb63d8e2f311eae6ea985891e16a1..55b19cbf5e2bb144c7421e54d84360e55f0fcd8f 100644 (file)
@@ -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 =
   };
 \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
   {
@@ -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,
+};
index 11b9dcb79bf5890205fc20138ac1a06aa4d1d715..b908927bdf6415438542a708f92050761575b9e0 100644 (file)
@@ -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,
+};
index 26bb2e12cd12bb2238000eb7bcf1c08023e52c3e..657d53c35074a23e2660717937001fae087646fd 100644 (file)
@@ -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_);
 \f
 /* 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,
+};
+
index 190de124c3a7979da91ffa2df9033be145b091f6..d903dd3eb508031d0784b4415d23f9e5ee24be09 100644 (file)
@@ -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,
+};
+
index a5fef752686a18f4daf2ad1d7f462668dd5bfb92..2d569a0436eed60105da88150650cc1ae23e9811 100644 (file)
@@ -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,
+};
index 1fcc3097497f0bac373b1e5ffd993422ab450010..95c57740b2a25110c2d3ed3084b77634a692eda0 100644 (file)
@@ -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);
 }
 \f
 /* Statistical calculation. */
index 3aff0e8a46879e2148c24ff6f77b6758f3c1bc81..be04af929fb1dc435a090f481965d359b054ab20 100644 (file)
@@ -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);
index 597c08fe3eaeb991072732f6936389f05a15b4a8..7e76d68abac4d74b8b858b83254966976c9af550 100644 (file)
@@ -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);
index a65dd757673f8a9b76b8087a7d30fc2fee4ada66..b4448dd9e58ead03cb61cf3d5e5b3c97201b1edf 100644 (file)
@@ -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);
     }
 
 
index ca8f200d4faf6bd6d830a2f76438de517b384079..083d7d219f386f456bcfb0262e3d283ee4f702d5 100644 (file)
@@ -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 *);
 \f
 /* 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)
 \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
index 4dfc68bd89d10afd449732a04ad0560622cd0928..1a1422b31f0a69ff695abe4cc7e76888957d0ce4 100644 (file)
@@ -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_);
 \f
 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,
+};
index ec94fe25a5e8b8a0569b609f466ae4d770639248..f90b19673ebc6d8bf2d9d820dd9498e1678f839f 100644 (file)
@@ -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;
 }
index b359661bdfe95723841553f27947c3468961a865..4d491dd9be1462f49d46a0f0054d50e1f255d2d7 100644 (file)
@@ -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;
 \f
 /* 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,
+};
index 072cd68e225bd5603263aba8104b20e7f7a000e6..665cd4468edc370e80390441cb27d1ddb9fa3f27 100644 (file)
@@ -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,
+};
index 313b5fc4fc9ad9ab6122b1cc41894cc7105ad68c..deb13047e9fd7fcc49a18629e3ccb32d4417ebea 100644 (file)
@@ -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)