X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fexpressions%2Fparse.c;h=1e3844a6cf1a1d0541407a634ee1d44f2714cb05;hb=refs%2Fheads%2Fctables3;hp=2b78b0b14b41491cc172fc301ac4476fdf0765ba;hpb=d3c96903451307e60d1d4a680ecf58c86cac7eaa;p=pspp diff --git a/src/language/expressions/parse.c b/src/language/expressions/parse.c index 2b78b0b14b..1e3844a6cf 100644 --- a/src/language/expressions/parse.c +++ b/src/language/expressions/parse.c @@ -60,12 +60,22 @@ atom_type expr_node_returns (const struct expr_node *); static const char *atom_type_name (atom_type); static struct expression *finish_expression (struct expr_node *, struct expression *); -static bool type_check (const struct expr_node *, enum val_type expected_type); +static bool type_check (const struct expression *, const struct expr_node *, + enum val_type expected_type); static struct expr_node *allocate_unary_variable (struct expression *, const struct variable *); /* Public functions. */ +static struct expr_node * +parse_expr (struct lexer *lexer, struct expression *e) +{ + struct expr_node *n = parse_or (lexer, e); + if (n && n->type == OP_VEC_ELEM_NUM_RAW) + n->type = OP_VEC_ELEM_NUM; + return n; +} + /* Parses an expression of the given TYPE. If DS is nonnull then variables and vectors within it may be referenced within the expression; otherwise, the expression must not reference any variables or vectors. Returns the new @@ -76,8 +86,8 @@ expr_parse (struct lexer *lexer, struct dataset *ds, enum val_type type) assert (val_type_is_valid (type)); struct expression *e = expr_create (ds); - struct expr_node *n = parse_or (lexer, e); - if (!n || !type_check (n, type)) + struct expr_node *n = parse_expr (lexer, e); + if (!n || !type_check (e, n, type)) { expr_free (e); return NULL; @@ -91,7 +101,7 @@ struct expression * expr_parse_bool (struct lexer *lexer, struct dataset *ds) { struct expression *e = expr_create (ds); - struct expr_node *n = parse_or (lexer, e); + struct expr_node *n = parse_expr (lexer, e); if (!n) { expr_free (e); @@ -100,10 +110,12 @@ expr_parse_bool (struct lexer *lexer, struct dataset *ds) atom_type actual_type = expr_node_returns (n); if (actual_type == OP_number) - n = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, n); + n = expr_allocate_binary (e, OP_EXPR_TO_BOOLEAN, n, + expr_allocate_expr_node (e, n)); else if (actual_type != OP_boolean) { - msg (SE, _("Type mismatch: expression has %s type, " + msg_at (SE, expr_location (e, n), + _("Type mismatch: expression has %s type, " "but a boolean value is required here."), atom_type_name (actual_type)); expr_free (e); @@ -121,7 +133,7 @@ expr_parse_new_variable (struct lexer *lexer, struct dataset *ds, const char *new_var_name) { struct expression *e = expr_create (ds); - struct expr_node *n = parse_or (lexer, e); + struct expr_node *n = parse_expr (lexer, e); if (!n) { expr_free (e); @@ -158,7 +170,7 @@ expr_parse_any (struct lexer *lexer, struct dataset *ds, bool optimize) struct expression *e; e = expr_create (ds); - n = parse_or (lexer, e); + n = parse_expr (lexer, e); if (n == NULL) { expr_free (e); @@ -195,6 +207,7 @@ atom_type_stack (atom_type type) { case OP_number: case OP_boolean: + case OP_num_vec_elem: return &on_number_stack; case OP_string: @@ -208,6 +221,7 @@ atom_type_stack (atom_type type) case OP_integer: case OP_pos_int: case OP_vector: + case OP_expr_node: return ¬_on_stack; default: @@ -284,7 +298,8 @@ finish_expression (struct expr_node *n, struct expression *e) converted to type EXPECTED_TYPE, inserting a conversion at *N if necessary. Returns true if successful, false on failure. */ static bool -type_check (const struct expr_node *n, enum val_type expected_type) +type_check (const struct expression *e, const struct expr_node *n, + enum val_type expected_type) { atom_type actual_type = expr_node_returns (n); @@ -293,8 +308,9 @@ type_check (const struct expr_node *n, enum val_type expected_type) case VAL_NUMERIC: if (actual_type != OP_number && actual_type != OP_boolean) { - msg (SE, _("Type mismatch: expression has %s type, " - "but a numeric value is required here."), + msg_at (SE, expr_location (e, n), + _("Type mismatch: expression has type '%s', " + "but a numeric value is required."), atom_type_name (actual_type)); return false; } @@ -303,8 +319,9 @@ type_check (const struct expr_node *n, enum val_type expected_type) case VAL_STRING: if (actual_type != OP_string) { - msg (SE, _("Type mismatch: expression has %s type, " - "but a string value is required here."), + msg_at (SE, expr_location (e, n), + _("Type mismatch: expression has type '%s', " + "but a string value is required."), atom_type_name (actual_type)); return false; } @@ -361,8 +378,8 @@ expr_location__ (struct expression *e, /* Returns the source code location corresponding to expression NODE, computing it lazily if needed. */ -static const struct msg_location * -expr_location (struct expression *e, const struct expr_node *node_) +const struct msg_location * +expr_location (const struct expression *e_, const struct expr_node *node_) { struct expr_node *node = CONST_CAST (struct expr_node *, node_); if (!node) @@ -370,6 +387,7 @@ expr_location (struct expression *e, const struct expr_node *node_) if (!node->location) { + struct expression *e = CONST_CAST (struct expression *, e_); const struct msg_location *min = NULL; const struct msg_location *max = NULL; expr_location__ (e, node, &min, &max); @@ -432,6 +450,12 @@ type_coercion__ (struct expression *e, struct expr_node *node, size_t arg_idx, *argp = expr_allocate_unary (e, OP_BOOLEAN_TO_NUM, arg); return true; } + else if (actual_type == OP_num_vec_elem) + { + if (do_coercion) + arg->type = OP_VEC_ELEM_NUM; + return true; + } break; case OP_string: @@ -443,12 +467,24 @@ type_coercion__ (struct expression *e, struct expr_node *node, size_t arg_idx, { /* Convert numeric to boolean. */ if (do_coercion) - *argp = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, arg); + *argp = expr_allocate_binary (e, OP_OPERAND_TO_BOOLEAN, arg, + expr_allocate_expr_node (e, node)); + return true; + } + break; + + case OP_integer: + if (actual_type == OP_number) + { + /* Convert number to integer. */ + if (do_coercion) + *argp = expr_allocate_unary (e, OP_NUM_TO_INTEGER, arg); return true; } break; case OP_format: + /* We never coerce to OP_format, only to OP_ni_format or OP_no_format. */ NOT_REACHED (); case OP_ni_format: @@ -711,8 +747,7 @@ parse_rel (struct lexer *lexer, struct expression *e) "not produce the mathematically expected result. " "Use the AND logical operator to fix the problem " "(e.g. `a < b AND b < c'). " - "If chaining is really intended, parentheses will disable " - "this warning (e.g. `(a < b) < c'.)"); + "To disable this warning, insert parentheses."); static const struct operator ops[] = { @@ -772,9 +807,8 @@ parse_exp (struct lexer *lexer, struct expression *e) static const struct operator op = { .token = T_EXP, .num_op = OP_POW }; const char *chain_warning = - _("The exponentiation operator (`**') is left-associative, " - "even though right-associative semantics are more useful. " - "That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'. " + _("The exponentiation operator (`**') is left-associative: " + "`a**b**c' equals `(a**b)**c', not `a**(b**c)'. " "To disable this warning, insert parentheses."); if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP) @@ -787,6 +821,7 @@ parse_exp (struct lexer *lexer, struct expression *e) int start_ofs = lex_ofs (lexer); struct expr_node *lhs = expr_allocate_number (e, -lex_tokval (lexer)); lex_get (lexer); + expr_add_location (lexer, e, start_ofs, lhs); struct expr_node *node = parse_binary_operators__ ( lexer, e, &op, 1, parse_primary, chain_warning, lhs); @@ -798,6 +833,46 @@ parse_exp (struct lexer *lexer, struct expression *e) return node; } +static double +ymd_to_offset (int y, int m, int d) +{ + char *error; + double retval = calendar_gregorian_to_offset ( + y, m, d, settings_get_fmt_settings (), &error); + if (error) + { + msg (SE, "%s", error); + free (error); + } + return retval; +} + +static struct expr_node * +expr_date (struct expression *e, int year_digits) +{ + static const char *months[12] = + { + "JAN", "FEB", "MAR", "APR", "MAY", "JUN", + "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", + }; + + time_t last_proc_time = time_of_last_procedure (e->ds); + struct tm *time = localtime (&last_proc_time); + + char *tmp = (year_digits == 2 + ? xasprintf ("%02d-%s-%02d", time->tm_mday, months[time->tm_mon], + time->tm_year % 100) + : xasprintf ("%02d-%s-%04d", time->tm_mday, months[time->tm_mon], + time->tm_year + 1900)); + + struct substring s; + ss_alloc_substring_pool (&s, ss_cstr (tmp), e->expr_pool); + + free (tmp); + + return expr_allocate_string (e, s); +} + /* Parses system variables. */ static struct expr_node * parse_sysvar (struct lexer *lexer, struct expression *e) @@ -805,25 +880,9 @@ parse_sysvar (struct lexer *lexer, struct expression *e) if (lex_match_id (lexer, "$CASENUM")) return expr_allocate_nullary (e, OP_CASENUM); else if (lex_match_id (lexer, "$DATE")) - { - static const char *months[12] = - { - "JAN", "FEB", "MAR", "APR", "MAY", "JUN", - "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", - }; - - time_t last_proc_time = time_of_last_procedure (e->ds); - struct tm *time; - char temp_buf[10]; - struct substring s; - - time = localtime (&last_proc_time); - sprintf (temp_buf, "%02d %s %02d", abs (time->tm_mday) % 100, - months[abs (time->tm_mon) % 12], abs (time->tm_year) % 100); - - ss_alloc_substring (&s, ss_cstr (temp_buf)); - return expr_allocate_string (e, s); - } + return expr_date (e, 2); + else if (lex_match_id (lexer, "$DATE11")) + return expr_date (e, 4); else if (lex_match_id (lexer, "$TRUE")) return expr_allocate_boolean (e, 1.0); else if (lex_match_id (lexer, "$FALSE")) @@ -834,16 +893,15 @@ parse_sysvar (struct lexer *lexer, struct expression *e) { time_t time = time_of_last_procedure (e->ds); struct tm *tm = localtime (&time); - return expr_allocate_number (e, expr_ymd_to_ofs (tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday)); + return expr_allocate_number (e, ymd_to_offset (tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday)); } else if (lex_match_id (lexer, "$TIME")) { time_t time = time_of_last_procedure (e->ds); struct tm *tm = localtime (&time); - return expr_allocate_number (e, - expr_ymd_to_date (tm->tm_year + 1900, + return expr_allocate_number (e, ymd_to_offset (tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday) + tm->tm_hour * 60 * 60. @@ -936,23 +994,9 @@ parse_primary__ (struct lexer *lexer, struct expression *e) case T_LPAREN: { - /* Count number of left parentheses so that we can match them against - an equal number of right parentheses. This defeats trivial attempts - to exhaust the stack with a lot of left parentheses. (More - sophisticated attacks will still succeed.) */ - size_t n = 0; - while (lex_match (lexer, T_LPAREN)) - n++; - + lex_get (lexer); struct expr_node *node = parse_or (lexer, e); - if (!node) - return NULL; - - for (size_t i = 0; i < n; i++) - if (!lex_force_match (lexer, T_RPAREN)) - return NULL; - - return node; + return !node || !lex_force_match (lexer, T_RPAREN) ? NULL : node; } default: @@ -999,12 +1043,12 @@ parse_vector_element (struct lexer *lexer, struct expression *e) return NULL; operation_type type = (vector_get_type (vector) == VAL_NUMERIC - ? OP_VEC_ELEM_NUM : OP_VEC_ELEM_STR); + ? OP_VEC_ELEM_NUM_RAW : OP_VEC_ELEM_STR); struct expr_node *node = expr_allocate_binary ( e, type, element, expr_allocate_vector (e, vector)); expr_add_location (lexer, e, vector_start_ofs, node); - if (!type_coercion (e, node, 1)) + if (!type_coercion (e, node, 0)) { msg_at (SE, expr_location (e, node), _("A vector index must be numeric.")); @@ -1144,7 +1188,8 @@ match_function (struct expr_node *node, } static bool -validate_function_args (const struct operation *f, int n_args, int min_valid) +validate_function_args (const struct expression *e, const struct expr_node *n, + const struct operation *f, int n_args, int min_valid) { /* Count the function arguments that go into the trailing array (if any). We know that there must be at least the minimum number because @@ -1160,7 +1205,8 @@ validate_function_args (const struct operation *f, int n_args, int min_valid) here. */ assert (f->array_granularity == 2); assert (n_args % 2 == 0); - msg (SE, _("%s must have an odd number of arguments."), f->prototype); + msg_at (SE, expr_location (e, n), + _("%s must have an odd number of arguments."), f->prototype); return false; } @@ -1169,9 +1215,10 @@ validate_function_args (const struct operation *f, int n_args, int min_valid) if (f->array_min_elems == 0) { assert ((f->flags & OPF_MIN_VALID) == 0); - msg (SE, _("%s function cannot accept suffix .%d to specify the " - "minimum number of valid arguments."), - f->prototype, min_valid); + msg_at (SE, expr_location (e, n), + _("%s function cannot accept suffix .%d to specify the " + "minimum number of valid arguments."), + f->prototype, min_valid); return false; } else @@ -1179,9 +1226,10 @@ validate_function_args (const struct operation *f, int n_args, int min_valid) assert (f->flags & OPF_MIN_VALID); if (min_valid > array_n_args) { - msg (SE, _("For %s with %d arguments, at most %d (not %d) may be " - "required to be valid."), - f->prototype, n_args, array_n_args, min_valid); + msg_at (SE, expr_location (e, n), + _("For %s with %d arguments, at most %d (not %d) may be " + "required to be valid."), + f->prototype, n_args, array_n_args, min_valid); return false; } } @@ -1220,16 +1268,15 @@ put_invocation (struct string *s, static void no_match (struct expression *e, const char *func_name, struct expr_node *node, - const struct operation *first, const struct operation *last) + const struct operation *ops, size_t n) { struct string s; - const struct operation *f; ds_init_empty (&s); - if (last - first == 1) + if (n == 1) { - ds_put_format (&s, _("Type mismatch invoking %s as "), first->prototype); + ds_put_format (&s, _("Type mismatch invoking %s as "), ops->prototype); put_invocation (&s, func_name, node); } else @@ -1238,13 +1285,33 @@ no_match (struct expression *e, const char *func_name, struct expr_node *node, put_invocation (&s, func_name, node); ds_put_cstr (&s, _(" does not match any known function. Candidates are:")); - for (f = first; f < last; f++) - ds_put_format (&s, "\n%s", f->prototype); + for (size_t i = 0; i < n; i++) + ds_put_format (&s, "\n%s", ops[i].prototype); } ds_put_byte (&s, '.'); msg_at (SE, expr_location (e, node), "%s", ds_cstr (&s)); + if (n == 1 && ops->n_args == node->n_args) + { + for (size_t i = 0; i < ops->n_args; i++) + if ((ops->args[i] == OP_ni_format + || ops->args[i] == OP_no_format) + && expr_node_returns (node->args[i]) == OP_format) + { + const struct fmt_spec *f = &node->args[i]->format; + char *error = fmt_check__ (f, (ops->args[i] == OP_ni_format + ? FMT_FOR_INPUT : FMT_FOR_OUTPUT)); + if (!error) + error = fmt_check_type_compat__ (f, VAL_NUMERIC); + if (error) + { + msg_at (SN, expr_location (e, node->args[i]), "%s", error); + free (error); + } + } + } + ds_destroy (&s); } @@ -1318,7 +1385,7 @@ parse_function (struct lexer *lexer, struct expression *e) const struct operation *f = match_function (n, first, last); if (!f) { - no_match (e, ds_cstr (&func_name), n, first, last); + no_match (e, ds_cstr (&func_name), n, first, last - first); goto fail; } n->type = f - operations; @@ -1331,21 +1398,23 @@ parse_function (struct lexer *lexer, struct expression *e) arguments were coercible. */ NOT_REACHED (); } - if (!validate_function_args (f, n_args, min_valid)) + if (!validate_function_args (e, n, f, n_args, min_valid)) goto fail; if ((f->flags & OPF_EXTENSION) && settings_get_syntax () == COMPATIBLE) - msg (SW, _("%s is a PSPP extension."), f->prototype); + msg_at (SW, expr_location (e, n), + _("%s is a PSPP extension."), f->prototype); if (f->flags & OPF_UNIMPLEMENTED) { - msg (SE, _("%s is not available in this version of PSPP."), - f->prototype); + msg_at (SE, expr_location (e, n), + _("%s is not available in this version of PSPP."), f->prototype); goto fail; } if ((f->flags & OPF_PERM_ONLY) && proc_in_temporary_transformations (e->ds)) { - msg (SE, _("%s may not appear after %s."), f->prototype, "TEMPORARY"); + msg_at (SE, expr_location (e, n), + _("%s may not appear after %s."), f->prototype, "TEMPORARY"); goto fail; } @@ -1518,6 +1587,15 @@ expr_allocate_format (struct expression *e, const struct fmt_spec *format) return n; } +struct expr_node * +expr_allocate_expr_node (struct expression *e, + const struct expr_node *expr_node) +{ + struct expr_node *n = pool_alloc (e->expr_pool, sizeof *n); + *n = (struct expr_node) { .type = OP_expr_node, .expr_node = expr_node }; + return n; +} + /* Allocates a unary composite node that represents the value of variable V in expression E. */ static struct expr_node *