Fixed bug 12931
[pspp-builds.git] / src / expressions / parse.c
index ea3b06a5dbd18ce5fa8394aad8d1c83c2801e9a3..15efe00bed59f56a8bddeeee0b3ef6fe374fb8cd 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 "private.h"
@@ -56,6 +56,8 @@ static struct expression *finish_expression (union any_node *,
                                              struct expression *);
 static bool type_check (struct expression *, union any_node **,
                         enum expr_type expected_type);
+static union any_node *allocate_unary_variable (struct expression *,
+                                                struct variable *); 
 \f
 /* Public functions. */
 
@@ -267,13 +269,12 @@ type_check (struct expression *e,
 /* Considers whether *NODE may be coerced to type REQUIRED_TYPE.
    Returns true if possible, false if disallowed.
 
-   If DO_COERCION is zero, then *NODE is not modified and there
+   If DO_COERCION is false, then *NODE is not modified and there
    are no side effects.
 
-   Otherwise, DO_COERCION is nonzero.  In this case, we perform
-   the coercion if possible, possibly modifying *NODE.  If the
-   coercion is not possible then we free *NODE and set *NODE to
-   a null pointer.
+   If DO_COERCION is true, we perform the coercion if possible,
+   modifying *NODE if necessary.  If the coercion is not possible
+   then we free *NODE and set *NODE to a null pointer.
 
    This function's interface is somewhat awkward.  Use one of the
    wrapper functions type_coercion(), type_coercion_assert(), or
@@ -335,7 +336,8 @@ type_coercion_core (struct expression *e,
 
     case OP_ni_format:
       if ((*node)->type == OP_format
-          && check_input_specifier (&(*node)->format.f, 0))
+          && check_input_specifier (&(*node)->format.f, false)
+          && check_specifier_type (&(*node)->format.f, NUMERIC, false))
         {
           if (do_coercion)
             (*node)->type = OP_ni_format;
@@ -345,7 +347,8 @@ type_coercion_core (struct expression *e,
 
     case OP_no_format:
       if ((*node)->type == OP_format
-          && check_output_specifier (&(*node)->format.f, 0))
+          && check_output_specifier (&(*node)->format.f, false)
+          && check_specifier_type (&(*node)->format.f, NUMERIC, false))
         {
           if (do_coercion)
             (*node)->type = OP_no_format;
@@ -387,10 +390,13 @@ type_coercion_core (struct expression *e,
     }
 
   if (do_coercion) 
-    msg (SE, _("Type mismatch while applying %s operator: "
-               "cannot convert %s to %s."),
-         operator_name,
-         atom_type_name (actual_type), atom_type_name (required_type));
+    {
+      msg (SE, _("Type mismatch while applying %s operator: "
+                 "cannot convert %s to %s."),
+           operator_name,
+           atom_type_name (actual_type), atom_type_name (required_type));
+      *node = NULL;
+    }
   return false;
 }
 
@@ -402,7 +408,7 @@ type_coercion (struct expression *e,
                atom_type required_type, union any_node **node,
                const char *operator_name)
 {
-  return type_coercion_core (e, required_type, node, operator_name, 1);
+  return type_coercion_core (e, required_type, node, operator_name, true);
 }
 
 /* Coerces *NODE to type REQUIRED_TYPE.
@@ -411,7 +417,7 @@ static void
 type_coercion_assert (struct expression *e,
                       atom_type required_type, union any_node **node)
 {
-  int success = type_coercion_core (e, required_type, node, NULL, 1);
+  int success = type_coercion_core (e, required_type, node, NULL, true);
   assert (success);
 }
 
@@ -421,7 +427,7 @@ static bool
 is_coercible (atom_type required_type, union any_node *const *node)
 {
   return type_coercion_core (NULL, required_type,
-                             (union any_node **) node, NULL, 0);
+                             (union any_node **) node, NULL, false);
 }
 
 /* How to parse an operator. */
@@ -517,7 +523,7 @@ parse_binary_operators (struct expression *e, union any_node *node,
 
       /* Convert the left-hand side to type OPERAND_TYPE. */
       if (!type_coercion (e, operand_type, &node, operator->name))
-        return node;
+        return NULL;
 
       /* Parse the right-hand side and coerce to type
          OPERAND_TYPE. */
@@ -651,7 +657,7 @@ parse_add (struct expression *e)
   static const struct operator ops[] = 
     {
       { '+', OP_ADD, "addition (\"+\")" },
-      { '-', OP_SUB, "subtraction (\"-\")-" },
+      { '-', OP_SUB, "subtraction (\"-\")" },
     };
   
   return parse_binary_operators (e, parse_mul (e),
@@ -783,12 +789,7 @@ parse_primary (struct expression *e)
           /* It looks like a user variable.
              (It could be a format specifier, but we'll assume
              it's a variable unless proven otherwise. */
-          struct variable *v = parse_dict_variable (e->dict);
-          assert (v != NULL);
-          return expr_allocate_unary (e,
-                                      (v->type == NUMERIC
-                                       ? OP_NUM_VAR : OP_STR_VAR),
-                                      expr_allocate_variable (e, v));
+          return allocate_unary_variable (e, parse_dict_variable (e->dict));
         }
       else 
         {
@@ -803,7 +804,8 @@ parse_primary (struct expression *e)
         }
       break;
       
-    case T_NUM: 
+    case T_POS_NUM: 
+    case T_NEG_NUM: 
       {
         union any_node *node = expr_allocate_number (e, tokval);
         lex_get ();
@@ -863,7 +865,7 @@ parse_vector_element (struct expression *e)
 
   return expr_allocate_binary (e, (vector->var[0]->type == NUMERIC
                                    ? OP_VEC_ELEM_NUM : OP_VEC_ELEM_STR),
-                               expr_allocate_vector (e, vector), element);
+                               element, expr_allocate_vector (e, vector));
 }
 \f
 /* Individual function parsing. */
@@ -879,14 +881,14 @@ word_matches (const char **test, const char **name)
   size_t name_len = strcspn (*name, ".");
   if (test_len == name_len) 
     {
-      if (memcmp (*test, *name, test_len))
+      if (mm_case_compare (*test, *name, test_len))
         return false;
     }
   else if (test_len < 3 || test_len > name_len)
     return false;
   else 
     {
-      if (memcmp (*test, *name, test_len))
+      if (mm_case_compare (*test, *name, test_len))
         return false;
     }
 
@@ -915,6 +917,12 @@ compare_names (const char *test, const char *name)
     }
 }
 
+static int
+compare_strings (const char *test, const char *name) 
+{
+  return strcasecmp (test, name);
+}
+
 static bool
 lookup_function_helper (const char *name,
                         int (*compare) (const char *test, const char *name),
@@ -945,7 +953,7 @@ lookup_function (const char *name,
                  const struct operation **last) 
 {
   *first = *last = NULL;
-  return (lookup_function_helper (name, strcmp, first, last)
+  return (lookup_function_helper (name, compare_strings, first, last)
           || lookup_function_helper (name, compare_names, first, last));
 }
 
@@ -1098,14 +1106,12 @@ no_match (const char *func_name,
     }
   else 
     {
-      ds_create (&s, _("Function invocation "));
+      ds_puts (&s, _("Function invocation "));
       put_invocation (&s, func_name, args, arg_cnt);
       ds_puts (&s, _(" does not match any known function.  Candidates are:"));
 
       for (f = first; f < last; f++)
-        {
-          ds_printf (&s, "\n%s", f->prototype);
-        }
+        ds_printf (&s, "\n%s", f->prototype);
     }
   ds_putc (&s, '.');
 
@@ -1159,7 +1165,7 @@ parse_function (struct expression *e)
               goto fail;
             for (i = 0; i < var_cnt; i++)
               add_arg (&args, &arg_cnt, &arg_cap,
-                       expr_allocate_variable (e, vars[i]));
+                       allocate_unary_variable (e, vars[i]));
             free (vars);
           }
         else
@@ -1204,13 +1210,18 @@ parse_function (struct expression *e)
   n = expr_allocate_composite (e, f - operations, args, arg_cnt);
   n->composite.min_valid = min_valid != -1 ? min_valid : f->array_min_elems; 
 
-  if (n->type == OP_LAG_Vnn || n->type == OP_LAG_Vsn) 
+  if (n->type == OP_LAG_Vn || n->type == OP_LAG_Vs) 
+    {
+      if (n_lag < 1)
+        n_lag = 1; 
+    }
+  else if (n->type == OP_LAG_Vnn || n->type == OP_LAG_Vsn)
     {
       int n_before;
       assert (n->composite.arg_cnt == 2);
       assert (n->composite.args[1]->type == OP_pos_int);
       n_before = n->composite.args[1]->integer.i;
-      if (n_before > n_lag)
+      if (n_lag < n_before)
         n_lag = n_before;
     }
   
@@ -1268,7 +1279,7 @@ expr_allocate_nullary (struct expression *e, operation_type op)
 
 union any_node *
 expr_allocate_unary (struct expression *e, operation_type op,
-union any_node *arg0)
+                     union any_node *arg0)
 {
   return expr_allocate_composite (e, op, &arg0, 1);
 }
@@ -1422,3 +1433,13 @@ expr_allocate_format (struct expression *e, const struct fmt_spec *format)
   n->format.f = *format;
   return n;
 }
+
+/* Allocates a unary composite node that represents the value of
+   variable V in expression E. */
+static union any_node *
+allocate_unary_variable (struct expression *e, struct variable *v) 
+{
+  assert (v != NULL);
+  return expr_allocate_unary (e, v->type == NUMERIC ? OP_NUM_VAR : OP_STR_VAR,
+                              expr_allocate_variable (e, v));
+}