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.
+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.
.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 \
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
/* 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. */
};
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;
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;
}
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. */
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 *);
/* COMPUTE and IF transformation. */
struct compute_trns
{
- struct trns_header h;
-
/* Test expression (IF only). */
struct expression *test; /* Test expression. */
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. */
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
/* 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)
/* 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)
/* 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)
/* 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)
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. */
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;
/* 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. */
}
/* 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;
/* 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)
{
static void
lvalue_destroy (struct lvalue *lvalue)
{
- if ( ! lvalue )
- return ;
+ if (lvalue == NULL)
+ return;
expr_free (lvalue->element);
free (lvalue);
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)
{
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 (;;)
{
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;
}
/* 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)
/* 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);
--- /dev/null
+#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;
+}
--- /dev/null
+/* 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 */
/* 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. */
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;
}
}
}
-/* 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;
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 =
/* 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. */
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;
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;
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 ('/'))
{
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;
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;
}
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)
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. */
/* 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;
}
#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 */
/* 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. */
(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;
/* 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));
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;
t->var_cnt = 0;
t->vars = NULL;
}
-
for (cnt = i = 0; i < dsc->var_cnt; i++)
{
}
}
- add_transformation ((struct trns_header *) t);
+ add_transformation (descriptives_trns_proc, descriptives_trns_free, t);
}
\f
/* Statistical calculation. */
#include "alloc.h"
#include "command.h"
#include "error.h"
+#include "file-handle.h"
#include "file-handle-def.h"
#include "filename.h"
#include "getl.h"
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 ();
}
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,
+ };
+++ /dev/null
-/* 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 */
}
}
+/* 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)
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 *,
#include <config.h>
#include "file-handle.h"
+#include "file-handle-def.h"
#include "error.h"
#include <errno.h>
#include <stdlib.h>
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;
goto lossage;
}
-
- enum file_handle_mode mode = MODE_TEXT;
- size_t length = 1024;
- size_t tab_width = 4;
-
-
switch (cmd.mode)
{
case FH_CHARACTER:
handle = create_file_handle (handle_name, cmd.s_name,
mode, length, tab_width);
-
+ free_file_handle (&cmd);
return CMD_SUCCESS;
lossage:
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. */
aw->writer = pfm_open_writer (handle, dict, porfile_opts);
break;
}
+
+ dict_destroy (dict);
return aw;
/* Transformation. */
struct output_trns
{
- struct trns_header h; /* Header. */
struct any_writer *aw; /* Writer. */
};
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)
{
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)
{
#include "calendar.h"
#include "command.h"
#include "dictionary.h"
-#include "do-ifP.h"
#include "error.h"
#include "file-handle.h"
#include "filename.h"
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;
struct file_handle *default_handle;
-struct ctl_stmt *ctl_stack;
-
/* log.h */
char *logfn;
FILE *logfile;
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
/* 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 (;;)
{
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))
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:
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 "
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 ();
}
/* 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);
/* 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. */
};
}
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);
/* 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);
}
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 "
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;
#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,
+ };
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)
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
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;
/* 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 *);
/* 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. */
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;
/* 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;
}
/* 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;
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;
/* 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;
/* 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)
if (prt->writer != NULL)
dfm_close_writer (prt->writer);
free (prt->line);
+ free (prt);
}
\f
/* PRINT SPACE. */
/* 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. */
}
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)
}
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);
}
/* RECODE transformation. */
struct recode_trns
{
- struct trns_header h;
struct rcd_var *codings;
};
#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);
}
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;
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;
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;
/* 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))
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;
}
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;
}
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;
/* 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. */
};
static trns_proc_func sample_trns_proc;
+static trns_free_func sample_trns_free;
int
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)
return -1;
}
}
+
+static void
+sample_trns_free (void *t_)
+{
+ struct sample_trns *t = t_;
+ free (t);
+}
02110-1301, USA. */
#include <config.h>
+#include <stdlib.h>
#include "alloc.h"
#include "command.h"
#include "dictionary.h"
/* SELECT IF transformation. */
struct select_if_trns
{
- struct trns_header h;
struct expression *e; /* Test expression. */
};
}
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. */
#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;
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. */
\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;
#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"
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);
}
/* Close any unclosed DO IF or LOOP constructs. */
- discard_ctl_stack ();
+ ctl_stack_clear ();
}
/* Transforms trns_case and writes it to the replacement active
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)
{
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:
/* 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
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);
cancel_transformations ();
- ctl_stack = NULL;
+ ctl_stack_clear ();
expr_free (process_if_expr);
process_if_expr = NULL;
#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)
{
+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.
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