Fixed a bug causing pspp to crash when computed variables had no format
[pspp-builds.git] / src / expr-evl.c
index b8991547a359ae9a43f68331d9e9c536e4288e42..a1b540e4974d984f78036eb8305be6ed285c5682 100644 (file)
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA. */
 
-/* AIX requires this to be the first thing in the file.  */
 #include <config.h>
-#if __GNUC__
-#define alloca __builtin_alloca
-#else
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else
-#ifdef _AIX
-#pragma alloca
-#else
-#ifndef alloca                 /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#endif
-#endif
-#endif
-#endif
 
 #if TIME_WITH_SYS_TIME
 #include <sys/time.h>
@@ -53,11 +37,12 @@ char *alloca ();
 #include <math.h>
 #include <errno.h>
 #include <stdio.h>
-#include "approx.h"
 #include "data-in.h"
 #include "error.h"
 #include "julcal/julcal.h"
 #include "magic.h"
+#include "misc.h"
+#include "pool.h"
 #include "random.h"
 #include "stats.h"
 #include "str.h"
@@ -65,62 +50,20 @@ char *alloca ();
 #include "vfm.h"
 #include "vfmP.h"
 
-/* FIXME: This could be even more efficient if we caught SYSMIS when
-   it first reared its ugly head, then threw it into an entirely new
-   switch that handled SYSMIS aggressively like all the code does now.
-   But I've spent a couple of weeks on the expression code, and that's
-   enough to make anyone sick.  For that matter, it could be more
-   efficient if I hand-coded it in assembly for a dozen processors,
-   but I'm not going to do that either. */
-
-/* These macros are defined differently depending on the way that
-   the stack is managed.  (i.e., I have to adapt the code to inferior
-   environments.)
-
-   void CHECK_STRING_SPACE(int x): Assure that at least X+1 bytes of
-   space are available in the string evaluation stack.
-
-   unsigned char *ALLOC_STRING_SPACE(int x): Return a pointer to X+1
-   bytes of space.  CHECK_STRING_SPACE must have previously been
-   called with an argument of at least X. */
-
-#if PAGED_STACK
-#define CHECK_STRING_SPACE(X)  /* nothing to do! */
-#define ALLOC_STRING_SPACE(X)                  \
-       alloca((X) + 1)
-#else /* !PAGED_STACK */
-#define CHECK_STRING_SPACE(X)                                          \
-       do                                                              \
-          {                                                            \
-           if (str_stk + X >= str_end)                                 \
-             {                                                         \
-               e->str_size += 1024;                                    \
-               e->str_stk = xrealloc (e->str_stk, e->str_size);        \
-               str_end = e->str_stk + e->str_size - 1;                 \
-             }                                                         \
-         }                                                             \
-       while (0)
-     
-#define ALLOC_STRING_SPACE(X)                  \
-       (str_stk += X + 1, str_stk - X - 1)
-#endif /* !PAGED_STACK */
-
 double
 expr_evaluate (struct expression *e, struct ccase *c, union value *v)
 {
   unsigned char *op = e->op;
   double *dbl = e->num;
   unsigned char *str = e->str;
-#if !PAGED_STACK
-  unsigned char *str_stk = e->str_stk;
-  unsigned char *str_end = e->str_stk + e->str_size - 1;
-#endif
   struct variable **vars = e->var;
   int i, j;
 
   /* Stack pointer. */
   union value *sp = e->stack;
 
+  pool_clear (e->pool);
+
   for (;;)
     {
       switch (*op++)
@@ -159,7 +102,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
          sp--;
          if (sp[0].f == SYSMIS)
            {
-             if (approx_eq (sp[1].f, 0.0))
+             if (sp[1].f == 0.0)
                sp->f = 1.0;
            }
          else if (sp[1].f == SYSMIS)
@@ -170,16 +113,14 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              else
                sp->f = SYSMIS;
            }
-         else if (approx_eq (sp[0].f, 0.0) && approx_eq (sp[1].f, 0.0))
+         else if (sp[0].f == 0.0 && sp[1].f == 0.0)
            sp->f = SYSMIS;
          else
            sp->f = pow (sp[0].f, sp[1].f);
          break;
 
        case OP_AND:
-         /* Note that the equality operator (==) may be used here
-            (instead of approx_eq) because booleans are always
-            *exactly* 0, 1, or SYSMIS.
+         /* Note that booleans are always one of 0, 1, or SYSMIS.
 
             Truth table (in order of detection):
 
@@ -250,7 +191,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_eq (sp[0].f, sp[1].f);
+               sp->f = sp[0].f == sp[1].f;
            }
          break;
        case OP_GE:
@@ -260,7 +201,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_ge (sp[0].f, sp[1].f);
+               sp->f = sp[0].f >= sp[1].f;
            }
          break;
        case OP_GT:
@@ -270,7 +211,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_gt (sp[0].f, sp[1].f);
+               sp->f = sp[0].f > sp[1].f;
            }
          break;
        case OP_LE:
@@ -280,7 +221,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_le (sp[0].f, sp[1].f);
+               sp->f = sp[0].f <= sp[1].f;
            }
          break;
        case OP_LT:
@@ -290,7 +231,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_lt (sp[0].f, sp[1].f);
+               sp->f = sp[0].f < sp[1].f;
            }
          break;
        case OP_NE:
@@ -300,7 +241,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              if (sp[1].f == SYSMIS)
                sp->f = SYSMIS;
              else
-               sp->f = approx_ne (sp[0].f, sp[1].f);
+               sp->f = sp[0].f != sp[1].f;
            }
          break;
 
@@ -453,7 +394,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            if (sp->f == SYSMIS)
              break;
            for (i = 1; i <= n_args; i++)
-             if (approx_eq (sp[0].f, sp[i].f))
+             if (sp[0].f == sp[i].f)
                {
                  sp->f = 1.0;
                  goto main_loop;
@@ -594,8 +535,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            for (i = 1; i <= n_args; i += 2)
              if (sp[i].f == SYSMIS || sp[i + 1].f == SYSMIS)
                continue;
-             else if (approx_ge (sp[0].f, sp[i].f)
-                      && approx_le (sp[0].f, sp[i + 1].f))
+             else if (sp[0].f >= sp[i].f && sp[0].f <= sp[i + 1].f)
                {
                  sp->f = 1.0;
                  goto main_loop;
@@ -829,8 +769,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            int n_args = *op++;
            unsigned char *dest;
 
-           CHECK_STRING_SPACE (255);
-           dest = ALLOC_STRING_SPACE (255);
+           dest = pool_alloc (e->pool, 256);
            dest[0] = 0;
 
            sp -= n_args - 1;
@@ -952,8 +891,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              {
                unsigned char *dest;
 
-               CHECK_STRING_SPACE (len);
-               dest = ALLOC_STRING_SPACE (len);
+               dest = pool_alloc (e->pool, len + 1);
                dest[0] = len;
                memset (&dest[1], ' ', len - sp->c[0]);
                memcpy (&dest[len - sp->c[0] + 1], &sp->c[1], sp->c[0]);
@@ -972,8 +910,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              {
                unsigned char *dest;
 
-               CHECK_STRING_SPACE (len);
-               dest = ALLOC_STRING_SPACE (len);
+               dest = pool_alloc (e->pool, len + 1);
                dest[0] = len;
                memset (&dest[1], sp[2].c[1], len - sp->c[0]);
                memcpy (&dest[len - sp->c[0] + 1], &sp->c[1], sp->c[0]);
@@ -992,8 +929,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              {
                unsigned char *dest;
 
-               CHECK_STRING_SPACE (len);
-               dest = ALLOC_STRING_SPACE (len);
+               dest = pool_alloc (e->pool, len + 1);
                dest[0] = len;
                memcpy (&dest[1], &sp->c[1], sp->c[0]);
                memset (&dest[sp->c[0] + 1], ' ', len - sp->c[0]);
@@ -1012,8 +948,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
              {
                unsigned char *dest;
 
-               CHECK_STRING_SPACE (len);
-               dest = ALLOC_STRING_SPACE (len);
+               dest = pool_alloc (e->pool, len + 1);
                dest[0] = len;
                memcpy (&dest[1], &sp->c[1], sp->c[0]);
                memset (&dest[sp->c[0] + 1], sp[2].c[1], len - sp->c[0]);
@@ -1112,10 +1047,10 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            f.w = *op++;
            f.d = *op++;
 
-           CHECK_STRING_SPACE (f.w);
-           dest = ALLOC_STRING_SPACE (f.w);
+           dest = pool_alloc (e->pool, f.w + 1);
            dest[0] = f.w;
 
+            assert ((formats[f.type].cat & FCAT_STRING) == 0);
            data_out (&dest[1], &f, sp);
            sp->c = dest;
          }
@@ -1171,9 +1106,9 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            sp->f *= sp->f;
          break;
        case OP_NUM_TO_BOOL:
-         if (approx_eq (sp->f, 0.0))
+         if (sp->f == 0.0)
            sp->f = 0.0;
-         else if (approx_eq (sp->f, 1.0))
+         else if (sp->f == 1.0)
            sp->f = 1.0;
          else if (sp->f != SYSMIS)
            {
@@ -1192,7 +1127,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            {
              if (sp[1].f == SYSMIS)
                {
-                 if (approx_ne (sp[0].f, 0.0))
+                 if (sp[0].f != 0.0)
                    sp->f = SYSMIS;
                }
              else
@@ -1251,15 +1186,13 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
                  msg (SE, _("%g is not a valid index value for vector %s.  "
                             "The result will be set to the empty string."),
                       sp[0].f, vect->name);
-               CHECK_STRING_SPACE (0);
-               sp->c = ALLOC_STRING_SPACE (0);
+               sp->c = pool_alloc (e->pool, 1);
                sp->c[0] = 0;
                break;
              }
 
            v = vect->var[rindx - 1];
-           CHECK_STRING_SPACE (v->width);
-           sp->c = ALLOC_STRING_SPACE (v->width);
+           sp->c = pool_alloc (e->pool, v->width + 1);
            sp->c[0] = v->width;
            memcpy (&sp->c[1], c->data[v->fv].s, v->width);
          }
@@ -1272,8 +1205,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
          break;
        case OP_STR_CON:
          sp++;
-         CHECK_STRING_SPACE (*str);
-         sp->c = ALLOC_STRING_SPACE (*str);
+         sp->c = pool_alloc (e->pool, *str + 1);
          memcpy (sp->c, str, *str + 1);
          str += *str + 1;
          break;
@@ -1289,8 +1221,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            int width = (*vars)->width;
 
            sp++;
-           CHECK_STRING_SPACE (width);
-           sp->c = ALLOC_STRING_SPACE (width);
+           sp->c = pool_alloc (e->pool, width + 1);
            sp->c[0] = width;
            memcpy (&sp->c[1], &c->data[(*vars)->fv], width);
            vars++;
@@ -1318,8 +1249,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
            int width = (*vars)->width;
 
            sp++;
-           CHECK_STRING_SPACE (width);
-           sp->c = ALLOC_STRING_SPACE (width);
+           sp->c = pool_alloc (e->pool, width + 1);
            sp->c[0] = width;
            
            if (c == NULL)
@@ -1352,12 +1282,6 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v)
          goto finished;
 
        default:
-#if GLOBAL_DEBUGGING
-         printf (_("evaluate_expression(): not implemented: %s\n"),
-                 ops[op[-1]].name);
-#else
-         printf (_("evaluate_expression(): not implemented: %d\n"), op[-1]);
-#endif
          assert (0);
        }
 
@@ -1377,12 +1301,7 @@ finished:
     {
       assert (v);
 
-#if PAGED_STACK
-      memcpy (e->str_stack, sp->c, sp->c[0] + 1);
-      v->c = e->str_stack;
-#else
       v->c = sp->c;
-#endif
 
       return 0.0;
     }