Home | History | Annotate | Line # | Download | only in expr
      1 /* mpf expression evaluation
      2 
      3 Copyright 2000-2002, 2004 Free Software Foundation, Inc.
      4 
      5 This file is part of the GNU MP Library.
      6 
      7 The GNU MP Library is free software; you can redistribute it and/or modify
      8 it under the terms of either:
      9 
     10   * the GNU Lesser General Public License as published by the Free
     11     Software Foundation; either version 3 of the License, or (at your
     12     option) any later version.
     13 
     14 or
     15 
     16   * the GNU General Public License as published by the Free Software
     17     Foundation; either version 2 of the License, or (at your option) any
     18     later version.
     19 
     20 or both in parallel, as here.
     21 
     22 The GNU MP Library is distributed in the hope that it will be useful, but
     23 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     24 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     25 for more details.
     26 
     27 You should have received copies of the GNU General Public License and the
     28 GNU Lesser General Public License along with the GNU MP Library.  If not,
     29 see https://www.gnu.org/licenses/.  */
     30 
     31 
     32 /* Future: Bitwise "&", "|" and "&" could be done, if desired.  Not sure
     33    those functions would be much value though.  */
     34 
     35 
     36 #include <ctype.h>
     37 #include <stdio.h>
     38 #include <string.h>
     39 
     40 #include "gmp.h"
     41 #include "expr-impl.h"
     42 
     43 
     44 /* Change this to "#define TRACE(x) x" to get some traces. */
     45 #define TRACE(x)
     46 
     47 
     48 static size_t
     49 e_mpf_number (mpf_ptr res, const char *e, size_t elen, int base)
     50 {
     51   char    *edup;
     52   size_t  i, ret, extra=0;
     53   int     mant_base, exp_base;
     54   void    *(*allocate_func) (size_t);
     55   void    (*free_func) (void *, size_t);
     56 
     57   TRACE (printf ("mpf_number base=%d \"%.*s\"\n", base, (int) elen, e));
     58 
     59   /* mpf_set_str doesn't currently accept 0x for hex in base==0, so do it
     60      here instead.  FIXME: Would prefer to let mpf_set_str handle this.  */
     61   if (base == 0 && elen >= 2 && e[0] == '0' && (e[1] == 'x' || e[1] == 'X'))
     62     {
     63       base = 16;
     64       extra = 2;
     65       e += extra;
     66       elen -= extra;
     67     }
     68 
     69   if (base == 0)
     70     mant_base = 10;
     71   else if (base < 0)
     72     mant_base = -base;
     73   else
     74     mant_base = base;
     75 
     76   /* exponent in decimal if base is negative */
     77   if (base < 0)
     78     exp_base = 10;
     79   else if (base == 0)
     80     exp_base = 10;
     81   else
     82     exp_base = base;
     83 
     84 #define IS_EXPONENT(c) \
     85   (c == '@' || (base <= 10 && base >= -10 && (e[i] == 'e' || e[i] == 'E')))
     86 
     87   i = 0;
     88   for (;;)
     89     {
     90       if (i >= elen)
     91         goto parsed;
     92       if (e[i] == '.')
     93         break;
     94       if (IS_EXPONENT (e[i]))
     95         goto exponent;
     96       if (! isasciidigit_in_base (e[i], mant_base))
     97         goto parsed;
     98       i++;
     99     }
    100 
    101   /* fraction */
    102   i++;
    103   for (;;)
    104     {
    105       if (i >= elen)
    106         goto parsed;
    107       if (IS_EXPONENT (e[i]))
    108         goto exponent;
    109       if (! isasciidigit_in_base (e[i], mant_base))
    110         goto parsed;
    111       i++;
    112     }
    113 
    114  exponent:
    115   i++;
    116   if (i >= elen)
    117     goto parsed;
    118   if (e[i] == '-')
    119     i++;
    120   for (;;)
    121     {
    122       if (i >= elen)
    123         goto parsed;
    124       if (! isasciidigit_in_base (e[i], exp_base))
    125         break;
    126       i++;
    127     }
    128 
    129  parsed:
    130   TRACE (printf ("  parsed i=%u \"%.*s\"\n", i, (int) i, e));
    131 
    132   mp_get_memory_functions (&allocate_func, NULL, &free_func);
    133   edup = (*allocate_func) (i+1);
    134   memcpy (edup, e, i);
    135   edup[i] = '\0';
    136 
    137   if (mpf_set_str (res, edup, base) == 0)
    138     ret = i + extra;
    139   else
    140     ret = 0;
    141 
    142   (*free_func) (edup, i+1);
    143   return ret;
    144 }
    145 
    146 static int
    147 e_mpf_ulong_p (mpf_srcptr f)
    148 {
    149   return mpf_integer_p (f) && mpf_fits_ulong_p (f);
    150 }
    151 
    152 /* Don't want to change the precision of w, can only do an actual swap when
    153    w and x have the same precision.  */
    154 static void
    155 e_mpf_set_or_swap (mpf_ptr w, mpf_ptr x)
    156 {
    157   if (mpf_get_prec (w) == mpf_get_prec (x))
    158     mpf_swap (w, x);
    159   else
    160     mpf_set (w, x);
    161 }
    162 
    163 
    164 int
    165 mpf_expr_a (const struct mpexpr_operator_t *table,
    166             mpf_ptr res, int base, unsigned long prec,
    167             const char *e, size_t elen,
    168             mpf_srcptr var[26])
    169 {
    170   struct mpexpr_parse_t  p;
    171 
    172   p.table = table;
    173   p.res = (mpX_ptr) res;
    174   p.base = base;
    175   p.prec = prec;
    176   p.e = e;
    177   p.elen = elen;
    178   p.var = (mpX_srcptr *) var;
    179 
    180   p.mpX_clear       = (mpexpr_fun_one_t)      mpf_clear;
    181   p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  e_mpf_ulong_p;
    182   p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   mpf_get_ui;
    183   p.mpX_init        = (mpexpr_fun_unary_ui_t) mpf_init2;
    184   p.mpX_number      = (mpexpr_fun_number_t)   e_mpf_number;
    185   p.mpX_set         = (mpexpr_fun_unary_t)    mpf_set;
    186   p.mpX_set_or_swap = (mpexpr_fun_unary_t)    e_mpf_set_or_swap;
    187   p.mpX_set_si      = (mpexpr_fun_set_si_t)   mpf_set_si;
    188   p.mpX_swap        = (mpexpr_fun_swap_t)     mpf_swap;
    189 
    190   return mpexpr_evaluate (&p);
    191 }
    192