Tizen 2.1 base
[external/gmp.git] / demos / expr / exprfa.c
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 }