Work toward getting rid of finalizers and control stacks and jumping around among...
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 10 Dec 2021 06:23:59 +0000 (22:23 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 10 Dec 2021 06:23:59 +0000 (22:23 -0800)
31 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/automake.mk
src/language/control/control-stack.c [deleted file]
src/language/control/control-stack.h [deleted file]
src/language/control/do-if.c
src/language/control/loop.c
src/language/control/temporary.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/expressions/parse.c
src/language/expressions/public.h
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 8b3332ec0d78aee2b6636e7147d251ccbf5f4c70..2ffc4eb423b263976a6dec17ba325b1698e717b1 100644 (file)
@@ -425,7 +425,6 @@ proc_open_filtering (struct dataset *ds, bool filter)
   add_case_limit_trns (ds);
   if (filter)
     add_filter_trns (ds);
-  trns_chain_finalize (ds->cur_trns_chain);
 
   /* Make permanent_dict refer to the dictionary right before
      data reaches the sink. */
@@ -694,30 +693,6 @@ add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *fr
   dataset_transformations_changed__ (ds, true);
 }
 
-/* Adds a transformation that processes a case with PROC and
-   frees itself with FREE to the current set of transformations.
-   When parsing of the block of transformations is complete,
-   FINALIZE will be called.
-   The functions are passed AUX as auxiliary data. */
-void
-add_transformation_with_finalizer (struct dataset *ds,
-                                  trns_finalize_func *finalize,
-                                   trns_proc_func *proc,
-                                   trns_free_func *free, void *aux)
-{
-  trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux);
-  dataset_transformations_changed__ (ds, true);
-}
-
-/* Returns the index of the next transformation.
-   This value can be returned by a transformation procedure
-   function to indicate a "jump" to that transformation. */
-size_t
-next_transformation (const struct dataset *ds)
-{
-  return trns_chain_next (ds->cur_trns_chain);
-}
-
 /* Returns true if the next call to add_transformation() will add
    a temporary transformation, false if it will add a permanent
    transformation. */
@@ -739,7 +714,6 @@ proc_start_temporary_transformations (struct dataset *ds)
 
       ds->permanent_dict = dict_clone (ds->dict);
 
-      trns_chain_finalize (ds->permanent_trns_chain);
       ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create ();
       dataset_transformations_changed__ (ds, true);
     }
@@ -758,7 +732,6 @@ proc_make_temporary_transformations_permanent (struct dataset *ds)
 {
   if (proc_in_temporary_transformations (ds))
     {
-      trns_chain_finalize (ds->temporary_trns_chain);
       trns_chain_splice (ds->permanent_trns_chain, ds->temporary_trns_chain);
       ds->temporary_trns_chain = NULL;
 
@@ -811,7 +784,7 @@ proc_cancel_all_transformations (struct dataset *ds)
   return ok;
 }
 
-static int
+static enum trns_result
 store_case_num (void *var_, struct ccase **cc, casenumber case_num)
 {
   struct variable *var = var_;
@@ -836,7 +809,6 @@ add_permanent_ordering_transformation (struct dataset *ds)
       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);
-      trns_chain_finalize (ds->permanent_trns_chain);
     }
   else
     add_transformation (ds, store_case_num, NULL, temp_var);
@@ -897,7 +869,7 @@ add_case_limit_trns (struct dataset *ds)
 
 /* Limits the maximum number of cases processed to
    *CASES_REMAINING. */
-static int
+static enum trns_result
 case_limit_trns_proc (void *cases_remaining_,
                       struct ccase **c UNUSED, casenumber case_nr UNUSED)
 {
@@ -936,7 +908,7 @@ add_filter_trns (struct dataset *ds)
 }
 
 /* FILTER transformation. */
-static int
+static enum trns_result
 filter_trns_proc (void *filter_var_,
                   struct ccase **c, casenumber case_nr UNUSED)
 
index ce8b980d2e69c1cbc6207bd7c3ce8dc3b77a3c23..fec342ef623e335c7d72ce75205d5ba2336ec19d 100644 (file)
@@ -26,6 +26,7 @@ struct casereader;
 struct dataset;
 struct dictionary;
 struct session;
+struct transformation;
 \f
 struct dataset *dataset_create (struct session *, const char *);
 struct dataset *dataset_clone (struct dataset *, const char *);
@@ -80,14 +81,12 @@ void dataset_set_display (struct dataset *, enum dataset_display);
 
 void add_transformation (struct dataset *ds,
                         trns_proc_func *, trns_free_func *, void *);
-void add_transformation_with_finalizer (struct dataset *ds,
-                                       trns_finalize_func *,
-                                        trns_proc_func *,
-                                        trns_free_func *, void *);
-size_t next_transformation (const struct dataset *ds);
 
 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_start_temporary_transformations (struct dataset *ds);
 bool proc_in_temporary_transformations (const struct dataset *ds);
index cd5c6a188c8048319090083ab6c221cf870527fc..4501b90f0b6e38a54932344e4e977c1bb211c1ac 100644 (file)
@@ -32,7 +32,6 @@ struct transformation
        transformation index.  Normally 0 but set to the starting
        index of a spliced chain after splicing. */
     int idx_ofs;
-    trns_finalize_func *finalize;       /* Finalize proc. */
     trns_proc_func *execute;            /* Executes the transformation. */
     trns_free_func *free;               /* Garbage collector proc. */
     void *aux;                          /* Auxiliary data. */
@@ -44,7 +43,6 @@ struct trns_chain
     struct transformation *trns;        /* Array of transformations. */
     size_t n_trns;                      /* Number of transformations. */
     size_t allocated_trns;              /* Allocated capacity. */
-    bool finalized;                     /* Finalize functions called? */
   };
 
 /* Allocates and returns a new transformation chain. */
@@ -55,56 +53,24 @@ trns_chain_create (void)
   chain->trns = NULL;
   chain->n_trns = 0;
   chain->allocated_trns = 0;
-  chain->finalized = false;
   return chain;
 }
 
-/* Finalizes all the un-finalized transformations in CHAIN.
-   Any given transformation is only finalized once. */
-void
-trns_chain_finalize (struct trns_chain *chain)
-{
-  while (!chain->finalized)
-    {
-      size_t i;
-
-      chain->finalized = true;
-      for (i = 0; i < chain->n_trns; i++)
-        {
-          struct transformation *trns = &chain->trns[i];
-          trns_finalize_func *finalize = trns->finalize;
-
-          trns->finalize = NULL;
-          if (finalize != NULL)
-            finalize (trns->aux);
-        }
-    }
-}
-
-/* Destroys CHAIN, finalizing it in the process if it has not
-   already been finalized. */
+/* Destroys CHAIN. */
 bool
 trns_chain_destroy (struct trns_chain *chain)
 {
-  bool ok = true;
+  if (!chain)
+    return true;
 
-  if (chain != NULL)
+  for (size_t i = 0; i < chain->n_trns; i++)
     {
-      size_t i;
-
-      /* Needed to ensure that the control stack gets cleared. */
-      trns_chain_finalize (chain);
-
-      for (i = 0; i < chain->n_trns; i++)
-        {
-          struct transformation *trns = &chain->trns[i];
-          if (trns->free != NULL)
-            ok = trns->free (trns->aux) && ok;
-        }
-      free (chain->trns);
-      free (chain);
+      struct transformation *trns = &chain->trns[i];
+      if (trns->free)
+        ok = trns->free (trns->aux) && ok;
     }
-
+  free (chain->trns);
+  free (chain);
   return ok;
 }
 
@@ -116,48 +82,36 @@ trns_chain_is_empty (const struct trns_chain *chain)
   return chain->n_trns == 0;
 }
 
-/* Adds a transformation to CHAIN with finalize function
-   FINALIZE, execute function EXECUTE, free function FREE, and
-   auxiliary data AUX. */
+/* 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_finalize_func *finalize,
-                   trns_proc_func *execute, trns_free_func *free,
-                   void *aux)
+trns_chain_append (struct trns_chain *chain, trns_proc_func *execute,
+                   trns_free_func *free, void *aux)
 {
   struct transformation *trns;
 
-  chain->finalized = false;
-
   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->finalize = finalize;
   trns->execute = execute;
   trns->free = free;
   trns->aux = aux;
 }
 
-/* Appends the transformations in SRC to those in DST,
-   and destroys SRC.
-   Both DST and SRC must already be finalized. */
+/* Appends the transformations in SRC to those in DST, and destroys SRC. */
 void
 trns_chain_splice (struct trns_chain *dst, struct trns_chain *src)
 {
-  size_t i;
-
-  assert (dst->finalized);
-  assert (src->finalized);
-
   if (dst->n_trns + src->n_trns > dst->allocated_trns)
     {
       dst->allocated_trns = dst->n_trns + src->n_trns;
       dst->trns = xnrealloc (dst->trns, dst->allocated_trns, sizeof *dst->trns);
     }
 
-  for (i = 0; i < src->n_trns; i++)
+  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];
@@ -190,7 +144,6 @@ trns_chain_execute (const struct trns_chain *chain, enum trns_result start,
 {
   size_t i;
 
-  assert (chain->finalized);
   for (i = start < 0 ? 0 : start; i < chain->n_trns;)
     {
       struct transformation *trns = &chain->trns[i];
index 013bcaa731e8e29adedaad8eb04d75b46e3e37e4..209149978261c831c0615b8736c890c7da89e9d5 100644 (file)
 /* trns_proc_func return values. */
 enum trns_result
   {
-    TRNS_CONTINUE = -1,         /* Continue to next transformation. */
-    TRNS_DROP_CASE = -2,        /* Drop this case. */
-    TRNS_ERROR = -3,            /* A serious error, so stop the procedure. */
-    TRNS_END_CASE = -4,         /* Skip to next case.  INPUT PROGRAM only. */
-    TRNS_END_FILE = -5          /* End of input.  INPUT PROGRAM only. */
+    TRNS_CONTINUE,              /* Continue to next transformation. */
+    TRNS_BREAK,                 /* Break out of LOOP. */
+    TRNS_DROP_CASE,             /* Drop this case. */
+    TRNS_ERROR,                 /* A serious error, so stop the procedure. */
+    TRNS_END_CASE,              /* Skip to next case.  INPUT PROGRAM only. */
+    TRNS_END_FILE               /* End of input.  INPUT PROGRAM only. */
   };
 
 struct ccase;
-typedef void trns_finalize_func (void *);
-typedef int trns_proc_func (void *, struct ccase **, casenumber);
+
+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);
+    bool (*destroy) (void *aux);
+  };
 \f
 /* Transformation chains. */
 
-struct trns_chain *trns_chain_create (void);
-void trns_chain_finalize (struct trns_chain *);
-bool trns_chain_destroy (struct trns_chain *);
+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);
+
+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 *);
 
 bool trns_chain_is_empty (const struct trns_chain *);
 
-void trns_chain_append (struct trns_chain *, trns_finalize_func *,
-                        trns_proc_func *, trns_free_func *, void *);
 size_t trns_chain_next (struct trns_chain *);
 enum trns_result trns_chain_execute (const struct trns_chain *,
                                      enum trns_result, struct ccase **,
index 924b221b22d2e3851dadc578bec58e64710fc284..522d53eaa2d34217a20371c0664d6709dda723f8 100644 (file)
@@ -89,19 +89,21 @@ cmd_result_is_failure (enum cmd_result result)
 /* Command processing states. */
 enum states
   {
-    S_INITIAL = 0x01,         /* Allowed before active dataset defined. */
-    S_DATA = 0x02,            /* Allowed after active dataset defined. */
-    S_INPUT_PROGRAM = 0x04,   /* Allowed in INPUT PROGRAM. */
-    S_FILE_TYPE = 0x08,       /* Allowed in FILE TYPE. */
-    S_ANY = 0x0f              /* Allowed anywhere. */
+    S_INITIAL = 1 << 0,         /* Allowed before active dataset defined. */
+    S_DATA = 1 << 1,            /* Allowed after active dataset defined. */
+    S_INPUT_PROGRAM = 1 << 2,   /* Allowed in INPUT PROGRAM. */
+    S_FILE_TYPE = 1 << 3,       /* Allowed in FILE TYPE. */
+    S_NESTED = 1 << 4,          /* Allowed in LOOP and DO IF. */
+
+    S_ANY = S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE | S_NESTED,
   };
 
 /* Other command requirements. */
 enum flags
   {
-    F_ENHANCED = 0x10,        /* Allowed only in enhanced syntax mode. */
-    F_TESTING = 0x20,         /* Allowed only in testing mode. */
-    F_ABBREV = 0x80           /* Not a candidate for name completion. */
+    F_ENHANCED = 1 << 0,        /* Allowed only in enhanced syntax mode. */
+    F_TESTING = 1 << 1,         /* Allowed only in testing mode. */
+    F_ABBREV = 1 << 2           /* Not a candidate for name completion. */
   };
 
 /* A single command. */
@@ -126,7 +128,7 @@ static const struct command commands[] =
 static const size_t n_commands = sizeof commands / sizeof *commands;
 
 static bool in_correct_state (const struct command *, enum cmd_state);
-static bool report_state_mismatch (const struct command *, enum cmd_state);
+static void report_state_mismatch (const struct command *, enum cmd_state);
 static void set_completion_state (enum cmd_state);
 \f
 /* Command parser. */
@@ -360,21 +362,39 @@ parse_command_name (struct lexer *lexer, int *n_tokens)
 static bool
 in_correct_state (const struct command *command, enum cmd_state state)
 {
-  return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL)
-          || (state == CMD_STATE_DATA && command->states & S_DATA)
-          || (state == CMD_STATE_INPUT_PROGRAM
-              && command->states & S_INPUT_PROGRAM)
-          || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE));
+  switch (state)
+    {
+    case CMD_STATE_INITIAL:
+      return command->states & S_INITIAL;
+
+    case CMD_STATE_DATA:
+      return command->states & S_DATA;
+
+    case CMD_STATE_INPUT_PROGRAM:
+      return command->states & S_INPUT_PROGRAM;
+
+    case CMD_STATE_FILE_TYPE:
+      return command->states & S_FILE_TYPE;
+
+    case CMD_STATE_NESTED:
+      return command->states & S_NESTED;
+
+    default:
+      NOT_REACHED ();
+    }
 }
 
 /* Emits an appropriate error message for trying to invoke
    COMMAND in STATE. */
-static bool
+static void
 report_state_mismatch (const struct command *command, enum cmd_state state)
 {
   assert (!in_correct_state (command, state));
-  if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
+
+  switch (state)
     {
+    case CMD_STATE_INITIAL:
+    case CMD_STATE_DATA:
       switch ((int) command->states)
         {
           /* One allowed state. */
@@ -441,14 +461,21 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
         default:
           NOT_REACHED ();
         }
-    }
-  else if (state == CMD_STATE_INPUT_PROGRAM)
-    msg (SE, _("%s is not allowed inside %s."),
-        command->name, "INPUT PROGRAM");
-  else if (state == CMD_STATE_FILE_TYPE)
-    msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
+      break;
+
+    case CMD_STATE_INPUT_PROGRAM:
+      msg (SE, _("%s is not allowed inside %s."),
+           command->name, "INPUT PROGRAM");
+      break;
 
-  return false;
+    case CMD_STATE_FILE_TYPE:
+      msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
+      break;
+
+    case CMD_STATE_NESTED:
+      msg (SE, _("%s is not allowed inside DO IF or LOOP."), command->name);
+      break;
+    }
 }
 \f
 /* Command name completion. */
index 88cbaf5cbed8f305b3b071794e61129f0d00ff26..253885857e008c1be3765a4dad487422e450d900 100644 (file)
@@ -49,7 +49,7 @@ DEF_CMD (S_ANY, 0, "TITLE", cmd_title)
 
 /* Commands that define (or replace) the active dataset. */
 DEF_CMD (S_INITIAL | S_DATA, 0, "ADD FILES", cmd_add_files)
-DEF_CMD (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE, 0, "DATA LIST", cmd_data_list)
+DEF_CMD (S_ANY, 0, "DATA LIST", cmd_data_list)
 DEF_CMD (S_INITIAL | S_DATA, 0, "GET", cmd_get)
 DEF_CMD (S_INITIAL | S_DATA, 0, "GET DATA", cmd_get_data)
 DEF_CMD (S_INITIAL | S_DATA, 0, "IMPORT", cmd_import)
@@ -64,50 +64,51 @@ DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET COPY", cmd_dataset_copy)
 DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET NAME", cmd_dataset_name)
 DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET DISPLAY", cmd_dataset_display)
 
-/* Transformations and utilities that may appear after active
-   file definition or within INPUT PROGRAM. */
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ADD VALUE LABELS", cmd_add_value_labels)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ADD DOCUMENT", cmd_add_documents)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "APPLY DICTIONARY", cmd_apply_dictionary)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "BREAK", cmd_break)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "COMPUTE", cmd_compute)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DISPLAY", cmd_display)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DOCUMENT", cmd_document)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DO IF", cmd_do_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DROP DOCUMENTS", cmd_drop_documents)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE IF", cmd_else_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE", cmd_else)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "END IF", cmd_end_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "END LOOP", cmd_end_loop)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "FORMATS", cmd_formats)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "IF", cmd_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "LEAVE", cmd_leave)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "LOOP", cmd_loop)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "MISSING VALUES", cmd_missing_values)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "MRSETS", cmd_mrsets)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "NUMERIC", cmd_numeric)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT EJECT", cmd_print_eject)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT FORMATS", cmd_print_formats)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT SPACE", cmd_print_space)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT", cmd_print)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "RECODE", cmd_recode)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "SELECT IF", cmd_select_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "SPLIT FILE", cmd_split_file)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "STRING", cmd_string)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VALUE LABELS", cmd_value_labels)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ALIGNMENT", cmd_variable_alignment)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LABELS", cmd_variable_labels)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LEVEL", cmd_variable_level)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ROLE", cmd_variable_role)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE WIDTH", cmd_variable_width)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VECTOR", cmd_vector)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WEIGHT", cmd_weight)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WRITE FORMATS", cmd_write_formats)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WRITE", cmd_write)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, F_ENHANCED, "XEXPORT", cmd_xexport)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "XSAVE", cmd_xsave)
+/* Utilities that may appear after active file definition or within INPUT PROGRAM. */
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ADD VALUE LABELS", cmd_add_value_labels)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ADD DOCUMENT", cmd_add_documents)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "APPLY DICTIONARY", cmd_apply_dictionary)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DISPLAY", cmd_display)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DOCUMENT", cmd_document)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DROP DOCUMENTS", cmd_drop_documents)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "FORMATS", cmd_formats)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "LEAVE", cmd_leave)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "MISSING VALUES", cmd_missing_values)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "MRSETS", cmd_mrsets)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT FORMATS", cmd_print_formats)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "SPLIT FILE", cmd_split_file)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VALUE LABELS", cmd_value_labels)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ALIGNMENT", cmd_variable_alignment)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE LABELS", cmd_variable_labels)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE LEVEL", cmd_variable_level)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ROLE", cmd_variable_role)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE WIDTH", cmd_variable_width)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VECTOR", cmd_vector)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WEIGHT", cmd_weight)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WRITE FORMATS", cmd_write_formats)
+
+/* Transformations. */
+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)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT EJECT", cmd_print_eject)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT SPACE", cmd_print_space)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT", cmd_print)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "RECODE", cmd_recode)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "SELECT IF", cmd_select_if)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "STRING", cmd_string)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WRITE", cmd_write)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, F_ENHANCED, "XEXPORT", cmd_xexport)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "XSAVE", cmd_xsave)
 
 /* Commands that may appear after active dataset definition. */
 DEF_CMD (S_DATA, 0, "AGGREGATE", cmd_aggregate)
@@ -151,10 +152,10 @@ DEF_CMD (S_DATA, 0, "TEMPORARY", cmd_temporary)
 DEF_CMD (S_DATA, 0, "USE", cmd_use)
 
 /* Commands valid only with INPUT PROGRAM. */
-DEF_CMD (S_INPUT_PROGRAM, 0, "END CASE", cmd_end_case)
-DEF_CMD (S_INPUT_PROGRAM, 0, "END FILE", cmd_end_file)
-DEF_CMD (S_INPUT_PROGRAM, 0, "END INPUT PROGRAM", cmd_end_input_program)
-DEF_CMD (S_INPUT_PROGRAM, 0, "REREAD", cmd_reread)
+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. */
 DEF_CMD (S_ANY, F_TESTING, "DEBUG EXPAND", cmd_debug_expand)
index ab133c25e7932cf60f5e4fd835353659231c21d6..766a637b0ba5ce694fa0d556a0160f32f53efeed 100644 (file)
@@ -48,7 +48,8 @@ enum cmd_state
     CMD_STATE_INITIAL,          /* No active dataset yet defined. */
     CMD_STATE_DATA,             /* Active dataset has been defined. */
     CMD_STATE_INPUT_PROGRAM,    /* Inside INPUT PROGRAM. */
-    CMD_STATE_FILE_TYPE         /* Inside FILE TYPE. */
+    CMD_STATE_FILE_TYPE,        /* Inside FILE TYPE. */
+    CMD_STATE_NESTED,           /* Inside LOOP or DO IF. */
   };
 
 struct dataset;
index 9d09687c81e38330552f5f23c5d6f3b01385edf4..38ecf683644e50e40ed01252fe6d594fe3b4b5cf 100644 (file)
@@ -18,8 +18,6 @@
 
 
 language_control_sources = \
-       src/language/control/control-stack.c \
-       src/language/control/control-stack.h \
        src/language/control/define.c \
        src/language/control/do-if.c \
        src/language/control/loop.c \
diff --git a/src/language/control/control-stack.c b/src/language/control/control-stack.c
deleted file mode 100644 (file)
index 8d0962b..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-PSPP - a program for statistical analysis.
-Copyright (C) 2017 Free Software Foundation, Inc.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <config.h>
-
-#include "language/control/control-stack.h"
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "libpspp/compiler.h"
-#include "libpspp/message.h"
-
-#include "gl/xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-struct ctl_struct
-  {
-    const struct ctl_class *class;    /* Class of control structure. */
-    struct ctl_struct *down;   /* Points toward the bottom of ctl_stack. */
-    void *private;              /* Private data. */
-  };
-
-static struct ctl_struct *ctl_stack;
-
-void
-ctl_stack_clear (void)
-{
-  while (ctl_stack != NULL)
-    {
-      struct ctl_struct *top = ctl_stack;
-      msg (SE, _("%s without %s."),
-           top->class->start_name, top->class->end_name);
-      ctl_stack_pop (top->private);
-    }
-}
-
-void
-ctl_stack_push (const struct ctl_class *class, void *private)
-{
-  struct ctl_struct *ctl;
-
-  assert (private != NULL);
-  ctl = xmalloc (sizeof *ctl);
-  ctl->class = class;
-  ctl->down = ctl_stack;
-  ctl->private = private;
-  ctl_stack = ctl;
-}
-
-void *
-ctl_stack_top (const struct ctl_class *class)
-{
-  struct ctl_struct *top = ctl_stack;
-  if (top != NULL && top->class == class)
-    return top->private;
-  else
-    {
-      if (ctl_stack_search (class) != NULL)
-        msg (SE, _("This command must appear inside %s...%s, "
-                   "without intermediate %s...%s."),
-             class->start_name, class->end_name,
-             top->class->start_name, top->class->end_name);
-      return NULL;
-    }
-}
-
-void *
-ctl_stack_search (const struct ctl_class *class)
-{
-  struct ctl_struct *ctl;
-
-  for (ctl = ctl_stack; ctl != NULL; ctl = ctl->down)
-    if (ctl->class == class)
-      return ctl->private;
-
-  msg (SE, _("This command cannot appear outside %s...%s."),
-       class->start_name, class->end_name);
-  return NULL;
-}
-
-void
-ctl_stack_pop (void *private)
-{
-  struct ctl_struct *top = ctl_stack;
-
-  assert (top != NULL);
-  assert (top->private == private);
-
-  top->class->close (top->private);
-  ctl_stack = top->down;
-  free (top);
-}
-
-bool
-ctl_stack_is_empty (void)
-{
-  return ctl_stack == NULL;
-}
diff --git a/src/language/control/control-stack.h b/src/language/control/control-stack.h
deleted file mode 100644 (file)
index 9c6824b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2011 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef CTL_STACK_H
-#define CTL_STACK_H 1
-
-#include <stdbool.h>
-
-/* The following #include avoids a potential problem when Gnulib substitutes
- * for close() by putting "#define close rpl_close" into <unistd.h>, by
- * ensuring that every source file that includes this one sees the #define..
- * (It would probably be better to rename the 'close' member of struct
- * ctl_class.)  */
-#include <unistd.h>
-
-struct ctl_class
-  {
-    const char *start_name;     /* e.g. LOOP. */
-    const char *end_name;       /* e.g. END LOOP. */
-    void (*close) (void *);     /* Closes the control structure. */
-  };
-
-void ctl_stack_clear (void);
-void ctl_stack_push (const struct ctl_class *, void *private);
-void *ctl_stack_top (const struct ctl_class *);
-void *ctl_stack_search (const struct ctl_class *);
-void ctl_stack_pop (void *);
-bool ctl_stack_is_empty (void);
-
-#endif /* ctl_stack.h */
index b361fba920702e4939395857481207f09bb8d71d..b45694804ae35dc2c728c187661b0a3b5f873dc2 100644 (file)
 
 #include <stdlib.h>
 
-#include "data/case.h"
 #include "data/dataset.h"
 #include "data/transformations.h"
-#include "data/value.h"
 #include "language/command.h"
-#include "language/control/control-stack.h"
 #include "language/expressions/public.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/compiler.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* DO IF, ELSE IF, and ELSE are translated as a single
-   transformation that evaluates each condition and jumps to the
-   start of the appropriate block of transformations.  Each block
-   of transformations (except for the last) ends with a
-   transformation that jumps past the remaining blocks.
-
-   So, the following code:
-
-       DO IF a.
-       ...block 1...
-       ELSE IF b.
-       ...block 2...
-       ELSE.
-       ...block 3...
-       END IF.
-
-   is effectively translated like this:
-
-       IF a GOTO 1, IF b GOTO 2, ELSE GOTO 3.
-       1: ...block 1...
-          GOTO 4
-       2: ...block 2...
-          GOTO 4
-       3: ...block 3...
-       4:
-
-*/
-
 /* A conditional clause. */
 struct clause
   {
+    struct msg_location *location;
     struct expression *condition; /* Test expression; NULL for ELSE clause. */
-    int target_index;           /* Transformation to jump to if true. */
+    struct transformation *xforms;
+    size_t n_xforms;
   };
 
 /* DO IF transformation. */
 struct do_if_trns
   {
-    struct dataset *ds;         /* The dataset */
     struct clause *clauses;     /* Clauses. */
     size_t n_clauses;           /* Number of clauses. */
-    int past_END_IF_index;      /* Transformation just past last clause. */
   };
 
-static const struct ctl_class do_if_class;
-
-static int parse_clause (struct lexer *, struct do_if_trns *, struct dataset *ds);
-static void add_clause (struct do_if_trns *, struct expression *condition);
-static void add_else (struct do_if_trns *);
-
-static bool has_else (struct do_if_trns *);
-static bool must_not_have_else (struct do_if_trns *);
-static void close_do_if (void *do_if);
-
-static trns_finalize_func do_if_finalize_func;
-static trns_proc_func do_if_trns_proc, break_trns_proc;
+static trns_proc_func do_if_trns_proc;
 static trns_free_func do_if_trns_free;
 
-/* Parse DO IF. */
-int
-cmd_do_if (struct lexer *lexer, struct dataset *ds)
-{
-  struct do_if_trns *do_if = xmalloc (sizeof *do_if);
-  do_if->clauses = NULL;
-  do_if->n_clauses = 0;
-  do_if->ds = ds;
-
-  ctl_stack_push (&do_if_class, do_if);
-  add_transformation_with_finalizer (ds, do_if_finalize_func,
-                                     do_if_trns_proc, do_if_trns_free, do_if);
-
-  return parse_clause (lexer, do_if, ds);
-}
-
-/* Parse ELSE IF. */
-int
-cmd_else_if (struct lexer *lexer, struct dataset *ds)
-{
-  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
-  if (do_if == NULL || !must_not_have_else (do_if))
-    return CMD_CASCADING_FAILURE;
-  return parse_clause (lexer, do_if, ds);
-}
-
-/* Parse ELSE. */
-int
-cmd_else (struct lexer *lexer UNUSED, struct dataset *ds)
+static void
+start_clause (struct lexer *lexer, struct dataset *ds,
+              bool condition, struct do_if_trns *do_if,
+              size_t *allocated_clauses, bool *ok)
 {
-  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
-
-  if (do_if == NULL || !must_not_have_else (do_if))
-    return CMD_CASCADING_FAILURE;
+  if (*ok && do_if->n_clauses > 0
+      && !do_if->clauses[do_if->n_clauses - 1].condition)
+    {
+      if (condition)
+        msg (SE, _("ELSE IF is not allowed following ELSE "
+                   "within DO IF...END IF."));
+      else
+        msg (SE, _("Only one ELSE is allowed within DO IF...END IF."));
 
-  assert (ds == do_if->ds);
+      msg_at (SN, do_if->clauses[do_if->n_clauses - 1].location,
+              _("This is the location of the previous ELSE clause."));
 
-  add_else (do_if);
-  return CMD_SUCCESS;
-}
+      msg_at (SN, do_if->clauses[0].location,
+              _("This is the location of the DO IF command."));
+    }
 
-/* Parse END IF. */
-int
-cmd_end_if (struct lexer *lexer UNUSED, struct dataset *ds)
-{
-  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
+  if (do_if->n_clauses >= *allocated_clauses)
+    do_if->clauses = x2nrealloc (do_if->clauses, allocated_clauses,
+                                 sizeof *do_if->clauses);
+  struct clause *clause = &do_if->clauses[do_if->n_clauses++];
 
-  if (do_if == NULL)
-    return CMD_CASCADING_FAILURE;
+  *clause = (struct clause) { .n_xforms = 0 };
+  if (condition)
+    {
+      clause->condition = expr_parse_bool (lexer, ds);
+      if (!clause->condition)
+        lex_discard_rest_of_command (lexer);
+    }
+  clause->location = lex_ofs_location (lexer, 0, lex_ofs (lexer));
 
-  assert (ds == do_if->ds);
-  ctl_stack_pop (do_if);
+  lex_end_of_command (lexer);
+  lex_get (lexer);
 
-  return CMD_SUCCESS;
+  proc_push_transformations (ds);
 }
 
-/* Closes out DO_IF, by adding a sentinel ELSE clause if
-   necessary and setting past_END_IF_index. */
 static void
-close_do_if (void *do_if_)
+finish_clause (struct dataset *ds, struct do_if_trns *do_if)
 {
-  struct do_if_trns *do_if = do_if_;
-
-  if (!has_else (do_if))
-    add_else (do_if);
-  do_if->past_END_IF_index = next_transformation (do_if->ds);
+  struct clause *clause = &do_if->clauses[do_if->n_clauses - 1];
+  proc_pop_transformations (ds, &clause->xforms, &clause->n_xforms);
 }
 
-/* Adds an ELSE clause to DO_IF pointing to the next
-   transformation. */
-static void
-add_else (struct do_if_trns *do_if)
+/* Parse DO IF. */
+int
+cmd_do_if (struct lexer *lexer, struct dataset *ds)
 {
-  assert (!has_else (do_if));
-  add_clause (do_if, NULL);
-}
+  struct do_if_trns *do_if = xmalloc (sizeof *do_if);
+  *do_if = (struct do_if_trns) { .n_clauses = 0 };
 
-/* Returns true if DO_IF does not yet have an ELSE clause.
-   Reports an error and returns false if it does already. */
-static bool
-must_not_have_else (struct do_if_trns *do_if)
-{
-  if (has_else (do_if))
+  size_t allocated_clauses = 0;
+  bool ok = true;
+
+  start_clause (lexer, ds, true, do_if, &allocated_clauses, &ok);
+  while (!lex_match_phrase (lexer, "END IF"))
     {
-      msg (SE, _("This command may not follow %s in %s ... %s."), "ELSE", "DO IF", "END IF");
-      return false;
+      if (lex_token (lexer) == T_STOP)
+        {
+          lex_error (lexer, NULL);
+          ok = false;
+          break;
+        }
+      else if (lex_match_phrase (lexer, "ELSE IF"))
+        {
+          finish_clause (ds, do_if);
+          start_clause (lexer, ds, true, do_if, &allocated_clauses, &ok);
+        }
+      else if (lex_match_id (lexer, "ELSE"))
+        {
+          finish_clause (ds, do_if);
+          start_clause (lexer, ds, false, do_if, &allocated_clauses, &ok);
+        }
+      else
+        cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED);
     }
-  else
-    return true;
-}
-
-/* Returns true if DO_IF already has an ELSE clause,
-   false otherwise. */
-static bool
-has_else (struct do_if_trns *do_if)
-{
-  return (do_if->n_clauses != 0
-          && do_if->clauses[do_if->n_clauses - 1].condition == NULL);
-}
-
-/* Parses a DO IF or ELSE IF expression and appends the
-   corresponding clause to DO_IF.  Checks for end of command and
-   returns a command return code. */
-static int
-parse_clause (struct lexer *lexer, struct do_if_trns *do_if, struct dataset *ds)
-{
-  struct expression *condition;
-
-  condition = expr_parse_bool (lexer, NULL, ds);
-  if (condition == NULL)
-    return CMD_CASCADING_FAILURE;
-
-  add_clause (do_if, condition);
-
-  return CMD_SUCCESS;
-}
+  finish_clause (ds, do_if);
 
-/* Adds a clause to DO_IF that tests for the given CONDITION and,
-   if true, jumps to the set of transformations produced by
-   following commands. */
-static void
-add_clause (struct do_if_trns *do_if, struct expression *condition)
-{
-  struct clause *clause;
-
-  if (do_if->n_clauses > 0)
-    add_transformation (do_if->ds, break_trns_proc, NULL, do_if);
+  add_transformation (ds, do_if_trns_proc, do_if_trns_free, do_if);
 
-  do_if->clauses = xnrealloc (do_if->clauses,
-                              do_if->n_clauses + 1, sizeof *do_if->clauses);
-  clause = &do_if->clauses[do_if->n_clauses++];
-  clause->condition = condition;
-  clause->target_index = next_transformation (do_if->ds);
-}
-
-/* Finalizes DO IF by clearing the control stack, thus ensuring
-   that all open DO IFs are closed. */
-static void
-do_if_finalize_func (void *do_if_ UNUSED)
-{
-  /* This will be called multiple times if multiple DO IFs were
-     executed, which is slightly unclean, but at least it's
-     idempotent. */
-  ctl_stack_clear ();
+  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
 /* DO IF transformation procedure.
    Checks each clause and jumps to the appropriate
    transformation. */
-static int
-do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num UNUSED)
+static enum trns_result
+do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num)
 {
   struct do_if_trns *do_if = do_if_;
-  struct clause *clause;
 
-  for (clause = do_if->clauses; clause < do_if->clauses + do_if->n_clauses;
-       clause++)
+  for (size_t i = 0; i < do_if->n_clauses; i++)
     {
+      const struct clause *clause = &do_if->clauses[i];
       if (clause->condition != NULL)
         {
           double boolean = expr_evaluate_num (clause->condition, *c, case_num);
-          if (boolean == 1.0)
-            return clause->target_index;
+          if (boolean == 0.0)
+            continue;
           else if (boolean == SYSMIS)
-            return do_if->past_END_IF_index;
+            return TRNS_CONTINUE;
         }
-      else
-        return clause->target_index;
+
+      return transformations_execute (clause->xforms, clause->n_xforms,
+                                      c, case_num);
     }
-  return do_if->past_END_IF_index;
+  return TRNS_CONTINUE;
 }
 
 /* Frees a DO IF transformation. */
@@ -270,30 +169,17 @@ static bool
 do_if_trns_free (void *do_if_)
 {
   struct do_if_trns *do_if = do_if_;
-  struct clause *clause;
 
-  for (clause = do_if->clauses; clause < do_if->clauses + do_if->n_clauses;
-       clause++)
-    expr_free (clause->condition);
+  for (size_t i = 0; i < do_if->n_clauses; i++)
+    {
+      struct clause *clause = &do_if->clauses[i];
+
+      msg_location_destroy (clause->location);
+      expr_free (clause->condition);
+
+      transformations_destroy (clause->xforms, clause->n_xforms);
+    }
   free (do_if->clauses);
   free (do_if);
   return true;
 }
-
-/* Breaks out of a DO IF construct. */
-static int
-break_trns_proc (void *do_if_, struct ccase **c UNUSED,
-                 casenumber case_num UNUSED)
-{
-  struct do_if_trns *do_if = do_if_;
-
-  return do_if->past_END_IF_index;
-}
-
-/* DO IF control structure class definition. */
-static const struct ctl_class do_if_class =
-  {
-    "DO IF",
-    "END IF",
-    close_do_if,
-  };
index 156e647ea0e617ac16446a8c8a38d84814b47071..604af4556940bb2156c0048ce641b17d0cd73579 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include "language/control/control-stack.h"
+#include <limits.h>
 
 #include "data/case.h"
 #include "data/dataset.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* LOOP outputs a transformation that is executed only on the
-   first pass through the loop.  On this trip, it initializes for
-   the first pass by resetting the pass number, setting up the
-   indexing clause, and testing the LOOP IF clause.  If the loop
-   is not to be entered at all, it jumps forward just past the
-   END LOOP transformation; otherwise, it continues to the
-   transformation following LOOP.
-
-   END LOOP outputs a transformation that executes at the end of
-   each trip through the loop.  It checks the END LOOP IF clause,
-   then updates the pass number, increments the indexing clause,
-   and tests the LOOP IF clause.  If another pass through the
-   loop is due, it jumps backward to just after the LOOP
-   transformation; otherwise, it continues to the transformation
-   following END LOOP. */
-
 struct loop_trns
   {
-    struct pool *pool;
-    struct dataset *ds;
-
-    /* Iteration limit. */
-    int max_pass_count;         /* Maximum number of passes (-1=unlimited). */
-    int pass;                  /* Number of passes through the loop so far. */
-
     /* a=a TO b [BY c]. */
     struct variable *index_var; /* Index variable. */
-    struct expression *first_expr; /* Starting index. */
-    struct expression *by_expr;        /* Index increment (default 1.0 if null). */
-    struct expression *last_expr; /* Terminal index. */
-    double cur, by, last;       /* Current value, increment, last value. */
+    struct expression *first;   /* Starting index. */
+    struct expression *by;     /* Index increment (or NULL). */
+    struct expression *last;    /* Terminal index. */
 
     /* IF condition for LOOP or END LOOP. */
     struct expression *loop_condition;
     struct expression *end_loop_condition;
 
-    /* Transformation indexes. */
-    int past_LOOP_index;        /* Just past LOOP transformation. */
-    int past_END_LOOP_index;    /* Just past END LOOP transformation. */
+    /* Inner transformations. */
+    struct transformation *xforms;
+    size_t n_xforms;
   };
 
-static const struct ctl_class loop_class;
-
-static trns_finalize_func loop_trns_finalize;
-static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc;
+static trns_proc_func loop_trns_proc;
 static trns_free_func loop_trns_free;
 
-static struct loop_trns *create_loop_trns (struct dataset *);
-static bool parse_if_clause (struct lexer *,
-                             struct loop_trns *, struct expression **);
+static bool parse_if_clause (struct lexer *, struct dataset *,
+                             struct expression **);
 static bool parse_index_clause (struct dataset *, struct lexer *,
-                                struct loop_trns *, bool *created_index_var);
-static void close_loop (void *);
+                                struct loop_trns *);
 \f
 /* LOOP. */
 
@@ -98,95 +69,59 @@ static void close_loop (void *);
 int
 cmd_loop (struct lexer *lexer, struct dataset *ds)
 {
-  struct loop_trns *loop;
-  bool created_index_var = false;
-  bool ok = true;
+  struct loop_trns *loop = xmalloc (sizeof *loop);
+  *loop = (struct loop_trns) { .index_var = NULL };
 
-  loop = create_loop_trns (ds);
+  bool ok = true;
   while (lex_token (lexer) != T_ENDCMD && ok)
     {
       if (lex_match_id (lexer, "IF"))
-        ok = parse_if_clause (lexer, loop, &loop->loop_condition);
+        ok = parse_if_clause (lexer, ds, &loop->loop_condition);
       else
-        ok = parse_index_clause (ds, lexer, loop, &created_index_var);
+        ok = parse_index_clause (ds, lexer, loop);
     }
+  lex_end_of_command (lexer);
 
-  /* Clean up if necessary. */
-  if (!ok)
+  proc_push_transformations (ds);
+  for (;;)
     {
-      loop->max_pass_count = 0;
-      if (loop->index_var != NULL && created_index_var)
+      if (lex_token (lexer) == T_STOP)
         {
-          dict_delete_var (dataset_dict (ds), loop->index_var);
-          loop->index_var = NULL;
+          lex_error (lexer, NULL);
+          ok = false;
+          break;
         }
+      else if (lex_match_phrase (lexer, "END LOOP"))
+        {
+          if (lex_match_id (lexer, "IF"))
+            ok = parse_if_clause (lexer, ds, &loop->end_loop_condition) && ok;
+          break;
+        }
+      else
+        cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED);
     }
+  proc_pop_transformations (ds, &loop->xforms, &loop->n_xforms);
 
-  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
-}
-
-/* Parses END LOOP. */
-int
-cmd_end_loop (struct lexer *lexer, struct dataset *ds)
-{
-  struct loop_trns *loop;
-  bool ok = true;
-
-  loop = ctl_stack_top (&loop_class);
-  if (loop == NULL)
-    return CMD_CASCADING_FAILURE;
-
-  assert (loop->ds == ds);
-
-  /* Parse syntax. */
-  if (lex_match_id (lexer, "IF"))
-    ok = parse_if_clause (lexer, loop, &loop->end_loop_condition);
-  if (ok)
-    ok = lex_end_of_command (lexer) == CMD_SUCCESS;
+  add_transformation (ds, loop_trns_proc, loop_trns_free, loop);
 
-  if (!ok)
-    loop->max_pass_count = 0;
-
-  ctl_stack_pop (loop);
-
-  return ok ? CMD_SUCCESS : CMD_FAILURE;
+  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
 /* Parses BREAK. */
 int
-cmd_break (struct lexer *lexer UNUSED, struct dataset *ds)
+cmd_break (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
-  struct ctl_stmt *loop = ctl_stack_search (&loop_class);
-  if (loop == NULL)
-    return CMD_CASCADING_FAILURE;
-
-  add_transformation (ds, break_trns_proc, NULL, loop);
+  //add_transformation (ds, break_trns_proc, NULL, NULL);
 
   return CMD_SUCCESS;
 }
 
-/* Closes a LOOP construct by emitting the END LOOP
-   transformation and finalizing its members appropriately. */
-static void
-close_loop (void *loop_)
-{
-  struct loop_trns *loop = loop_;
-
-  add_transformation (loop->ds, end_loop_trns_proc, NULL, loop);
-  loop->past_END_LOOP_index = next_transformation (loop->ds);
-
-  /* If there's nothing else limiting the number of loops, use
-     MXLOOPS as a limit. */
-  if (loop->max_pass_count == -1 && loop->index_var == NULL)
-    loop->max_pass_count = settings_get_mxloops ();
-}
-
 /* Parses an IF clause for LOOP or END LOOP and stores the
    resulting expression to *CONDITION.
    Returns true if successful, false on failure. */
 static bool
-parse_if_clause (struct lexer *lexer,
-                struct loop_trns *loop, struct expression **condition)
+parse_if_clause (struct lexer *lexer, struct dataset *ds,
+                struct expression **condition)
 {
   if (*condition != NULL)
     {
@@ -194,17 +129,15 @@ parse_if_clause (struct lexer *lexer,
       return false;
     }
 
-  *condition = expr_parse_bool (lexer, loop->pool, loop->ds);
+  *condition = expr_parse_bool (lexer, ds);
   return *condition != NULL;
 }
 
-/* Parses an indexing clause into LOOP.
-   Stores true in *CREATED_INDEX_VAR if the index clause created
-   a new variable, false otherwise.
-   Returns true if successful, false on failure. */
+/* Parses an indexing clause into LOOP.  Returns true if successful, false on
+   failure. */
 static bool
 parse_index_clause (struct dataset *ds, struct lexer *lexer,
-                    struct loop_trns *loop, bool *created_index_var)
+                    struct loop_trns *loop)
 {
   if (loop->index_var != NULL)
     {
@@ -219,127 +152,102 @@ parse_index_clause (struct dataset *ds, struct lexer *lexer,
     }
 
   loop->index_var = dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer));
-  if (loop->index_var != NULL)
-    *created_index_var = false;
-  else
-    {
-      loop->index_var = dict_create_var_assert (dataset_dict (ds),
-                                                lex_tokcstr (lexer), 0);
-      *created_index_var = true;
-    }
+  if (!loop->index_var)
+    loop->index_var = dict_create_var_assert (dataset_dict (ds),
+                                              lex_tokcstr (lexer), 0);
   lex_get (lexer);
 
   if (!lex_force_match (lexer, T_EQUALS))
     return false;
 
-  loop->first_expr = expr_parse (lexer, loop->pool, loop->ds, VAL_NUMERIC);
-  if (loop->first_expr == NULL)
+  loop->first = expr_parse (lexer, ds, VAL_NUMERIC);
+  if (loop->first == NULL)
     return false;
 
   for (;;)
     {
       struct expression **e;
       if (lex_match (lexer, T_TO))
-        e = &loop->last_expr;
+        e = &loop->last;
       else if (lex_match (lexer, T_BY))
-        e = &loop->by_expr;
+        e = &loop->by;
       else
         break;
 
       if (*e != NULL)
         {
-          lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
+          lex_sbc_only_once (e == &loop->last ? "TO" : "BY");
           return false;
         }
-      *e = expr_parse (lexer, loop->pool, loop->ds, VAL_NUMERIC);
+      *e = expr_parse (lexer, ds, VAL_NUMERIC);
       if (*e == NULL)
         return false;
     }
-  if (loop->last_expr == NULL)
+  if (loop->last == NULL)
     {
       lex_sbc_missing ("TO");
       return false;
     }
-  if (loop->by_expr == NULL)
-    loop->by = 1.0;
 
   return true;
 }
 
-/* Creates, initializes, and returns a new loop_trns. */
-static struct loop_trns *
-create_loop_trns (struct dataset *ds)
-{
-  struct loop_trns *loop = pool_create_container (struct loop_trns, pool);
-  loop->max_pass_count = -1;
-  loop->pass = 0;
-  loop->index_var = NULL;
-  loop->first_expr = loop->by_expr = loop->last_expr = NULL;
-  loop->loop_condition = loop->end_loop_condition = NULL;
-  loop->ds = ds;
-
-  add_transformation_with_finalizer (ds, loop_trns_finalize,
-                                     loop_trns_proc, loop_trns_free, loop);
-  loop->past_LOOP_index = next_transformation (ds);
-
-  ctl_stack_push (&loop_class, loop);
-
-  return loop;
-}
-
-/* Finalizes LOOP by clearing the control stack, thus ensuring
-   that all open LOOPs are closed. */
-static void
-loop_trns_finalize (void *do_if_ UNUSED)
-{
-  /* This will be called multiple times if multiple LOOPs were
-     executed, which is slightly unclean, but at least it's
-     idempotent. */
-  ctl_stack_clear ();
-}
-
 /* Sets up LOOP for the first pass. */
-static int
+static enum trns_result
 loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num)
 {
   struct loop_trns *loop = loop_;
 
-  if (loop->index_var != NULL)
+  double cur, by, last;
+  if (loop->index_var)
     {
       /* Evaluate loop index expressions. */
-      loop->cur = expr_evaluate_num (loop->first_expr, *c, case_num);
-      if (loop->by_expr != NULL)
-       loop->by = expr_evaluate_num (loop->by_expr, *c, case_num);
-      loop->last = expr_evaluate_num (loop->last_expr, *c, case_num);
+      cur = expr_evaluate_num (loop->first, *c, case_num);
+      by = loop->by ? expr_evaluate_num (loop->by, *c, case_num) : 1.0;
+      last = expr_evaluate_num (loop->last, *c, case_num);
 
       /* Even if the loop is never entered, set the index
          variable to the initial value. */
       *c = case_unshare (*c);
-      *case_num_rw (*c, loop->index_var) = loop->cur;
+      *case_num_rw (*c, loop->index_var) = cur;
 
       /* Throw out pathological cases. */
-      if (!isfinite (loop->cur) || !isfinite (loop->by)
-          || !isfinite (loop->last)
-          || loop->by == 0.0
-          || (loop->by > 0.0 && loop->cur > loop->last)
-          || (loop->by < 0.0 && loop->cur < loop->last))
-        goto zero_pass;
+      if (!isfinite (cur) || !isfinite (by) || !isfinite (last)
+          || by == 0.0
+          || (by > 0.0 && cur > last)
+          || (by < 0.0 && cur < last))
+        return TRNS_CONTINUE;
     }
+  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++)
+    {
+      if (loop->loop_condition
+          && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
+        break;
 
-  /* Initialize pass count. */
-  loop->pass = 0;
-  if (loop->max_pass_count >= 0 && loop->pass >= loop->max_pass_count)
-    goto zero_pass;
+      enum trns_result r = transformations_execute (
+        loop->xforms, loop->n_xforms, c, case_num);
+      if (r != TRNS_CONTINUE)
+        return r == TRNS_BREAK ? TRNS_CONTINUE : r;
 
-  /* Check condition. */
-  if (loop->loop_condition != NULL
-      && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
-    goto zero_pass;
+      if (loop->end_loop_condition != NULL
+          && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0)
+        break;
 
-  return loop->past_LOOP_index;
+      if (loop->index_var)
+        {
+          cur += by;
+          if (by > 0.0 ? cur > last : cur < last)
+            break;
 
- zero_pass:
-  return loop->past_END_LOOP_index;
+          *c = case_unshare (*c);
+          *case_num_rw (*c, loop->index_var) = cur;
+        }
+    }
+  return TRNS_CONTINUE;
 }
 
 /* Frees LOOP. */
@@ -348,59 +256,15 @@ loop_trns_free (void *loop_)
 {
   struct loop_trns *loop = loop_;
 
-  pool_destroy (loop->pool);
-  return true;
-}
-
-/* Finishes a pass through the loop and starts the next. */
-static int
-end_loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num UNUSED)
-{
-  struct loop_trns *loop = loop_;
-
-  if (loop->end_loop_condition != NULL
-      && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0)
-    goto break_out;
-
-  /* MXLOOPS limiter. */
-  if (loop->max_pass_count >= 0 && ++loop->pass >= loop->max_pass_count)
-    goto break_out;
-
-  /* Indexing clause limiter: counting downward. */
-  if (loop->index_var != NULL)
-    {
-      loop->cur += loop->by;
-      if ((loop->by > 0.0 && loop->cur > loop->last)
-          || (loop->by < 0.0 && loop->cur < loop->last))
-        goto break_out;
-      *c = case_unshare (*c);
-      *case_num_rw (*c, loop->index_var) = loop->cur;
-    }
-
-  if (loop->loop_condition != NULL
-      && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
-    goto break_out;
-
-  return loop->past_LOOP_index;
+  expr_free (loop->first);
+  expr_free (loop->by);
+  expr_free (loop->last);
 
- break_out:
-  return loop->past_END_LOOP_index;
-}
+  expr_free (loop->loop_condition);
+  expr_free (loop->end_loop_condition);
 
-/* Executes BREAK. */
-static int
-break_trns_proc (void *loop_, struct ccase **c UNUSED,
-                 casenumber case_num UNUSED)
-{
-  struct loop_trns *loop = loop_;
+  transformations_destroy (loop->xforms, loop->n_xforms);
 
-  return loop->past_END_LOOP_index;
+  free (loop);
+  return true;
 }
-
-/* LOOP control structure class definition. */
-static const struct ctl_class loop_class =
-  {
-    "LOOP",
-    "END LOOP",
-    close_loop,
-  };
index b350759b024e3c0d2393f0bf32ddf50313dcbecc..c7514413727424dd7c455aaf28f0e65a7c9d1a44 100644 (file)
@@ -24,7 +24,6 @@
 #include "data/value-labels.h"
 #include "data/variable.h"
 #include "language/command.h"
-#include "language/control/control-stack.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
index 02cabd8cde0ca3df01042945eec85299df164e2b..a340f207f10a1ebd121c4b504e3450cc80102806 100644 (file)
@@ -511,11 +511,11 @@ data_list_trns_free (void *trns_)
 }
 
 /* Handle DATA LIST transformation TRNS, parsing data into *C. */
-static int
+static enum trns_result
 data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct data_list_trns *trns = trns_;
-  int retval;
+  enum trns_result retval;
 
   *c = case_unshare (*c);
   if (data_parser_parse (trns->parser, trns->reader, *c))
index e2cfbd1bb8899e52b450890a13dc98999b4fe4d5..6ce75f6a4dafb63d8e2f311eae6ea985891e16a1 100644 (file)
@@ -155,7 +155,6 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
     }
 
   inp->trns_chain = proc_capture_transformations (inp->ds);
-  trns_chain_finalize (inp->trns_chain);
 
   inp->restart = TRNS_CONTINUE;
 
@@ -265,7 +264,7 @@ cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED)
 }
 
 /* Outputs the current case */
-int
+enum trns_result
 end_case_trns_proc (void *inp_, struct ccase **c UNUSED,
                     casenumber case_nr UNUSED)
 {
@@ -304,7 +303,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds)
               goto error;
            }
 
-         e = expr_parse (lexer, NULL, ds, VAL_NUMERIC);
+         e = expr_parse (lexer, ds, VAL_NUMERIC);
          if (!e)
             goto error;
        }
@@ -350,7 +349,7 @@ error:
 }
 
 /* Executes a REREAD transformation. */
-static int
+static enum trns_result
 reread_trns_proc (void *t_, struct ccase **c, casenumber case_num)
 {
   struct reread_trns *t = t_;
@@ -395,7 +394,7 @@ cmd_end_file (struct lexer *lexer UNUSED, struct dataset *ds)
 }
 
 /* Executes an END FILE transformation. */
-static int
+static enum trns_result
 end_file_trns_proc (void *trns_ UNUSED, struct ccase **c UNUSED,
                     casenumber case_num UNUSED)
 {
index f077e9c39573e30760303704d0c356e95895bbf7..11b9dcb79bf5890205fc20138ac1a06aa4d1d715 100644 (file)
@@ -77,7 +77,7 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds)
 
   if (lex_token (lexer) != T_ENDCMD)
     {
-      expr = expr_parse (lexer, NULL, ds, VAL_NUMERIC);
+      expr = expr_parse (lexer, ds, VAL_NUMERIC);
       if (lex_token (lexer) != T_ENDCMD)
        {
           lex_error (lexer, _("expecting end of command"));
@@ -112,7 +112,7 @@ error:
 }
 
 /* Executes a PRINT SPACE transformation. */
-static int
+static enum trns_result
 print_space_trns_proc (void *t_, struct ccase **c,
                        casenumber case_num UNUSED)
 {
index 5c9ef7af993e903c0b0ebf18781e7379b525611f..26bb2e12cd12bb2238000eb7bcf1c08023e52c3e 100644 (file)
@@ -474,7 +474,7 @@ static void print_text_flush_records (struct print_trns *, struct u8_line *,
                                       bool *eject, int *record);
 
 /* Performs the transformation inside print_trns T on case C. */
-static int
+static enum trns_result
 print_text_trns_proc (void *trns_, struct ccase **c,
                       casenumber case_num UNUSED)
 {
@@ -587,7 +587,7 @@ static void print_binary_flush_records (struct print_trns *,
                                         bool *eject, int *record);
 
 /* Performs the transformation inside print_trns T on case C. */
-static int
+static enum trns_result
 print_binary_trns_proc (void *trns_, struct ccase **c,
                         casenumber case_num UNUSED)
 {
index a5848e59f5ce12f08b5de428df5fb7154cc9ed09..190de124c3a7979da91ffa2df9033be145b091f6 100644 (file)
@@ -364,7 +364,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
 }
 
 /* Writes case *C to the system file specified on XSAVE or XEXPORT. */
-static int
+static enum trns_result
 output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct output_trns *t = trns_;
index ab603c0b892d987c1f50dbdd9e6a26a03331fa50..22c7a410802d2fb4556f7cfa0a541b90b34f3e20 100644 (file)
@@ -68,12 +68,9 @@ static union any_node *allocate_unary_variable (struct expression *,
 /* Parses an expression of the given TYPE.  If DS is nonnull then variables and
    vectors within it may be referenced within the expression; otherwise, the
    expression must not reference any variables or vectors.  Returns the new
-   expression if successful or a null pointer otherwise.  If POOL is nonnull,
-   then destroying POOL will free the expression; otherwise, the caller must
-   eventually free it with expr_free(). */
+   expression if successful or a null pointer otherwise. */
 struct expression *
-expr_parse (struct lexer *lexer, struct pool *pool, struct dataset *ds,
-            enum val_type type)
+expr_parse (struct lexer *lexer, struct dataset *ds, enum val_type type)
 {
   assert (val_type_is_valid (type));
 
@@ -85,15 +82,12 @@ expr_parse (struct lexer *lexer, struct pool *pool, struct dataset *ds,
       return NULL;
     }
 
-  e = finish_expression (expr_optimize (n, e), e);
-  if (pool)
-    pool_add_subpool (pool, e->expr_pool);
-  return e;
+  return finish_expression (expr_optimize (n, e), e);
 }
 
 /* Parses a boolean expression, otherwise similar to expr_parse(). */
 struct expression *
-expr_parse_bool (struct lexer *lexer, struct pool *pool, struct dataset *ds)
+expr_parse_bool (struct lexer *lexer, struct dataset *ds)
 {
   struct expression *e = expr_create (ds);
   union any_node *n = parse_or (lexer, e);
@@ -116,17 +110,14 @@ expr_parse_bool (struct lexer *lexer, struct pool *pool, struct dataset *ds)
       return NULL;
     }
 
-  e = finish_expression (expr_optimize (n, e), e);
-  if (pool)
-    pool_add_subpool (pool, e->expr_pool);
-  return e;
+  return finish_expression (expr_optimize (n, e), e);
 }
 
 /* Parses a numeric expression that is intended to be assigned to newly created
    variable NEW_VAR_NAME.  (This allows for a better error message if the
    expression is not numeric.)  Otherwise similar to expr_parse(). */
 struct expression *
-expr_parse_new_variable (struct lexer *lexer, struct pool *pool, struct dataset *ds,
+expr_parse_new_variable (struct lexer *lexer, struct dataset *ds,
                          const char *new_var_name)
 {
   struct expression *e = expr_create (ds);
@@ -149,10 +140,7 @@ expr_parse_new_variable (struct lexer *lexer, struct pool *pool, struct dataset
       return NULL;
     }
 
-  e = finish_expression (expr_optimize (n, e), e);
-  if (pool)
-    pool_add_subpool (pool, e->expr_pool);
-  return e;
+  return finish_expression (expr_optimize (n, e), e);
 }
 
 /* Free expression E. */
index a4313a40c0aff4750353c2e5fceb5498e4b809bb..950e3a17baf80e089c96f473447eb87572dfe6d8 100644 (file)
@@ -29,15 +29,14 @@ struct lexer;
 struct pool;
 union value;
 
-struct expression *expr_parse (struct lexer *lexer, struct pool *,
-                               struct dataset *, enum val_type);
-struct expression *expr_parse_bool (struct lexer *lexer, struct pool *,
-                                    struct dataset *);
-struct expression *expr_parse_new_variable (struct lexer *lexer, struct pool *,
-                                            struct dataset *,
+struct expression *expr_parse (struct lexer *, struct dataset *, enum val_type);
+struct expression *expr_parse_bool (struct lexer *, struct dataset *);
+struct expression *expr_parse_new_variable (struct lexer *, struct dataset *,
                                             const char *new_var_name);
 void expr_free (struct expression *);
 
+struct expression *expr_create_false (void);
+
 struct dataset;
 double expr_evaluate_num (struct expression *, const struct ccase *,
                           int case_idx);
index 1a74b1e4a9e4e3365e5fc77ca0fcbeb05147a654..a5fef752686a18f4daf2ad1d7f462668dd5bfb92 100644 (file)
@@ -553,7 +553,7 @@ compare_arc_items (const void *a_, const void *b_, const void *direction_)
   return direction == ASCENDING ? cmp : -cmp;
 }
 
-static int
+static enum trns_result
 autorecode_trns_proc (void *arc_, struct ccase **c,
                       casenumber case_idx UNUSED)
 {
index 819e836d0ef23cc45bc9aecc509271d55f7a1004..1fcc3097497f0bac373b1e5ffd993422ab450010 100644 (file)
@@ -615,7 +615,7 @@ descriptives_set_all_sysmis_zscores (const struct dsc_trns *t, struct ccase *c)
    analyis. 4) any of the variables in the original analysis were missing
    (either system or user-missing values that weren't included).
 */
-static int
+static enum trns_result
 descriptives_trns_proc (void *trns_, struct ccase **c,
                         casenumber case_idx UNUSED)
 {
index e3bb76e42257362387c0077c2f4fb7f3a047ab64..3aff0e8a46879e2148c24ff6f77b6758f3c1bc81 100644 (file)
@@ -610,7 +610,7 @@ quick_cluster_show_centers (struct Kmeans *kmeans, bool initial, const struct qc
 /* A transformation function which juxtaposes the dataset with the
    (pre-prepared) dataset containing membership and/or distance
    values.  */
-static int
+static enum trns_result
 save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED)
 {
   const struct save_trans_data *std = aux;
index ecf9a65914bd6403ceb3defd673463b3dd647cff..597c08fe3eaeb991072732f6936389f05a15b4a8 100644 (file)
@@ -912,7 +912,7 @@ advance_ranking (struct rank_trns_input_var *iv)
   iv->current = casereader_read (iv->input);
 }
 
-static int
+static enum trns_result
 rank_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED)
 {
   struct rank_trns *trns = trns_;
index e08f4a1d76f051b4686f3d4a1b19cd00cee725f7..a65dd757673f8a9b76b8087a7d30fc2fee4ada66 100644 (file)
@@ -159,7 +159,7 @@ save_trans_free (void *aux)
   return true;
 }
 
-static int
+static enum trns_result
 save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED)
 {
   struct save_trans_data *save_trans_data = aux;
@@ -191,7 +191,6 @@ save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED)
   return TRNS_CONTINUE;
 }
 
-
 int
 cmd_regression (struct lexer *lexer, struct dataset *ds)
 {
index 9193dbc71e9c0f057efc911c12dfbb2c3462eb38..ca8f200d4faf6bd6d830a2f76438de517b384079 100644 (file)
@@ -124,7 +124,7 @@ cmd_compute (struct lexer *lexer, struct dataset *ds)
 /* Transformation functions. */
 
 /* Handle COMPUTE or IF with numeric target variable. */
-static int
+static enum trns_result
 compute_num (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
@@ -142,7 +142,7 @@ compute_num (void *compute_, struct ccase **c, casenumber case_num)
 
 /* Handle COMPUTE or IF with numeric vector element target
    variable. */
-static int
+static enum trns_result
 compute_num_vec (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
@@ -178,7 +178,7 @@ compute_num_vec (void *compute_, struct ccase **c, casenumber case_num)
 }
 
 /* Handle COMPUTE or IF with string target variable. */
-static int
+static enum trns_result
 compute_str (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
@@ -198,7 +198,7 @@ compute_str (void *compute_, struct ccase **c, casenumber case_num)
 
 /* Handle COMPUTE or IF with string vector element target
    variable. */
-static int
+static enum trns_result
 compute_str_vec (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
@@ -249,7 +249,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds)
   compute = compute_trns_create ();
 
   /* Test expression. */
-  compute->test = expr_parse_bool (lexer, NULL, ds);
+  compute->test = expr_parse_bool (lexer, ds);
   if (compute->test == NULL)
     goto fail;
 
@@ -297,9 +297,9 @@ parse_rvalue (struct lexer *lexer,
              const struct lvalue *lvalue, struct dataset *ds)
 {
   if (lvalue->is_new_variable)
-    return expr_parse_new_variable (lexer, NULL, ds, var_get_name (lvalue->variable));
+    return expr_parse_new_variable (lexer, ds, var_get_name (lvalue->variable));
   else
-    return expr_parse (lexer, NULL, ds, lvalue_get_type (lvalue));
+    return expr_parse (lexer, ds, lvalue_get_type (lvalue));
 }
 
 /* Returns a new struct compute_trns after initializing its fields. */
@@ -362,7 +362,7 @@ lvalue_parse (struct lexer *lexer, struct dataset *ds)
       lex_get (lexer);
       if (!lex_force_match (lexer, T_LPAREN))
        goto lossage;
-      lvalue->element = expr_parse (lexer, NULL, ds, VAL_NUMERIC);
+      lvalue->element = expr_parse (lexer, ds, VAL_NUMERIC);
       if (lvalue->element == NULL)
         goto lossage;
       if (!lex_force_match (lexer, T_RPAREN))
index 0369af1e5d8687071edd44350c45c89760c42d75..4dfc68bd89d10afd449732a04ad0560622cd0928 100644 (file)
@@ -337,7 +337,7 @@ count_string (struct criteria *crit, const struct ccase *c)
 }
 
 /* Performs the COUNT transformation T on case C. */
-static int
+static enum trns_result
 count_trns_proc (void *trns_, struct ccase **c,
                  casenumber case_num UNUSED)
 {
index f23fcec3f1fc79c6b8511e34f54b9e60a56ecaf1..ec94fe25a5e8b8a0569b609f466ae4d770639248 100644 (file)
 #include "language/command.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/message.h"
-
-static int trns_fail (void *x, struct ccase **c, casenumber n);
 \f
 /* A transformation which is guaranteed to fail. */
 
-static int
+static enum trns_result
 trns_fail (void *x UNUSED, struct ccase **c UNUSED,
           casenumber n UNUSED)
 {
index a2d963188ac949d64fa5e1ea9829d8f59375411a..b359661bdfe95723841553f27947c3468961a865 100644 (file)
@@ -690,7 +690,7 @@ find_src_string (struct recode_trns *trns, const uint8_t *value,
 }
 
 /* Performs RECODE transformation. */
-static int
+static enum trns_result
 recode_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED)
 {
   struct recode_trns *trns = trns_;
index 7184562ef2943fd060357450adee5f600658c529..072cd68e225bd5603263aba8104b20e7f7a000e6 100644 (file)
@@ -107,7 +107,7 @@ cmd_sample (struct lexer *lexer, struct dataset *ds)
 }
 
 /* Executes a SAMPLE transformation. */
-static int
+static enum trns_result
 sample_trns_proc (void *t_, struct ccase **c UNUSED,
                   casenumber case_num UNUSED)
 {
index 72284f36539ca14d658c3298612b0e8d13ca0034..313b5fc4fc9ad9ab6122b1cc41894cc7105ad68c 100644 (file)
@@ -50,7 +50,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds)
   struct expression *e;
   struct select_if_trns *t;
 
-  e = expr_parse_bool (lexer, NULL, ds);
+  e = expr_parse_bool (lexer, ds);
   if (!e)
     return CMD_CASCADING_FAILURE;
 
@@ -69,7 +69,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds)
 }
 
 /* Performs the SELECT IF transformation T on case C. */
-static int
+static enum trns_result
 select_if_proc (void *t_, struct ccase **c,
                 casenumber case_num)
 {