diff --git a/src/c/Makefile.in b/src/c/Makefile.in index 5aeb36cf7..1bb386312 100644 --- a/src/c/Makefile.in +++ b/src/c/Makefile.in @@ -78,8 +78,8 @@ WRITER_OBJS = print.o printer/float_to_digits.o printer/float_to_string.o printer/write_list.o printer/write_code.o printer/write_sse.o \ printer/print_unreadable.o -READER_OBJS = reader.o read.o reader/rtab_cl.o \ - reader/parse_token.o reader/parse_integer.o reader/parse_number.o +READER_OBJS = reader.o read.o reader/rtab_cl.o reader/parse_token.o \ + reader/parse_fixnum.o reader/parse_integer.o reader/parse_number.o STREAM_OBJS = stream.o file.o streams/strm_os.o streams/strm_clos.o \ streams/strm_string.o streams/strm_composite.o streams/strm_common.o \ diff --git a/src/c/format.d b/src/c/format.d index 9dc5aff56..5aa9cb4f3 100644 --- a/src/c/format.d +++ b/src/c/format.d @@ -40,19 +40,6 @@ typedef struct format_stack_struct { int nparam; } *format_stack; -#if MOST_POSITIVE_FIXNUM_VAL < INT_MAX -# define FMT_VALUE_UPPER_LIMIT MOST_POSITIVE_FIXNUM -#else -# define FMT_VALUE_UPPER_LIMIT INT_MAX -#endif - -#if MOST_NEGATIVE_FIXNUM_VAL > INT_MIN -# define FMT_VALUE_LOWER_LIMIT MOST_NEGATIVE_FIXNUM -#else -# define FMT_VALUE_LOWER_LIMIT INT_MIN -#endif - - /******************* COMMON ***************************/ #define NONE 0 @@ -2000,25 +1987,11 @@ format(format_stack fmt, cl_index start, cl_index end) do { c = ctl_advance(fmt); } while (ecl_digitp(c,10) != -1); - x = ecl_parse_integer(fmt->ctl_str, i, fmt->ctl_index, &i, 10); + x = ecl_parse_fixnum(fmt->ctl_str, i, fmt->ctl_index, &i, 10); INTEGER: - /* FIXME! A hack to solve the problem of bignums in arguments */ if (x == OBJNULL || !ecl_numberp(x)) - fmt_error(fmt, "integer expected"); - if (ecl_number_compare(x, ecl_make_fixnum(FMT_VALUE_UPPER_LIMIT)) > 0) { - fmt->param[n] = ecl_make_fixnum(FMT_VALUE_UPPER_LIMIT); - } else if (ecl_number_compare(x, ecl_make_fixnum(FMT_VALUE_LOWER_LIMIT)) < 0) { - fmt->param[n] = ecl_make_fixnum(FMT_VALUE_LOWER_LIMIT); - } else { - fmt->param[n] = x; - } - if (ECL_FIXNUMP(x)) { - fmt->param[n] = x; - } else if (ecl_plusp(x)) { - fmt->param[n] = ecl_make_fixnum(MOST_POSITIVE_FIXNUM); - } else { - fmt->param[n] = ecl_make_fixnum(MOST_NEGATIVE_FIXNUM); - } + fmt_error(fmt, "fixnum expected"); + fmt->param[n] = x; break; case '\'': diff --git a/src/c/reader/parse_fixnum.d b/src/c/reader/parse_fixnum.d new file mode 100644 index 000000000..006617412 --- /dev/null +++ b/src/c/reader/parse_fixnum.d @@ -0,0 +1,102 @@ +/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */ + +/* + * + * Copyright (c) 1984 Taiichi Yuasa and Masami Hagiya + * Copyright (c) 1990 Giuseppe Attardi + * Copyright (c) 2001 Juan Jose Garcia Ripoll + * Copyright (c) 2026 Daniel KochmaƄski + * + * See file 'LICENSE' for the copyright details. + * + */ + +#include +#include +#include + +#define basep(d) (d <= 36) + +static ecl_character +_ecl_char(cl_object object, cl_index index) +{ + switch(ecl_t_of(object)) { +#ifdef ECL_UNICODE + case t_string: + return object->string.self[index]; +#endif + case t_base_string: + return object->base_string.self[index]; + default: + ecl_internal_error("ecl_parse_fixnum: source is not a string."); + } +} + +static int +_ecl_digitp(ecl_character i, int r) +{ + if (('0' <= i) && (i <= '9') && (i < '0' + r)) + return i - '0'; + if (('A' <= i) && (10 < r) && (i < 'A' + (r - 10))) + return i - 'A' + 10; + if (('a' <= i) && (10 < r) && (i < 'a' + (r - 10))) + return i - 'a' + 10; +/* #ifdef ECL_UNICODE */ +/* if (i > 255) { */ +/* int number = ucd_decimal_digit(i); */ +/* if (number < r) */ +/* return number; */ +/* } */ +/* #endif */ + return -1; +} + +/* This is like ecl_parse_integer (including the API), but returns OBJNULL also + when the result does not fit in a fixnum. */ +cl_object +ecl_parse_fixnum(cl_object str, cl_index start, cl_index end, + cl_index *ep, unsigned int radix) +{ + int sign, d; + cl_fixnum aux, integer_part; + cl_object output; + cl_index i, c; + + if (start >= end || !basep(radix)) { + *ep = start; + return OBJNULL; + } + sign = 1; + c = _ecl_char(str, start); + if (c == '+') { + start++; + } else if (c == '-') { + sign = -1; + start++; + } + integer_part = 0; + for (i = start; i < end; i++) { + c = _ecl_char(str, i); + d = _ecl_digitp(c, radix); + if (d < 0) { + break; + } + aux = integer_part; + integer_part *= radix; + if (integer_part/radix != aux) { + *ep = i-1; + return OBJNULL; + } + integer_part += d; + if (integer_part > MOST_POSITIVE_FIXNUM) { + *ep = i-1; + return OBJNULL;; + } + } + if (sign < 0) { + integer_part = -integer_part; + } + *ep = i; + return (i == start)? OBJNULL : ecl_make_fixnum(integer_part); +} diff --git a/src/h/external.h b/src/h/external.h index b8a791c95..1f292107e 100755 --- a/src/h/external.h +++ b/src/h/external.h @@ -1582,6 +1582,7 @@ extern ECL_API cl_object ecl_read_object(cl_object in); extern ECL_API cl_object ecl_read_token(cl_object rtbl, cl_object in, int flags); extern ECL_API cl_object ecl_parse_token(cl_object token, cl_object in, int flags); extern ECL_API cl_object ecl_parse_number(cl_object s, cl_index start, cl_index end, cl_index *ep, unsigned int radix); +extern ECL_API cl_object ecl_parse_fixnum(cl_object s, cl_index start, cl_index end, cl_index *ep, unsigned int radix); extern ECL_API cl_object ecl_parse_integer(cl_object s, cl_index start, cl_index end, cl_index *ep, unsigned int radix); extern ECL_API bool ecl_invalid_character_p(int c); extern ECL_API cl_object ecl_copy_readtable(cl_object from, cl_object to);