X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fexpressions%2Fparse.c;h=b841953b7ea5125e3308975dab36efbda6d6d928;hb=db5df54124af56dc1dfce71f839d78da2b49e346;hp=2288d5277b6afb3e362ef00d979967219b09bc3e;hpb=d807ad29cc0d3caa4f0e04ee4b75c70a225cfeaf;p=pspp diff --git a/src/expressions/parse.c b/src/expressions/parse.c index 2288d5277b..b841953b7e 100644 --- a/src/expressions/parse.c +++ b/src/expressions/parse.c @@ -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 #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 *); /* Public functions. */ @@ -66,7 +68,7 @@ static bool type_check (struct expression *, union any_node **, Returns the new expression if successful or a null pointer otherwise. */ struct expression * -expr_parse (struct dictionary *dict, atom_type type) +expr_parse (struct dictionary *dict, enum expr_type type) { union any_node *n; struct expression *e; @@ -84,6 +86,19 @@ expr_parse (struct dictionary *dict, atom_type type) } } +/* Parses and returns an expression of the given TYPE, as + expr_parse(), and sets up so that destroying POOL will free + the expression as well. */ +struct expression * +expr_parse_pool (struct pool *pool, + struct dictionary *dict, enum expr_type type) +{ + struct expression *e = expr_parse (dict, type); + if (e != NULL) + pool_add_subpool (pool, e->expr_pool); + return e; +} + /* Free expression E. */ void expr_free (struct expression *e) @@ -267,13 +282,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 +349,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 +360,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 +403,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 +421,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 +430,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 +440,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 +536,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 +670,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 +802,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 +817,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 +878,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)); } /* Individual function parsing. */ @@ -879,14 +894,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 (buf_compare_case (*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 (buf_compare_case (*test, *name, test_len)) return false; } @@ -915,6 +930,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 +966,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)); } @@ -1025,7 +1046,7 @@ validate_function_args (const struct operation *f, int arg_cnt, int min_valid) { assert ((f->flags & OPF_MIN_VALID) == 0); msg (SE, _("%s function does not accept a minimum valid " - "argument count.")); + "argument count."), f->prototype); return false; } else @@ -1034,7 +1055,7 @@ validate_function_args (const struct operation *f, int arg_cnt, int min_valid) if (array_arg_cnt < f->array_min_elems) { msg (SE, _("%s requires at least %d valid arguments in list."), - f->prototype); + f->prototype, f->array_min_elems); return false; } else if (min_valid > array_arg_cnt) @@ -1098,14 +1119,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, '.'); @@ -1152,14 +1171,14 @@ parse_function (struct expression *e) if (token == T_ID && lex_look_ahead () == 'T') { struct variable **vars; - int var_cnt; - int i; + size_t var_cnt; + size_t i; if (!parse_variables (default_dict, &vars, &var_cnt, PV_SINGLE)) 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 +1223,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 +1292,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 +1446,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)); +}