Adopt use of gnulib for portability.
[pspp-builds.git] / src / compute.c
index ff127e359f7e984f51075e9117700ddad54bf3c9..6e6bd96ad18992c1b361b2d191825d6c0459ff7a 100644 (file)
 
    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 <config.h>
-#include <assert.h>
+#include "error.h"
 #include <stdlib.h>
 #include "alloc.h"
-#include "approx.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;
 
@@ -75,8 +80,6 @@ cmd_compute (void)
   struct lvalue *lvalue = NULL;
   struct compute_trns *compute = NULL;
 
-  lex_match_id ("COMPUTE");
-
   lvalue = lvalue_parse ();
   if (lvalue == NULL)
     goto fail;
@@ -104,111 +107,105 @@ cmd_compute (void)
 \f
 /* Transformation functions. */
 
+/* Handle COMPUTE or IF with numeric target variable. */
 static int
-compute_num (struct trns_header *compute_, struct ccase *c)
+compute_num (struct trns_header *compute_, struct ccase *c,
+             int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) 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 (struct trns_header *compute_, struct ccase *c,
+                 int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) 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;
-
-      /* Rounded index value. */
-      int rindx;
+      double index;     /* Index into the vector. */
+      int rindx;        /* Rounded index value. */
 
-      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 (struct trns_header *compute_, struct ccase *c,
+             int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) 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 (struct trns_header *compute_, struct ccase *c,
+                 int case_num)
 {
   struct compute_trns *compute = (struct compute_trns *) 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;
-
-      /* Index into the vector. */
-      union value index;
-
-      /* Rounded index value. */
-      int rindx;
-
-      /* Variable reference by indexed vector. */
-      struct variable *vr;
+      double index;             /* Index into the vector. */
+      int rindx;                /* Rounded index value. */
+      struct variable *vr;      /* Variable reference by indexed vector. */
 
-      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 +219,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;
 
@@ -269,7 +265,8 @@ parse_rvalue_expression (struct compute_trns *compute,
 
   assert (type == NUMERIC || type == ALPHA);
 
-  compute->rvalue = expr_parse (type == ALPHA ? PXP_STRING : PXP_NUMERIC);
+  compute->rvalue = expr_parse (default_dict,
+                                type == ALPHA ? EXPR_STRING : EXPR_NUMBER);
   if (compute->rvalue == NULL)
     return 0;
 
@@ -313,13 +310,16 @@ compute_trns_free (struct trns_header *compute_)
   expr_free (compute->rvalue);
 }
 \f
+/* 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 +347,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 +356,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 +366,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,12 +383,15 @@ lvalue_get_type (const struct lvalue *lvalue)
     return lvalue->vector->var[0]->type;
 }
 
+/* Returns nonzero if LVALUE has a vector as its target. */
 static int
 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) 
@@ -397,8 +400,9 @@ lvalue_finalize (struct lvalue *lvalue,
     {
       compute->variable = dict_lookup_var (default_dict, lvalue->var_name);
       if (compute->variable == NULL)
-        compute->variable = dict_create_var_assert (default_dict,
-                                                    lvalue->var_name, 0);
+         compute->variable = dict_create_var_assert (default_dict,
+                                                     lvalue->var_name, 0);
+
       compute->fv = compute->variable->fv;
       compute->width = compute->variable->width;
 
@@ -416,31 +420,13 @@ lvalue_finalize (struct lvalue *lvalue,
   lvalue_destroy (lvalue);
 }
 
+/* Destroys LVALUE. */
 static void 
 lvalue_destroy (struct lvalue *lvalue) 
 {
+  if ( ! lvalue ) 
+     return ;
+
   expr_free (lvalue->element);
   free (lvalue);
 }
-\f
-/* 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;
-}