From ad01fea350354a7df11790a561e935a8bffd3636 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 3 Nov 2005 06:21:46 +0000 Subject: [PATCH] DO IF, LOOP cleanup. 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. --- src/ChangeLog | 86 +++++ src/Makefile.am | 238 +++++++++++-- src/autorecode.c | 43 +-- src/compute.c | 133 ++++---- src/count.c | 20 +- src/ctl-stack.c | 93 ++++++ src/ctl-stack.h | 39 +++ src/data-list.c | 72 ++-- src/data-list.h | 2 +- src/descript.c | 14 +- src/dfm-read.c | 1 + src/do-if.c | 408 ++++++++++------------ src/do-ifP.h | 83 ----- src/expressions/parse.c | 13 + src/expressions/public.h | 3 + src/file-handle-def.c | 1 + src/file-handle.q | 11 +- src/file-type.c | 3 +- src/get.c | 15 +- src/glob.c | 9 +- src/inpt-pgm.c | 45 +-- src/loop.c | 706 +++++++++++++-------------------------- src/pool.c | 42 +++ src/pool.h | 9 + src/print.c | 40 +-- src/recode.c | 30 +- src/sample.c | 17 +- src/sel-if.c | 16 +- src/temporary.c | 6 +- src/var.h | 23 +- src/vfm.c | 44 ++- src/weight.c | 8 - tests/ChangeLog | 4 + tests/command/loop.sh | 1 - 34 files changed, 1152 insertions(+), 1126 deletions(-) create mode 100644 src/ctl-stack.c create mode 100644 src/ctl-stack.h delete mode 100644 src/do-ifP.h diff --git a/src/ChangeLog b/src/ChangeLog index 0d65dcd8..ba6d517a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,89 @@ +Wed Nov 2 21:24:48 2005 Ben Pfaff + + * 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 + + 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 + + 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 + + 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 * count.c: Major cleanups. Rename practically everything. diff --git a/src/Makefile.am b/src/Makefile.am index 15734f10..7a52f2b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 - noinst_PROGRAMS = q2c q2c_SOURCES = q2c.c diff --git a/src/autorecode.c b/src/autorecode.c index bf38d922..5240423d 100644 --- a/src/autorecode.c +++ b/src/autorecode.c @@ -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); } /* AUTORECODE procedure. */ diff --git a/src/compute.c b/src/compute.c index 6e6bd96a..37592c88 100644 --- a/src/compute.c +++ b/src/compute.c @@ -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; /* 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; } @@ -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; } /* 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); + } } /* 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); diff --git a/src/count.c b/src/count.c index 38374fa6..26509dcf 100644 --- a/src/count.c +++ b/src/count.c @@ -80,19 +80,16 @@ struct dst_var struct count_trns { - struct trns_header h; struct dst_var *dst_vars; struct pool *pool; }; - -/* 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 *); - + 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 index 00000000..1536094b --- /dev/null +++ b/src/ctl-stack.c @@ -0,0 +1,93 @@ +#include +#include "ctl-stack.h" +#include +#include +#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 index 00000000..87ef4bee --- /dev/null +++ b/src/ctl-stack.h @@ -0,0 +1,39 @@ +/* PSPP - computes sample statistics. + Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Written by Ben Pfaff . + + 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 + +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 */ diff --git a/src/data-list.c b/src/data-list.c index d1dbbc24..b615beea 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -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; } diff --git a/src/data-list.h b/src/data-list.h index dae80e35..80545f7e 100644 --- a/src/data-list.h +++ b/src/data-list.h @@ -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 */ diff --git a/src/descript.c b/src/descript.c index 0a96b65e..a7152301 100644 --- a/src/descript.c +++ b/src/descript.c @@ -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); } /* Statistical calculation. */ diff --git a/src/dfm-read.c b/src/dfm-read.c index 238b8080..6d173cf3 100644 --- a/src/dfm-read.c +++ b/src/dfm-read.c @@ -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" diff --git a/src/do-if.c b/src/do-if.c index 1acf8493..ad636f79 100644 --- a/src/do-if.c +++ b/src/do-if.c @@ -18,7 +18,7 @@ 02110-1301, USA. */ #include -#include "do-ifP.h" +#include "ctl-stack.h" #include "error.h" #include #include "alloc.h" @@ -32,159 +32,95 @@ #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<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V - V V - >>1. ELSE IF V - V<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V - V V - >>1. ELSE IF V - V<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>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 index 3570a901..00000000 --- a/src/do-ifP.h +++ /dev/null @@ -1,83 +0,0 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . - - 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 */ diff --git a/src/expressions/parse.c b/src/expressions/parse.c index 14dedfc9..b841953b 100644 --- a/src/expressions/parse.c +++ b/src/expressions/parse.c @@ -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) diff --git a/src/expressions/public.h b/src/expressions/public.h index f4d89350..9a90cef7 100644 --- a/src/expressions/public.h +++ b/src/expressions/public.h @@ -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 *, diff --git a/src/file-handle-def.c b/src/file-handle-def.c index 5dd13e54..6cf572b3 100644 --- a/src/file-handle-def.c +++ b/src/file-handle-def.c @@ -19,6 +19,7 @@ #include #include "file-handle.h" +#include "file-handle-def.h" #include "error.h" #include #include diff --git a/src/file-handle.q b/src/file-handle.q index 98b2354c..24a91a9f 100644 --- a/src/file-handle.q +++ b/src/file-handle.q @@ -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: diff --git a/src/file-type.c b/src/file-type.c index 0774c683..ff97f8db 100644 --- a/src/file-type.c +++ b/src/file-type.c @@ -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. */ diff --git a/src/get.c b/src/get.c index af6607ba..e47850c3 100644 --- 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) { diff --git a/src/glob.c b/src/glob.c index 1b5de099..a026ede6 100644 --- a/src/glob.c +++ b/src/glob.c @@ -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; diff --git a/src/inpt-pgm.c b/src/inpt-pgm.c index eb2503c7..eaa19532 100644 --- a/src/inpt-pgm.c +++ b/src/inpt-pgm.c @@ -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; diff --git a/src/loop.c b/src/loop.c index 06936778..f388d9e2 100644 --- a/src/loop.c +++ b/src/loop.c @@ -23,11 +23,12 @@ #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" @@ -35,552 +36,327 @@ #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 *); /* 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 initloop_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); } - -/* 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; -} - -/* 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, + }; diff --git a/src/pool.c b/src/pool.c index 0f6b11e0..e8aede40 100644 --- a/src/pool.c +++ b/src/pool.c @@ -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 diff --git a/src/pool.h b/src/pool.h index ff589843..fc23df05 100644 --- a/src/pool.h +++ b/src/pool.h @@ -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 *); diff --git a/src/print.c b/src/print.c index a42c82d5..0376fa1c 100644 --- a/src/print.c +++ b/src/print.c @@ -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); } /* 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); } diff --git a/src/recode.c b/src/recode.c index b364a1ac..394e9be1 100644 --- a/src/recode.c +++ b/src/recode.c @@ -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; diff --git a/src/sample.c b/src/sample.c index 57548c1c..fceadbbb 100644 --- a/src/sample.c +++ b/src/sample.c @@ -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); +} diff --git a/src/sel-if.c b/src/sel-if.c index c703e2f4..10d1030f 100644 --- a/src/sel-if.c +++ b/src/sel-if.c @@ -18,6 +18,7 @@ 02110-1301, USA. */ #include +#include #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. */ diff --git a/src/temporary.c b/src/temporary.c index f277152e..840e5d2b 100644 --- a/src/temporary.c +++ b/src/temporary.c @@ -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" @@ -37,14 +37,14 @@ 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; diff --git a/src/var.h b/src/var.h index a1059a20..802004bc 100644 --- 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 *); /* 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); struct var_set; diff --git a/src/vfm.c b/src/vfm.c index 08e3ca30..7f2cb693 100644 --- 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; diff --git a/src/weight.c b/src/weight.c index 9128bc3e..f1326f09 100644 --- a/src/weight.c +++ b/src/weight.c @@ -30,14 +30,6 @@ #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) { diff --git a/tests/ChangeLog b/tests/ChangeLog index 0b5d0de2..67610b89 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +Wed Nov 2 21:54:11 2005 Ben Pfaff + + * command/loop.sh: Update expected error messages. + Sun Aug 21 00:20:02 2005 Ben Pfaff * command/import-export.sh: Simplify. diff --git a/tests/command/loop.sh b/tests/command/loop.sh index 1e76c6da..bcf4bfcd 100755 --- a/tests/command/loop.sh +++ b/tests/command/loop.sh @@ -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 - <