blob: 1918cb55cd91ed4aa19a184a33fc4e3c54ce41d2 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* mpf expression evaluation
2
3Copyright 2000-2002, 2004 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it 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
14or
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
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see 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
48static size_t
49e_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
146static int
147e_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. */
154static void
155e_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
164int
165mpf_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}