configury: improve dlsym underscore detection.
[m4.git] / modules / mpeval.c
blob625441630107383d5a8967aa9d069ad11c5ed59b
1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 2000-2001, 2006-2008, 2010, 2013-2014 Free Software
3 Foundation, Inc.
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 /* Build using only the exported interfaces, unless NDEBUG is set, in
24 which case use private symbols to speed things up as much as possible. */
25 #ifndef NDEBUG
26 # include <m4/m4module.h>
27 #else
28 # include "m4private.h"
29 #endif
31 #if HAVE_GMP_H
32 # include <gmp.h>
33 #endif
35 /* Maintain each of the builtins implemented in this modules along
36 with their details in a single table for easy maintenance.
38 function macros blind side minargs maxargs */
39 #define builtin_functions \
40 BUILTIN (mpeval, false, true, true, 1, 3 ) \
44 #define numb_set(ans, i) mpq_set (ans, i)
45 #define numb_set_si(ans, i) mpq_set_si (*(ans), (long) i, (unsigned long) 1)
47 #define numb_init(x) mpq_init (x)
48 #define numb_fini(x) mpq_clear (x)
50 #define numb_zerop(x) (mpq_cmp (x, numb_ZERO) == 0)
51 #define numb_positivep(x) (mpq_cmp (x, numb_ZERO) > 0)
52 #define numb_negativep(x) (mpq_cmp (x, numb_ZERO) < 0)
54 #define numb_eq(x, y) numb_set (x, mpq_cmp (x, y) == 0 ? numb_ONE : numb_ZERO)
55 #define numb_ne(x, y) numb_set (x, mpq_cmp (x, y) != 0 ? numb_ONE : numb_ZERO)
56 #define numb_lt(x, y) numb_set (x, mpq_cmp (x, y) < 0 ? numb_ONE : numb_ZERO)
57 #define numb_le(x, y) numb_set (x, mpq_cmp (x, y) <= 0 ? numb_ONE : numb_ZERO)
58 #define numb_gt(x, y) numb_set (x, mpq_cmp (x, y) > 0 ? numb_ONE : numb_ZERO)
59 #define numb_ge(x, y) numb_set (x, mpq_cmp (x, y) >= 0 ? numb_ONE : numb_ZERO)
61 #define numb_lnot(x) numb_set (x, numb_zerop (x) ? numb_ONE : numb_ZERO)
62 #define numb_lior(x, y) numb_set (x, numb_zerop (x) ? y : x)
63 #define numb_land(x, y) numb_set (x, numb_zerop (x) ? numb_ZERO : y)
65 #define reduce1(f1, x) \
66 do \
67 { \
68 number T; \
69 mpq_init (T); \
70 f1 (T, x); \
71 mpq_set (x, T); \
72 mpq_clear (T); \
73 } \
74 while (0)
75 #define reduce2(f2,x,y) \
76 do \
77 { \
78 number T; \
79 mpq_init (T); \
80 f2 (T, (x), (y)); \
81 mpq_set ((x), T); \
82 mpq_clear (T); \
83 } \
84 while (0)
86 #define numb_plus(x, y) reduce2 (mpq_add, x, y)
87 #define numb_minus(x, y) reduce2 (mpq_sub, x, y)
88 #define numb_negate(x) reduce1 (mpq_neg, x)
90 #define numb_times(x, y) reduce2 (mpq_mul, x, y)
91 #define numb_ratio(x, y) reduce2 (mpq_div, x, y)
92 #define numb_invert(x) reduce1 (mpq_inv, x)
94 #define numb_incr(n) numb_plus (n, numb_ONE)
95 #define numb_decr(n) numb_minus (n, numb_ONE)
97 /* Generate prototypes for each builtin handler function. */
98 #define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN (handler)
99 builtin_functions
100 #undef BUILTIN
103 /* Generate a table for mapping m4 symbol names to handler functions. */
104 static const m4_builtin m4_builtin_table[] =
106 #define BUILTIN(handler, macros, blind, side, min, max) \
107 M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max)
109 builtin_functions
110 #undef BUILTIN
112 { NULL, NULL, 0, 0, 0 },
116 /* A table for mapping m4 symbol names to simple expansion text. */
117 static const m4_macro m4_macro_table[] =
119 /* name text min max */
120 { "__mpeval__", "", 0, 0 },
121 { NULL, NULL, 0, 0 },
125 void
126 include_mpeval (m4 *context, m4_module *module, m4_obstack *obs)
128 m4_install_builtins (context, module, m4_builtin_table);
129 m4_install_macros (context, module, m4_macro_table);
133 /* GMP defines mpq_t as a 1-element array of struct. Therefore, `mpq_t'
134 is not compatible with `const mpq_t'. */
135 typedef mpq_t number;
137 static void numb_initialise (void);
138 static void numb_obstack (m4_obstack *obs, const number value,
139 const int radix, int min);
140 static void mpq2mpz (m4 *context, mpz_t z, const number q, const char *noisily);
141 static void mpz2mpq (number q, const mpz_t z);
142 static void numb_divide (number *x, number *y);
143 static void numb_modulo (m4 *context, number *x, number *y);
144 static void numb_and (m4 *context, number *x, number *y);
145 static void numb_ior (m4 *context, number *x, number *y);
146 static void numb_eor (m4 *context, number *x, number *y);
147 static void numb_not (m4 *context, number *x);
148 static void numb_lshift (m4 *context, number *x, number *y);
149 static void numb_rshift (m4 *context, number *x, number *y);
150 #define numb_urshift(c, x, y) numb_rshift (c, x, y)
153 static number numb_ZERO;
154 static number numb_ONE;
156 static int numb_initialised = 0;
158 static void
159 numb_initialise (void)
161 if (numb_initialised)
162 return;
164 numb_init (numb_ZERO);
165 numb_set_si (&numb_ZERO, 0);
167 numb_init (numb_ONE);
168 numb_set_si (&numb_ONE, 1);
170 numb_initialised = 1;
173 static void
174 numb_obstack (m4_obstack *obs, const number value, const int radix,
175 int min)
177 const char *s;
178 size_t len;
180 mpz_t i;
181 mpz_init (i);
183 mpq_get_num (i, value);
184 s = mpz_get_str (NULL, radix, i);
186 if (*s == '-')
188 obstack_1grow (obs, '-');
189 s++;
191 len = strlen (s);
192 for (min -= len; --min >= 0;)
193 obstack_1grow (obs, '0');
195 obstack_grow (obs, s, len);
197 mpq_get_den (i, value);
198 if (mpz_cmp_si (i, (long) 1) != 0)
200 obstack_1grow (obs, '\\');
201 s = mpz_get_str ((char *) 0, radix, i);
202 obstack_grow (obs, s, strlen (s));
205 mpz_clear (i);
208 #define NOISY ""
209 #define QUIET (char *)0
211 static void
212 mpq2mpz (m4 *context, mpz_t z, const number q, const char *noisily)
214 if (noisily && mpz_cmp_si (mpq_denref (q), (long) 1) != 0)
215 m4_warn (context, 0, NULL, _("loss of precision in eval: %s"), noisily);
217 mpz_div (z, mpq_numref (q), mpq_denref (q));
220 static void
221 mpz2mpq (number q, const mpz_t z)
223 mpq_set_si (q, (long) 0, (unsigned long) 1);
224 mpq_set_num (q, z);
227 static void
228 numb_divide (number * x, number * y)
230 mpq_t qres;
231 mpz_t zres;
233 mpq_init (qres);
234 mpq_div (qres, *x, *y);
236 mpz_init (zres);
237 mpz_div (zres, mpq_numref (qres), mpq_denref (qres));
238 mpq_clear (qres);
240 mpz2mpq (*x, zres);
241 mpz_clear (zres);
244 static void
245 numb_modulo (m4 *context, number * x, number * y)
247 mpz_t xx, yy, res;
249 /* x should be integral */
250 /* y should be integral */
252 mpz_init (xx);
253 mpq2mpz (context, xx, *x, NOISY);
255 mpz_init (yy);
256 mpq2mpz (context, yy, *y, NOISY);
258 mpz_init (res);
259 mpz_mod (res, xx, yy);
261 mpz_clear (xx);
262 mpz_clear (yy);
264 mpz2mpq (*x, res);
265 mpz_clear (res);
268 static void
269 numb_and (m4 *context, number * x, number * y)
271 mpz_t xx, yy, res;
273 /* x should be integral */
274 /* y should be integral */
276 mpz_init (xx);
277 mpq2mpz (context, xx, *x, NOISY);
279 mpz_init (yy);
280 mpq2mpz (context, yy, *y, NOISY);
282 mpz_init (res);
283 mpz_and (res, xx, yy);
285 mpz_clear (xx);
286 mpz_clear (yy);
288 mpz2mpq (*x, res);
289 mpz_clear (res);
292 static void
293 numb_ior (m4 *context, number * x, number * y)
295 mpz_t xx, yy, res;
297 /* x should be integral */
298 /* y should be integral */
300 mpz_init (xx);
301 mpq2mpz (context, xx, *x, NOISY);
303 mpz_init (yy);
304 mpq2mpz (context, yy, *y, NOISY);
306 mpz_init (res);
307 mpz_ior (res, xx, yy);
309 mpz_clear (xx);
310 mpz_clear (yy);
312 mpz2mpq (*x, res);
313 mpz_clear (res);
316 static void
317 numb_eor (m4 *context, number * x, number * y)
319 mpz_t xx, yy, res;
321 /* x should be integral */
322 /* y should be integral */
324 mpz_init (xx);
325 mpq2mpz (context, xx, *x, NOISY);
327 mpz_init (yy);
328 mpq2mpz (context, yy, *y, NOISY);
330 mpz_init (res);
332 #if 0
333 mpz_xor (res, xx, yy);
334 #else /* 0 */
335 /* a^b = (a|b) & !(a&b) */
337 mpz_t and_ab, ior_ab, nand_ab;
339 mpz_init (ior_ab);
340 mpz_ior (ior_ab, xx, yy);
342 mpz_init (and_ab);
343 mpz_and (and_ab, xx, yy);
345 mpz_init (nand_ab);
346 mpz_com (nand_ab, and_ab);
348 mpz_and (res, ior_ab, nand_ab);
350 mpz_clear (and_ab);
351 mpz_clear (ior_ab);
352 mpz_clear (nand_ab);
354 #endif /* 0 */
356 mpz_clear (xx);
357 mpz_clear (yy);
359 mpz2mpq (*x, res);
360 mpz_clear (res);
363 static void
364 numb_not (m4 *context, number * x)
366 mpz_t xx, res;
368 /* x should be integral */
370 mpz_init (xx);
371 mpq2mpz (context, xx, *x, NOISY);
373 mpz_init (res);
374 mpz_com (res, xx);
376 mpz_clear (xx);
378 mpz2mpq (*x, res);
379 mpz_clear (res);
382 static void
383 numb_lshift (m4 *context, number * x, number * y)
385 mpz_t xx, yy, res;
387 /* x should be integral */
388 /* y should be integral */
390 mpz_init (xx);
391 mpq2mpz (context, xx, *x, NOISY);
393 mpz_init (yy);
394 mpq2mpz (context, yy, *y, NOISY);
396 mpz_init (res);
398 /* bug: need to determine if y is too big or negative. */
399 long int exp = mpz_get_si (yy);
400 if (exp >= 0)
402 mpz_mul_2exp (res, xx, (unsigned) exp);
404 else
406 mpz_div_2exp (res, xx, (unsigned) -exp);
410 mpz_clear (xx);
411 mpz_clear (yy);
413 mpz2mpq (*x, res);
414 mpz_clear (res);
417 static void
418 numb_rshift (m4 *context, number * x, number * y)
420 mpz_t xx, yy, res;
422 /* x should be integral */
423 /* y should be integral */
425 mpz_init (xx);
426 mpq2mpz (context, xx, *x, NOISY);
428 mpz_init (yy);
429 mpq2mpz (context, yy, *y, NOISY);
431 mpz_init (res);
433 /* FIXME: bug - need to determine if y is too big or negative */
434 long int exp = mpz_get_si (yy);
435 if (exp >= 0)
437 mpz_div_2exp (res, xx, (unsigned) exp);
439 else
441 mpz_mul_2exp (res, xx, (unsigned) -exp);
445 mpz_clear (xx);
446 mpz_clear (yy);
448 mpz2mpq (*x, res);
449 mpz_clear (res);
452 #define m4_evaluate builtin_mpeval
453 #include "evalparse.c"