DO IF, LOOP cleanup.
authorBen Pfaff <blp@gnu.org>
Thu, 3 Nov 2005 06:21:46 +0000 (06:21 +0000)
committerBen Pfaff <blp@gnu.org>
Thu, 3 Nov 2005 06:21:46 +0000 (06:21 +0000)
New pool functions.

Clean up transformations, by getting rid of `struct trns_header',
replacing it by `struct transformation' that has a void * `private'
member.  Updated all uses of transformations to match, which was a lot
of code.

Miscellaneous other fixes, cleanups.

34 files changed:
src/ChangeLog
src/Makefile.am
src/autorecode.c
src/compute.c
src/count.c
src/ctl-stack.c [new file with mode: 0644]
src/ctl-stack.h [new file with mode: 0644]
src/data-list.c
src/data-list.h
src/descript.c
src/dfm-read.c
src/do-if.c
src/do-ifP.h [deleted file]
src/expressions/parse.c
src/expressions/public.h
src/file-handle-def.c
src/file-handle.q
src/file-type.c
src/get.c
src/glob.c
src/inpt-pgm.c
src/loop.c
src/pool.c
src/pool.h
src/print.c
src/recode.c
src/sample.c
src/sel-if.c
src/temporary.c
src/var.h
src/vfm.c
src/weight.c
tests/ChangeLog
tests/command/loop.sh

index 0d65dcd8ac2617801c62312bf53d1fef1414b62f..ba6d517a26ef2f2f53dbbe2d9682792e486c3222 100644 (file)
@@ -1,3 +1,89 @@
+Wed Nov  2 21:24:48 2005  Ben Pfaff  <blp@gnu.org>
+
+       * file-handle-def.c: Needed another #include, to avoid missing
+       prototype warning.
+
+       * file-handle.q: (cmd_file_handle) Declarations must precede
+       statements.  Free parse data on success as well as on failure, to
+       avoid memory leak.
+
+       * get.c: (parse_write_command) Destroy dict on success, to avoid
+       memory leak.
+       
+       * data-list.c: (cmd_repeating_data) Fix usage of saw_occurs,
+       saw_length, saw_continued, saw_id, which were boolean but
+       incorrectly treated as bitmaps as result of a previous
+       half-finished cleanup.
+
+       * weight.c: (struct weight_trns) Unused, so removed.
+
+       * Makefile.am: Add range-prs.h to sources.
+
+Wed Nov  2 21:24:15 2005  Ben Pfaff  <blp@gnu.org>
+
+       DO IF, LOOP cleanup.
+
+       * Makefile.am: Add ctl-stack.c, ctl-stack.h to source files.
+       Reformat source file list to list one file per file, so that
+       patches for future changes will be easier to read.
+
+       * ctl-stack.c, ctl-stack.h: New files.
+
+       * do-if.c: Rewrote whole file.
+
+       * do-ifP.h: Removed.
+
+       * loop.c: Rewrote whole file.
+
+       * glob.c: (global var ctl_stack) Move into ctl-stack.c.
+
+       * temporary.c: (cmd_temporary) Use ctl_stack_is_empty().
+
+       * vfm.c: (open_active_file) Use ctl_stack_clear().
+
+Wed Nov  2 21:18:13 2005  Ben Pfaff  <blp@gnu.org>
+
+       New pool functions.
+       
+       * pool.c: (pool_create_at_offset) New function.
+       (pool_add_subpool) New function.
+
+       * pool.h: (pool_create_container) New macro.
+       
+       * expressions/parse.c: (expr_parse_pool) New function.
+       
+       * autorecode.c: (recode) Use pool_create_container().
+
+       * count.c: (cmd_count) Ditto.
+
+Wed Nov  2 19:59:32 2005  Ben Pfaff  <blp@gnu.org>
+
+       Clean up transformations, by getting rid of `struct trns_header',
+       replacing it by `struct transformation' that has a void *
+       `private' member.  Updated all uses of transformations to match,
+       which was a lot of code.  Only major related changes listed below.
+
+       * compute.c: (cmd_if) Use get_proc_func().
+       (cmd_compute) Use get_proc_func().
+       (get_proc_func) New function.
+
+       * glob.c: (global var m_trns) Change type to size_t.
+       (global var n_trns) Ditto.
+       (global var f_trns) Ditto.
+       (global var t_trns) Change type to struct transformation *.
+
+       * var.h: (struct trns_header) Removed.
+       (struct transformation) New.
+       (typedef trns_proc_func) Takes a void * instead of a struct
+       trns_header *.
+       (typedef trns_free_func) Ditto.
+
+       * vfm.c: (execute_transformations) Takes an array of
+       transformations instead of trns_headers.
+       (add_transformation) Change prototype from (trns_header *) to
+       (trns_proc_func *, trns_free_func *, void *).
+       (next_transformation) New function.
+
 Sat Oct 29 16:25:36 2005  Ben Pfaff  <blp@gnu.org>
 
        * count.c: Major cleanups.  Rename practically everything.
index 15734f100c2571c3dc0d9e518ca5d586e2f17319..7a52f2b10b3bb8705e7e3fa78f489e42b5eace8a 100644 (file)
@@ -21,53 +21,218 @@ $(q_sources_c): q2c$(EXEEXT)
 .q.c:
        ./q2c $< $@
 
-q_sources_c = correlations.c crosstabs.c examine.c file-handle.c       \
-frequencies.c list.c means.c oneway.c rank.c regression.c set.c  t-test.c 
+q_sources_c =                                  \
+       correlations.c                          \
+       crosstabs.c                             \
+       examine.c                               \
+       file-handle.c                           \
+       frequencies.c                           \
+       list.c                                  \
+       means.c                                 \
+       oneway.c                                \
+       rank.c                                  \
+       regression.c                            \
+       set.c                                   \
+       t-test.c
 
 CLEANFILES=$(q_sources_c)
 DISTCLEANFILES=version.c
 
-q_sources_q = correlations.q crosstabs.q examine.q file-handle.q       \
-frequencies.q list.q means.q oneway.q rank.q regression.q set.q  t-test.q
+q_sources_q =                                  \
+       correlations.q                          \
+       crosstabs.q                             \
+       examine.q                               \
+       file-handle.q                           \
+       frequencies.q                           \
+       list.q                                  \
+       means.q                                 \
+       oneway.q                                \
+       rank.q                                  \
+       regression.q                            \
+       set.q                                   \
+       t-test.q
 
 if WITHCHARTS
-chart_sources = barchart.c \
-       box-whisker.c \
-       cartesian.c \
-       plot-chart.c \
-       plot-hist.c \
+chart_sources =                                \
+       barchart.c                              \
+       box-whisker.c                           \
+       cartesian.c                             \
+       plot-chart.c                            \
+       plot-hist.c                             \
        piechart.c 
 else
 chart_sources = dummy-chart.c
 endif
 
-pspp_SOURCES = $(q_sources_c) $(chart_sources) aggregate.c algorithm.c \
-algorithm.h alloc.c alloc.h apply-dict.c ascii.c autorecode.c          \
-bitvector.h calendar.c calendar.h case.c case.h casefile.c casefile.h  \
-cat.c cat.h chart.c chart.h cmdline.c cmdline.h command.c command.def  \
-command.h compute.c copyleft.c copyleft.h count.c data-in.c data-in.h  \
-data-list.c data-list.h data-out.c date.c debug-print.h descript.c     \
-devind.c devind.h dfm-read.c dfm-read.h dfm-write.c dfm-write.h                \
-dictionary.c dictionary.h do-if.c do-ifP.h echo.c error.c error.h      \
-factor_stats.c factor_stats.h file-handle-def.c file-handle-def.h      \
-file-handle.h file-type.c filename.c filename.h flip.c font.h format.c \
-format-prs.c format.def format.h formats.c get.c getl.c getl.h glob.c  \
-glob.h groff-font.c group.c group.h group_proc.h hash.c hash.h         \
-histogram.c histogram.h html.c htmlP.h include.c inpt-pgm.c lexer.c    \
-lexer.h lex-def.h lex-def.c levene.c levene.h linked-list.c            \
-linked-list.h log.h loop.c magic.c magic.h main.c main.h matrix-data.c \
-mis-val.c misc.c misc.h missing-values.c missing-values.h              \
-modify-vars.c moments.c moments.h numeric.c output.c output.h          \
-percentiles.c percentiles.h permissions.c pfm-read.c pfm-read.h                \
-pfm-write.c pfm-write.h pool.c pool.h postscript.c print.c range-prs.c \
-recode.c rename-vars.c repeat.c repeat.h sample.c sel-if.c settings.h  \
-sfm-read.c sfm-read.h sfm-write.c sfm-write.h sfmP.h som.c som.h       \
-sort.c sort.h sort-prs.c sort-prs.h split-file.c str.c str.h           \
-subclist.c subclist.h sysfile-info.c tab.c tab.h temporary.c mkfile.c  \
-mkfile.h title.c val.h val-labs.c value-labels.c value-labels.h                \
-var-display.c var-labs.c var.h vars-atr.c vars-prs.c vector.c          \
-version.h vfm.c vfm.h vfmP.h weight.c
-
+pspp_SOURCES =                                 \
+       $(q_sources_c)                          \
+       $(chart_sources)                        \
+       aggregate.c                             \
+       algorithm.c                             \
+       algorithm.h                             \
+       alloc.c                                 \
+       alloc.h                                 \
+       apply-dict.c                            \
+       ascii.c                                 \
+       autorecode.c                            \
+       bitvector.h                             \
+       calendar.c                              \
+       calendar.h                              \
+       case.c                                  \
+       case.h                                  \
+       casefile.c                              \
+       casefile.h                              \
+       cat.c                                   \
+       cat.h                                   \
+       chart.c                                 \
+       chart.h                                 \
+       ctl-stack.c                             \
+       ctl-stack.h                             \
+       cmdline.c                               \
+       cmdline.h                               \
+       command.c                               \
+       command.def                             \
+       command.h                               \
+       compute.c                               \
+       copyleft.c                              \
+       copyleft.h                              \
+       count.c                                 \
+       data-in.c                               \
+       data-in.h                               \
+       data-list.c                             \
+       data-list.h                             \
+       data-out.c                              \
+       date.c                                  \
+       debug-print.h                           \
+       descript.c                              \
+       devind.c                                \
+       devind.h                                \
+       dfm-read.c                              \
+       dfm-read.h                              \
+       dfm-write.c                             \
+       dfm-write.h                             \
+       dictionary.c                            \
+       dictionary.h                            \
+       do-if.c                                 \
+       echo.c                                  \
+       error.c                                 \
+       error.h                                 \
+       factor_stats.c                          \
+       factor_stats.h                          \
+       file-handle-def.c                       \
+       file-handle-def.h                       \
+       file-handle.h                           \
+       file-type.c                             \
+       filename.c                              \
+       filename.h                              \
+       flip.c                                  \
+       font.h                                  \
+       format.c                                \
+       format-prs.c                            \
+       format.def                              \
+       format.h                                \
+       formats.c                               \
+       get.c                                   \
+       getl.c                                  \
+       getl.h                                  \
+       glob.c                                  \
+       glob.h                                  \
+       groff-font.c                            \
+       group.c                                 \
+       group.h                                 \
+       group_proc.h                            \
+       hash.c                                  \
+       hash.h                                  \
+       histogram.c                             \
+       histogram.h                             \
+       html.c                                  \
+       htmlP.h                                 \
+       include.c                               \
+       inpt-pgm.c                              \
+       lexer.c                                 \
+       lexer.h                                 \
+       lex-def.h                               \
+       lex-def.c                               \
+       levene.c                                \
+       levene.h                                \
+       linked-list.c                           \
+       linked-list.h                           \
+       log.h                                   \
+       loop.c                                  \
+       magic.c                                 \
+       magic.h                                 \
+       main.c                                  \
+       main.h                                  \
+       matrix-data.c                           \
+       mis-val.c                               \
+       misc.c                                  \
+       misc.h                                  \
+       missing-values.c                        \
+       missing-values.h                        \
+       modify-vars.c                           \
+       moments.c                               \
+       moments.h                               \
+       numeric.c                               \
+       output.c                                \
+       output.h                                \
+       percentiles.c                           \
+       percentiles.h                           \
+       permissions.c                           \
+       pfm-read.c                              \
+       pfm-read.h                              \
+       pfm-write.c                             \
+       pfm-write.h                             \
+       pool.c                                  \
+       pool.h                                  \
+       postscript.c                            \
+       print.c                                 \
+       range-prs.c                             \
+       range-prs.h                             \
+       recode.c                                \
+       rename-vars.c                           \
+       repeat.c                                \
+       repeat.h                                \
+       sample.c                                \
+       sel-if.c                                \
+       settings.h                              \
+       sfm-read.c                              \
+       sfm-read.h                              \
+       sfm-write.c                             \
+       sfm-write.h                             \
+       sfmP.h                                  \
+       som.c                                   \
+       som.h                                   \
+       sort.c                                  \
+       sort.h                                  \
+       sort-prs.c                              \
+       sort-prs.h                              \
+       split-file.c                            \
+       str.c                                   \
+       str.h                                   \
+       subclist.c                              \
+       subclist.h                              \
+       sysfile-info.c                          \
+       tab.c                                   \
+       tab.h                                   \
+       temporary.c                             \
+       mkfile.c                                \
+       mkfile.h                                \
+       title.c                                 \
+       val.h                                   \
+       val-labs.c                              \
+       value-labels.c                          \
+       value-labels.h                          \
+       var-display.c                           \
+       var-labs.c                              \
+       var.h                                   \
+       vars-atr.c                              \
+       vars-prs.c                              \
+       vector.c                                \
+       version.h                               \
+       vfm.c                                   \
+       vfm.h                                   \
+       vfmP.h                                  \
+       weight.c
 
 pspp_LDADD =                                   \
        expressions/libexpressions.a            \
@@ -98,7 +263,6 @@ version.c:
        echo "  \"/usr/local/share/groff/font:\" \\" >> version.c
        echo "  \"/usr/share/groff/font\";" >> version.c
        echo "const char locale_dir[] = \"$(datadir)/locale\";" >> version.c
-\f
 
 noinst_PROGRAMS = q2c
 q2c_SOURCES = q2c.c
index bf38d922122da5b49566873d9569dc001e433f71..5240423d98b5db3283b75795a322b94ed6ca9d4c 100644 (file)
@@ -55,8 +55,7 @@ struct arc_spec
 /* AUTORECODE transformation. */
 struct autorecode_trns
   {
-    struct trns_header h;
-    struct pool *owner;                /* Contains AUTORECODE specs. */
+    struct pool *pool;         /* Contains AUTORECODE specs. */
     struct arc_spec *specs;    /* AUTORECODE specifications. */
     size_t spec_cnt;           /* Number of specifications. */
   };
@@ -222,20 +221,15 @@ arc_free (struct autorecode_pgm *arc)
 static void
 recode (const struct autorecode_pgm *arc)
 {
-  struct autorecode_trns *t;
-  struct pool *pool;
+  struct autorecode_trns *trns;
   size_t i;
 
-  pool = pool_create ();
-  t = xmalloc (sizeof *t);
-  t->h.proc = autorecode_trns_proc;
-  t->h.free = autorecode_trns_free;
-  t->owner = pool;
-  t->specs = pool_nalloc (t->owner, arc->var_cnt, sizeof *t->specs);
-  t->spec_cnt = arc->var_cnt;
+  trns = pool_create_container (struct autorecode_trns, pool);
+  trns->specs = pool_nalloc (trns->pool, arc->var_cnt, sizeof *trns->specs);
+  trns->spec_cnt = arc->var_cnt;
   for (i = 0; i < arc->var_cnt; i++)
     {
-      struct arc_spec *spec = &t->specs[i];
+      struct arc_spec *spec = &trns->specs[i];
       void *const *p = hsh_sort (arc->src_values[i]);
       int count = hsh_count (arc->src_values[i]);
       int j;
@@ -252,30 +246,29 @@ recode (const struct autorecode_pgm *arc)
 
       for (j = 0; *p; p++, j++)
        {
-         struct arc_item *item = pool_alloc (t->owner, sizeof *item);
+         struct arc_item *item = pool_alloc (trns->pool, sizeof *item);
           union value *vp = *p;
           
          if (arc->src_vars[i]->type == NUMERIC)
             item->from.f = vp->f;
           else
-           item->from.c = pool_strdup (t->owner, vp->c);
+           item->from.c = pool_strdup (trns->pool, vp->c);
          item->to = arc->direction == ASCENDING ? j + 1 : count - j;
          hsh_force_insert (spec->items, item);
        }
     }
-  add_transformation (&t->h);
+  add_transformation (autorecode_trns_proc, autorecode_trns_free, trns);
 }
 
 static int
-autorecode_trns_proc (struct trns_header * trns, struct ccase * c,
-                      int case_idx UNUSED)
+autorecode_trns_proc (void *trns_, struct ccase *c, int case_idx UNUSED)
 {
-  struct autorecode_trns *t = (struct autorecode_trns *) trns;
+  struct autorecode_trns *trns = trns_;
   size_t i;
 
-  for (i = 0; i < t->spec_cnt; i++)
+  for (i = 0; i < trns->spec_cnt; i++)
     {
-      struct arc_spec *spec = &t->specs[i];
+      struct arc_spec *spec = &trns->specs[i];
       struct arc_item *item;
       union value v;
 
@@ -291,14 +284,14 @@ autorecode_trns_proc (struct trns_header * trns, struct ccase * c,
 }
 
 static void
-autorecode_trns_free (struct trns_header * trns)
+autorecode_trns_free (void *trns_)
 {
-  struct autorecode_trns *t = (struct autorecode_trns *) trns;
+  struct autorecode_trns *trns = trns_;
   size_t i;
 
-  for (i = 0; i < t->spec_cnt; i++)
-    hsh_destroy (t->specs[i].items);
-  pool_destroy (t->owner);
+  for (i = 0; i < trns->spec_cnt; i++)
+    hsh_destroy (trns->specs[i].items);
+  pool_destroy (trns->pool);
 }
 \f
 /* AUTORECODE procedure. */
index 6e6bd96ad18992c1b361b2d191825d6c0459ff7a..37592c885862c4b4d64064e251411ea5b3a06f9b 100644 (file)
@@ -41,7 +41,7 @@ struct lvalue;
    vector element. */
 static struct lvalue *lvalue_parse (void);
 static int lvalue_get_type (const struct lvalue *);
-static int lvalue_is_vector (const struct lvalue *);
+static bool lvalue_is_vector (const struct lvalue *);
 static void lvalue_finalize (struct lvalue *,
                              struct compute_trns *);
 static void lvalue_destroy (struct lvalue *);
@@ -49,8 +49,6 @@ static void lvalue_destroy (struct lvalue *);
 /* COMPUTE and IF transformation. */
 struct compute_trns
   {
-    struct trns_header h;
-
     /* Test expression (IF only). */
     struct expression *test;    /* Test expression. */
 
@@ -67,10 +65,10 @@ struct compute_trns
     struct expression *rvalue;  /* Rvalue expression. */
   };
 
-static int parse_rvalue_expression (struct compute_trns *,
-                                    const struct lvalue *);
+static struct expression *parse_rvalue (const struct lvalue *);
 static struct compute_trns *compute_trns_create (void);
-static void compute_trns_free (struct trns_header *);
+static trns_proc_func *get_proc_func (const struct lvalue *);
+static trns_free_func compute_trns_free;
 \f
 /* COMPUTE. */
 
@@ -80,28 +78,27 @@ cmd_compute (void)
   struct lvalue *lvalue = NULL;
   struct compute_trns *compute = NULL;
 
+  compute = compute_trns_create ();
+
   lvalue = lvalue_parse ();
   if (lvalue == NULL)
     goto fail;
 
-  compute = compute_trns_create ();
-
-  if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
+  if (!lex_force_match ('='))
+    goto fail;
+  compute->rvalue = parse_rvalue (lvalue);
+  if (compute->rvalue == NULL)
     goto fail;
 
-  lvalue_finalize (lvalue, compute);
+  add_transformation (get_proc_func (lvalue), compute_trns_free, compute);
 
-  add_transformation (&compute->h);
+  lvalue_finalize (lvalue, compute);
 
-  return CMD_SUCCESS;
+  return lex_end_of_command ();
 
  fail:
   lvalue_destroy (lvalue);
-  if (compute != NULL) 
-    {
-      compute_trns_free (&compute->h);
-      free (compute); 
-    }
+  compute_trns_free (compute);
   return CMD_FAILURE;
 }
 \f
@@ -109,10 +106,9 @@ cmd_compute (void)
 
 /* Handle COMPUTE or IF with numeric target variable. */
 static int
-compute_num (struct trns_header *compute_, struct ccase *c,
-             int case_num)
+compute_num (void *compute_, struct ccase *c, int case_num)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
@@ -125,10 +121,9 @@ compute_num (struct trns_header *compute_, struct ccase *c,
 /* Handle COMPUTE or IF with numeric vector element target
    variable. */
 static int
-compute_num_vec (struct trns_header *compute_, struct ccase *c,
-                 int case_num)
+compute_num_vec (void *compute_, struct ccase *c, int case_num)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
@@ -158,10 +153,9 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c,
 
 /* Handle COMPUTE or IF with string target variable. */
 static int
-compute_str (struct trns_header *compute_, struct ccase *c,
-             int case_num)
+compute_str (void *compute_, struct ccase *c, int case_num)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
@@ -174,10 +168,9 @@ compute_str (struct trns_header *compute_, struct ccase *c,
 /* Handle COMPUTE or IF with string vector element target
    variable. */
 static int
-compute_str_vec (struct trns_header *compute_, struct ccase *c,
-                 int case_num)
+compute_str_vec (void *compute_, struct ccase *c, int case_num)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
       || expr_evaluate_num (compute->test, c, case_num) == 1.0) 
@@ -232,56 +225,45 @@ cmd_if (void)
     goto fail;
 
   /* Rvalue expression. */
-  if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
+  if (!lex_force_match ('='))
+    goto fail;
+  compute->rvalue = parse_rvalue (lvalue);
+  if (compute->rvalue == NULL)
     goto fail;
 
-  lvalue_finalize (lvalue, compute);
+  add_transformation (get_proc_func (lvalue), compute_trns_free, compute);
 
-  add_transformation (&compute->h);
+  lvalue_finalize (lvalue, compute);
 
-  return CMD_SUCCESS;
+  return lex_end_of_command ();
 
  fail:
   lvalue_destroy (lvalue);
-  if (compute != NULL) 
-    {
-      compute_trns_free (&compute->h);
-      free (compute); 
-    }
+  compute_trns_free (compute);
   return CMD_FAILURE;
 }
 \f
 /* Code common to COMPUTE and IF. */
 
-/* Checks for type mismatches on transformation C.  Also checks for
-   command terminator, sets the case-handling proc from the array
-   passed. */
-static int
-parse_rvalue_expression (struct compute_trns *compute,
-                         const struct lvalue *lvalue)
+static trns_proc_func *
+get_proc_func (const struct lvalue *lvalue) 
 {
-  int type = lvalue_get_type (lvalue);
-  int vector = lvalue_is_vector (lvalue);
+  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
+  bool is_vector = lvalue_is_vector (lvalue);
 
-  assert (type == NUMERIC || type == ALPHA);
-
-  compute->rvalue = expr_parse (default_dict,
-                                type == ALPHA ? EXPR_STRING : EXPR_NUMBER);
-  if (compute->rvalue == NULL)
-    return 0;
+  return (is_numeric
+          ? (is_vector ? compute_num_vec : compute_num)
+          : (is_vector ? compute_str_vec : compute_str));
+}
 
-  if (type == NUMERIC)
-    compute->h.proc = vector ? compute_num_vec : compute_num;
-  else
-    compute->h.proc = vector ? compute_str_vec : compute_str;
+/* Parses and returns an rvalue expression of the same type as
+   LVALUE, or a null pointer on failure. */
+static struct expression *
+parse_rvalue (const struct lvalue *lvalue)
+{
+  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
 
-  if (token != '.')
-    {
-      lex_error (_("expecting end of command"));
-      return 0;
-    }
-  
-  return 1;
+  return expr_parse (default_dict, is_numeric ? EXPR_NUMBER : EXPR_STRING);
 }
 
 /* Returns a new struct compute_trns after initializing its fields. */
@@ -289,8 +271,6 @@ static struct compute_trns *
 compute_trns_create (void)
 {
   struct compute_trns *compute = xmalloc (sizeof *compute);
-  compute->h.proc = NULL;
-  compute->h.free = compute_trns_free;
   compute->test = NULL;
   compute->variable = NULL;
   compute->vector = NULL;
@@ -301,13 +281,17 @@ compute_trns_create (void)
 
 /* Deletes all the fields in COMPUTE. */
 static void
-compute_trns_free (struct trns_header *compute_)
+compute_trns_free (void *compute_)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
-  expr_free (compute->test);
-  expr_free (compute->element);
-  expr_free (compute->rvalue);
+  if (compute != NULL) 
+    {
+      expr_free (compute->test);
+      expr_free (compute->element);
+      expr_free (compute->rvalue);
+      free (compute);
+    }
 }
 \f
 /* COMPUTE or IF target variable or vector element. */
@@ -384,7 +368,7 @@ lvalue_get_type (const struct lvalue *lvalue)
 }
 
 /* Returns nonzero if LVALUE has a vector as its target. */
-static int
+static bool
 lvalue_is_vector (const struct lvalue *lvalue) 
 {
   return lvalue->vector != NULL;
@@ -393,8 +377,7 @@ lvalue_is_vector (const struct lvalue *lvalue)
 /* Finalizes making LVALUE the target of COMPUTE, by creating the
    target variable if necessary and setting fields in COMPUTE. */
 static void
-lvalue_finalize (struct lvalue *lvalue,
-                 struct compute_trns *compute) 
+lvalue_finalize (struct lvalue *lvalue, struct compute_trns *compute) 
 {
   if (lvalue->vector == NULL)
     {
@@ -424,8 +407,8 @@ lvalue_finalize (struct lvalue *lvalue,
 static void 
 lvalue_destroy (struct lvalue *lvalue) 
 {
-  if ( ! lvalue 
-     return ;
+  if (lvalue == NULL
+     return;
 
   expr_free (lvalue->element);
   free (lvalue);
index 38374fa638222997d01ab7936e116ffe58f89526..26509dcf3ba1e3e1669ff8dada6848144ac41c9a 100644 (file)
@@ -80,19 +80,16 @@ struct dst_var
 
 struct count_trns
   {
-    struct trns_header h;
     struct dst_var *dst_vars;
     struct pool *pool;
   };
-\f
-/* Parser. */
 
 static trns_proc_func count_trns_proc;
 static trns_free_func count_trns_free;
 
 static bool parse_numeric_criteria (struct pool *, struct criteria *);
 static bool parse_string_criteria (struct pool *, struct criteria *);
-
+\f
 int
 cmd_count (void)
 {
@@ -100,10 +97,7 @@ cmd_count (void)
   struct count_trns *trns;      /* Transformation. */
 
   /* Parses each slash-delimited specification. */
-  trns = xmalloc (sizeof *trns);
-  trns->h.proc = count_trns_proc;
-  trns->h.free = count_trns_free;
-  trns->pool = pool_create ();
+  trns = pool_create_container (struct count_trns, pool);
   trns->dst_vars = dv = pool_alloc (trns->pool, sizeof *dv);
   for (;;)
     {
@@ -182,11 +176,11 @@ cmd_count (void)
           dv->var = dict_create_var_assert (default_dict, dv->name, 0);
       }
 
-  add_transformation (&trns->h);
+  add_transformation (count_trns_proc, count_trns_free, trns);
   return CMD_SUCCESS;
 
 fail:
-  count_trns_free (&trns->h);
+  count_trns_free (trns);
   return CMD_FAILURE;
 }
 
@@ -324,10 +318,10 @@ count_string (struct criteria *crit, struct ccase *c)
 
 /* Performs the COUNT transformation T on case C. */
 static int
-count_trns_proc (struct trns_header *trns_, struct ccase *c,
+count_trns_proc (void *trns_, struct ccase *c,
                  int case_num UNUSED)
 {
-  struct count_trns *trns = (struct count_trns *) trns_;
+  struct count_trns *trns = trns_;
   struct dst_var *dv;
 
   for (dv = trns->dst_vars; dv; dv = dv->next)
@@ -348,7 +342,7 @@ count_trns_proc (struct trns_header *trns_, struct ccase *c,
 
 /* Destroys all dynamic data structures associated with TRNS. */
 static void
-count_trns_free (struct trns_header *trns_)
+count_trns_free (void *trns_)
 {
   struct count_trns *trns = (struct count_trns *) trns_;
   pool_destroy (trns->pool);
diff --git a/src/ctl-stack.c b/src/ctl-stack.c
new file mode 100644 (file)
index 0000000..1536094
--- /dev/null
@@ -0,0 +1,93 @@
+#include <config.h>
+#include "ctl-stack.h"
+#include <assert.h>
+#include <stdlib.h>
+#include "error.h"
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct ctl_struct
+  {
+    struct ctl_class *class;    /* Class of control structure. */
+    struct ctl_struct *down;   /* Points toward the bottom of ctl_stack. */
+    void *private;              /* Private data. */
+  };
+
+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 (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 (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 (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 UNUSED) 
+{
+  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/ctl-stack.h b/src/ctl-stack.h
new file mode 100644 (file)
index 0000000..87ef4be
--- /dev/null
@@ -0,0 +1,39 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#ifndef CTL_STACK_H
+#define CTL_STACK_H 1
+
+#include <stdbool.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 (struct ctl_class *, void *private);
+void *ctl_stack_top (struct ctl_class *);
+void *ctl_stack_search (struct ctl_class *);
+void ctl_stack_pop (void *);
+bool ctl_stack_is_empty (void);
+
+#endif /* ctl_stack.h */
index d1dbbc248858b3607e71e2e0db1326616baaa641..b615beea4b4925245e16f7b419667d2a7bd6e3c9 100644 (file)
@@ -83,8 +83,6 @@ enum
 /* DATA LIST private data structure. */
 struct data_list_pgm
   {
-    struct trns_header h;
-
     struct dls_var_spec *first, *last; /* Variable parsing specifications. */
     struct dfm_reader *reader;  /* Data file reader. */
 
@@ -270,20 +268,14 @@ cmd_data_list (void)
     goto error;
 
   if (vfm_source != NULL)
-    {
-      dls->h.proc = data_list_trns_proc;
-      dls->h.free = data_list_trns_free;
-      add_transformation (&dls->h);
-    }
+    add_transformation (data_list_trns_proc, data_list_trns_free, dls);
   else 
     vfm_source = create_case_source (&data_list_source_class, dls);
 
   return CMD_SUCCESS;
 
  error:
-  destroy_dls_var_spec (dls->first);
-  free (dls->delims);
-  free (dls);
+  data_list_trns_free (dls);
   return CMD_FAILURE;
 }
 
@@ -1233,22 +1225,22 @@ destroy_dls_var_spec (struct dls_var_spec *spec)
     }
 }
 
-/* Destroys DATA LIST transformation PGM. */
+/* Destroys DATA LIST transformation DLS. */
 static void
-data_list_trns_free (struct trns_header *pgm)
+data_list_trns_free (void *dls_)
 {
-  struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
+  struct data_list_pgm *dls = dls_;
   free (dls->delims);
   destroy_dls_var_spec (dls->first);
   dfm_close_reader (dls->reader);
+  free (dls);
 }
 
-/* Handle DATA LIST transformation T, parsing data into C. */
+/* Handle DATA LIST transformation DLS, parsing data into C. */
 static int
-data_list_trns_proc (struct trns_header *t, struct ccase *c,
-                     int case_num UNUSED)
+data_list_trns_proc (void *dls_, struct ccase *c, int case_num UNUSED)
 {
-  struct data_list_pgm *dls = (struct data_list_pgm *) t;
+  struct data_list_pgm *dls = dls_;
   data_list_read_func *read_func;
   int retval;
 
@@ -1315,7 +1307,6 @@ static void
 data_list_source_destroy (struct case_source *source)
 {
   data_list_trns_free (source->aux);
-  free (source->aux);
 }
 
 const struct case_source_class data_list_source_class = 
@@ -1338,7 +1329,6 @@ struct rpd_num_or_var
 /* REPEATING DATA private data structure. */
 struct repeating_data_trns
   {
-    struct trns_header h;
     struct dls_var_spec *first, *last; /* Variable parsing specifications. */
     struct dfm_reader *reader;         /* Input file, never NULL. */
 
@@ -1452,7 +1442,7 @@ cmd_repeating_data (void)
              msg (SE, _("%s subcommand given multiple times."),"OCCURS");
              goto error;
            }
-         saw_occurs |= 2;
+         saw_occurs = true;
 
          if (!parse_num_or_var (&rpd->occurs, "OCCURS"))
            goto error;
@@ -1460,12 +1450,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("LENGTH"))
        {
          lex_match ('=');
-         if (saw_length & 4)
+         if (saw_length)
            {
              msg (SE, _("%s subcommand given multiple times."),"LENGTH");
              goto error;
            }
-         saw_length |= 4;
+         saw_length = true;
 
          if (!parse_num_or_var (&rpd->length, "LENGTH"))
            goto error;
@@ -1473,12 +1463,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("CONTINUED"))
        {
          lex_match ('=');
-         if (saw_continued & 8)
+         if (saw_continued)
            {
              msg (SE, _("%s subcommand given multiple times."),"CONTINUED");
              goto error;
            }
-         saw_continued |= 8;
+         saw_continued = true;
 
          if (!lex_match ('/'))
            {
@@ -1507,12 +1497,12 @@ cmd_repeating_data (void)
       else if (lex_match_id ("ID"))
        {
          lex_match ('=');
-         if (saw_id & 16)
+         if (saw_id)
            {
              msg (SE, _("%s subcommand given multiple times."),"ID");
              goto error;
            }
-         saw_id |= 16;
+         saw_id = true;
          
          if (!lex_force_int ())
            goto error;
@@ -1638,15 +1628,12 @@ cmd_repeating_data (void)
   if (table)
     dump_fixed_table (rpd->first, fh, rpd->last->rec);
 
-  rpd->h.proc = repeating_data_trns_proc;
-  rpd->h.free = repeating_data_trns_free;
-  add_transformation (&rpd->h);
+  add_transformation (repeating_data_trns_proc, repeating_data_trns_free, rpd);
 
   return lex_end_of_command ();
 
  error:
-  destroy_dls_var_spec (rpd->first);
-  free (rpd->id_value);
+  repeating_data_trns_free (rpd);
   return CMD_FAILURE;
 }
 
@@ -1656,14 +1643,15 @@ cmd_repeating_data (void)
 static void 
 find_variable_input_spec (struct variable *v, struct fmt_spec *spec)
 {
-  int i;
+  size_t i;
   
   for (i = 0; i < n_trns; i++)
     {
-      struct data_list_pgm *pgm = (struct data_list_pgm *) t_trns[i];
+      struct transformation *trns = &t_trns[i];
       
-      if (pgm->h.proc == data_list_trns_proc)
+      if (trns->proc == data_list_trns_proc)
        {
+          struct data_list_pgm *pgm = trns->private;
          struct dls_var_spec *iter;
 
          for (iter = pgm->first; iter; iter = iter->next)
@@ -1900,10 +1888,9 @@ rpd_parse_record (const struct rpd_parse_info *info)
    DATA structure.  Returns -1 on success, -2 on end of file or
    on failure. */
 int
-repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
-                          int case_num UNUSED)
+repeating_data_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
 {
-  struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+  struct repeating_data_trns *t = trns_;
     
   struct fixed_string line;       /* Current record. */
 
@@ -2055,25 +2042,26 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
 
 /* Frees a REPEATING DATA transformation. */
 void
-repeating_data_trns_free (struct trns_header *rpd_) 
+repeating_data_trns_free (void *rpd_) 
 {
-  struct repeating_data_trns *rpd = (struct repeating_data_trns *) rpd_;
+  struct repeating_data_trns *rpd = rpd_;
 
   destroy_dls_var_spec (rpd->first);
   dfm_close_reader (rpd->reader);
   free (rpd->id_value);
+  free (rpd);
 }
 
 /* Lets repeating_data_trns_proc() know how to write the cases
    that it composes.  Not elegant. */
 void
-repeating_data_set_write_case (struct trns_header *trns,
+repeating_data_set_write_case (struct transformation *trns_,
                                write_case_func *write_case,
                                write_case_data wc_data) 
 {
-  struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+  struct repeating_data_trns *t = trns_->private;
 
-  assert (trns->proc == repeating_data_trns_proc);
+  assert (trns_->proc == repeating_data_trns_proc);
   t->write_case = write_case;
   t->wc_data = wc_data;
 }
index dae80e355d47a572169c016de03de25780779fb3..80545f7e4765399dd71e3786651163f66b88a5bf 100644 (file)
@@ -27,7 +27,7 @@
 #include "vfm.h"
 
 trns_proc_func repeating_data_trns_proc;
-void repeating_data_set_write_case (struct trns_header *,
+void repeating_data_set_write_case (struct transformation *,
                                     write_case_func *, write_case_data);
 
 #endif /* data-list.h */
index 0a96b65ec5aaabfd86411254d33d4533cdf8dc71..a7152301abfdfcfcefb93af2dfea68b6d1b3205f 100644 (file)
@@ -68,7 +68,6 @@ struct dsc_z_score
 /* DESCRIPTIVES transformation (for calculating Z-scores). */
 struct dsc_trns
   {
-    struct trns_header h;
     struct dsc_z_score *z_scores; /* Array of Z-scores. */
     int z_score_cnt;            /* Number of Z-scores. */
     struct variable **vars;     /* Variables for listwise missing checks. */
@@ -569,10 +568,10 @@ dump_z_table (struct dsc_proc *dsc)
    (either system or user-missing values that weren't included).
 */
 static int
-descriptives_trns_proc (struct trns_header *trns, struct ccase * c,
+descriptives_trns_proc (void *trns_, struct ccase * c,
                         int case_idx UNUSED)
 {
-  struct dsc_trns *t = (struct dsc_trns *) trns;
+  struct dsc_trns *t = trns_;
   struct dsc_z_score *z;
   struct variable **vars;
   int all_sysmis = 0;
@@ -611,9 +610,9 @@ descriptives_trns_proc (struct trns_header *trns, struct ccase * c,
 
 /* Frees a descriptives_trns struct. */
 static void
-descriptives_trns_free (struct trns_header * trns)
+descriptives_trns_free (void *trns_)
 {
-  struct dsc_trns *t = (struct dsc_trns *) trns;
+  struct dsc_trns *t = trns_;
 
   free (t->z_scores);
   assert((t->missing_type != DSC_LISTWISE) ^ (t->vars != NULL));
@@ -632,8 +631,6 @@ setup_z_trns (struct dsc_proc *dsc)
       cnt++;
 
   t = xmalloc (sizeof *t);
-  t->h.proc = descriptives_trns_proc;
-  t->h.free = descriptives_trns_free;
   t->z_scores = xnmalloc (cnt, sizeof *t->z_scores);
   t->z_score_cnt = cnt;
   t->missing_type = dsc->missing_type;
@@ -650,7 +647,6 @@ setup_z_trns (struct dsc_proc *dsc)
       t->var_cnt = 0;
       t->vars = NULL;
     }
-  
 
   for (cnt = i = 0; i < dsc->var_cnt; i++)
     {
@@ -685,7 +681,7 @@ setup_z_trns (struct dsc_proc *dsc)
        }
     }
 
-  add_transformation ((struct trns_header *) t);
+  add_transformation (descriptives_trns_proc, descriptives_trns_free, t);
 }
 \f
 /* Statistical calculation. */
index 238b808056fe3babcd706d22ef5f2056802b8dde..6d173cf3e929bdace5c73f4b0c3da606460fac23 100644 (file)
@@ -26,6 +26,7 @@
 #include "alloc.h"
 #include "command.h"
 #include "error.h"
+#include "file-handle.h"
 #include "file-handle-def.h"
 #include "filename.h"
 #include "getl.h"
index 1acf84936c0b8b96c1bb16501a7b8dc882b2fa0a..ad636f79c1a81f7c70d272f3e70967a9775dae02 100644 (file)
@@ -18,7 +18,7 @@
    02110-1301, USA. */
 
 #include <config.h>
-#include "do-ifP.h"
+#include "ctl-stack.h"
 #include "error.h"
 #include <stdlib.h>
 #include "alloc.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include "debug-print.h"
-
-/* *INDENT-OFF* */
-/* Description of DO IF transformations:
-
-   DO IF has two transformations.  One is a conditional jump around
-   a false condition.  The second is an unconditional jump around
-   the rest of the code after a true condition.  Both of these types
-   have their destinations backpatched in by the next clause (ELSE IF,
-   END IF).
-
-   The characters `^V<>' are meant to represent arrows.
-
-   1. DO IF
- V<<<<if false
- V
- V *. Transformations executed when the condition on DO IF is true.
- V
- V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
- V                                                                    V
- >>1. ELSE IF                                                         V
- V<<<<if false                                                        V
- V                                                                    V
- V *. Transformations executed when condition on 1st ELSE IF is true.  V
- V                                                                    V
- V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
- V                                                                    V
- >>1. ELSE IF                                                         V
- V<<<<if false                                                        V
- V                                                                    V
- V *. Transformations executed when condition on 2nd ELSE IF is true.  V
- V                                                                    V
- V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
- V                                                                    V
- >>*. Transformations executed when no condition is true. (ELSE)       V
-                                                                      V
-   *. Transformations after DO IF structure.<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+/* 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:
 
 */
-/* *INDENT-ON* */
 
-static struct do_if_trns *parse_do_if (void);
-static void add_ELSE_IF (struct do_if_trns *);
-static trns_proc_func goto_trns_proc, do_if_trns_proc;
+/* A conditional clause. */
+struct clause 
+  {
+    struct expression *condition; /* Test expression; NULL for ELSE clause. */
+    int target_index;           /* Transformation to jump to if true. */
+  };
+
+/* DO IF transformation. */
+struct do_if_trns
+  {
+    struct clause *clauses;     /* Clauses. */
+    size_t clause_cnt;          /* Number of clauses. */
+    int past_END_IF_index;      /* Transformation just past last clause. */
+  };
+
+static struct ctl_class do_if_class;
+
+static int parse_clause (struct do_if_trns *);
+static void add_clause (struct do_if_trns *,
+                        struct expression *condition, int target_index);
+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_proc_func do_if_trns_proc, break_trns_proc;
 static trns_free_func do_if_trns_free;
 
 /* Parse DO IF. */
 int
 cmd_do_if (void)
 {
-  struct do_if_trns *t;
+  struct do_if_trns *do_if = xmalloc (sizeof *do_if);
+  do_if->clauses = NULL;
+  do_if->clause_cnt = 0;
 
-  /* Parse the transformation. */
-  t = parse_do_if ();
-  if (!t)
-    return CMD_FAILURE;
+  ctl_stack_push (&do_if_class, do_if);
+  add_transformation (do_if_trns_proc, do_if_trns_free, do_if);
 
-  /* Finish up the transformation, add to control stack, add to
-     transformation list. */
-  t->brk = NULL;
-  t->ctl.type = CST_DO_IF;
-  t->ctl.down = ctl_stack;
-  t->ctl.trns = (struct trns_header *) t;
-  t->ctl.brk = NULL;
-  t->has_else = 0;
-  ctl_stack = &t->ctl;
-  add_transformation ((struct trns_header *) t);
-
-  return CMD_SUCCESS;
+  return parse_clause (do_if);
 }
 
 /* Parse ELSE IF. */
 int
 cmd_else_if (void)
 {
-  /* Transformation created. */
-  struct do_if_trns *t;
-
-  /* Check that we're in a pleasing situation. */
-  if (!ctl_stack || ctl_stack->type != CST_DO_IF)
-    {
-      msg (SE, _("There is no DO IF to match with this ELSE IF."));
-      return CMD_FAILURE;
-    }
-  if (((struct do_if_trns *) ctl_stack->trns)->has_else)
-    {
-      msg (SE, _("The ELSE command must follow all ELSE IF commands "
-                "in a DO IF structure."));
-      return CMD_FAILURE;
-    }
-
-  /* Parse the transformation. */
-  t = parse_do_if ();
-  if (!t)
+  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
+  if (do_if == NULL || !must_not_have_else (do_if))
     return CMD_FAILURE;
-
-  /* Stick in the breakout transformation. */
-  t->brk = xmalloc (sizeof *t->brk);
-  t->brk->h.proc = goto_trns_proc;
-  t->brk->h.free = NULL;
-
-  /* Add to list of transformations, add to string of ELSE IFs. */
-  add_transformation ((struct trns_header *) t->brk);
-  add_transformation ((struct trns_header *) t);
-
-  add_ELSE_IF (t);
-
-  if (token != '.')
-    {
-      msg (SE, _("End of command expected."));
-      return CMD_TRAILING_GARBAGE;
-    }
-
-  return CMD_SUCCESS;
+  return parse_clause (do_if);
 }
 
 /* Parse ELSE. */
 int
 cmd_else (void)
 {
-  struct do_if_trns *t;
-
-  /* Check that we're in a pleasing situation. */
-  if (!ctl_stack || ctl_stack->type != CST_DO_IF)
-    {
-      msg (SE, _("There is no DO IF to match with this ELSE."));
-      return CMD_FAILURE;
-    }
-  
-  if (((struct do_if_trns *) ctl_stack->trns)->has_else)
-    {
-      msg (SE, _("There may be at most one ELSE clause in each DO IF "
-                "structure.  It must be the last clause."));
-      return CMD_FAILURE;
-    }
-
-  /* Note that the ELSE transformation is *not* added to the list of
-     transformations.  That's because it doesn't need to do anything.
-     Its goto transformation *is* added, because that's necessary.
-     The main DO IF do_if_trns is the destructor for this ELSE
-     do_if_trns. */
-  t = xmalloc (sizeof *t);
-  t->next = NULL;
-  t->brk = xmalloc (sizeof *t->brk);
-  t->brk->h.proc = goto_trns_proc;
-  t->brk->h.free = NULL;
-  t->cond = NULL;
-  add_transformation ((struct trns_header *) t->brk);
-  t->h.index = t->brk->h.index + 1;
-
-  /* Add to string of ELSE IFs. */
-  add_ELSE_IF (t);
-
+  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
+  if (do_if == NULL || !must_not_have_else (do_if))
+    return CMD_FAILURE;
+  add_else (do_if);
   return lex_end_of_command ();
 }
 
@@ -192,133 +128,147 @@ cmd_else (void)
 int
 cmd_end_if (void)
 {
-  /* List iterator. */
-  struct do_if_trns *iter;
-
-  /* Check that we're in a pleasing situation. */
-  if (!ctl_stack || ctl_stack->type != CST_DO_IF)
-    {
-      msg (SE, _("There is no DO IF to match with this END IF."));
-      return CMD_FAILURE;
-    }
-
-  /* Chain down the list, backpatching destinations for gotos. */
-  iter = (struct do_if_trns *) ctl_stack->trns;
-  for (;;)
-    {
-      if (iter->brk)
-       iter->brk->dest = n_trns;
-      iter->missing_jump = n_trns;
-      if (iter->next)
-       iter = iter->next;
-      else
-       break;
-    }
-  iter->false_jump = n_trns;
+  struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
+  if (do_if == NULL)
+    return CMD_FAILURE;
 
-  /* Pop control stack. */
-  ctl_stack = ctl_stack->down;
+  ctl_stack_pop (do_if);
 
   return lex_end_of_command ();
 }
 
-/* Adds an ELSE IF or ELSE to the chain of them that hangs off the
-   main DO IF. */
+/* Closes out DO_IF, by adding a sentinel ELSE clause if
+   necessary and setting past_END_IF_index. */
 static void
-add_ELSE_IF (struct do_if_trns * t)
+close_do_if (void *do_if_) 
 {
-  /* List iterator. */
-  struct do_if_trns *iter;
-
-  iter = (struct do_if_trns *) ctl_stack->trns;
-  while (iter->next)
-    iter = iter->next;
-  assert (iter != NULL);
-
-  iter->next = t;
-  iter->false_jump = t->h.index;
+  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 ();
 }
 
-/* Parses a DO IF or ELSE IF command and returns a pointer to a mostly
-   filled in transformation. */
-static struct do_if_trns *
-parse_do_if (void)
+/* Adds an ELSE clause to DO_IF pointing to the next
+   transformation. */
+static void
+add_else (struct do_if_trns *do_if) 
 {
-  struct do_if_trns *t;
-  struct expression *e;
+  assert (!has_else (do_if));
+  add_clause (do_if, NULL, next_transformation ());
+}
 
-  e = expr_parse (default_dict, EXPR_BOOLEAN);
-  if (!e)
-    return NULL;
-  if (token != '.')
+/* 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))
     {
-      expr_free (e);
-      lex_error (_("expecting end of command"));
-      return NULL;
+      msg (SE, _("This command may not follow ELSE in DO IF...END IF."));
+      return false;
     }
+  else
+    return true;
+}
 
-  t = xmalloc (sizeof *t);
-  t->h.proc = do_if_trns_proc;
-  t->h.free = do_if_trns_free;
-  t->next = NULL;
-  t->cond = e;
+/* 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->clause_cnt != 0
+          && do_if->clauses[do_if->clause_cnt - 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 do_if_trns *do_if)
+{
+  struct expression *condition;
 
-  return t;
+  condition = expr_parse (default_dict, EXPR_BOOLEAN);
+  if (condition == NULL)
+    return CMD_FAILURE;
+
+  add_clause (do_if, condition, next_transformation ());
+
+  return lex_end_of_command ();
 }
 
-/* Executes a goto transformation. */
-static int 
-goto_trns_proc (struct trns_header * t, struct ccase * c UNUSED,
-                int case_num UNUSED)
+/* Adds a clause to DO_IF that tests for the given CONDITION and,
+   if true, jumps to TARGET_INDEX. */
+static void
+add_clause (struct do_if_trns *do_if,
+            struct expression *condition, int target_index) 
 {
-  return ((struct goto_trns *) t)->dest;
+  struct clause *clause;
+
+  if (do_if->clause_cnt > 0)
+    add_transformation (break_trns_proc, NULL, do_if);
+
+  do_if->clauses = xnrealloc (do_if->clauses,
+                              do_if->clause_cnt + 1, sizeof *do_if->clauses);
+  clause = &do_if->clauses[do_if->clause_cnt++];
+  clause->condition = condition;
+  clause->target_index = target_index;
 }
 
+/* DO IF transformation procedure.
+   Checks each clause and jumps to the appropriate
+   transformation. */
 static int 
-do_if_trns_proc (struct trns_header * trns, struct ccase * c,
-                 int case_num UNUSED)
+do_if_trns_proc (void *do_if_, struct ccase *c, int case_num UNUSED)
 {
-  struct do_if_trns *t = (struct do_if_trns *) trns;
-  double boolean;
+  struct do_if_trns *do_if = do_if_;
+  struct clause *clause;
 
-  boolean = expr_evaluate_num (t->cond, c, case_num);
-  if (boolean == 1.0)
-    {
-      debug_printf ((_("DO IF %d: true\n"), t->h.index));
-      return -1;
-    }
-  else if (boolean == 0.0)
-    {
-      debug_printf ((_("DO IF %d: false\n"), t->h.index));
-      return t->false_jump;
-    }
-  else
+  for (clause = do_if->clauses; clause < do_if->clauses + do_if->clause_cnt;
+       clause++) 
     {
-      debug_printf ((_("DO IF %d: missing\n"), t->h.index));
-      return t->missing_jump;
+      if (clause->condition != NULL)
+        {
+          double boolean = expr_evaluate_num (clause->condition, c, case_num);
+          if (boolean == 1.0)
+            return clause->target_index;
+          else if (boolean == SYSMIS)
+            return do_if->past_END_IF_index;
+        }
+      else 
+        return clause->target_index;
     }
+  return do_if->past_END_IF_index;
 }
 
+/* Frees a DO IF transformation. */
 static void 
-do_if_trns_free (struct trns_header * trns)
+do_if_trns_free (void *do_if_)
 {
-  struct do_if_trns *t = (struct do_if_trns *) trns;
-  expr_free (t->cond);
+  struct do_if_trns *do_if = do_if_;
+  struct clause *clause;
+
+  for (clause = do_if->clauses; clause < do_if->clauses + do_if->clause_cnt;
+       clause++)
+    expr_free (clause->condition);
+  free (do_if->clauses);
+  free (do_if);
+}
 
-  /* If brk is NULL then this is the main DO IF; therefore we
-     need to chain down to the ELSE and delete it. */
-  if (t->brk == NULL)
-    {
-      struct do_if_trns *iter = t->next;
-      while (iter)
-       {
-         if (!iter->cond)
-           {
-             /* This is the ELSE. */
-             free (iter);
-             break;
-           }
-         iter = iter->next;
-       }
-    }
+/* Breaks out of a DO IF construct. */
+static int 
+break_trns_proc (void *do_if_, struct ccase *c UNUSED, int 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 struct ctl_class do_if_class = 
+  {
+    "DO IF",
+    "END IF",
+    close_do_if,
+  };
diff --git a/src/do-ifP.h b/src/do-ifP.h
deleted file mode 100644 (file)
index 3570a90..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* PSPP - computes sample statistics.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
-
-   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 2 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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
-
-#if !do_ifP_h
-#define do_ifP_h 1
-
-#include "var.h"
-
-/* BREAK transformation. */
-struct break_trns
-  {
-    struct trns_header h;
-
-    struct break_trns *next;   /* Next in chain of BREAKs associated
-                                  with a single LOOP. */
-    int loop_term;             /* t_trns[] index to jump to; backpatched
-                                  in by END LOOP. */
-  };
-
-/* Types of control structures. */
-enum
-  {
-    CST_LOOP,
-    CST_DO_IF
-  };
-
-/* Control structure info. */
-struct ctl_stmt
-  {
-    int type;                  /* One of CST_*. */
-    struct ctl_stmt *down;     /* Points toward the bottom of ctl_stack. */
-    struct trns_header *trns;  /* Associated transformation. */
-    struct break_trns *brk;    /* (LOOP only): Chain of associated BREAKs. */
-  };                           /* ctl_stmt */
-
-/* Goto transformation. */
-struct goto_trns
-  {
-    struct trns_header h;
-
-    int dest;                  /* t_trns[] index of destination of jump. */
-  };
-
-/* DO IF/ELSE IF/ELSE transformation. */
-struct do_if_trns
-  {
-    struct trns_header h;
-
-    struct ctl_stmt ctl;       /* DO IF: Control information for nesting. */
-
-    /* Keeping track of clauses. */
-    struct do_if_trns *next;   /* Points toward next ELSE IF. */
-    struct goto_trns *brk;     /* ELSE IF: jumps out of DO IF structure. */
-    int has_else;              /* DO IF: 1=there's been an ELSE. */
-
-    /* Runtime info. */
-    struct expression *cond;   /* Condition. */
-    int false_jump;            /* t_trns[] index of destination when false. */
-    int missing_jump;          /* t_trns[] index to break out of DO IF. */
-  };
-
-/* Top of the control structure stack. */
-extern struct ctl_stmt *ctl_stack;
-
-void discard_ctl_stack (void);
-
-#endif /* !do_ifP_h */
index 14dedfc998e8add71b4a65668b4d44dbf2a911a9..b841953b7ea5125e3308975dab36efbda6d6d928 100644 (file)
@@ -86,6 +86,19 @@ expr_parse (struct dictionary *dict, enum expr_type type)
     }
 }
 
+/* Parses and returns an expression of the given TYPE, as
+   expr_parse(), and sets up so that destroying POOL will free
+   the expression as well. */
+struct expression *
+expr_parse_pool (struct pool *pool,
+                 struct dictionary *dict, enum expr_type type) 
+{
+  struct expression *e = expr_parse (dict, type);
+  if (e != NULL)
+    pool_add_subpool (pool, e->expr_pool);
+  return e;
+}
+
 /* Free expression E. */
 void
 expr_free (struct expression *e)
index f4d89350c744f4360d729c55ae21acdd735ae32f..9a90cef70e8d72f1b12522d7c8fd3c17c57539e2 100644 (file)
@@ -33,9 +33,12 @@ enum expr_type
 struct dictionary;
 struct expression;
 struct ccase;
+struct pool;
 union value;
 
 struct expression *expr_parse (struct dictionary *, enum expr_type);
+struct expression *expr_parse_pool (struct pool *,
+                                    struct dictionary *, enum expr_type);
 void expr_free (struct expression *);
 
 double expr_evaluate_num (struct expression *, const struct ccase *,
index 5dd13e5415f5d692577c05403b8f6efebb8e0425..6cf572b305e06c2602c4a6aced257321fb8052e8 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <config.h>
 #include "file-handle.h"
+#include "file-handle-def.h"
 #include "error.h"
 #include <errno.h>
 #include <stdlib.h>
index 98b2354c60e891ca1362f73dbc0cbd32c486bb96..24a91a9fed371922a05438bb47460afe706476ef 100644 (file)
@@ -54,6 +54,9 @@ int
 cmd_file_handle (void)
 {
   char handle_name[LONG_NAME_LEN + 1];
+  enum file_handle_mode mode = MODE_TEXT;
+  size_t length = 1024;
+  size_t tab_width = 4;
 
   struct cmd_file_handle cmd;
   struct file_handle *handle;
@@ -91,12 +94,6 @@ cmd_file_handle (void)
       goto lossage;
     }
 
-
-  enum file_handle_mode mode = MODE_TEXT;
-  size_t length = 1024;
-  size_t tab_width = 4;
-
-
   switch (cmd.mode)
     {
     case FH_CHARACTER:
@@ -131,7 +128,7 @@ cmd_file_handle (void)
   handle = create_file_handle (handle_name, cmd.s_name, 
                               mode, length, tab_width);
 
-
+  free_file_handle (&cmd);
   return CMD_SUCCESS;
 
  lossage:
index 0774c68325543dc5fb6dfede5acccf1e8d7fd76b..ff97f8dbbfbfd868c7adcd72c10672fb3a32bf1b 100644 (file)
@@ -74,8 +74,7 @@ struct record_type
     int ft, lt;                        /* First, last transformation index. */
   };                           /* record_type */
 
-/* Represents a FILE TYPE input program.  Does not contain a
-   trns_header because it's never submitted as a transformation. */
+/* Represents a FILE TYPE input program. */
 struct file_type_pgm
   {
     int type;                  /* One of the FTY_* constants. */
index af6607baa0f62f26c83dbb71300a0974dad46166..e47850c364919c2d4d01481112a443ab1f8b9da2 100644 (file)
--- a/src/get.c
+++ b/src/get.c
@@ -383,6 +383,8 @@ parse_write_command (enum writer_type writer_type,
       aw->writer = pfm_open_writer (handle, dict, porfile_opts);
       break;
     }
+
+  dict_destroy (dict);
   
   return aw;
 
@@ -465,7 +467,6 @@ cmd_export (void)
 /* Transformation. */
 struct output_trns 
   {
-    struct trns_header h;       /* Header. */
     struct any_writer *aw;      /* Writer. */
   };
 
@@ -477,8 +478,6 @@ static int
 parse_output_trns (enum writer_type writer_type) 
 {
   struct output_trns *t = xmalloc (sizeof *t);
-  t->h.proc = output_trns_proc;
-  t->h.free = output_trns_free;
   t->aw = parse_write_command (writer_type, XFORM_CMD, NULL);
   if (t->aw == NULL) 
     {
@@ -486,24 +485,24 @@ parse_output_trns (enum writer_type writer_type)
       return CMD_FAILURE;
     }
 
-  add_transformation (&t->h);
+  add_transformation (output_trns_proc, output_trns_free, t);
   return CMD_SUCCESS;
 }
 
 /* Writes case C to the system file specified on XSAVE or XEXPORT. */
 static int
-output_trns_proc (struct trns_header *h, struct ccase *c, int case_num UNUSED)
+output_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
 {
-  struct output_trns *t = (struct output_trns *) h;
+  struct output_trns *t = trns_;
   any_writer_write_case (t->aw, c);
   return -1;
 }
 
 /* Frees an XSAVE or XEXPORT transformation. */
 static void
-output_trns_free (struct trns_header *h)
+output_trns_free (void *trns_)
 {
-  struct output_trns *t = (struct output_trns *) h;
+  struct output_trns *t = trns_;
 
   if (t != NULL)
     {
index 1b5de09955e0bc4ee2611c4fda74e2d1c5cbe5f0..a026ede65ffb13492f5d79c6790d4705864f7d0f 100644 (file)
@@ -63,7 +63,6 @@ extern void stifle_history ();
 #include "calendar.h"
 #include "command.h"
 #include "dictionary.h"
-#include "do-ifP.h"
 #include "error.h"
 #include "file-handle.h"
 #include "filename.h"
@@ -84,10 +83,8 @@ extern void stifle_history ();
 struct dictionary *default_dict;
 struct expression *process_if_expr;
 
-struct trns_header **t_trns;
-int n_trns;
-int m_trns;
-int f_trns;
+struct transformation *t_trns;
+size_t n_trns, m_trns, f_trns;
 
 short test_mode=0;
 
@@ -95,8 +92,6 @@ int FILTER_before_TEMPORARY;
 
 struct file_handle *default_handle;
 
-struct ctl_stmt *ctl_stack;
-
 /* log.h */
 char *logfn;
 FILE *logfile;
index eb2503c79e7ce616a5bc6780a8837326a124bf42..eaa19532eaef4b80ecf2921dafaaa3b0efde03e0 100644 (file)
@@ -180,7 +180,7 @@ input_program_source_read (struct case_source *source,
                            write_case_data wc_data)
 {
   struct input_program_pgm *inp = source->aux;
-  int i;
+  size_t i;
 
   /* Nonzero if there were any END CASE commands in the set of
      transformations.  If so, we don't automatically write out
@@ -197,13 +197,13 @@ input_program_source_read (struct case_source *source,
 
   /* Figure end_case. */
   for (i = 0; i < f_trns; i++)
-    if (t_trns[i]->proc == end_case_trns_proc)
+    if (t_trns[i].proc == end_case_trns_proc)
       end_case = 1;
 
   /* FIXME: This is an ugly kluge. */
   for (i = 0; i < f_trns; i++)
-    if (t_trns[i]->proc == repeating_data_trns_proc)
-      repeating_data_set_write_case (t_trns[i], write_case, wc_data);
+    if (t_trns[i].proc == repeating_data_trns_proc)
+      repeating_data_set_write_case (t_trns[i].private, write_case, wc_data);
 
   init_case (inp, c);
   for (;;)
@@ -213,7 +213,7 @@ input_program_source_read (struct case_source *source,
        {
           int code;     /* Return value of last-called transformation. */
 
-          if (t_trns[i]->proc == end_case_trns_proc) 
+          if (t_trns[i].proc == end_case_trns_proc) 
             {
               cases_written++;
               if (!write_case (wc_data))
@@ -223,7 +223,7 @@ input_program_source_read (struct case_source *source,
               continue;
             }
 
-         code = t_trns[i]->proc (t_trns[i], c, cases_written + 1);
+         code = t_trns[i].proc (t_trns[i].private, c, cases_written + 1);
          switch (code)
            {
            case -1:
@@ -280,8 +280,6 @@ const struct case_source_class input_program_source_class =
 int
 cmd_end_case (void)
 {
-  struct trns_header *t;
-
   if (!case_source_is_class (vfm_source, &input_program_source_class))
     {
       msg (SE, _("This command may only be executed between INPUT PROGRAM "
@@ -289,10 +287,7 @@ cmd_end_case (void)
       return CMD_FAILURE;
     }
 
-  t = xmalloc (sizeof *t);
-  t->proc = end_case_trns_proc;
-  t->free = NULL;
-  add_transformation ((struct trns_header *) t);
+  add_transformation (end_case_trns_proc, NULL, NULL);
 
   return lex_end_of_command ();
 }
@@ -300,7 +295,7 @@ cmd_end_case (void)
 /* Should never be called, because this is handled in
    input_program_source_read(). */
 int
-end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
+end_case_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
                     int case_num UNUSED)
 {
   assert (0);
@@ -310,8 +305,6 @@ end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
 /* REREAD transformation. */
 struct reread_trns
   {
-    struct trns_header h;
-
     struct dfm_reader *reader; /* File to move file pointer back on. */
     struct expression *column; /* Column to reset file pointer to. */
   };
@@ -362,21 +355,18 @@ cmd_reread (void)
     }
 
   t = xmalloc (sizeof *t);
-  t->h.proc = reread_trns_proc;
-  t->h.free = reread_trns_free;
   t->reader = dfm_open_reader (fh);
   t->column = e;
-  add_transformation ((struct trns_header *) t);
+  add_transformation (reread_trns_proc, reread_trns_free, t);
 
   return CMD_SUCCESS;
 }
 
 /* Executes a REREAD transformation. */
 static int
-reread_trns_proc (struct trns_header * pt, struct ccase * c,
-                  int case_num)
+reread_trns_proc (void *t_, struct ccase *c, int case_num)
 {
-  struct reread_trns *t = (struct reread_trns *) pt;
+  struct reread_trns *t = t_;
 
   if (t->column == NULL)
     dfm_reread_record (t->reader, 1);
@@ -397,9 +387,9 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c,
 
 /* Frees a REREAD transformation. */
 static void
-reread_trns_free (struct trns_header *t_)
+reread_trns_free (void *t_)
 {
-  struct reread_trns *t = (struct reread_trns *) t_;
+  struct reread_trns *t = t_;
   expr_free (t->column);
   dfm_close_reader (t->reader);
 }
@@ -408,8 +398,6 @@ reread_trns_free (struct trns_header *t_)
 int
 cmd_end_file (void)
 {
-  struct trns_header *t;
-
   if (!case_source_is_class (vfm_source, &input_program_source_class))
     {
       msg (SE, _("This command may only be executed between INPUT PROGRAM "
@@ -417,17 +405,14 @@ cmd_end_file (void)
       return CMD_FAILURE;
     }
 
-  t = xmalloc (sizeof *t);
-  t->proc = end_file_trns_proc;
-  t->free = NULL;
-  add_transformation ((struct trns_header *) t);
+  add_transformation (end_file_trns_proc, NULL, NULL);
 
   return lex_end_of_command ();
 }
 
 /* Executes an END FILE transformation. */
 static int
-end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED,
+end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
                     int case_num UNUSED)
 {
   return -2;
index 06936778ef0f990751174373f5b7499a339c4eee..f388d9e270e09313cfda4b1e8595ed8fe2d6f14b 100644 (file)
 #include "case.h"
 #include "command.h"
 #include "dictionary.h"
-#include "do-ifP.h"
+#include "ctl-stack.h"
 #include "error.h"
 #include "expressions/public.h"
 #include "lexer.h"
 #include "misc.h"
+#include "pool.h"
 #include "settings.h"
 #include "str.h"
 #include "var.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include "debug-print.h"
-
-/* LOOP strategy:
-
-   Each loop causes 3 different transformations to be output.  The
-   first two are output when the LOOP command is encountered; the last
-   is output when the END LOOP command is encountered.
-
-   The first to be output resets the pass number in the second
-   transformation to -1.  This ensures that the pass number is set to
-   -1 every time the loop is encountered, before the first iteration.
-
-   The second transformation increments the pass number.  If
-   there is no indexing or test clause on either LOOP or END
-   LOOP, then the pass number is checked against MXLOOPS and
-   control may pass out of the loop.  Otherwise the indexing or
-   test clause(s) on LOOP are checked, and again control may pass
-   out of the loop.
-
-   After the second transformation the body of the loop is
-   executed.
-
-   The last transformation checks the test clause if present and
-   either jumps back up to the second transformation or
-   terminates the loop.
-
-   Flow of control:
-
-   1. LOOP.  Sets pass number to -1 and continues to next
-      transformation.
-
-   2. LOOP.  Increments pass number.  Tests optional indexing
-      clause and optional IF clause.  If we're done with the
-      loop, we jump to the transformation just after LOOP
-      transformation 3.
-
-      Otherwise, we continue through the transformations in the
-      loop body.
-
-   3. END LOOP.  We test the optional IF clause.  If we need to
-      make another pass through the loop, we jump to LOOP
-      transformation 2.
-
-      Otherwise, we continue with the transformation jump after
-      the loop.
- */
-
-/* Types of limits on loop execution. */
-enum
+/* 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
   {
-    LPC_INDEX = 001,           /* Limited by indexing clause. */
-    LPC_COND = 002,            /* Limited by IF clause. */
-    LPC_RINDEX = 004           /* Indexing clause counts downward, at least
-                                  for this pass thru the loop. */
-  };
+    struct pool *pool;
 
-/* LOOP transformation 1. */
-struct loop_1_trns
-  {
-    struct trns_header h;
-
-    struct loop_2_trns *two;   /* Allows modification of associated
-                                  second transformation. */
-
-    struct expression *init;   /* Starting index. */
-    struct expression *incr;   /* Index increment. */
-    struct expression *term;   /* Terminal index. */
-  };
-
-/* LOOP transformation 2. */
-struct loop_2_trns
-  {
-    struct trns_header h;
-
-    struct ctl_stmt ctl;       /* Nesting control info. */
-
-    int flags;                 /* Types of limits on loop execution. */
+    /* Iteration limit. */
+    int max_pass_count;         /* Maximum number of passes (-1=unlimited). */
     int pass;                  /* Number of passes thru the loop so far. */
 
-    struct variable *index;    /* Index variable. */
-    double curr;               /* Current index. */
-    double incr;               /* Increment. */
-    double term;               /* Terminal index. */
+    /* 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 *cond;   /* Optional IF condition when non-NULL. */
+    /* IF condition for LOOP or END LOOP. */
+    struct expression *loop_condition;
+    struct expression *end_loop_condition;
 
-    int loop_term;             /* 1+(t_trns[] index of transformation 3);
-                                  backpatched in by END LOOP. */
+    /* Transformation indexes. */
+    int past_LOOP_index;        /* Just past LOOP transformation. */
+    int past_END_LOOP_index;    /* Just past END LOOP transformation. */
   };
 
-/* LOOP transformation 3.  (Actually output by END LOOP.)  */
-struct loop_3_trns
-  {
-    struct trns_header h;
-
-    struct expression *cond;   /* Optional IF condition when non-NULL. */
+static struct ctl_class loop_class;
 
-    int loop_start;            /* t_trns[] index of transformation 2. */
-  };
+static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc;
+static trns_free_func loop_trns_free;
 
-/* LOOP transformations being created. */
-static struct loop_1_trns *one;
-static struct loop_2_trns *two;
-static struct loop_3_trns *thr;
-
-static int internal_cmd_loop (void);
-static int internal_cmd_end_loop (void);
-static trns_proc_func break_trns_proc;
-static trns_proc_func loop_1_trns_proc, loop_2_trns_proc, loop_3_trns_proc;
-static trns_free_func loop_1_trns_free, loop_2_trns_free, loop_3_trns_free;
-static void pop_ctl_stack (void);
+static struct loop_trns *create_loop_trns (void);
+static bool parse_if_clause (struct loop_trns *, struct expression **);
+static bool parse_index_clause (struct loop_trns *, char index_var_name[]);
+static void close_loop (void *);
 \f
 /* LOOP. */
 
-/* Parses a LOOP command.  Passes the real work off to
-   internal_cmd_loop(). */
+/* Parses LOOP. */
 int
 cmd_loop (void)
 {
-  if (!internal_cmd_loop ())
-    {
-      loop_1_trns_free ((struct trns_header *) one);
-      loop_2_trns_free ((struct trns_header *) two);
-      return CMD_FAILURE;
-    }
-
-  return CMD_SUCCESS;
-}
-
-/* Parses a LOOP command, returns success. */
-static int
-internal_cmd_loop (void)
-{
-  /* Name of indexing variable if applicable. */
-  char name[LONG_NAME_LEN + 1];
-
-  /* Create and initialize transformations to facilitate
-     error-handling. */
-  two = xmalloc (sizeof *two);
-  two->h.proc = loop_2_trns_proc;
-  two->h.free = loop_2_trns_free;
-  two->cond = NULL;
-  two->flags = 0;
-
-  one = xmalloc (sizeof *one);
-  one->h.proc = loop_1_trns_proc;
-  one->h.free = loop_1_trns_free;
-  one->init = one->incr = one->term = NULL;
-  one->two = two;
-
-  /* Parse indexing clause. */
-  if (token == T_ID && lex_look_ahead () == '=')
-    {
-      struct variable *v = dict_lookup_var (default_dict, tokid);
-
-      two->flags |= LPC_INDEX;
-
-      if (v && v->type == ALPHA)
-       {
-         msg (SE, _("The index variable may not be a string variable."));
-         return 0;
-       }
-      strcpy (name, tokid);
-
-      lex_get ();
-      assert (token == '=');
-      lex_get ();
-
-      one->init = expr_parse (default_dict, EXPR_NUMBER);
-      if (!one->init)
-       return 0;
-
-      if (!lex_force_match (T_TO))
-       {
-         expr_free (one->init);
-         return 0;
-       }
-      one->term = expr_parse (default_dict, EXPR_NUMBER);
-      if (!one->term)
-       {
-         expr_free (one->init);
-         return 0;
-       }
-
-      if (lex_match (T_BY))
-       {
-         one->incr = expr_parse (default_dict, EXPR_NUMBER);
-         if (!one->incr)
-           return 0;
-       }
-    }
-  else
-    name[0] = '\0';
+  struct loop_trns *loop;
+  char index_var_name[LONG_NAME_LEN + 1];
+  bool ok = true;
 
-  /* Parse IF clause. */
-  if (lex_match_id ("IF"))
+  loop = create_loop_trns ();
+  while (token != '.' && ok) 
     {
-      two->flags |= LPC_COND;
-
-      two->cond = expr_parse (default_dict, EXPR_BOOLEAN);
-      if (!two->cond)
-       return 0;
-    }
-
-  if (token != '.')
-    {
-      lex_error (_("expecting end of command"));
-      return 0;
+      if (lex_match_id ("IF")) 
+        ok = parse_if_clause (loop, &loop->loop_condition);
+      else
+        ok = parse_index_clause (loop, index_var_name);
     }
 
-  /* Find variable; create if necessary. */
-  if (name[0] != '\0')
+  /* Find index variable and create if necessary. */
+  if (ok && index_var_name[0] != '\0')
     {
-      two->index = dict_lookup_var (default_dict, name);
-      if (!two->index)
-        two->index = dict_create_var (default_dict, name, 0);
+      loop->index_var = dict_lookup_var (default_dict, index_var_name);
+      if (loop->index_var == NULL)
+        loop->index_var = dict_create_var (default_dict, index_var_name, 0);
     }
   
-  /* Push on control stack. */
-  two->ctl.down = ctl_stack;
-  two->ctl.type = CST_LOOP;
-  two->ctl.trns = (struct trns_header *) two;
-  two->ctl.brk = NULL;
-  ctl_stack = &two->ctl;
-
-  /* Dump out the transformations. */
-  add_transformation ((struct trns_header *) one);
-  add_transformation ((struct trns_header *) two);
-
-  return 1;
+  if (!ok)
+    loop->max_pass_count = 0;
+  return ok ? CMD_SUCCESS : CMD_PART_SUCCESS;
 }
 
-/* Parses the END LOOP command by passing the buck off to
-   cmd_internal_end_loop(). */
+/* Parses END LOOP. */
 int
 cmd_end_loop (void)
 {
-  if (!internal_cmd_end_loop ())
-    {
-      loop_3_trns_free ((struct trns_header *) thr);
-      if (ctl_stack && ctl_stack->type == CST_LOOP)
-       pop_ctl_stack ();
-      return CMD_FAILURE;
-    }
-
-  return CMD_SUCCESS;
-}
+  struct loop_trns *loop;
+  bool ok = true;
 
-/* Parses the END LOOP command. */
-int
-internal_cmd_end_loop (void)
-{
-  /* Backpatch pointer for BREAK commands. */
-  struct break_trns *brk;
-
-  /* Allocate, initialize transformation to facilitate
-     error-handling. */
-  thr = xmalloc (sizeof *thr);
-  thr->h.proc = loop_3_trns_proc;
-  thr->h.free = loop_3_trns_free;
-  thr->cond = NULL;
-
-  /* There must be a matching LOOP command. */
-  if (!ctl_stack || ctl_stack->type != CST_LOOP)
-    {
-      msg (SE, _("There is no LOOP command that corresponds to this "
-                "END LOOP."));
-      return 0;
-    }
-  thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
-
-  /* Parse the expression if any. */
+  loop = ctl_stack_top (&loop_class);
+  if (loop == NULL)
+    return CMD_FAILURE;
+  
+  /* Parse syntax. */
   if (lex_match_id ("IF"))
-    {
-      thr->cond = expr_parse (default_dict, EXPR_BOOLEAN);
-      if (!thr->cond)
-       return 0;
-    }
-
-  add_transformation ((struct trns_header *) thr);
-
-  /* Backpatch. */
-  ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
-  for (brk = ctl_stack->brk; brk; brk = brk->next)
-    brk->loop_term = n_trns;
+    ok = parse_if_clause (loop, &loop->end_loop_condition);
+  if (ok)
+    ok = lex_end_of_command () == CMD_SUCCESS;
 
-  /* Pop off the top of stack. */
-  ctl_stack = ctl_stack->down;
+  if (!ok)
+    loop->max_pass_count = 0;
 
-  return 1;
+  ctl_stack_pop (loop);
+  
+  return ok ? CMD_SUCCESS : CMD_PART_SUCCESS;
 }
 
-/* Performs transformation 1. */
-static int
-loop_1_trns_proc (struct trns_header * trns, struct ccase * c,
-                  int case_num)
+/* Parses BREAK. */
+int
+cmd_break (void)
 {
-  struct loop_1_trns *one = (struct loop_1_trns *) trns;
-  struct loop_2_trns *two = one->two;
+  struct ctl_stmt *loop = ctl_stack_search (&loop_class);
+  if (loop == NULL)
+    return CMD_FAILURE;
 
-  two->pass = -1;
-  if (two->flags & LPC_INDEX)
-    {
-      double t1, t2, t3;
-
-      t1 = expr_evaluate_num (one->init, c, case_num);
-      if (one->incr)
-       t2 = expr_evaluate_num (one->incr, c, case_num);
-      else
-       t2 = 1.0;
-      t3 = expr_evaluate_num (one->term, c, case_num);
-
-      /* Even if the loop is never entered, force the index variable
-         to assume the initial value. */
-      case_data_rw (c, two->index->fv)->f = t1;
-
-      /* Throw out various pathological cases. */
-      if (!finite (t1) || !finite (t2) || !finite (t3) || t2 == 0.0)
-       return two->loop_term;
-      debug_printf (("LOOP %s=%g TO %g BY %g.\n", two->index->name,
-                    t1, t3, t2));
-      if (t2 > 0.0)
-       {
-         /* Loop counts upward: I=1 TO 5 BY 1. */
-         two->flags &= ~LPC_RINDEX;
-
-         /* incr>0 but init>term */
-         if (t1 > t3)
-           return two->loop_term;
-       }
-      else
-       {
-         /* Loop counts downward: I=5 TO 1 BY -1. */
-         two->flags |= LPC_RINDEX;
-
-         /* incr<0 but init<term */
-         if (t1 < t3)
-           return two->loop_term;
-       }
-
-      two->curr = t1;
-      two->incr = t2;
-      two->term = t3;
-    }
+  add_transformation (break_trns_proc, NULL, loop);
 
-  return -1;
+  return lex_end_of_command ();
 }
 
-/* Frees transformation 1. */
+/* Closes a LOOP construct by emitting the END LOOP
+   transformation and finalizing its members appropriately. */
 static void
-loop_1_trns_free (struct trns_header * trns)
+close_loop (void *loop_)
 {
-  struct loop_1_trns *one = (struct loop_1_trns *) trns;
-
-  expr_free (one->init);
-  expr_free (one->incr);
-  expr_free (one->term);
+  struct loop_trns *loop = loop_;
+  
+  add_transformation (end_loop_trns_proc, NULL, loop);
+  loop->past_END_LOOP_index = next_transformation ();
+
+  /* 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->loop_condition == NULL
+      && loop->end_loop_condition == NULL)
+    loop->max_pass_count = get_mxloops ();
 }
 
-/* Performs transformation 2. */
-static int
-loop_2_trns_proc (struct trns_header * trns, struct ccase * c,
-                  int case_num UNUSED)
+/* 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 loop_trns *loop, struct expression **condition) 
 {
-  struct loop_2_trns *two = (struct loop_2_trns *) trns;
+  *condition = expr_parse_pool (loop->pool, default_dict, EXPR_BOOLEAN);
+  return *condition != NULL;
+}
 
-  /* MXLOOPS limiter. */
-  if (two->flags == 0)
+/* Parses an indexing clause into LOOP.
+   Stores the index variable's name in INDEX_VAR_NAME[].
+   Returns true if successful, false on failure. */
+static bool
+parse_index_clause (struct loop_trns *loop, char index_var_name[]) 
+{
+  if (token != T_ID) 
     {
-      two->pass++;
-      if (two->pass > get_mxloops() )
-         return two->loop_term;
+      lex_error (NULL);
+      return false;
     }
+  strcpy (index_var_name, tokid);
+  lex_get ();
 
-  /* Indexing clause limiter: counting downward. */
-  if (two->flags & LPC_RINDEX)
-    {
-      /* Test if we're at the end of the looping. */
-      if (two->curr < two->term)
-       return two->loop_term;
+  if (!lex_force_match ('='))
+    return false;
 
-      /* Set the current value into the case. */
-      case_data_rw (c, two->index->fv)->f = two->curr;
+  loop->first_expr = expr_parse_pool (loop->pool, default_dict, EXPR_NUMBER);
+  if (loop->first_expr == NULL)
+    return false;
 
-      /* Decrement the current value. */
-      two->curr += two->incr;
+  for (;;)
+    {
+      struct expression **e;
+      if (lex_match (T_TO)) 
+        e = &loop->last_expr;
+      else if (lex_match (T_BY)) 
+        e = &loop->by_expr;
+      else
+        break;
+
+      if (*e != NULL) 
+        {
+          lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
+          return false;
+        }
+      *e = expr_parse_pool (loop->pool, default_dict, EXPR_NUMBER);
+      if (*e == NULL)
+        return false;
     }
-  /* Indexing clause limiter: counting upward. */
-  else if (two->flags & LPC_INDEX)
+  if (loop->last_expr == NULL) 
     {
-      /* Test if we're at the end of the looping. */
-      if (two->curr > two->term)
-       return two->loop_term;
-
-      /* Set the current value into the case. */
-      case_data_rw (c, two->index->fv)->f = two->curr;
-
-      /* Increment the current value. */
-      two->curr += two->incr;
+      lex_sbc_missing ("TO");
+      return false;
     }
+  if (loop->by_expr == NULL)
+    loop->by = 1.0;
 
-  /* Conditional clause limiter. */
-  if ((two->flags & LPC_COND)
-      && expr_evaluate_num (two->cond, c, case_num) != 1.0)
-    return two->loop_term;
-
-  return -1;
+  return true;
 }
 
-/* Frees transformation 2. */
-static void
-loop_2_trns_free (struct trns_header * trns)
+/* Creates, initializes, and returns a new loop_trns. */
+static struct loop_trns *
+create_loop_trns (void) 
 {
-  struct loop_2_trns *two = (struct loop_2_trns *) trns;
+  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;
 
-  expr_free (two->cond);
+  add_transformation (loop_trns_proc, loop_trns_free, loop);
+  loop->past_LOOP_index = next_transformation ();
+
+  ctl_stack_push (&loop_class, loop);
+
+  return loop;
 }
 
-/* Performs transformation 3. */
+/* Sets up LOOP for the first pass. */
 static int
-loop_3_trns_proc (struct trns_header * trns, struct ccase * c,
-                  int case_num)
+loop_trns_proc (void *loop_, struct ccase *c, int case_num)
 {
-  struct loop_3_trns *thr = (struct loop_3_trns *) trns;
+  struct loop_trns *loop = loop_;
 
-  /* Note that it breaks out of the loop if the expression is true *or
-     missing*.  This is conformant. */
-  if (thr->cond && expr_evaluate_num (two->cond, c, case_num) != 0.0)
-    return -1;
+  if (loop->index_var != NULL)
+    {
+      /* 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);
+
+      /* Even if the loop is never entered, set the index
+         variable to the initial value. */
+      case_data_rw (c, loop->index_var->fv)->f = loop->cur;
+
+      /* Throw out pathological cases. */
+      if (!finite (loop->cur) || !finite (loop->by) || !finite (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;
+    }
+
+  /* Initialize pass count. */
+  loop->pass = 0;
+  if (loop->max_pass_count >= 0 && loop->pass >= loop->max_pass_count)
+    goto zero_pass;
+
+  /* Check condition. */
+  if (loop->loop_condition != NULL
+      && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+    goto zero_pass;
+
+  return loop->past_LOOP_index;
 
-  return thr->loop_start;
+ zero_pass:
+  return loop->past_END_LOOP_index;
 }
 
-/* Frees transformation 3. */
+/* Frees LOOP. */
 static void
-loop_3_trns_free (struct trns_header * trns)
+loop_trns_free (void *loop_)
 {
-  struct loop_3_trns *thr = (struct loop_3_trns *) trns;
+  struct loop_trns *loop = loop_;
 
-  expr_free (thr->cond);
+  pool_destroy (loop->pool);
 }
-\f
-/* BREAK. */
 
-/* Parses the BREAK command. */
-int
-cmd_break (void)
+/* Finishes a pass through the loop and starts the next. */
+static int
+end_loop_trns_proc (void *loop_, struct ccase *c, int case_num UNUSED)
 {
-  /* Climbs down the stack to find a LOOP. */
-  struct ctl_stmt *loop;
+  struct loop_trns *loop = loop_;
 
-  /* New transformation. */
-  struct break_trns *t;
+  if (loop->end_loop_condition != NULL
+      && expr_evaluate_num (loop->end_loop_condition, c, case_num) != 1.0)
+    goto break_out;
 
-  for (loop = ctl_stack; loop; loop = loop->down)
-    if (loop->type == CST_LOOP)
-      break;
-  if (!loop)
+  /* MXLOOPS limiter. */
+  if (loop->max_pass_count >= 0)
     {
-      msg (SE, _("This command may only appear enclosed in a LOOP/"
-                "END LOOP control structure."));
-      return CMD_FAILURE;
+      if (loop->pass >= loop->max_pass_count)
+        goto break_out;
+      loop->pass++;
+    }
+
+  /* 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;
+      case_data_rw (c, loop->index_var->fv)->f = loop->cur;
     }
-  
-  if (ctl_stack->type != CST_DO_IF)
-    msg (SW, _("BREAK not enclosed in DO IF structure."));
 
-  t = xmalloc (sizeof *t);
-  t->h.proc = break_trns_proc;
-  t->h.free = NULL;
-  t->next = loop->brk;
-  loop->brk = t;
-  add_transformation ((struct trns_header *) t);
+  if (loop->loop_condition != NULL
+      && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+    goto break_out;
 
-  return lex_end_of_command ();
+  return loop->past_LOOP_index;
+
+ break_out:
+  return loop->past_END_LOOP_index;
 }
 
+/* Executes BREAK. */
 static int
-break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED,
-                 int case_num UNUSED)
+break_trns_proc (void *loop_, struct ccase *c UNUSED, int case_num UNUSED)
 {
-  return ((struct break_trns *) trns)->loop_term;
-}
-\f
-/* Control stack operations. */
+  struct loop_trns *loop = loop_;
 
-/* Pops the top of stack element off of ctl_stack.  Does not
-   check that ctl_stack is indeed non-NULL. */
-static void
-pop_ctl_stack (void)
-{
-  switch (ctl_stack->type)
-    {
-    case CST_LOOP:
-      {
-       /* Pointer for chasing down and backpatching BREAKs. */
-       struct break_trns *brk;
-
-       /* Terminate the loop. */
-       thr = xmalloc (sizeof *thr);
-       thr->h.proc = loop_3_trns_proc;
-       thr->h.free = loop_3_trns_free;
-       thr->cond = NULL;
-       thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
-       add_transformation ((struct trns_header *) thr);
-
-       /* Backpatch. */
-       ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
-       for (brk = ctl_stack->brk; brk; brk = brk->next)
-         brk->loop_term = n_trns;
-      }
-      break;
-    case CST_DO_IF:
-      {
-       /* List iterator. */
-       struct do_if_trns *iter;
-
-       iter = ((struct do_if_trns *) ctl_stack->trns);
-       for (;;)
-         {
-           if (iter->brk)
-             iter->brk->dest = n_trns;
-           iter->missing_jump = n_trns;
-           if (iter->next)
-             iter = iter->next;
-           else
-             break;
-         }
-       iter->false_jump = n_trns;
-      }
-      break;
-    default:
-      assert (0);
-    }
-  ctl_stack = ctl_stack->down;
+  return loop->past_END_LOOP_index;
 }
 
-/* Checks for unclosed LOOPs and DO IFs and closes them out. */
-void
-discard_ctl_stack (void)
-{
-  if (!ctl_stack)
-    return;
-  msg (SE, _("%s without %s."), ctl_stack->type == CST_LOOP ? "LOOP" : "DO IF",
-       ctl_stack->type == CST_LOOP ? "END LOOP" : "END IF");
-  while (ctl_stack)
-    pop_ctl_stack ();
-  ctl_stack = NULL;
-}
+/* LOOP control structure class definition. */
+static struct ctl_class loop_class =
+  {
+    "LOOP",
+    "END LOOP",
+    close_loop,
+  };
index 0f6b11e05caa7c3a090660cbddb86a6ed5161bec..e8aede403f85e5c9bc35a398ae428d360a4f9a73 100644 (file)
@@ -167,6 +167,27 @@ pool_create (void)
   return pool;
 }
 
+/* Creates a pool, allocates a block STRUCT_SIZE bytes in
+   length from it, stores the pool's address at offset
+   POOL_MEMBER_OFFSET within the block, and returns the allocated
+   block.
+
+   Meant for use indirectly via pool_create_container(). */
+void *
+pool_create_at_offset (size_t struct_size, size_t pool_member_offset) 
+{
+  struct pool *pool;
+  char *struct_;
+
+  assert (struct_size >= sizeof pool);
+  assert (pool_member_offset <= struct_size - sizeof pool);
+
+  pool = pool_create ();
+  struct_ = pool_alloc (pool, struct_size);
+  *(struct pool **) (struct_ + pool_member_offset) = pool;
+  return struct_;
+}
+
 /* Destroy the specified pool, including all subpools. */
 void
 pool_destroy (struct pool *pool)
@@ -578,6 +599,27 @@ pool_create_subpool (struct pool *pool)
   return subpool;
 }
 
+/* Makes SUBPOOL a subpool of POOL.
+   SUBPOOL must not already have a parent pool.
+   The subpool will be destroyed automatically when POOL is destroyed.
+   It may also be destroyed explicitly in advance. */
+void
+pool_add_subpool (struct pool *pool, struct pool *subpool) 
+{
+  struct pool_gizmo *g;
+
+  assert (pool != NULL);
+  assert (subpool != NULL);
+  assert (subpool->parent == NULL);
+  
+  g = pool_alloc (subpool, sizeof *g);
+  g->type = POOL_GIZMO_SUBPOOL;
+  g->p.subpool = subpool;
+  add_gizmo (pool, g);
+
+  subpool->parent = pool;
+}
+
 /* Opens file FILENAME with mode MODE and returns a handle to it
    if successful or a null pointer if not.
    The file will be closed automatically when POOL is destroyed, or it
index ff5898434e5d03eb0ec070b83a991a9a91374a22..fc23df0591aab910b6ae621968d03b2358a10258 100644 (file)
@@ -38,6 +38,14 @@ struct pool *pool_create (void);
 void pool_destroy (struct pool *);
 void pool_clear (struct pool *);
 
+/* Creates a pool, allocates an instance of the given STRUCT
+   within it, sets the struct's MEMBER to the pool's address, and
+   returns the allocated structure. */
+#define pool_create_container(STRUCT, MEMBER)                           \
+        ((STRUCT *) pool_create_at_offset (sizeof (STRUCT),             \
+                                           offsetof (STRUCT, MEMBER)))
+void *pool_create_at_offset (size_t struct_size, size_t pool_member_offset);
+
 /* Suballocation routines. */
 void *pool_alloc (struct pool *, size_t) MALLOC_LIKE;
 void *pool_nalloc (struct pool *, size_t n, size_t s) MALLOC_LIKE;
@@ -56,6 +64,7 @@ void pool_free (struct pool *, void *);
 
 /* Gizmo allocations. */
 struct pool *pool_create_subpool (struct pool *);
+void pool_add_subpool (struct pool *, struct pool *subpool);
 FILE *pool_fopen (struct pool *, const char *, const char *);
 int pool_fclose (struct pool *, FILE *);
 
index a42c82d5bca3e4da742cd5fdc70d819e07e470be..0376fa1cbb6497b33e4bead8f92ebaa2b7a4dbd6 100644 (file)
@@ -80,7 +80,6 @@ enum
 /* PRINT, PRINT EJECT, WRITE private data structure. */
 struct print_trns
   {
-    struct trns_header h;
     struct dfm_writer *writer; /* Output file, NULL=listing file. */
     int options;               /* PRT_* bitmapped field. */
     struct prt_out_spec *spec; /* Output specifications. */
@@ -141,8 +140,6 @@ internal_cmd_print (int f)
   struct file_handle *fh = NULL;
 
   /* Fill in prt to facilitate error-handling. */
-  prt.h.proc = print_trns_proc;
-  prt.h.free = print_trns_free;
   prt.writer = NULL;
   prt.options = f;
   prt.spec = NULL;
@@ -209,12 +206,12 @@ internal_cmd_print (int f)
   /* Put the transformation in the queue. */
   trns = xmalloc (sizeof *trns);
   memcpy (trns, &prt, sizeof *trns);
-  add_transformation ((struct trns_header *) trns);
+  add_transformation (print_trns_proc, print_trns_free, trns);
 
   return CMD_SUCCESS;
 
  error:
-  print_trns_free ((struct trns_header *) & prt);
+  print_trns_free (&prt);
   return CMD_FAILURE;
 }
 
@@ -640,7 +637,7 @@ fixed_parse_compatible (void)
 
 /* Destroy a format list and, optionally, all its sublists. */
 static void
-destroy_fmt_list (struct fmt_list * f, int recurse)
+destroy_fmt_list (struct fmt_list *f, int recurse)
 {
   struct fmt_list *next;
 
@@ -657,7 +654,7 @@ destroy_fmt_list (struct fmt_list * f, int recurse)
    FORTRAN-like format specifications, like 4(F10,2X)) into the
    structure prt. */
 static int
-dump_fmt_list (struct fmt_list * f)
+dump_fmt_list (struct fmt_list *f)
 {
   int i;
 
@@ -899,11 +896,10 @@ alloc_line (void)
 
 /* Performs the transformation inside print_trns T on case C. */
 static int
-print_trns_proc (struct trns_header * trns, struct ccase * c,
-                 int case_num UNUSED)
+print_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
 {
   /* Transformation. */
-  struct print_trns *t = (struct print_trns *) trns;
+  struct print_trns *t = trns_;
 
   /* Iterator. */
   struct prt_out_spec *i;
@@ -976,9 +972,9 @@ print_trns_proc (struct trns_header * trns, struct ccase * c,
 
 /* Frees all the data inside print_trns T.  Does not free T. */
 static void
-print_trns_free (struct trns_header * t)
+print_trns_free (void *prt_)
 {
-  struct print_trns *prt = (struct print_trns *) t;
+  struct print_trns *prt = prt_;
   struct prt_out_spec *i, *n;
 
   for (i = prt->spec; i; i = n)
@@ -1003,6 +999,7 @@ print_trns_free (struct trns_header * t)
   if (prt->writer != NULL)
     dfm_close_writer (prt->writer);
   free (prt->line);
+  free (prt);
 }
 \f
 /* PRINT SPACE. */
@@ -1010,8 +1007,6 @@ print_trns_free (struct trns_header * t)
 /* PRINT SPACE transformation. */
 struct print_space_trns
 {
-  struct trns_header h;
-
   struct dfm_writer *writer;    /* Output data file. */
   struct expression *e;                /* Number of lines; NULL=1. */
 }
@@ -1066,23 +1061,18 @@ cmd_print_space (void)
     writer = NULL;
   
   t = xmalloc (sizeof *t);
-  t->h.proc = print_space_trns_proc;
-  if (e)
-    t->h.free = print_space_trns_free;
-  else
-    t->h.free = NULL;
   t->writer = writer;
   t->e = e;
 
-  add_transformation ((struct trns_header *) t);
+  add_transformation (print_space_trns_proc, print_space_trns_free, t);
   return CMD_SUCCESS;
 }
 
 static int
-print_space_trns_proc (struct trns_header * trns, struct ccase * c,
+print_space_trns_proc (void *t_, struct ccase *c,
                        int case_num UNUSED)
 {
-  struct print_space_trns *t = (struct print_space_trns *) trns;
+  struct print_space_trns *t = t_;
   double n = 1.;
 
   if (t->e)
@@ -1118,7 +1108,9 @@ print_space_trns_proc (struct trns_header * trns, struct ccase * c,
 }
 
 static void
-print_space_trns_free (struct trns_header * trns)
+print_space_trns_free (void *trns_)
 {
-  expr_free (((struct print_space_trns *) trns)->e);
+  struct print_space_trns *trns = trns_;
+  expr_free (trns->e);
+  free (trns);
 }
index b364a1ac3ef2422f06d8ffad0086cbf5f5ad7c8a..394e9be14fbd0ef45b249d65c6de6d52a84c3d16 100644 (file)
@@ -81,7 +81,6 @@ struct rcd_var
 /* RECODE transformation. */
 struct recode_trns
   {
-    struct trns_header h;
     struct rcd_var *codings;
   };
 
@@ -105,9 +104,9 @@ struct recode_trns
 #define RCD_MISC_MISSING       0100u   /* Encountered MISSING or SYSMIS in
                                           this input spec. */
 
-static int parse_dest_spec (struct rcd_var * rcd, union value *v,
+static int parse_dest_spec (struct rcd_var *rcd, union value *v,
                            size_t *max_dst_width);
-static int parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width);
+static int parse_src_spec (struct rcd_var *rcd, int type, size_t max_src_width);
 static trns_proc_func recode_trns_proc;
 static trns_free_func recode_trns_free;
 static double convert_to_double (const char *, int);
@@ -425,10 +424,8 @@ cmd_recode (void)
       }
 
   trns = xmalloc (sizeof *trns);
-  trns->h.proc = recode_trns_proc;
-  trns->h.free = recode_trns_free;
   trns->codings = head;
-  add_transformation ((struct trns_header *) trns);
+  add_transformation (recode_trns_proc, recode_trns_free, trns);
 
   return CMD_SUCCESS;
 
@@ -438,13 +435,13 @@ cmd_recode (void)
     struct recode_trns t;
 
     t.codings = head;
-    recode_trns_free ((struct trns_header *) &t);
+    recode_trns_free (&t);
     return CMD_FAILURE;
   }
 }
 
 static int
-parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
+parse_dest_spec (struct rcd_var *rcd, union value *v, size_t *max_dst_width)
 {
   int flags;
 
@@ -515,7 +512,7 @@ parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
    but with CONVERT as the keyword; 3 for success but with ELSE as the
    keyword. */
 static int
-parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
+parse_src_spec (struct rcd_var *rcd, int type, size_t max_src_width)
 {
   struct coding *c;
 
@@ -649,12 +646,13 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
 /* Data transformation. */
 
 static void
-recode_trns_free (struct trns_header * t)
+recode_trns_free (void *t_)
 {
+  struct recode_trns *t = t_;
   size_t i;
   struct rcd_var *head, *next;
 
-  head = ((struct recode_trns *) t)->codings;
+  head = t->codings;
   while (head)
     {
       if (head->map && !(head->flags & RCD_MISC_DUPLICATE))
@@ -689,10 +687,11 @@ recode_trns_free (struct trns_header * t)
       free (head);
       head = next;
     }
+  free (t);
 }
 
 static inline struct coding *
-find_src_numeric (struct rcd_var * v, struct ccase * c)
+find_src_numeric (struct rcd_var *v, struct ccase *c)
 {
   double cmp = case_num (c, v->src->fv);
   struct coding *cp;
@@ -743,7 +742,7 @@ find_src_numeric (struct rcd_var * v, struct ccase * c)
 }
 
 static inline struct coding *
-find_src_string (struct rcd_var * v, struct ccase * c)
+find_src_string (struct rcd_var *v, struct ccase *c)
 {
   const char *cmp = case_str (c, v->src->fv);
   int w = v->src->width;
@@ -776,12 +775,13 @@ find_src_string (struct rcd_var * v, struct ccase * c)
 }
 
 static int
-recode_trns_proc (struct trns_header * t, struct ccase * c,
+recode_trns_proc (void *t_, struct ccase *c,
                   int case_idx UNUSED)
 {
+  struct recode_trns *t = t_;
   struct rcd_var *v;
 
-  for (v = ((struct recode_trns *) t)->codings; v; v = v->next)
+  for (v = t->codings; v; v = v->next)
     {
       struct coding *cp;
 
index 57548c1cd306fc95e0c3bdc06ba915deeed1bdb8..fceadbbbf37e72a9ef0b0846419407e41e227115 100644 (file)
@@ -45,7 +45,6 @@ enum
 /* SAMPLE transformation. */
 struct sample_trns
   {
-    struct trns_header h;
     int type;                  /* One of TYPE_*. */
     int n, N;                  /* TYPE_A_FROM_B: n from N. */
     int m, t;                  /* TYPE_A_FROM_B: # picked so far; # so far. */
@@ -53,6 +52,7 @@ struct sample_trns
   };
 
 static trns_proc_func sample_trns_proc;
+static trns_free_func sample_trns_free;
 
 int
 cmd_sample (void)
@@ -104,24 +104,22 @@ cmd_sample (void)
   lex_get ();
 
   trns = xmalloc (sizeof *trns);
-  trns->h.proc = sample_trns_proc;
-  trns->h.free = NULL;
   trns->type = type;
   trns->n = a;
   trns->N = b;
   trns->m = trns->t = 0;
   trns->frac = frac;
-  add_transformation ((struct trns_header *) trns);
+  add_transformation (sample_trns_proc, sample_trns_free, trns);
 
   return lex_end_of_command ();
 }
 
 /* Executes a SAMPLE transformation. */
 static int
-sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED,
+sample_trns_proc (void *t_, struct ccase *c UNUSED,
                   int case_num UNUSED)
 {
-  struct sample_trns *t = (struct sample_trns *) trns;
+  struct sample_trns *t = t_;
   double U;
 
   if (t->type == TYPE_FRACTION) 
@@ -148,3 +146,10 @@ sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED,
       return -1;
     }
 }
+
+static void
+sample_trns_free (void *t_) 
+{
+  struct sample_trns *t = t_;
+  free (t);
+}
index c703e2f460fcc898140bffc37448a35661d76f54..10d1030f004f70eb4419c2a1a060482e2519bebf 100644 (file)
@@ -18,6 +18,7 @@
    02110-1301, USA. */
 
 #include <config.h>
+#include <stdlib.h>
 #include "alloc.h"
 #include "command.h"
 #include "dictionary.h"
@@ -33,7 +34,6 @@
 /* SELECT IF transformation. */
 struct select_if_trns
   {
-    struct trns_header h;
     struct expression *e;      /* Test expression. */
   };
 
@@ -59,28 +59,28 @@ cmd_select_if (void)
     }
 
   t = xmalloc (sizeof *t);
-  t->h.proc = select_if_proc;
-  t->h.free = select_if_free;
   t->e = e;
-  add_transformation ((struct trns_header *) t);
+  add_transformation (select_if_proc, select_if_free, t);
 
   return CMD_SUCCESS;
 }
 
 /* Performs the SELECT IF transformation T on case C. */
 static int
-select_if_proc (struct trns_header *t_, struct ccase *c,
+select_if_proc (void *t_, struct ccase *c,
                 int case_num)
 {
-  struct select_if_trns *t = (struct select_if_trns *) t_;
+  struct select_if_trns *t = t_;
   return expr_evaluate_num (t->e, c, case_num) == 1.0 ? -1 : -2;
 }
 
 /* Frees SELECT IF transformation T. */
 static void
-select_if_free (struct trns_header * t)
+select_if_free (void *t_)
 {
-  expr_free (((struct select_if_trns *) t)->e);
+  struct select_if_trns *t = t_;
+  expr_free (t->e);
+  free (t);
 }
 
 /* Parses the FILTER command. */
index f277152e8f00beb6159a8d8605eecf7dbcc6848b..840e5d2b4e73941b95242b5b1b65c7087dea974a 100644 (file)
@@ -24,7 +24,7 @@
 #include "alloc.h"
 #include "command.h"
 #include "dictionary.h"
-#include "do-ifP.h"
+#include "ctl-stack.h"
 #include "error.h"
 #include "hash.h"
 #include "lexer.h"
 
 int temporary;
 struct dictionary *temp_dict;
-int temp_trns;
+size_t temp_trns;
 
 /* Parses the TEMPORARY command. */
 int
 cmd_temporary (void)
 {
   /* TEMPORARY is not allowed inside DO IF or LOOP. */
-  if (ctl_stack)
+  if (!ctl_stack_is_empty ())
     {
       msg (SE, _("This command is not valid inside DO IF or LOOP."));
       return CMD_FAILURE;
index a1059a20828a04c76d14184825a037643942e195..802004bccab843c590c5f426c49fbec1ef01ea5d 100644 (file)
--- a/src/var.h
+++ b/src/var.h
@@ -147,7 +147,7 @@ extern struct dictionary *temp_dict;
    gives the point at which data should be written out.  -1 means that
    the data shouldn't be changed since all transformations are
    temporary. */
-extern int temp_trns;
+extern size_t temp_trns;
 
 /* If FILTER is active, whether it was executed before or after
    TEMPORARY. */
@@ -160,29 +160,30 @@ void dump_split_vars (const struct ccase *);
 \f
 /* Transformations. */
 
-struct trns_header;
-typedef int trns_proc_func (struct trns_header *, struct ccase *, int);
-typedef void trns_free_func (struct trns_header *);
+struct transformation;
+typedef int trns_proc_func (void *, struct ccase *, int);
+typedef void trns_free_func (void *);
 
-/* Header for all transformations. */
-struct trns_header
+/* A transformation. */
+struct transformation
   {
-    int index;                  /* Index into t_trns[]. */
     trns_proc_func *proc;       /* Transformation proc. */
     trns_free_func *free;       /* Garbage collector proc. */
+    void *private;              /* Private data. */
   };
 
 /* Array of transformations */
-extern struct trns_header **t_trns;
+extern struct transformation *t_trns;
 
 /* Number of transformations, maximum number in array currently. */
-extern int n_trns, m_trns;
+extern size_t n_trns, m_trns;
 
 /* Index of first transformation that is really a transformation.  Any
    transformations before this belong to INPUT PROGRAM. */
-extern int f_trns;
+extern size_t f_trns;
 
-void add_transformation (struct trns_header *trns);
+void add_transformation (trns_proc_func *, trns_free_func *, void *);
+size_t next_transformation (void);
 void cancel_transformations (void);
 \f
 struct var_set;
index 08e3ca30f1f5818a88b8ea1dddadce283260abfa..7f2cb693301f06fc68894bf47b983a6d7efdcacb 100644 (file)
--- a/src/vfm.c
+++ b/src/vfm.c
@@ -32,7 +32,7 @@
 #include "casefile.h"
 #include "command.h"
 #include "dictionary.h"
-#include "do-ifP.h"
+#include "ctl-stack.h"
 #include "error.h"
 #include "expressions/public.h"
 #include "misc.h"
@@ -94,7 +94,7 @@ static void create_trns_case (struct ccase *, struct dictionary *);
 static void open_active_file (void);
 static int write_case (struct write_case_data *wc_data);
 static int execute_transformations (struct ccase *c,
-                                    struct trns_header **trns,
+                                    struct transformation *trns,
                                     int first_idx, int last_idx,
                                     int case_num);
 static int filter_case (const struct ccase *c, int case_num);
@@ -233,7 +233,7 @@ open_active_file (void)
     }
 
   /* Close any unclosed DO IF or LOOP constructs. */
-  discard_ctl_stack ();
+  ctl_stack_clear ();
 }
 
 /* Transforms trns_case and writes it to the replacement active
@@ -299,7 +299,7 @@ write_case (struct write_case_data *wc_data)
    transformations, nonzero otherwise. */
 static int
 execute_transformations (struct ccase *c,
-                         struct trns_header **trns,
+                         struct transformation *trns,
                          int first_idx, int last_idx,
                          int case_num) 
 {
@@ -307,7 +307,8 @@ execute_transformations (struct ccase *c,
 
   for (idx = first_idx; idx != last_idx; )
     {
-      int retval = trns[idx]->proc (trns[idx], c, case_num);
+      struct transformation *t = &trns[idx];
+      int retval = t->proc (t->private, c, case_num);
       switch (retval)
         {
         case -1:
@@ -603,15 +604,24 @@ lagged_case (int n_before)
 /* Appends TRNS to t_trns[], the list of all transformations to be
    performed on data as it is read from the active file. */
 void
-add_transformation (struct trns_header * trns)
+add_transformation (trns_proc_func *proc, trns_free_func *free, void *private)
 {
+  struct transformation *trns;
   if (n_trns >= m_trns)
-    {
-      m_trns += 16;
-      t_trns = xnrealloc (t_trns, m_trns, sizeof *t_trns);
-    }
-  t_trns[n_trns] = trns;
-  trns->index = n_trns++;
+    t_trns = x2nrealloc (t_trns, &m_trns, sizeof *t_trns);
+  trns = &t_trns[n_trns++];
+  trns->proc = proc;
+  trns->free = free;
+  trns->private = private;
+}
+
+/* Returns the index number that the next transformation added by
+   add_transformation() will receive.  A trns_proc_func that
+   returns this index causes control flow to jump to it. */
+size_t
+next_transformation (void) 
+{
+  return n_trns;
 }
 
 /* Cancels all active transformations, including any transformations
@@ -619,12 +629,12 @@ add_transformation (struct trns_header * trns)
 void
 cancel_transformations (void)
 {
-  int i;
+  size_t i;
   for (i = 0; i < n_trns; i++)
     {
-      if (t_trns[i]->free)
-       t_trns[i]->free (t_trns[i]);
-      free (t_trns[i]);
+      struct transformation *t = &t_trns[i];
+      if (t->free != NULL)
+       t->free (t->private);
     }
   n_trns = f_trns = 0;
   free (t_trns);
@@ -928,7 +938,7 @@ discard_variables (void)
 
   cancel_transformations ();
 
-  ctl_stack = NULL;
+  ctl_stack_clear ();
 
   expr_free (process_if_expr);
   process_if_expr = NULL;
index 9128bc3e90038b2f44bb33e0df94528144ea5195..f1326f09d25fc6a70e99670b9ab68266f6c826f2 100644 (file)
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* WEIGHT transformation. */
-struct weight_trns
-  {
-    struct trns_header h;
-    int src;                   /* `value' index of weighting variable. */
-    int dest;                  /* `value' index of $WEIGHT. */
-  };
-
 int
 cmd_weight (void)
 {
index 0b5d0de2032914e19f72c86827fd93d0802e61dd..67610b89f95210fc63ba1f7a7dfcb7e69c95b82e 100644 (file)
@@ -1,3 +1,7 @@
+Wed Nov  2 21:54:11 2005  Ben Pfaff  <blp@gnu.org>
+
+       * command/loop.sh: Update expected error messages.
+
 Sun Aug 21 00:20:02 2005  Ben Pfaff  <blp@gnu.org>
 
        * command/import-export.sh: Simplify.
index 1e76c6da1887be3545589a650ebf5663e6e09864..bcf4bfcd8c6429a24455be71c3542d1501ebf75a 100755 (executable)
@@ -72,7 +72,6 @@ if [ $? -ne 0 ] ; then no_result ; fi
 activity="compare stdout"
 perl -pi -e 's/^\s*$//g' $TEMPDIR/stdout
 diff -b $TEMPDIR/stdout  - <<EOF
-$TEMPDIR/loop.stat:10: warning: BREAK: BREAK not enclosed in DO IF structure.
 EOF
 if [ $? -ne 0 ] ; then fail ; fi