xref: /netbsd-src/external/lgpl3/gmp/dist/demos/expr/exprfa.c (revision ce54336801cf28877c3414aa2fcb251dddd543a2)
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
e_mpf_number(mpf_ptr res,const char * e,size_t elen,int base)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
e_mpf_ulong_p(mpf_srcptr f)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
e_mpf_set_or_swap(mpf_ptr w,mpf_ptr x)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
mpf_expr_a(const struct mpexpr_operator_t * table,mpf_ptr res,int base,unsigned long prec,const char * e,size_t elen,mpf_srcptr var[26])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