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