Subcommand to export a model as a C function
[pspp-builds.git] / src / compute.c
index e6afe0b62d7e76383f54f524cfbec587a5058a66..37592c885862c4b4d64064e251411ea5b3a06f9b 100644 (file)
@@ -14,8 +14,8 @@
 
    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 "error.h"
@@ -31,6 +31,9 @@
 #include "str.h"
 #include "var.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 struct compute_trns;
 struct lvalue;
 
@@ -38,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 *);
@@ -46,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. */
 
@@ -64,10 +65,10 @@ struct compute_trns
     struct expression *rvalue;  /* Rvalue expression. */
   };
 
-static int parse_rvalue_expression (struct compute_trns *,
-                                    const struct lvalue *);
+static struct expression *parse_rvalue (const struct lvalue *);
 static struct compute_trns *compute_trns_create (void);
-static void compute_trns_free (struct trns_header *);
+static trns_proc_func *get_proc_func (const struct lvalue *);
+static trns_free_func compute_trns_free;
 \f
 /* COMPUTE. */
 
@@ -77,28 +78,27 @@ cmd_compute (void)
   struct lvalue *lvalue = NULL;
   struct compute_trns *compute = NULL;
 
+  compute = compute_trns_create ();
+
   lvalue = lvalue_parse ();
   if (lvalue == NULL)
     goto fail;
 
-  compute = compute_trns_create ();
-
-  if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
+  if (!lex_force_match ('='))
+    goto fail;
+  compute->rvalue = parse_rvalue (lvalue);
+  if (compute->rvalue == NULL)
     goto fail;
 
-  lvalue_finalize (lvalue, compute);
+  add_transformation (get_proc_func (lvalue), compute_trns_free, compute);
 
-  add_transformation (&compute->h);
+  lvalue_finalize (lvalue, compute);
 
-  return CMD_SUCCESS;
+  return lex_end_of_command ();
 
  fail:
   lvalue_destroy (lvalue);
-  if (compute != NULL) 
-    {
-      compute_trns_free (&compute->h);
-      free (compute); 
-    }
+  compute_trns_free (compute);
   return CMD_FAILURE;
 }
 \f
@@ -106,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) 
@@ -122,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) 
@@ -155,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) 
@@ -171,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) 
@@ -229,56 +225,45 @@ cmd_if (void)
     goto fail;
 
   /* Rvalue expression. */
-  if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
+  if (!lex_force_match ('='))
+    goto fail;
+  compute->rvalue = parse_rvalue (lvalue);
+  if (compute->rvalue == NULL)
     goto fail;
 
-  lvalue_finalize (lvalue, compute);
+  add_transformation (get_proc_func (lvalue), compute_trns_free, compute);
 
-  add_transformation (&compute->h);
+  lvalue_finalize (lvalue, compute);
 
-  return CMD_SUCCESS;
+  return lex_end_of_command ();
 
  fail:
   lvalue_destroy (lvalue);
-  if (compute != NULL) 
-    {
-      compute_trns_free (&compute->h);
-      free (compute); 
-    }
+  compute_trns_free (compute);
   return CMD_FAILURE;
 }
 \f
 /* Code common to COMPUTE and IF. */
 
-/* Checks for type mismatches on transformation C.  Also checks for
-   command terminator, sets the case-handling proc from the array
-   passed. */
-static int
-parse_rvalue_expression (struct compute_trns *compute,
-                         const struct lvalue *lvalue)
+static trns_proc_func *
+get_proc_func (const struct lvalue *lvalue) 
 {
-  int type = lvalue_get_type (lvalue);
-  int vector = lvalue_is_vector (lvalue);
+  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
+  bool is_vector = lvalue_is_vector (lvalue);
 
-  assert (type == NUMERIC || type == ALPHA);
-
-  compute->rvalue = expr_parse (default_dict,
-                                type == ALPHA ? EXPR_STRING : EXPR_NUMBER);
-  if (compute->rvalue == NULL)
-    return 0;
+  return (is_numeric
+          ? (is_vector ? compute_num_vec : compute_num)
+          : (is_vector ? compute_str_vec : compute_str));
+}
 
-  if (type == NUMERIC)
-    compute->h.proc = vector ? compute_num_vec : compute_num;
-  else
-    compute->h.proc = vector ? compute_str_vec : compute_str;
+/* Parses and returns an rvalue expression of the same type as
+   LVALUE, or a null pointer on failure. */
+static struct expression *
+parse_rvalue (const struct lvalue *lvalue)
+{
+  bool is_numeric = lvalue_get_type (lvalue) == NUMERIC;
 
-  if (token != '.')
-    {
-      lex_error (_("expecting end of command"));
-      return 0;
-    }
-  
-  return 1;
+  return expr_parse (default_dict, is_numeric ? EXPR_NUMBER : EXPR_STRING);
 }
 
 /* Returns a new struct compute_trns after initializing its fields. */
@@ -286,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;
@@ -298,24 +281,28 @@ compute_trns_create (void)
 
 /* Deletes all the fields in COMPUTE. */
 static void
-compute_trns_free (struct trns_header *compute_)
+compute_trns_free (void *compute_)
 {
-  struct compute_trns *compute = (struct compute_trns *) compute_;
+  struct compute_trns *compute = compute_;
 
-  expr_free (compute->test);
-  expr_free (compute->element);
-  expr_free (compute->rvalue);
+  if (compute != NULL) 
+    {
+      expr_free (compute->test);
+      expr_free (compute->element);
+      expr_free (compute->rvalue);
+      free (compute);
+    }
 }
 \f
 /* COMPUTE or IF target variable or vector element. */
 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 elector into a new
+/* Parses the target variable or vector element into a new
    `struct lvalue', which is returned. */
 static struct lvalue *
 lvalue_parse (void) 
@@ -353,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;
@@ -371,8 +357,7 @@ 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,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;
@@ -392,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)
     {
@@ -423,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);