pexpr.c revision 1.1 1 1.1 mrg /* Program for computing integer expressions using the GNU Multiple Precision
2 1.1 mrg Arithmetic Library.
3 1.1 mrg
4 1.1 mrg Copyright 1997, 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
5 1.1 mrg
6 1.1 mrg This program is free software; you can redistribute it and/or modify it under
7 1.1 mrg the terms of the GNU General Public License as published by the Free Software
8 1.1 mrg Foundation; either version 3 of the License, or (at your option) any later
9 1.1 mrg version.
10 1.1 mrg
11 1.1 mrg This program is distributed in the hope that it will be useful, but WITHOUT ANY
12 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 1.1 mrg PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 1.1 mrg
15 1.1 mrg You should have received a copy of the GNU General Public License along with
16 1.1 mrg this program. If not, see http://www.gnu.org/licenses/. */
17 1.1 mrg
18 1.1 mrg
19 1.1 mrg /* This expressions evaluator works by building an expression tree (using a
20 1.1 mrg recursive descent parser) which is then evaluated. The expression tree is
21 1.1 mrg useful since we want to optimize certain expressions (like a^b % c).
22 1.1 mrg
23 1.1 mrg Usage: pexpr [options] expr ...
24 1.1 mrg (Assuming you called the executable `pexpr' of course.)
25 1.1 mrg
26 1.1 mrg Command line options:
27 1.1 mrg
28 1.1 mrg -b print output in binary
29 1.1 mrg -o print output in octal
30 1.1 mrg -d print output in decimal (the default)
31 1.1 mrg -x print output in hexadecimal
32 1.1 mrg -b<NUM> print output in base NUM
33 1.1 mrg -t print timing information
34 1.1 mrg -html output html
35 1.1 mrg -wml output wml
36 1.1 mrg -split split long lines each 80th digit
37 1.1 mrg */
38 1.1 mrg
39 1.1 mrg /* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
40 1.1 mrg use up extensive resources (cpu, memory). Useful for the GMP demo on the
41 1.1 mrg GMP web site, since we cannot load the server too much. */
42 1.1 mrg
43 1.1 mrg #include "pexpr-config.h"
44 1.1 mrg
45 1.1 mrg #include <string.h>
46 1.1 mrg #include <stdio.h>
47 1.1 mrg #include <stdlib.h>
48 1.1 mrg #include <setjmp.h>
49 1.1 mrg #include <signal.h>
50 1.1 mrg #include <ctype.h>
51 1.1 mrg
52 1.1 mrg #include <time.h>
53 1.1 mrg #include <sys/types.h>
54 1.1 mrg #include <sys/time.h>
55 1.1 mrg #if HAVE_SYS_RESOURCE_H
56 1.1 mrg #include <sys/resource.h>
57 1.1 mrg #endif
58 1.1 mrg
59 1.1 mrg #include "gmp.h"
60 1.1 mrg
61 1.1 mrg /* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */
62 1.1 mrg #ifndef SIGSTKSZ
63 1.1 mrg #define SIGSTKSZ 4096
64 1.1 mrg #endif
65 1.1 mrg
66 1.1 mrg
67 1.1 mrg #define TIME(t,func) \
68 1.1 mrg do { int __t0, __tmp; \
69 1.1 mrg __t0 = cputime (); \
70 1.1 mrg {func;} \
71 1.1 mrg __tmp = cputime () - __t0; \
72 1.1 mrg (t) = __tmp; \
73 1.1 mrg } while (0)
74 1.1 mrg
75 1.1 mrg /* GMP version 1.x compatibility. */
76 1.1 mrg #if ! (__GNU_MP_VERSION >= 2)
77 1.1 mrg typedef MP_INT __mpz_struct;
78 1.1 mrg typedef __mpz_struct mpz_t[1];
79 1.1 mrg typedef __mpz_struct *mpz_ptr;
80 1.1 mrg #define mpz_fdiv_q mpz_div
81 1.1 mrg #define mpz_fdiv_r mpz_mod
82 1.1 mrg #define mpz_tdiv_q_2exp mpz_div_2exp
83 1.1 mrg #define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
84 1.1 mrg #endif
85 1.1 mrg
86 1.1 mrg /* GMP version 2.0 compatibility. */
87 1.1 mrg #if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
88 1.1 mrg #define mpz_swap(a,b) \
89 1.1 mrg do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
90 1.1 mrg #endif
91 1.1 mrg
92 1.1 mrg jmp_buf errjmpbuf;
93 1.1 mrg
94 1.1 mrg enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
95 1.1 mrg AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
96 1.1 mrg LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM,
97 1.1 mrg TIMING};
98 1.1 mrg
99 1.1 mrg /* Type for the expression tree. */
100 1.1 mrg struct expr
101 1.1 mrg {
102 1.1 mrg enum op_t op;
103 1.1 mrg union
104 1.1 mrg {
105 1.1 mrg struct {struct expr *lhs, *rhs;} ops;
106 1.1 mrg mpz_t val;
107 1.1 mrg } operands;
108 1.1 mrg };
109 1.1 mrg
110 1.1 mrg typedef struct expr *expr_t;
111 1.1 mrg
112 1.1 mrg void cleanup_and_exit __GMP_PROTO ((int));
113 1.1 mrg
114 1.1 mrg char *skipspace __GMP_PROTO ((char *));
115 1.1 mrg void makeexp __GMP_PROTO ((expr_t *, enum op_t, expr_t, expr_t));
116 1.1 mrg void free_expr __GMP_PROTO ((expr_t));
117 1.1 mrg char *expr __GMP_PROTO ((char *, expr_t *));
118 1.1 mrg char *term __GMP_PROTO ((char *, expr_t *));
119 1.1 mrg char *power __GMP_PROTO ((char *, expr_t *));
120 1.1 mrg char *factor __GMP_PROTO ((char *, expr_t *));
121 1.1 mrg int match __GMP_PROTO ((char *, char *));
122 1.1 mrg int matchp __GMP_PROTO ((char *, char *));
123 1.1 mrg int cputime __GMP_PROTO ((void));
124 1.1 mrg
125 1.1 mrg void mpz_eval_expr __GMP_PROTO ((mpz_ptr, expr_t));
126 1.1 mrg void mpz_eval_mod_expr __GMP_PROTO ((mpz_ptr, expr_t, mpz_ptr));
127 1.1 mrg
128 1.1 mrg char *error;
129 1.1 mrg int flag_print = 1;
130 1.1 mrg int print_timing = 0;
131 1.1 mrg int flag_html = 0;
132 1.1 mrg int flag_wml = 0;
133 1.1 mrg int flag_splitup_output = 0;
134 1.1 mrg char *newline = "";
135 1.1 mrg gmp_randstate_t rstate;
136 1.1 mrg
137 1.1 mrg
138 1.1 mrg
139 1.1 mrg /* cputime() returns user CPU time measured in milliseconds. */
140 1.1 mrg #if ! HAVE_CPUTIME
141 1.1 mrg #if HAVE_GETRUSAGE
142 1.1 mrg int
143 1.1 mrg cputime (void)
144 1.1 mrg {
145 1.1 mrg struct rusage rus;
146 1.1 mrg
147 1.1 mrg getrusage (0, &rus);
148 1.1 mrg return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
149 1.1 mrg }
150 1.1 mrg #else
151 1.1 mrg #if HAVE_CLOCK
152 1.1 mrg int
153 1.1 mrg cputime (void)
154 1.1 mrg {
155 1.1 mrg if (CLOCKS_PER_SEC < 100000)
156 1.1 mrg return clock () * 1000 / CLOCKS_PER_SEC;
157 1.1 mrg return clock () / (CLOCKS_PER_SEC / 1000);
158 1.1 mrg }
159 1.1 mrg #else
160 1.1 mrg int
161 1.1 mrg cputime (void)
162 1.1 mrg {
163 1.1 mrg return 0;
164 1.1 mrg }
165 1.1 mrg #endif
166 1.1 mrg #endif
167 1.1 mrg #endif
168 1.1 mrg
169 1.1 mrg
170 1.1 mrg int
171 1.1 mrg stack_downwards_helper (char *xp)
172 1.1 mrg {
173 1.1 mrg char y;
174 1.1 mrg return &y < xp;
175 1.1 mrg }
176 1.1 mrg int
177 1.1 mrg stack_downwards_p (void)
178 1.1 mrg {
179 1.1 mrg char x;
180 1.1 mrg return stack_downwards_helper (&x);
181 1.1 mrg }
182 1.1 mrg
183 1.1 mrg
184 1.1 mrg void
185 1.1 mrg setup_error_handler (void)
186 1.1 mrg {
187 1.1 mrg #if HAVE_SIGACTION
188 1.1 mrg struct sigaction act;
189 1.1 mrg act.sa_handler = cleanup_and_exit;
190 1.1 mrg sigemptyset (&(act.sa_mask));
191 1.1 mrg #define SIGNAL(sig) sigaction (sig, &act, NULL)
192 1.1 mrg #else
193 1.1 mrg struct { int sa_flags; } act;
194 1.1 mrg #define SIGNAL(sig) signal (sig, cleanup_and_exit)
195 1.1 mrg #endif
196 1.1 mrg act.sa_flags = 0;
197 1.1 mrg
198 1.1 mrg /* Set up a stack for signal handling. A typical cause of error is stack
199 1.1 mrg overflow, and in such situation a signal can not be delivered on the
200 1.1 mrg overflown stack. */
201 1.1 mrg #if HAVE_SIGALTSTACK
202 1.1 mrg {
203 1.1 mrg /* AIX uses stack_t, MacOS uses struct sigaltstack, various other
204 1.1 mrg systems have both. */
205 1.1 mrg #if HAVE_STACK_T
206 1.1 mrg stack_t s;
207 1.1 mrg #else
208 1.1 mrg struct sigaltstack s;
209 1.1 mrg #endif
210 1.1 mrg s.ss_sp = malloc (SIGSTKSZ);
211 1.1 mrg s.ss_size = SIGSTKSZ;
212 1.1 mrg s.ss_flags = 0;
213 1.1 mrg if (sigaltstack (&s, NULL) != 0)
214 1.1 mrg perror("sigaltstack");
215 1.1 mrg act.sa_flags = SA_ONSTACK;
216 1.1 mrg }
217 1.1 mrg #else
218 1.1 mrg #if HAVE_SIGSTACK
219 1.1 mrg {
220 1.1 mrg struct sigstack s;
221 1.1 mrg s.ss_sp = malloc (SIGSTKSZ);
222 1.1 mrg if (stack_downwards_p ())
223 1.1 mrg s.ss_sp += SIGSTKSZ;
224 1.1 mrg s.ss_onstack = 0;
225 1.1 mrg if (sigstack (&s, NULL) != 0)
226 1.1 mrg perror("sigstack");
227 1.1 mrg act.sa_flags = SA_ONSTACK;
228 1.1 mrg }
229 1.1 mrg #else
230 1.1 mrg #endif
231 1.1 mrg #endif
232 1.1 mrg
233 1.1 mrg #ifdef LIMIT_RESOURCE_USAGE
234 1.1 mrg {
235 1.1 mrg struct rlimit limit;
236 1.1 mrg
237 1.1 mrg limit.rlim_cur = limit.rlim_max = 0;
238 1.1 mrg setrlimit (RLIMIT_CORE, &limit);
239 1.1 mrg
240 1.1 mrg limit.rlim_cur = 3;
241 1.1 mrg limit.rlim_max = 4;
242 1.1 mrg setrlimit (RLIMIT_CPU, &limit);
243 1.1 mrg
244 1.1 mrg limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024;
245 1.1 mrg setrlimit (RLIMIT_DATA, &limit);
246 1.1 mrg
247 1.1 mrg getrlimit (RLIMIT_STACK, &limit);
248 1.1 mrg limit.rlim_cur = 4 * 1024 * 1024;
249 1.1 mrg setrlimit (RLIMIT_STACK, &limit);
250 1.1 mrg
251 1.1 mrg SIGNAL (SIGXCPU);
252 1.1 mrg }
253 1.1 mrg #endif /* LIMIT_RESOURCE_USAGE */
254 1.1 mrg
255 1.1 mrg SIGNAL (SIGILL);
256 1.1 mrg SIGNAL (SIGSEGV);
257 1.1 mrg #ifdef SIGBUS /* not in mingw */
258 1.1 mrg SIGNAL (SIGBUS);
259 1.1 mrg #endif
260 1.1 mrg SIGNAL (SIGFPE);
261 1.1 mrg SIGNAL (SIGABRT);
262 1.1 mrg }
263 1.1 mrg
264 1.1 mrg int
265 1.1 mrg main (int argc, char **argv)
266 1.1 mrg {
267 1.1 mrg struct expr *e;
268 1.1 mrg int i;
269 1.1 mrg mpz_t r;
270 1.1 mrg int errcode = 0;
271 1.1 mrg char *str;
272 1.1 mrg int base = 10;
273 1.1 mrg
274 1.1 mrg setup_error_handler ();
275 1.1 mrg
276 1.1 mrg gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);
277 1.1 mrg
278 1.1 mrg {
279 1.1 mrg #if HAVE_GETTIMEOFDAY
280 1.1 mrg struct timeval tv;
281 1.1 mrg gettimeofday (&tv, NULL);
282 1.1 mrg gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);
283 1.1 mrg #else
284 1.1 mrg time_t t;
285 1.1 mrg time (&t);
286 1.1 mrg gmp_randseed_ui (rstate, t);
287 1.1 mrg #endif
288 1.1 mrg }
289 1.1 mrg
290 1.1 mrg mpz_init (r);
291 1.1 mrg
292 1.1 mrg while (argc > 1 && argv[1][0] == '-')
293 1.1 mrg {
294 1.1 mrg char *arg = argv[1];
295 1.1 mrg
296 1.1 mrg if (arg[1] >= '0' && arg[1] <= '9')
297 1.1 mrg break;
298 1.1 mrg
299 1.1 mrg if (arg[1] == 't')
300 1.1 mrg print_timing = 1;
301 1.1 mrg else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
302 1.1 mrg {
303 1.1 mrg base = atoi (arg + 2);
304 1.1 mrg if (base < 2 || base > 62)
305 1.1 mrg {
306 1.1 mrg fprintf (stderr, "error: invalid output base\n");
307 1.1 mrg exit (-1);
308 1.1 mrg }
309 1.1 mrg }
310 1.1 mrg else if (arg[1] == 'b' && arg[2] == 0)
311 1.1 mrg base = 2;
312 1.1 mrg else if (arg[1] == 'x' && arg[2] == 0)
313 1.1 mrg base = 16;
314 1.1 mrg else if (arg[1] == 'X' && arg[2] == 0)
315 1.1 mrg base = -16;
316 1.1 mrg else if (arg[1] == 'o' && arg[2] == 0)
317 1.1 mrg base = 8;
318 1.1 mrg else if (arg[1] == 'd' && arg[2] == 0)
319 1.1 mrg base = 10;
320 1.1 mrg else if (arg[1] == 'v' && arg[2] == 0)
321 1.1 mrg {
322 1.1 mrg printf ("pexpr linked to gmp %s\n", __gmp_version);
323 1.1 mrg }
324 1.1 mrg else if (strcmp (arg, "-html") == 0)
325 1.1 mrg {
326 1.1 mrg flag_html = 1;
327 1.1 mrg newline = "<br>";
328 1.1 mrg }
329 1.1 mrg else if (strcmp (arg, "-wml") == 0)
330 1.1 mrg {
331 1.1 mrg flag_wml = 1;
332 1.1 mrg newline = "<br/>";
333 1.1 mrg }
334 1.1 mrg else if (strcmp (arg, "-split") == 0)
335 1.1 mrg {
336 1.1 mrg flag_splitup_output = 1;
337 1.1 mrg }
338 1.1 mrg else if (strcmp (arg, "-noprint") == 0)
339 1.1 mrg {
340 1.1 mrg flag_print = 0;
341 1.1 mrg }
342 1.1 mrg else
343 1.1 mrg {
344 1.1 mrg fprintf (stderr, "error: unknown option `%s'\n", arg);
345 1.1 mrg exit (-1);
346 1.1 mrg }
347 1.1 mrg argv++;
348 1.1 mrg argc--;
349 1.1 mrg }
350 1.1 mrg
351 1.1 mrg for (i = 1; i < argc; i++)
352 1.1 mrg {
353 1.1 mrg int s;
354 1.1 mrg int jmpval;
355 1.1 mrg
356 1.1 mrg /* Set up error handler for parsing expression. */
357 1.1 mrg jmpval = setjmp (errjmpbuf);
358 1.1 mrg if (jmpval != 0)
359 1.1 mrg {
360 1.1 mrg fprintf (stderr, "error: %s%s\n", error, newline);
361 1.1 mrg fprintf (stderr, " %s%s\n", argv[i], newline);
362 1.1 mrg if (! flag_html)
363 1.1 mrg {
364 1.1 mrg /* ??? Dunno how to align expression position with arrow in
365 1.1 mrg HTML ??? */
366 1.1 mrg fprintf (stderr, " ");
367 1.1 mrg for (s = jmpval - (long) argv[i]; --s >= 0; )
368 1.1 mrg putc (' ', stderr);
369 1.1 mrg fprintf (stderr, "^\n");
370 1.1 mrg }
371 1.1 mrg
372 1.1 mrg errcode |= 1;
373 1.1 mrg continue;
374 1.1 mrg }
375 1.1 mrg
376 1.1 mrg str = expr (argv[i], &e);
377 1.1 mrg
378 1.1 mrg if (str[0] != 0)
379 1.1 mrg {
380 1.1 mrg fprintf (stderr,
381 1.1 mrg "error: garbage where end of expression expected%s\n",
382 1.1 mrg newline);
383 1.1 mrg fprintf (stderr, " %s%s\n", argv[i], newline);
384 1.1 mrg if (! flag_html)
385 1.1 mrg {
386 1.1 mrg /* ??? Dunno how to align expression position with arrow in
387 1.1 mrg HTML ??? */
388 1.1 mrg fprintf (stderr, " ");
389 1.1 mrg for (s = str - argv[i]; --s; )
390 1.1 mrg putc (' ', stderr);
391 1.1 mrg fprintf (stderr, "^\n");
392 1.1 mrg }
393 1.1 mrg
394 1.1 mrg errcode |= 1;
395 1.1 mrg free_expr (e);
396 1.1 mrg continue;
397 1.1 mrg }
398 1.1 mrg
399 1.1 mrg /* Set up error handler for evaluating expression. */
400 1.1 mrg if (setjmp (errjmpbuf))
401 1.1 mrg {
402 1.1 mrg fprintf (stderr, "error: %s%s\n", error, newline);
403 1.1 mrg fprintf (stderr, " %s%s\n", argv[i], newline);
404 1.1 mrg if (! flag_html)
405 1.1 mrg {
406 1.1 mrg /* ??? Dunno how to align expression position with arrow in
407 1.1 mrg HTML ??? */
408 1.1 mrg fprintf (stderr, " ");
409 1.1 mrg for (s = str - argv[i]; --s >= 0; )
410 1.1 mrg putc (' ', stderr);
411 1.1 mrg fprintf (stderr, "^\n");
412 1.1 mrg }
413 1.1 mrg
414 1.1 mrg errcode |= 2;
415 1.1 mrg continue;
416 1.1 mrg }
417 1.1 mrg
418 1.1 mrg if (print_timing)
419 1.1 mrg {
420 1.1 mrg int t;
421 1.1 mrg TIME (t, mpz_eval_expr (r, e));
422 1.1 mrg printf ("computation took %d ms%s\n", t, newline);
423 1.1 mrg }
424 1.1 mrg else
425 1.1 mrg mpz_eval_expr (r, e);
426 1.1 mrg
427 1.1 mrg if (flag_print)
428 1.1 mrg {
429 1.1 mrg size_t out_len;
430 1.1 mrg char *tmp, *s;
431 1.1 mrg
432 1.1 mrg out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
433 1.1 mrg #ifdef LIMIT_RESOURCE_USAGE
434 1.1 mrg if (out_len > 100000)
435 1.1 mrg {
436 1.1 mrg printf ("result is about %ld digits, not printing it%s\n",
437 1.1 mrg (long) out_len - 3, newline);
438 1.1 mrg exit (-2);
439 1.1 mrg }
440 1.1 mrg #endif
441 1.1 mrg tmp = malloc (out_len);
442 1.1 mrg
443 1.1 mrg if (print_timing)
444 1.1 mrg {
445 1.1 mrg int t;
446 1.1 mrg printf ("output conversion ");
447 1.1 mrg TIME (t, mpz_get_str (tmp, base, r));
448 1.1 mrg printf ("took %d ms%s\n", t, newline);
449 1.1 mrg }
450 1.1 mrg else
451 1.1 mrg mpz_get_str (tmp, base, r);
452 1.1 mrg
453 1.1 mrg out_len = strlen (tmp);
454 1.1 mrg if (flag_splitup_output)
455 1.1 mrg {
456 1.1 mrg for (s = tmp; out_len > 80; s += 80)
457 1.1 mrg {
458 1.1 mrg fwrite (s, 1, 80, stdout);
459 1.1 mrg printf ("%s\n", newline);
460 1.1 mrg out_len -= 80;
461 1.1 mrg }
462 1.1 mrg
463 1.1 mrg fwrite (s, 1, out_len, stdout);
464 1.1 mrg }
465 1.1 mrg else
466 1.1 mrg {
467 1.1 mrg fwrite (tmp, 1, out_len, stdout);
468 1.1 mrg }
469 1.1 mrg
470 1.1 mrg free (tmp);
471 1.1 mrg printf ("%s\n", newline);
472 1.1 mrg }
473 1.1 mrg else
474 1.1 mrg {
475 1.1 mrg printf ("result is approximately %ld digits%s\n",
476 1.1 mrg (long) mpz_sizeinbase (r, base >= 0 ? base : -base),
477 1.1 mrg newline);
478 1.1 mrg }
479 1.1 mrg
480 1.1 mrg free_expr (e);
481 1.1 mrg }
482 1.1 mrg
483 1.1 mrg exit (errcode);
484 1.1 mrg }
485 1.1 mrg
486 1.1 mrg char *
487 1.1 mrg expr (char *str, expr_t *e)
488 1.1 mrg {
489 1.1 mrg expr_t e2;
490 1.1 mrg
491 1.1 mrg str = skipspace (str);
492 1.1 mrg if (str[0] == '+')
493 1.1 mrg {
494 1.1 mrg str = term (str + 1, e);
495 1.1 mrg }
496 1.1 mrg else if (str[0] == '-')
497 1.1 mrg {
498 1.1 mrg str = term (str + 1, e);
499 1.1 mrg makeexp (e, NEG, *e, NULL);
500 1.1 mrg }
501 1.1 mrg else if (str[0] == '~')
502 1.1 mrg {
503 1.1 mrg str = term (str + 1, e);
504 1.1 mrg makeexp (e, NOT, *e, NULL);
505 1.1 mrg }
506 1.1 mrg else
507 1.1 mrg {
508 1.1 mrg str = term (str, e);
509 1.1 mrg }
510 1.1 mrg
511 1.1 mrg for (;;)
512 1.1 mrg {
513 1.1 mrg str = skipspace (str);
514 1.1 mrg switch (str[0])
515 1.1 mrg {
516 1.1 mrg case 'p':
517 1.1 mrg if (match ("plus", str))
518 1.1 mrg {
519 1.1 mrg str = term (str + 4, &e2);
520 1.1 mrg makeexp (e, PLUS, *e, e2);
521 1.1 mrg }
522 1.1 mrg else
523 1.1 mrg return str;
524 1.1 mrg break;
525 1.1 mrg case 'm':
526 1.1 mrg if (match ("minus", str))
527 1.1 mrg {
528 1.1 mrg str = term (str + 5, &e2);
529 1.1 mrg makeexp (e, MINUS, *e, e2);
530 1.1 mrg }
531 1.1 mrg else
532 1.1 mrg return str;
533 1.1 mrg break;
534 1.1 mrg case '+':
535 1.1 mrg str = term (str + 1, &e2);
536 1.1 mrg makeexp (e, PLUS, *e, e2);
537 1.1 mrg break;
538 1.1 mrg case '-':
539 1.1 mrg str = term (str + 1, &e2);
540 1.1 mrg makeexp (e, MINUS, *e, e2);
541 1.1 mrg break;
542 1.1 mrg default:
543 1.1 mrg return str;
544 1.1 mrg }
545 1.1 mrg }
546 1.1 mrg }
547 1.1 mrg
548 1.1 mrg char *
549 1.1 mrg term (char *str, expr_t *e)
550 1.1 mrg {
551 1.1 mrg expr_t e2;
552 1.1 mrg
553 1.1 mrg str = power (str, e);
554 1.1 mrg for (;;)
555 1.1 mrg {
556 1.1 mrg str = skipspace (str);
557 1.1 mrg switch (str[0])
558 1.1 mrg {
559 1.1 mrg case 'm':
560 1.1 mrg if (match ("mul", str))
561 1.1 mrg {
562 1.1 mrg str = power (str + 3, &e2);
563 1.1 mrg makeexp (e, MULT, *e, e2);
564 1.1 mrg break;
565 1.1 mrg }
566 1.1 mrg if (match ("mod", str))
567 1.1 mrg {
568 1.1 mrg str = power (str + 3, &e2);
569 1.1 mrg makeexp (e, MOD, *e, e2);
570 1.1 mrg break;
571 1.1 mrg }
572 1.1 mrg return str;
573 1.1 mrg case 'd':
574 1.1 mrg if (match ("div", str))
575 1.1 mrg {
576 1.1 mrg str = power (str + 3, &e2);
577 1.1 mrg makeexp (e, DIV, *e, e2);
578 1.1 mrg break;
579 1.1 mrg }
580 1.1 mrg return str;
581 1.1 mrg case 'r':
582 1.1 mrg if (match ("rem", str))
583 1.1 mrg {
584 1.1 mrg str = power (str + 3, &e2);
585 1.1 mrg makeexp (e, REM, *e, e2);
586 1.1 mrg break;
587 1.1 mrg }
588 1.1 mrg return str;
589 1.1 mrg case 'i':
590 1.1 mrg if (match ("invmod", str))
591 1.1 mrg {
592 1.1 mrg str = power (str + 6, &e2);
593 1.1 mrg makeexp (e, REM, *e, e2);
594 1.1 mrg break;
595 1.1 mrg }
596 1.1 mrg return str;
597 1.1 mrg case 't':
598 1.1 mrg if (match ("times", str))
599 1.1 mrg {
600 1.1 mrg str = power (str + 5, &e2);
601 1.1 mrg makeexp (e, MULT, *e, e2);
602 1.1 mrg break;
603 1.1 mrg }
604 1.1 mrg if (match ("thru", str))
605 1.1 mrg {
606 1.1 mrg str = power (str + 4, &e2);
607 1.1 mrg makeexp (e, DIV, *e, e2);
608 1.1 mrg break;
609 1.1 mrg }
610 1.1 mrg if (match ("through", str))
611 1.1 mrg {
612 1.1 mrg str = power (str + 7, &e2);
613 1.1 mrg makeexp (e, DIV, *e, e2);
614 1.1 mrg break;
615 1.1 mrg }
616 1.1 mrg return str;
617 1.1 mrg case '*':
618 1.1 mrg str = power (str + 1, &e2);
619 1.1 mrg makeexp (e, MULT, *e, e2);
620 1.1 mrg break;
621 1.1 mrg case '/':
622 1.1 mrg str = power (str + 1, &e2);
623 1.1 mrg makeexp (e, DIV, *e, e2);
624 1.1 mrg break;
625 1.1 mrg case '%':
626 1.1 mrg str = power (str + 1, &e2);
627 1.1 mrg makeexp (e, MOD, *e, e2);
628 1.1 mrg break;
629 1.1 mrg default:
630 1.1 mrg return str;
631 1.1 mrg }
632 1.1 mrg }
633 1.1 mrg }
634 1.1 mrg
635 1.1 mrg char *
636 1.1 mrg power (char *str, expr_t *e)
637 1.1 mrg {
638 1.1 mrg expr_t e2;
639 1.1 mrg
640 1.1 mrg str = factor (str, e);
641 1.1 mrg while (str[0] == '!')
642 1.1 mrg {
643 1.1 mrg str++;
644 1.1 mrg makeexp (e, FAC, *e, NULL);
645 1.1 mrg }
646 1.1 mrg str = skipspace (str);
647 1.1 mrg if (str[0] == '^')
648 1.1 mrg {
649 1.1 mrg str = power (str + 1, &e2);
650 1.1 mrg makeexp (e, POW, *e, e2);
651 1.1 mrg }
652 1.1 mrg return str;
653 1.1 mrg }
654 1.1 mrg
655 1.1 mrg int
656 1.1 mrg match (char *s, char *str)
657 1.1 mrg {
658 1.1 mrg char *ostr = str;
659 1.1 mrg int i;
660 1.1 mrg
661 1.1 mrg for (i = 0; s[i] != 0; i++)
662 1.1 mrg {
663 1.1 mrg if (str[i] != s[i])
664 1.1 mrg return 0;
665 1.1 mrg }
666 1.1 mrg str = skipspace (str + i);
667 1.1 mrg return str - ostr;
668 1.1 mrg }
669 1.1 mrg
670 1.1 mrg int
671 1.1 mrg matchp (char *s, char *str)
672 1.1 mrg {
673 1.1 mrg char *ostr = str;
674 1.1 mrg int i;
675 1.1 mrg
676 1.1 mrg for (i = 0; s[i] != 0; i++)
677 1.1 mrg {
678 1.1 mrg if (str[i] != s[i])
679 1.1 mrg return 0;
680 1.1 mrg }
681 1.1 mrg str = skipspace (str + i);
682 1.1 mrg if (str[0] == '(')
683 1.1 mrg return str - ostr + 1;
684 1.1 mrg return 0;
685 1.1 mrg }
686 1.1 mrg
687 1.1 mrg struct functions
688 1.1 mrg {
689 1.1 mrg char *spelling;
690 1.1 mrg enum op_t op;
691 1.1 mrg int arity; /* 1 or 2 means real arity; 0 means arbitrary. */
692 1.1 mrg };
693 1.1 mrg
694 1.1 mrg struct functions fns[] =
695 1.1 mrg {
696 1.1 mrg {"sqrt", SQRT, 1},
697 1.1 mrg #if __GNU_MP_VERSION >= 2
698 1.1 mrg {"root", ROOT, 2},
699 1.1 mrg {"popc", POPCNT, 1},
700 1.1 mrg {"hamdist", HAMDIST, 2},
701 1.1 mrg #endif
702 1.1 mrg {"gcd", GCD, 0},
703 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
704 1.1 mrg {"lcm", LCM, 0},
705 1.1 mrg #endif
706 1.1 mrg {"and", AND, 0},
707 1.1 mrg {"ior", IOR, 0},
708 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
709 1.1 mrg {"xor", XOR, 0},
710 1.1 mrg #endif
711 1.1 mrg {"plus", PLUS, 0},
712 1.1 mrg {"pow", POW, 2},
713 1.1 mrg {"minus", MINUS, 2},
714 1.1 mrg {"mul", MULT, 0},
715 1.1 mrg {"div", DIV, 2},
716 1.1 mrg {"mod", MOD, 2},
717 1.1 mrg {"rem", REM, 2},
718 1.1 mrg #if __GNU_MP_VERSION >= 2
719 1.1 mrg {"invmod", INVMOD, 2},
720 1.1 mrg #endif
721 1.1 mrg {"log", LOG, 2},
722 1.1 mrg {"log2", LOG2, 1},
723 1.1 mrg {"F", FERMAT, 1},
724 1.1 mrg {"M", MERSENNE, 1},
725 1.1 mrg {"fib", FIBONACCI, 1},
726 1.1 mrg {"Fib", FIBONACCI, 1},
727 1.1 mrg {"random", RANDOM, 1},
728 1.1 mrg {"nextprime", NEXTPRIME, 1},
729 1.1 mrg {"binom", BINOM, 2},
730 1.1 mrg {"binomial", BINOM, 2},
731 1.1 mrg {"fac", FAC, 1},
732 1.1 mrg {"fact", FAC, 1},
733 1.1 mrg {"factorial", FAC, 1},
734 1.1 mrg {"time", TIMING, 1},
735 1.1 mrg {"", NOP, 0}
736 1.1 mrg };
737 1.1 mrg
738 1.1 mrg char *
739 1.1 mrg factor (char *str, expr_t *e)
740 1.1 mrg {
741 1.1 mrg expr_t e1, e2;
742 1.1 mrg
743 1.1 mrg str = skipspace (str);
744 1.1 mrg
745 1.1 mrg if (isalpha (str[0]))
746 1.1 mrg {
747 1.1 mrg int i;
748 1.1 mrg int cnt;
749 1.1 mrg
750 1.1 mrg for (i = 0; fns[i].op != NOP; i++)
751 1.1 mrg {
752 1.1 mrg if (fns[i].arity == 1)
753 1.1 mrg {
754 1.1 mrg cnt = matchp (fns[i].spelling, str);
755 1.1 mrg if (cnt != 0)
756 1.1 mrg {
757 1.1 mrg str = expr (str + cnt, &e1);
758 1.1 mrg str = skipspace (str);
759 1.1 mrg if (str[0] != ')')
760 1.1 mrg {
761 1.1 mrg error = "expected `)'";
762 1.1 mrg longjmp (errjmpbuf, (int) (long) str);
763 1.1 mrg }
764 1.1 mrg makeexp (e, fns[i].op, e1, NULL);
765 1.1 mrg return str + 1;
766 1.1 mrg }
767 1.1 mrg }
768 1.1 mrg }
769 1.1 mrg
770 1.1 mrg for (i = 0; fns[i].op != NOP; i++)
771 1.1 mrg {
772 1.1 mrg if (fns[i].arity != 1)
773 1.1 mrg {
774 1.1 mrg cnt = matchp (fns[i].spelling, str);
775 1.1 mrg if (cnt != 0)
776 1.1 mrg {
777 1.1 mrg str = expr (str + cnt, &e1);
778 1.1 mrg str = skipspace (str);
779 1.1 mrg
780 1.1 mrg if (str[0] != ',')
781 1.1 mrg {
782 1.1 mrg error = "expected `,' and another operand";
783 1.1 mrg longjmp (errjmpbuf, (int) (long) str);
784 1.1 mrg }
785 1.1 mrg
786 1.1 mrg str = skipspace (str + 1);
787 1.1 mrg str = expr (str, &e2);
788 1.1 mrg str = skipspace (str);
789 1.1 mrg
790 1.1 mrg if (fns[i].arity == 0)
791 1.1 mrg {
792 1.1 mrg while (str[0] == ',')
793 1.1 mrg {
794 1.1 mrg makeexp (&e1, fns[i].op, e1, e2);
795 1.1 mrg str = skipspace (str + 1);
796 1.1 mrg str = expr (str, &e2);
797 1.1 mrg str = skipspace (str);
798 1.1 mrg }
799 1.1 mrg }
800 1.1 mrg
801 1.1 mrg if (str[0] != ')')
802 1.1 mrg {
803 1.1 mrg error = "expected `)'";
804 1.1 mrg longjmp (errjmpbuf, (int) (long) str);
805 1.1 mrg }
806 1.1 mrg
807 1.1 mrg makeexp (e, fns[i].op, e1, e2);
808 1.1 mrg return str + 1;
809 1.1 mrg }
810 1.1 mrg }
811 1.1 mrg }
812 1.1 mrg }
813 1.1 mrg
814 1.1 mrg if (str[0] == '(')
815 1.1 mrg {
816 1.1 mrg str = expr (str + 1, e);
817 1.1 mrg str = skipspace (str);
818 1.1 mrg if (str[0] != ')')
819 1.1 mrg {
820 1.1 mrg error = "expected `)'";
821 1.1 mrg longjmp (errjmpbuf, (int) (long) str);
822 1.1 mrg }
823 1.1 mrg str++;
824 1.1 mrg }
825 1.1 mrg else if (str[0] >= '0' && str[0] <= '9')
826 1.1 mrg {
827 1.1 mrg expr_t res;
828 1.1 mrg char *s, *sc;
829 1.1 mrg
830 1.1 mrg res = malloc (sizeof (struct expr));
831 1.1 mrg res -> op = LIT;
832 1.1 mrg mpz_init (res->operands.val);
833 1.1 mrg
834 1.1 mrg s = str;
835 1.1 mrg while (isalnum (str[0]))
836 1.1 mrg str++;
837 1.1 mrg sc = malloc (str - s + 1);
838 1.1 mrg memcpy (sc, s, str - s);
839 1.1 mrg sc[str - s] = 0;
840 1.1 mrg
841 1.1 mrg mpz_set_str (res->operands.val, sc, 0);
842 1.1 mrg *e = res;
843 1.1 mrg free (sc);
844 1.1 mrg }
845 1.1 mrg else
846 1.1 mrg {
847 1.1 mrg error = "operand expected";
848 1.1 mrg longjmp (errjmpbuf, (int) (long) str);
849 1.1 mrg }
850 1.1 mrg return str;
851 1.1 mrg }
852 1.1 mrg
853 1.1 mrg char *
854 1.1 mrg skipspace (char *str)
855 1.1 mrg {
856 1.1 mrg while (str[0] == ' ')
857 1.1 mrg str++;
858 1.1 mrg return str;
859 1.1 mrg }
860 1.1 mrg
861 1.1 mrg /* Make a new expression with operation OP and right hand side
862 1.1 mrg RHS and left hand side lhs. Put the result in R. */
863 1.1 mrg void
864 1.1 mrg makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
865 1.1 mrg {
866 1.1 mrg expr_t res;
867 1.1 mrg res = malloc (sizeof (struct expr));
868 1.1 mrg res -> op = op;
869 1.1 mrg res -> operands.ops.lhs = lhs;
870 1.1 mrg res -> operands.ops.rhs = rhs;
871 1.1 mrg *r = res;
872 1.1 mrg return;
873 1.1 mrg }
874 1.1 mrg
875 1.1 mrg /* Free the memory used by expression E. */
876 1.1 mrg void
877 1.1 mrg free_expr (expr_t e)
878 1.1 mrg {
879 1.1 mrg if (e->op != LIT)
880 1.1 mrg {
881 1.1 mrg free_expr (e->operands.ops.lhs);
882 1.1 mrg if (e->operands.ops.rhs != NULL)
883 1.1 mrg free_expr (e->operands.ops.rhs);
884 1.1 mrg }
885 1.1 mrg else
886 1.1 mrg {
887 1.1 mrg mpz_clear (e->operands.val);
888 1.1 mrg }
889 1.1 mrg }
890 1.1 mrg
891 1.1 mrg /* Evaluate the expression E and put the result in R. */
892 1.1 mrg void
893 1.1 mrg mpz_eval_expr (mpz_ptr r, expr_t e)
894 1.1 mrg {
895 1.1 mrg mpz_t lhs, rhs;
896 1.1 mrg
897 1.1 mrg switch (e->op)
898 1.1 mrg {
899 1.1 mrg case LIT:
900 1.1 mrg mpz_set (r, e->operands.val);
901 1.1 mrg return;
902 1.1 mrg case PLUS:
903 1.1 mrg mpz_init (lhs); mpz_init (rhs);
904 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
905 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
906 1.1 mrg mpz_add (r, lhs, rhs);
907 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
908 1.1 mrg return;
909 1.1 mrg case MINUS:
910 1.1 mrg mpz_init (lhs); mpz_init (rhs);
911 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
912 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
913 1.1 mrg mpz_sub (r, lhs, rhs);
914 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
915 1.1 mrg return;
916 1.1 mrg case MULT:
917 1.1 mrg mpz_init (lhs); mpz_init (rhs);
918 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
919 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
920 1.1 mrg mpz_mul (r, lhs, rhs);
921 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
922 1.1 mrg return;
923 1.1 mrg case DIV:
924 1.1 mrg mpz_init (lhs); mpz_init (rhs);
925 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
926 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
927 1.1 mrg mpz_fdiv_q (r, lhs, rhs);
928 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
929 1.1 mrg return;
930 1.1 mrg case MOD:
931 1.1 mrg mpz_init (rhs);
932 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
933 1.1 mrg mpz_abs (rhs, rhs);
934 1.1 mrg mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
935 1.1 mrg mpz_clear (rhs);
936 1.1 mrg return;
937 1.1 mrg case REM:
938 1.1 mrg /* Check if lhs operand is POW expression and optimize for that case. */
939 1.1 mrg if (e->operands.ops.lhs->op == POW)
940 1.1 mrg {
941 1.1 mrg mpz_t powlhs, powrhs;
942 1.1 mrg mpz_init (powlhs);
943 1.1 mrg mpz_init (powrhs);
944 1.1 mrg mpz_init (rhs);
945 1.1 mrg mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
946 1.1 mrg mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
947 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
948 1.1 mrg mpz_powm (r, powlhs, powrhs, rhs);
949 1.1 mrg if (mpz_cmp_si (rhs, 0L) < 0)
950 1.1 mrg mpz_neg (r, r);
951 1.1 mrg mpz_clear (powlhs);
952 1.1 mrg mpz_clear (powrhs);
953 1.1 mrg mpz_clear (rhs);
954 1.1 mrg return;
955 1.1 mrg }
956 1.1 mrg
957 1.1 mrg mpz_init (lhs); mpz_init (rhs);
958 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
959 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
960 1.1 mrg mpz_fdiv_r (r, lhs, rhs);
961 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
962 1.1 mrg return;
963 1.1 mrg #if __GNU_MP_VERSION >= 2
964 1.1 mrg case INVMOD:
965 1.1 mrg mpz_init (lhs); mpz_init (rhs);
966 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
967 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
968 1.1 mrg mpz_invert (r, lhs, rhs);
969 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
970 1.1 mrg return;
971 1.1 mrg #endif
972 1.1 mrg case POW:
973 1.1 mrg mpz_init (lhs); mpz_init (rhs);
974 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
975 1.1 mrg if (mpz_cmpabs_ui (lhs, 1) <= 0)
976 1.1 mrg {
977 1.1 mrg /* For 0^rhs and 1^rhs, we just need to verify that
978 1.1 mrg rhs is well-defined. For (-1)^rhs we need to
979 1.1 mrg determine (rhs mod 2). For simplicity, compute
980 1.1 mrg (rhs mod 2) for all three cases. */
981 1.1 mrg expr_t two, et;
982 1.1 mrg two = malloc (sizeof (struct expr));
983 1.1 mrg two -> op = LIT;
984 1.1 mrg mpz_init_set_ui (two->operands.val, 2L);
985 1.1 mrg makeexp (&et, MOD, e->operands.ops.rhs, two);
986 1.1 mrg e->operands.ops.rhs = et;
987 1.1 mrg }
988 1.1 mrg
989 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
990 1.1 mrg if (mpz_cmp_si (rhs, 0L) == 0)
991 1.1 mrg /* x^0 is 1 */
992 1.1 mrg mpz_set_ui (r, 1L);
993 1.1 mrg else if (mpz_cmp_si (lhs, 0L) == 0)
994 1.1 mrg /* 0^y (where y != 0) is 0 */
995 1.1 mrg mpz_set_ui (r, 0L);
996 1.1 mrg else if (mpz_cmp_ui (lhs, 1L) == 0)
997 1.1 mrg /* 1^y is 1 */
998 1.1 mrg mpz_set_ui (r, 1L);
999 1.1 mrg else if (mpz_cmp_si (lhs, -1L) == 0)
1000 1.1 mrg /* (-1)^y just depends on whether y is even or odd */
1001 1.1 mrg mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
1002 1.1 mrg else if (mpz_cmp_si (rhs, 0L) < 0)
1003 1.1 mrg /* x^(-n) is 0 */
1004 1.1 mrg mpz_set_ui (r, 0L);
1005 1.1 mrg else
1006 1.1 mrg {
1007 1.1 mrg unsigned long int cnt;
1008 1.1 mrg unsigned long int y;
1009 1.1 mrg /* error if exponent does not fit into an unsigned long int. */
1010 1.1 mrg if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1011 1.1 mrg goto pow_err;
1012 1.1 mrg
1013 1.1 mrg y = mpz_get_ui (rhs);
1014 1.1 mrg /* x^y == (x/(2^c))^y * 2^(c*y) */
1015 1.1 mrg #if __GNU_MP_VERSION >= 2
1016 1.1 mrg cnt = mpz_scan1 (lhs, 0);
1017 1.1 mrg #else
1018 1.1 mrg cnt = 0;
1019 1.1 mrg #endif
1020 1.1 mrg if (cnt != 0)
1021 1.1 mrg {
1022 1.1 mrg if (y * cnt / cnt != y)
1023 1.1 mrg goto pow_err;
1024 1.1 mrg mpz_tdiv_q_2exp (lhs, lhs, cnt);
1025 1.1 mrg mpz_pow_ui (r, lhs, y);
1026 1.1 mrg mpz_mul_2exp (r, r, y * cnt);
1027 1.1 mrg }
1028 1.1 mrg else
1029 1.1 mrg mpz_pow_ui (r, lhs, y);
1030 1.1 mrg }
1031 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1032 1.1 mrg return;
1033 1.1 mrg pow_err:
1034 1.1 mrg error = "result of `pow' operator too large";
1035 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1036 1.1 mrg longjmp (errjmpbuf, 1);
1037 1.1 mrg case GCD:
1038 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1039 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1040 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1041 1.1 mrg mpz_gcd (r, lhs, rhs);
1042 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1043 1.1 mrg return;
1044 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1045 1.1 mrg case LCM:
1046 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1047 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1048 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1049 1.1 mrg mpz_lcm (r, lhs, rhs);
1050 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1051 1.1 mrg return;
1052 1.1 mrg #endif
1053 1.1 mrg case AND:
1054 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1055 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1056 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1057 1.1 mrg mpz_and (r, lhs, rhs);
1058 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1059 1.1 mrg return;
1060 1.1 mrg case IOR:
1061 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1062 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1063 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1064 1.1 mrg mpz_ior (r, lhs, rhs);
1065 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1066 1.1 mrg return;
1067 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1068 1.1 mrg case XOR:
1069 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1070 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1071 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1072 1.1 mrg mpz_xor (r, lhs, rhs);
1073 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1074 1.1 mrg return;
1075 1.1 mrg #endif
1076 1.1 mrg case NEG:
1077 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1078 1.1 mrg mpz_neg (r, r);
1079 1.1 mrg return;
1080 1.1 mrg case NOT:
1081 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1082 1.1 mrg mpz_com (r, r);
1083 1.1 mrg return;
1084 1.1 mrg case SQRT:
1085 1.1 mrg mpz_init (lhs);
1086 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1087 1.1 mrg if (mpz_sgn (lhs) < 0)
1088 1.1 mrg {
1089 1.1 mrg error = "cannot take square root of negative numbers";
1090 1.1 mrg mpz_clear (lhs);
1091 1.1 mrg longjmp (errjmpbuf, 1);
1092 1.1 mrg }
1093 1.1 mrg mpz_sqrt (r, lhs);
1094 1.1 mrg return;
1095 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1096 1.1 mrg case ROOT:
1097 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1098 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1099 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1100 1.1 mrg if (mpz_sgn (rhs) <= 0)
1101 1.1 mrg {
1102 1.1 mrg error = "cannot take non-positive root orders";
1103 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1104 1.1 mrg longjmp (errjmpbuf, 1);
1105 1.1 mrg }
1106 1.1 mrg if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
1107 1.1 mrg {
1108 1.1 mrg error = "cannot take even root orders of negative numbers";
1109 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1110 1.1 mrg longjmp (errjmpbuf, 1);
1111 1.1 mrg }
1112 1.1 mrg
1113 1.1 mrg {
1114 1.1 mrg unsigned long int nth = mpz_get_ui (rhs);
1115 1.1 mrg if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1116 1.1 mrg {
1117 1.1 mrg /* If we are asked to take an awfully large root order, cheat and
1118 1.1 mrg ask for the largest order we can pass to mpz_root. This saves
1119 1.1 mrg some error prone special cases. */
1120 1.1 mrg nth = ~(unsigned long int) 0;
1121 1.1 mrg }
1122 1.1 mrg mpz_root (r, lhs, nth);
1123 1.1 mrg }
1124 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1125 1.1 mrg return;
1126 1.1 mrg #endif
1127 1.1 mrg case FAC:
1128 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1129 1.1 mrg if (mpz_size (r) > 1)
1130 1.1 mrg {
1131 1.1 mrg error = "result of `!' operator too large";
1132 1.1 mrg longjmp (errjmpbuf, 1);
1133 1.1 mrg }
1134 1.1 mrg mpz_fac_ui (r, mpz_get_ui (r));
1135 1.1 mrg return;
1136 1.1 mrg #if __GNU_MP_VERSION >= 2
1137 1.1 mrg case POPCNT:
1138 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1139 1.1 mrg { long int cnt;
1140 1.1 mrg cnt = mpz_popcount (r);
1141 1.1 mrg mpz_set_si (r, cnt);
1142 1.1 mrg }
1143 1.1 mrg return;
1144 1.1 mrg case HAMDIST:
1145 1.1 mrg { long int cnt;
1146 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1147 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1148 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1149 1.1 mrg cnt = mpz_hamdist (lhs, rhs);
1150 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1151 1.1 mrg mpz_set_si (r, cnt);
1152 1.1 mrg }
1153 1.1 mrg return;
1154 1.1 mrg #endif
1155 1.1 mrg case LOG2:
1156 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1157 1.1 mrg { unsigned long int cnt;
1158 1.1 mrg if (mpz_sgn (r) <= 0)
1159 1.1 mrg {
1160 1.1 mrg error = "logarithm of non-positive number";
1161 1.1 mrg longjmp (errjmpbuf, 1);
1162 1.1 mrg }
1163 1.1 mrg cnt = mpz_sizeinbase (r, 2);
1164 1.1 mrg mpz_set_ui (r, cnt - 1);
1165 1.1 mrg }
1166 1.1 mrg return;
1167 1.1 mrg case LOG:
1168 1.1 mrg { unsigned long int cnt;
1169 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1170 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1171 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1172 1.1 mrg if (mpz_sgn (lhs) <= 0)
1173 1.1 mrg {
1174 1.1 mrg error = "logarithm of non-positive number";
1175 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1176 1.1 mrg longjmp (errjmpbuf, 1);
1177 1.1 mrg }
1178 1.1 mrg if (mpz_cmp_ui (rhs, 256) >= 0)
1179 1.1 mrg {
1180 1.1 mrg error = "logarithm base too large";
1181 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1182 1.1 mrg longjmp (errjmpbuf, 1);
1183 1.1 mrg }
1184 1.1 mrg cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
1185 1.1 mrg mpz_set_ui (r, cnt - 1);
1186 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1187 1.1 mrg }
1188 1.1 mrg return;
1189 1.1 mrg case FERMAT:
1190 1.1 mrg {
1191 1.1 mrg unsigned long int t;
1192 1.1 mrg mpz_init (lhs);
1193 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1194 1.1 mrg t = (unsigned long int) 1 << mpz_get_ui (lhs);
1195 1.1 mrg if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
1196 1.1 mrg {
1197 1.1 mrg error = "too large Mersenne number index";
1198 1.1 mrg mpz_clear (lhs);
1199 1.1 mrg longjmp (errjmpbuf, 1);
1200 1.1 mrg }
1201 1.1 mrg mpz_set_ui (r, 1);
1202 1.1 mrg mpz_mul_2exp (r, r, t);
1203 1.1 mrg mpz_add_ui (r, r, 1);
1204 1.1 mrg mpz_clear (lhs);
1205 1.1 mrg }
1206 1.1 mrg return;
1207 1.1 mrg case MERSENNE:
1208 1.1 mrg mpz_init (lhs);
1209 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1210 1.1 mrg if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
1211 1.1 mrg {
1212 1.1 mrg error = "too large Mersenne number index";
1213 1.1 mrg mpz_clear (lhs);
1214 1.1 mrg longjmp (errjmpbuf, 1);
1215 1.1 mrg }
1216 1.1 mrg mpz_set_ui (r, 1);
1217 1.1 mrg mpz_mul_2exp (r, r, mpz_get_ui (lhs));
1218 1.1 mrg mpz_sub_ui (r, r, 1);
1219 1.1 mrg mpz_clear (lhs);
1220 1.1 mrg return;
1221 1.1 mrg case FIBONACCI:
1222 1.1 mrg { mpz_t t;
1223 1.1 mrg unsigned long int n, i;
1224 1.1 mrg mpz_init (lhs);
1225 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1226 1.1 mrg if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1227 1.1 mrg {
1228 1.1 mrg error = "Fibonacci index out of range";
1229 1.1 mrg mpz_clear (lhs);
1230 1.1 mrg longjmp (errjmpbuf, 1);
1231 1.1 mrg }
1232 1.1 mrg n = mpz_get_ui (lhs);
1233 1.1 mrg mpz_clear (lhs);
1234 1.1 mrg
1235 1.1 mrg #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1236 1.1 mrg mpz_fib_ui (r, n);
1237 1.1 mrg #else
1238 1.1 mrg mpz_init_set_ui (t, 1);
1239 1.1 mrg mpz_set_ui (r, 1);
1240 1.1 mrg
1241 1.1 mrg if (n <= 2)
1242 1.1 mrg mpz_set_ui (r, 1);
1243 1.1 mrg else
1244 1.1 mrg {
1245 1.1 mrg for (i = 3; i <= n; i++)
1246 1.1 mrg {
1247 1.1 mrg mpz_add (t, t, r);
1248 1.1 mrg mpz_swap (t, r);
1249 1.1 mrg }
1250 1.1 mrg }
1251 1.1 mrg mpz_clear (t);
1252 1.1 mrg #endif
1253 1.1 mrg }
1254 1.1 mrg return;
1255 1.1 mrg case RANDOM:
1256 1.1 mrg {
1257 1.1 mrg unsigned long int n;
1258 1.1 mrg mpz_init (lhs);
1259 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1260 1.1 mrg if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1261 1.1 mrg {
1262 1.1 mrg error = "random number size out of range";
1263 1.1 mrg mpz_clear (lhs);
1264 1.1 mrg longjmp (errjmpbuf, 1);
1265 1.1 mrg }
1266 1.1 mrg n = mpz_get_ui (lhs);
1267 1.1 mrg mpz_clear (lhs);
1268 1.1 mrg mpz_urandomb (r, rstate, n);
1269 1.1 mrg }
1270 1.1 mrg return;
1271 1.1 mrg case NEXTPRIME:
1272 1.1 mrg {
1273 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1274 1.1 mrg mpz_nextprime (r, r);
1275 1.1 mrg }
1276 1.1 mrg return;
1277 1.1 mrg case BINOM:
1278 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1279 1.1 mrg mpz_eval_expr (lhs, e->operands.ops.lhs);
1280 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1281 1.1 mrg {
1282 1.1 mrg unsigned long int k;
1283 1.1 mrg if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1284 1.1 mrg {
1285 1.1 mrg error = "k too large in (n over k) expression";
1286 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1287 1.1 mrg longjmp (errjmpbuf, 1);
1288 1.1 mrg }
1289 1.1 mrg k = mpz_get_ui (rhs);
1290 1.1 mrg mpz_bin_ui (r, lhs, k);
1291 1.1 mrg }
1292 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1293 1.1 mrg return;
1294 1.1 mrg case TIMING:
1295 1.1 mrg {
1296 1.1 mrg int t0;
1297 1.1 mrg t0 = cputime ();
1298 1.1 mrg mpz_eval_expr (r, e->operands.ops.lhs);
1299 1.1 mrg printf ("time: %d\n", cputime () - t0);
1300 1.1 mrg }
1301 1.1 mrg return;
1302 1.1 mrg default:
1303 1.1 mrg abort ();
1304 1.1 mrg }
1305 1.1 mrg }
1306 1.1 mrg
1307 1.1 mrg /* Evaluate the expression E modulo MOD and put the result in R. */
1308 1.1 mrg void
1309 1.1 mrg mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
1310 1.1 mrg {
1311 1.1 mrg mpz_t lhs, rhs;
1312 1.1 mrg
1313 1.1 mrg switch (e->op)
1314 1.1 mrg {
1315 1.1 mrg case POW:
1316 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1317 1.1 mrg mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1318 1.1 mrg mpz_eval_expr (rhs, e->operands.ops.rhs);
1319 1.1 mrg mpz_powm (r, lhs, rhs, mod);
1320 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1321 1.1 mrg return;
1322 1.1 mrg case PLUS:
1323 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1324 1.1 mrg mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1325 1.1 mrg mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1326 1.1 mrg mpz_add (r, lhs, rhs);
1327 1.1 mrg if (mpz_cmp_si (r, 0L) < 0)
1328 1.1 mrg mpz_add (r, r, mod);
1329 1.1 mrg else if (mpz_cmp (r, mod) >= 0)
1330 1.1 mrg mpz_sub (r, r, mod);
1331 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1332 1.1 mrg return;
1333 1.1 mrg case MINUS:
1334 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1335 1.1 mrg mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1336 1.1 mrg mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1337 1.1 mrg mpz_sub (r, lhs, rhs);
1338 1.1 mrg if (mpz_cmp_si (r, 0L) < 0)
1339 1.1 mrg mpz_add (r, r, mod);
1340 1.1 mrg else if (mpz_cmp (r, mod) >= 0)
1341 1.1 mrg mpz_sub (r, r, mod);
1342 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1343 1.1 mrg return;
1344 1.1 mrg case MULT:
1345 1.1 mrg mpz_init (lhs); mpz_init (rhs);
1346 1.1 mrg mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1347 1.1 mrg mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1348 1.1 mrg mpz_mul (r, lhs, rhs);
1349 1.1 mrg mpz_mod (r, r, mod);
1350 1.1 mrg mpz_clear (lhs); mpz_clear (rhs);
1351 1.1 mrg return;
1352 1.1 mrg default:
1353 1.1 mrg mpz_init (lhs);
1354 1.1 mrg mpz_eval_expr (lhs, e);
1355 1.1 mrg mpz_mod (r, lhs, mod);
1356 1.1 mrg mpz_clear (lhs);
1357 1.1 mrg return;
1358 1.1 mrg }
1359 1.1 mrg }
1360 1.1 mrg
1361 1.1 mrg void
1362 1.1 mrg cleanup_and_exit (int sig)
1363 1.1 mrg {
1364 1.1 mrg switch (sig) {
1365 1.1 mrg #ifdef LIMIT_RESOURCE_USAGE
1366 1.1 mrg case SIGXCPU:
1367 1.1 mrg printf ("expression took too long to evaluate%s\n", newline);
1368 1.1 mrg break;
1369 1.1 mrg #endif
1370 1.1 mrg case SIGFPE:
1371 1.1 mrg printf ("divide by zero%s\n", newline);
1372 1.1 mrg break;
1373 1.1 mrg default:
1374 1.1 mrg printf ("expression required too much memory to evaluate%s\n", newline);
1375 1.1 mrg break;
1376 1.1 mrg }
1377 1.1 mrg exit (-2);
1378 1.1 mrg }
1379