diff --git a/lib/number.c b/lib/number.c index 83314b0..99b87a3 100644 --- a/lib/number.c +++ b/lib/number.c @@ -96,6 +96,26 @@ static hcl_ooi_t equalize_scale (hcl_t* hcl, hcl_oop_t* x, hcl_oop_t* y) return xs; } +static hcl_oop_t truncate (hcl_t* hcl, hcl_oop_t iv, hcl_ooi_t cs, hcl_ooi_t ns) +{ + /* this function truncates an existing fixed-point decimal. + * it doesn't create a new object */ + + if (cs > ns) + { + do + { + /* TODO: optimizatino... less divisions */ + iv = hcl_divints(hcl, iv, HCL_SMOOI_TO_OOP(10), 0, HCL_NULL); + if (!iv) return HCL_NULL; + cs--; + } + while (cs > ns); + } + + return iv; +} + hcl_oop_t hcl_addnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) { if (!HCL_IS_FPDEC(hcl, x) && !HCL_IS_FPDEC(hcl, y)) @@ -156,7 +176,7 @@ hcl_oop_t hcl_subnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) hcl_oop_t hcl_mulnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) { - hcl_ooi_t xs, ys, scale; + hcl_ooi_t xs, ys, cs, ns; hcl_oop_t nv; hcl_oop_t xv, yv; @@ -189,16 +209,21 @@ hcl_oop_t hcl_mulnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) nv = hcl_mulints(hcl, xv, yv); if (!nv) return HCL_NULL; - scale = xs + ys; - if (scale > HCL_SMOOI_MAX) - { - /* TODO: limit scale */ - } + cs = xs + ys; + if (cs <= 0) return nv; /* the result must be an integer */ - return hcl_makefpdec(hcl, nv, scale); + ns = (xs > ys)? xs: ys; + + /* cs may be larger than HCL_SMOOI_MAX. but ns is guaranteed to be + * equal to or less than HCL_SMOOI_MAX */ + HCL_ASSERT (hcl, ns > 0 && ns <= HCL_SMOOI_MAX); + + nv = truncate(hcl, nv, cs, ns); + if (!nv) return HCL_NULL; + + return hcl_makefpdec(hcl, nv, ns); } - hcl_oop_t hcl_divnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) { hcl_ooi_t xs, ys, i; diff --git a/lib/read.c b/lib/read.c index ecc0046..7efa3f5 100644 --- a/lib/read.c +++ b/lib/read.c @@ -260,12 +260,14 @@ static hcl_oop_t string_to_fpdec (hcl_t* hcl, hcl_oocs_t* str, const hcl_ioloc_t return HCL_NULL; } - if (scale > 0) HCL_MEMMOVE (&str->ptr[pos], &str->ptr[pos + 1], scale * HCL_SIZEOF(str->ptr[0])); + HCL_ASSERT (hcl, scale > 0); + /*if (scale > 0)*/ HCL_MEMMOVE (&str->ptr[pos], &str->ptr[pos + 1], scale * HCL_SIZEOF(str->ptr[0])); + break; } } v = hcl_strtoint(hcl, str->ptr, str->len - 1, 10); - if (scale > 0) HCL_MEMMOVE (&str->ptr[pos + 1], &str->ptr[pos], scale * HCL_SIZEOF(str->ptr[0])); + /*if (scale > 0)*/ HCL_MEMMOVE (&str->ptr[pos + 1], &str->ptr[pos], scale * HCL_SIZEOF(str->ptr[0])); if (!v) return HCL_NULL; return hcl_makefpdec (hcl, v, scale); @@ -1156,7 +1158,8 @@ retry: GET_CHAR_TO (hcl, c); if (!is_digitchar(c)) { - hcl_setsynerrbfmt (hcl, HCL_SYNERR_NUMLIT, TOKEN_LOC(hcl), TOKEN_NAME(hcl), "invalid numeric literal with no digit after fixed-point"); + /* the first character after the decimal point is not a decimal digit */ + hcl_setsynerrbfmt (hcl, HCL_SYNERR_NUMLIT, TOKEN_LOC(hcl), TOKEN_NAME(hcl), "invalid numeric literal with no digit after decimal point"); return -1; } }