1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 2000, 2001, 2006, 2007, 2008 Free Software
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/>.
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. */
26 # include <m4/m4module.h>
28 # include "m4private.h"
37 /* Rename exported symbols for dlpreload()ing. */
38 #define m4_builtin_table mpeval_LTX_m4_builtin_table
39 #define m4_macro_table mpeval_LTX_m4_macro_table
42 /* Maintain each of the builtins implemented in this modules along
43 with their details in a single table for easy maintenance.
45 function macros blind side minargs maxargs */
46 #define builtin_functions \
47 BUILTIN (mpeval, false, true, true, 1, 3 ) \
51 #define numb_set(ans, i) mpq_set (ans, i)
52 #define numb_set_si(ans, i) mpq_set_si (*(ans), (long) i, (unsigned long) 1)
54 #define numb_init(x) mpq_init (x)
55 #define numb_fini(x) mpq_clear (x)
57 #define numb_zerop(x) (mpq_cmp (x, numb_ZERO) == 0)
58 #define numb_positivep(x) (mpq_cmp (x, numb_ZERO) > 0)
59 #define numb_negativep(x) (mpq_cmp (x, numb_ZERO) < 0)
61 #define numb_eq(x, y) numb_set (x, mpq_cmp (x, y) == 0 ? numb_ONE : numb_ZERO)
62 #define numb_ne(x, y) numb_set (x, mpq_cmp (x, y) != 0 ? numb_ONE : numb_ZERO)
63 #define numb_lt(x, y) numb_set (x, mpq_cmp (x, y) < 0 ? numb_ONE : numb_ZERO)
64 #define numb_le(x, y) numb_set (x, mpq_cmp (x, y) <= 0 ? numb_ONE : numb_ZERO)
65 #define numb_gt(x, y) numb_set (x, mpq_cmp (x, y) > 0 ? numb_ONE : numb_ZERO)
66 #define numb_ge(x, y) numb_set (x, mpq_cmp (x, y) >= 0 ? numb_ONE : numb_ZERO)
68 #define numb_lnot(x) numb_set (x, numb_zerop (x) ? numb_ONE : numb_ZERO)
69 #define numb_lior(x, y) numb_set (x, numb_zerop (x) ? y : x)
70 #define numb_land(x, y) numb_set (x, numb_zerop (x) ? numb_ZERO : y)
72 #define reduce1(f1, x) \
82 #define reduce2(f2,x,y) \
93 #define numb_plus(x, y) reduce2 (mpq_add, x, y)
94 #define numb_minus(x, y) reduce2 (mpq_sub, x, y)
95 #define numb_negate(x) reduce1 (mpq_neg, x)
97 #define numb_times(x, y) reduce2 (mpq_mul, x, y)
98 #define numb_ratio(x, y) reduce2 (mpq_div, x, y)
99 #define numb_invert(x) reduce1 (mpq_inv, x)
101 #define numb_incr(n) numb_plus (n, numb_ONE)
102 #define numb_decr(n) numb_minus (n, numb_ONE)
104 /* Generate prototypes for each builtin handler function. */
105 #define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN (handler)
110 /* Generate a table for mapping m4 symbol names to handler functions. */
111 const m4_builtin m4_builtin_table
[] =
113 #define BUILTIN(handler, macros, blind, side, min, max) \
114 M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max)
119 { NULL
, NULL
, 0, 0, 0 },
123 /* A table for mapping m4 symbol names to simple expansion text. */
124 const m4_macro m4_macro_table
[] =
126 /* name text min max */
127 { "__mpeval__", "", 0, 0 },
128 { NULL
, NULL
, 0, 0 },
132 /* GMP defines mpq_t as a 1-element array of struct. Therefore, `mpq_t'
133 is not compatible with `const mpq_t'. */
134 typedef mpq_t number
;
136 static void numb_initialise (void);
137 static void numb_obstack (m4_obstack
*obs
, const number value
,
138 const int radix
, int min
);
139 static void mpq2mpz (m4
*context
, mpz_t z
, const number q
, const char *noisily
);
140 static void mpz2mpq (number q
, const mpz_t z
);
141 static void numb_divide (number
*x
, number
*y
);
142 static void numb_modulo (m4
*context
, number
*x
, number
*y
);
143 static void numb_and (m4
*context
, number
*x
, number
*y
);
144 static void numb_ior (m4
*context
, number
*x
, number
*y
);
145 static void numb_eor (m4
*context
, number
*x
, number
*y
);
146 static void numb_not (m4
*context
, number
*x
);
147 static void numb_lshift (m4
*context
, number
*x
, number
*y
);
148 static void numb_rshift (m4
*context
, number
*x
, number
*y
);
149 #define numb_urshift(c, x, y) numb_rshift (c, x, y)
152 static number numb_ZERO
;
153 static number numb_ONE
;
155 static int numb_initialised
= 0;
158 numb_initialise (void)
160 if (numb_initialised
)
163 numb_init (numb_ZERO
);
164 numb_set_si (&numb_ZERO
, 0);
166 numb_init (numb_ONE
);
167 numb_set_si (&numb_ONE
, 1);
169 numb_initialised
= 1;
173 numb_obstack (m4_obstack
*obs
, const number value
, const int radix
,
182 mpq_get_num (i
, value
);
183 s
= mpz_get_str (NULL
, radix
, i
);
187 obstack_1grow (obs
, '-');
191 for (min
-= len
; --min
>= 0;)
192 obstack_1grow (obs
, '0');
194 obstack_grow (obs
, s
, len
);
196 mpq_get_den (i
, value
);
197 if (mpz_cmp_si (i
, (long) 1) != 0)
199 obstack_1grow (obs
, '\\');
200 s
= mpz_get_str ((char *) 0, radix
, i
);
201 obstack_grow (obs
, s
, strlen (s
));
208 #define QUIET (char *)0
211 mpq2mpz (m4
*context
, mpz_t z
, const number q
, const char *noisily
)
213 if (noisily
&& mpz_cmp_si (mpq_denref (q
), (long) 1) != 0)
214 m4_warn (context
, 0, NULL
, _("loss of precision in eval: %s"), noisily
);
216 mpz_div (z
, mpq_numref (q
), mpq_denref (q
));
220 mpz2mpq (number q
, const mpz_t z
)
222 mpq_set_si (q
, (long) 0, (unsigned long) 1);
227 numb_divide (number
* x
, number
* y
)
233 mpq_div (qres
, *x
, *y
);
236 mpz_div (zres
, mpq_numref (qres
), mpq_denref (qres
));
244 numb_modulo (m4
*context
, number
* x
, number
* y
)
248 /* x should be integral */
249 /* y should be integral */
252 mpq2mpz (context
, xx
, *x
, NOISY
);
255 mpq2mpz (context
, yy
, *y
, NOISY
);
258 mpz_mod (res
, xx
, yy
);
268 numb_and (m4
*context
, number
* x
, number
* y
)
272 /* x should be integral */
273 /* y should be integral */
276 mpq2mpz (context
, xx
, *x
, NOISY
);
279 mpq2mpz (context
, yy
, *y
, NOISY
);
282 mpz_and (res
, xx
, yy
);
292 numb_ior (m4
*context
, number
* x
, number
* y
)
296 /* x should be integral */
297 /* y should be integral */
300 mpq2mpz (context
, xx
, *x
, NOISY
);
303 mpq2mpz (context
, yy
, *y
, NOISY
);
306 mpz_ior (res
, xx
, yy
);
316 numb_eor (m4
*context
, number
* x
, number
* y
)
320 /* x should be integral */
321 /* y should be integral */
324 mpq2mpz (context
, xx
, *x
, NOISY
);
327 mpq2mpz (context
, yy
, *y
, NOISY
);
332 mpz_xor (res
, xx
, yy
);
334 /* a^b = (a|b) & !(a&b) */
336 mpz_t and_ab
, ior_ab
, nand_ab
;
339 mpz_ior (ior_ab
, xx
, yy
);
342 mpz_and (and_ab
, xx
, yy
);
345 mpz_com (nand_ab
, and_ab
);
347 mpz_and (res
, ior_ab
, nand_ab
);
363 numb_not (m4
*context
, number
* x
)
367 /* x should be integral */
370 mpq2mpz (context
, xx
, *x
, NOISY
);
382 numb_lshift (m4
*context
, number
* x
, number
* y
)
386 /* x should be integral */
387 /* y should be integral */
390 mpq2mpz (context
, xx
, *x
, NOISY
);
393 mpq2mpz (context
, yy
, *y
, NOISY
);
397 /* bug: need to determine if y is too big or negative. */
398 long int exp
= mpz_get_si (yy
);
401 mpz_mul_2exp (res
, xx
, (unsigned) exp
);
405 mpz_div_2exp (res
, xx
, (unsigned) -exp
);
417 numb_rshift (m4
*context
, number
* x
, number
* y
)
421 /* x should be integral */
422 /* y should be integral */
425 mpq2mpz (context
, xx
, *x
, NOISY
);
428 mpq2mpz (context
, yy
, *y
, NOISY
);
432 /* FIXME: bug - need to determine if y is too big or negative */
433 long int exp
= mpz_get_si (yy
);
436 mpz_div_2exp (res
, xx
, (unsigned) exp
);
440 mpz_mul_2exp (res
, xx
, (unsigned) -exp
);
451 #define m4_evaluate builtin_mpeval
452 #include "evalparse.c"