X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fcompute.c;h=37592c885862c4b4d64064e251411ea5b3a06f9b;hb=92fb12eb06716d14c05b781f5d9dcde956d77c30;hp=aed443853d9a0d65800be651c7ebc80e2d368630;hpb=f85548f27a1958bb6c84a6917b874c537f4c0bd6;p=pspp diff --git a/src/compute.c b/src/compute.c index aed443853d..37592c8858 100644 --- a/src/compute.c +++ b/src/compute.c @@ -14,21 +14,26 @@ 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ #include -#include +#include "error.h" #include #include "alloc.h" +#include "case.h" #include "command.h" +#include "dictionary.h" #include "error.h" -#include "expr.h" +#include "expressions/public.h" #include "lexer.h" #include "misc.h" #include "str.h" #include "var.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + struct compute_trns; struct lvalue; @@ -36,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 *); @@ -44,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. */ @@ -62,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. */ @@ -75,140 +78,127 @@ cmd_compute (void) struct lvalue *lvalue = NULL; struct compute_trns *compute = NULL; - lex_match_id ("COMPUTE"); + 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; } /* Transformation functions. */ +/* Handle COMPUTE or IF with numeric target variable. */ static int -compute_num (struct trns_header *compute_, struct ccase *c) +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 (compute->test, c, NULL) == 1.0) - { - expr_evaluate (compute->rvalue, c, &c->data[compute->fv]); - } + || expr_evaluate_num (compute->test, c, case_num) == 1.0) + case_data_rw (c, compute->fv)->f = expr_evaluate_num (compute->rvalue, c, + case_num); return -1; } +/* Handle COMPUTE or IF with numeric vector element target + variable. */ static int -compute_num_vec (struct trns_header *compute_, struct ccase *c) +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 (compute->test, c, NULL) == 1.0) + || expr_evaluate_num (compute->test, c, case_num) == 1.0) { - /* Index into the vector. */ - union value index; + double index; /* Index into the vector. */ + int rindx; /* Rounded index value. */ - /* Rounded index value. */ - int rindx; - - expr_evaluate (compute->element, c, &index); - rindx = floor (index.f + EPSILON); - if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt) + index = expr_evaluate_num (compute->element, c, case_num); + rindx = floor (index + EPSILON); + if (index == SYSMIS || rindx < 1 || rindx > compute->vector->cnt) { - if (index.f == SYSMIS) + if (index == SYSMIS) msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value as " "an index into vector %s."), compute->vector->name); else msg (SW, _("When executing COMPUTE: %g is not a valid value as " "an index into vector %s."), - index.f, compute->vector->name); + index, compute->vector->name); return -1; } - expr_evaluate (compute->rvalue, c, - &c->data[compute->vector->var[rindx - 1]->fv]); + case_data_rw (c, compute->vector->var[rindx - 1]->fv)->f + = expr_evaluate_num (compute->rvalue, c, case_num); } return -1; } +/* Handle COMPUTE or IF with string target variable. */ static int -compute_str (struct trns_header *compute_, struct ccase *c) +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 (compute->test, c, NULL) == 1.0) - { - /* Temporary storage for string expression return value. */ - union value v; - - expr_evaluate (compute->rvalue, c, &v); - st_bare_pad_len_copy (c->data[compute->fv].s, &v.c[1], compute->width, - v.c[0]); - } + || expr_evaluate_num (compute->test, c, case_num) == 1.0) + expr_evaluate_str (compute->rvalue, c, case_num, + case_data_rw (c, compute->fv)->s, compute->width); return -1; } +/* Handle COMPUTE or IF with string vector element target + variable. */ static int -compute_str_vec (struct trns_header *compute_, struct ccase *c) +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 (compute->test, c, NULL) == 1.0) + || expr_evaluate_num (compute->test, c, case_num) == 1.0) { - /* Temporary storage for string expression return value. */ - union value v; + double index; /* Index into the vector. */ + int rindx; /* Rounded index value. */ + struct variable *vr; /* Variable reference by indexed vector. */ - /* Index into the vector. */ - union value index; - - /* Rounded index value. */ - int rindx; - - /* Variable reference by indexed vector. */ - struct variable *vr; - - expr_evaluate (compute->element, c, &index); - rindx = floor (index.f + EPSILON); - if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt) + index = expr_evaluate_num (compute->element, c, case_num); + rindx = floor (index + EPSILON); + if (index == SYSMIS) { - if (index.f == SYSMIS) - msg (SW, _("When executing COMPUTE: SYSMIS is not a valid " - "value as an index into vector %s."), - compute->vector->name); - else - msg (SW, _("When executing COMPUTE: %g is not a valid value as " - "an index into vector %s."), - index.f, compute->vector->name); + msg (SW, _("When executing COMPUTE: SYSMIS is not a valid " + "value as an index into vector %s."), + compute->vector->name); + return -1; + } + else if (rindx < 1 || rindx > compute->vector->cnt) + { + msg (SW, _("When executing COMPUTE: %g is not a valid value as " + "an index into vector %s."), + index, compute->vector->name); return -1; } - expr_evaluate (compute->rvalue, c, &v); vr = compute->vector->var[rindx - 1]; - st_bare_pad_len_copy (c->data[vr->fv].s, &v.c[1], vr->width, v.c[0]); + expr_evaluate_str (compute->rvalue, c, case_num, + case_data_rw (c, vr->fv)->s, vr->width); } return -1; @@ -222,11 +212,10 @@ cmd_if (void) struct compute_trns *compute = NULL; struct lvalue *lvalue = NULL; - lex_match_id ("IF"); compute = compute_trns_create (); /* Test expression. */ - compute->test = expr_parse (PXP_BOOLEAN); + compute->test = expr_parse (default_dict, EXPR_BOOLEAN); if (compute->test == NULL) goto fail; @@ -236,55 +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); - - assert (type == NUMERIC || type == ALPHA); + bool is_numeric = lvalue_get_type (lvalue) == NUMERIC; + bool is_vector = lvalue_is_vector (lvalue); - compute->rvalue = expr_parse (type == ALPHA ? PXP_STRING : PXP_NUMERIC); - 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. */ @@ -292,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; @@ -304,22 +281,29 @@ 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. */ struct lvalue { - char var_name[9]; /* Destination variable name, or "". */ + char var_name[LONG_NAME_LEN + 1]; /* Destination variable name, or "". */ const struct vector *vector; /* Destination vector, if any, or NULL. */ struct expression *element; /* Destination vector element, or NULL. */ }; +/* Parses the target variable or vector element into a new + `struct lvalue', which is returned. */ static struct lvalue * lvalue_parse (void) { @@ -347,7 +331,7 @@ lvalue_parse (void) lex_get (); if (!lex_force_match ('(')) goto lossage; - lvalue->element = expr_parse (PXP_NUMERIC); + lvalue->element = expr_parse (default_dict, EXPR_NUMBER); if (lvalue->element == NULL) goto lossage; if (!lex_force_match (')')) @@ -356,8 +340,7 @@ lvalue_parse (void) else { /* Variable name. */ - strncpy (lvalue->var_name, tokid, 8); - lvalue->var_name[8] = '\0'; + str_copy_trunc (lvalue->var_name, sizeof lvalue->var_name, tokid); lex_get (); } return lvalue; @@ -367,13 +350,14 @@ lvalue_parse (void) return NULL; } +/* Returns the type (NUMERIC or ALPHA) of the target variable or + vector in LVALUE. */ static int lvalue_get_type (const struct lvalue *lvalue) { if (lvalue->vector == NULL) { - struct variable *var - = dict_lookup_var (default_dict, lvalue->var_name); + struct variable *var = dict_lookup_var (default_dict, lvalue->var_name); if (var == NULL) return NUMERIC; else @@ -383,15 +367,17 @@ lvalue_get_type (const struct lvalue *lvalue) return lvalue->vector->var[0]->type; } -static int +/* Returns nonzero if LVALUE has a vector as its target. */ +static bool lvalue_is_vector (const struct lvalue *lvalue) { return lvalue->vector != NULL; } +/* Finalizes making LVALUE the target of COMPUTE, by creating the + target variable if necessary and setting fields in COMPUTE. */ static void -lvalue_finalize (struct lvalue *lvalue, - struct compute_trns *compute) +lvalue_finalize (struct lvalue *lvalue, struct compute_trns *compute) { if (lvalue->vector == NULL) { @@ -403,8 +389,6 @@ lvalue_finalize (struct lvalue *lvalue, compute->fv = compute->variable->fv; compute->width = compute->variable->width; - - /* Goofy behavior, but compatible: Turn off LEAVE. */ if (dict_class_from_id (compute->variable->name) != DC_SCRATCH) compute->variable->reinit = 1; @@ -419,31 +403,13 @@ lvalue_finalize (struct lvalue *lvalue, lvalue_destroy (lvalue); } +/* Destroys LVALUE. */ static void lvalue_destroy (struct lvalue *lvalue) { + if (lvalue == NULL) + return; + expr_free (lvalue->element); free (lvalue); } - -/* EVALUATE. */ - -int -cmd_evaluate (void) -{ - struct expression *expr; - - lex_match_id ("EVALUATE"); - expr = expr_parse (PXP_DUMP); - if (!expr) - return CMD_FAILURE; - - expr_free (expr); - if (token != '.') - { - msg (SE, _("Extra characters after expression.")); - return CMD_FAILURE; - } - - return CMD_SUCCESS; -}