|
Packit |
5c3484 |
Copyright 2001, 2004 Free Software Foundation, Inc.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This file is part of the GNU MP Library.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The GNU MP Library is free software; you can redistribute it and/or modify
|
|
Packit |
5c3484 |
it under the terms of either:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
* the GNU Lesser General Public License as published by the Free
|
|
Packit |
5c3484 |
Software Foundation; either version 3 of the License, or (at your
|
|
Packit |
5c3484 |
option) any later version.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
or
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
* the GNU General Public License as published by the Free Software
|
|
Packit |
5c3484 |
Foundation; either version 2 of the License, or (at your option) any
|
|
Packit |
5c3484 |
later version.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
or both in parallel, as here.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The GNU MP Library is distributed in the hope that it will be useful, but
|
|
Packit |
5c3484 |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit |
5c3484 |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
Packit |
5c3484 |
for more details.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
You should have received copies of the GNU General Public License and the
|
|
Packit |
5c3484 |
GNU Lesser General Public License along with the GNU MP Library. If not,
|
|
Packit |
5c3484 |
see https://www.gnu.org/licenses/.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
GMP EXPRESSION EVALUATION
|
|
Packit |
5c3484 |
-------------------------
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
THIS CODE IS PRELIMINARY AND MAY BE SUBJECT TO INCOMPATIBLE CHANGES IN
|
|
Packit |
5c3484 |
FUTURE VERSIONS OF GMP.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The files in this directory implement a simple scheme of string based
|
|
Packit |
5c3484 |
expression parsing and evaluation, supporting mpz, mpq and mpf.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This will be slower than direct GMP library calls, but may be convenient in
|
|
Packit |
5c3484 |
various circumstances, such as while prototyping, or for letting a user
|
|
Packit |
5c3484 |
enter values in symbolic form. "2**5723-7" for example is a lot easier to
|
|
Packit |
5c3484 |
enter or maintain than the equivalent written out in decimal.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
BUILDING
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Nothing in this directory is a normal part of libgmp, and nothing is built
|
|
Packit |
5c3484 |
or installed, but various Makefile rules are available to compile
|
|
Packit |
5c3484 |
everything.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
All the functions are available through a little library (there's no shared
|
|
Packit |
5c3484 |
library since upward binary compatibility is not guaranteed).
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
make libexpr.a
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
In a program, prototypes are available using
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include "expr.h"
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
run-expr.c is a sample program doing evaluations from the command line.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
make run-expr
|
|
Packit |
5c3484 |
./run-expr '1+2*3'
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
t-expr.c is self-test program, it prints nothing if successful.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
make t-expr
|
|
Packit |
5c3484 |
./t-expr
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The expr*.c sources don't depend on gmp-impl.h and can be compiled with just
|
|
Packit |
5c3484 |
a standard installed GMP. This isn't true of t-expr though, since it uses
|
|
Packit |
5c3484 |
some of the internal tests/libtests.la.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
SIMPLE USAGE
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int mpz_expr (mpz_t res, int base, const char *e, ...);
|
|
Packit |
5c3484 |
int mpq_expr (mpq_t res, int base, const char *e, ...);
|
|
Packit |
5c3484 |
int mpf_expr (mpf_t res, int base, const char *e, ...);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
These functions evaluate simple arithmetic expressions. For example,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_expr (result, 0, "123+456", NULL);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Numbers are parsed by mpz_expr and mpq_expr the same as mpz_set_str with the
|
|
Packit |
5c3484 |
given base. mpf_expr follows mpf_set_str, but supporting an "0x" prefix for
|
|
Packit |
5c3484 |
hex when base==0.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_expr (result, 0, "0xAAAA * 0x5555", NULL);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
White space, as indicated by <ctype.h> isspace(), is ignored except for the
|
|
Packit |
5c3484 |
purpose of separating tokens.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Variables can be included in expressions by putting them in the stdarg list
|
|
Packit |
5c3484 |
after the string. "a", "b", "c" etc in the expression string designate
|
|
Packit |
5c3484 |
those values. For example,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpq_t foo, bar;
|
|
Packit |
5c3484 |
...
|
|
Packit |
5c3484 |
mpq_expr (q, 10, "2/3 + 1/a + b/2", foo, bar, NULL);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Here "a" will be the value from foo and "b" from bar. Up to 26 variables
|
|
Packit |
5c3484 |
can be included this way. The NULL must be present to indicate the end of
|
|
Packit |
5c3484 |
the list.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Variables can also be written "$a", "$b" etc. This is necessary when using
|
|
Packit |
5c3484 |
bases greater than 10 since plain "a", "b" etc will otherwise be interpreted
|
|
Packit |
5c3484 |
as numbers. For example,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpf_t quux;
|
|
Packit |
5c3484 |
mpf_expr (f, 16, "F00F@-6 * $a", quux, NULL);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
All the standard C operators are available, with the usual precedences, plus
|
|
Packit |
5c3484 |
"**" for exponentiation at the highest precedence (and right associative).
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Operators Precedence
|
|
Packit |
5c3484 |
** 220
|
|
Packit |
5c3484 |
~ ! - (unary) 210
|
|
Packit |
5c3484 |
* / % 200
|
|
Packit |
5c3484 |
+ - 190
|
|
Packit |
5c3484 |
<< >> 180
|
|
Packit |
5c3484 |
<= < >= > 170
|
|
Packit |
5c3484 |
== != 160
|
|
Packit |
5c3484 |
& 150
|
|
Packit |
5c3484 |
^ 140
|
|
Packit |
5c3484 |
| 130
|
|
Packit |
5c3484 |
&& 120
|
|
Packit |
5c3484 |
|| 110
|
|
Packit |
5c3484 |
? : 100/101
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Currently only mpz_expr has the bitwise ~ % & ^ and | operators. The
|
|
Packit |
5c3484 |
precedence numbers are of interest in the advanced usage described below.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Various functions are available too. For example,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_expr (res, 10, "gcd(123,456,789) * abs(a)", var, NULL);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The following is the full set of functions,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_expr
|
|
Packit |
5c3484 |
abs bin clrbit cmp cmpabs congruent_p divisible_p even_p fib fac
|
|
Packit |
5c3484 |
gcd hamdist invert jacobi kronecker lcm lucnum max min nextprime
|
|
Packit |
5c3484 |
odd_p perfect_power_p perfect_square_p popcount powm
|
|
Packit |
5c3484 |
probab_prime_p root scan0 scan1 setbit sgn sqrt
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpq_expr
|
|
Packit |
5c3484 |
abs, cmp, den, max, min, num, sgn
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpf_expr
|
|
Packit |
5c3484 |
abs, ceil, cmp, eq, floor, integer_p, max, min, reldiff, sgn,
|
|
Packit |
5c3484 |
sqrt, trunc
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
All these are the same as the GMP library functions, except that min and max
|
|
Packit |
5c3484 |
don't exist in the library. Note also that min, max, gcd and lcm take any
|
|
Packit |
5c3484 |
number of arguments, not just two.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpf_expr does all calculations to the precision of the destination variable.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Expression parsing can succeed or fail. The return value indicates this,
|
|
Packit |
5c3484 |
and will be one of the following
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_RESULT_OK
|
|
Packit |
5c3484 |
MPEXPR_RESULT_BAD_VARIABLE
|
|
Packit |
5c3484 |
MPEXPR_RESULT_BAD_TABLE
|
|
Packit |
5c3484 |
MPEXPR_RESULT_PARSE_ERROR
|
|
Packit |
5c3484 |
MPEXPR_RESULT_NOT_UI
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
BAD_VARIABLE is when a variable is referenced that hasn't been provided.
|
|
Packit |
5c3484 |
For example if "c" is used when only two parameters have been passed.
|
|
Packit |
5c3484 |
BAD_TABLE is applicable to the advanced usage described below.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
PARSE_ERROR is a general syntax error, returned for any mal-formed input
|
|
Packit |
5c3484 |
string.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
NOT_UI is returned when an attempt is made to use an operand that's bigger
|
|
Packit |
5c3484 |
than an "unsigned long" with a function that's restricted to that range.
|
|
Packit |
5c3484 |
For example "fib" is mpz_fib_ui and only accepts an "unsigned long".
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ADVANCED USAGE
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int mpz_expr_a (const struct mpexpr_operator_t *table,
|
|
Packit |
5c3484 |
mpz_ptr res, int base, const char *e, size_t elen,
|
|
Packit |
5c3484 |
mpz_srcptr var[26])
|
|
Packit |
5c3484 |
int mpq_expr_a (const struct mpexpr_operator_t *table,
|
|
Packit |
5c3484 |
mpq_ptr res, int base, const char *e, size_t elen,
|
|
Packit |
5c3484 |
mpq_srcptr var[26])
|
|
Packit |
5c3484 |
int mpf_expr_a (const struct mpexpr_operator_t *table,
|
|
Packit |
5c3484 |
mpf_ptr res, int base, unsigned long prec,
|
|
Packit |
5c3484 |
const char *e, size_t elen,
|
|
Packit |
5c3484 |
mpf_srcptr var[26])
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
These functions are an advanced interface to expression parsing.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The string is taken as pointer and length. This makes it possible to parse
|
|
Packit |
5c3484 |
an expression in the middle of somewhere without copying and null
|
|
Packit |
5c3484 |
terminating it.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Variables are an array of 26 pointers to the appropriate operands, or NULL
|
|
Packit |
5c3484 |
for variables that are not available. Any combination of variables can be
|
|
Packit |
5c3484 |
given, for example just "x" and "y" (var[23] and var[24]) could be set.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Operators and functions are specified with a table. This makes it possible
|
|
Packit |
5c3484 |
to provide additional operators or functions, or to completely change the
|
|
Packit |
5c3484 |
syntax. The standard tables used by the simple functions above are
|
|
Packit |
5c3484 |
available as
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
const struct mpexpr_operator_t * const mpz_expr_standard_table;
|
|
Packit |
5c3484 |
const struct mpexpr_operator_t * const mpq_expr_standard_table;
|
|
Packit |
5c3484 |
const struct mpexpr_operator_t * const mpf_expr_standard_table;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct mpexpr_operator_t is the following
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct mpexpr_operator_t {
|
|
Packit |
5c3484 |
const char *name;
|
|
Packit |
5c3484 |
mpexpr_fun_t fun;
|
|
Packit |
5c3484 |
int type;
|
|
Packit |
5c3484 |
int precedence;
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
typedef void (*mpexpr_fun_t) (void);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
As an example, the standard mpz_expr table entry for multiplication is as
|
|
Packit |
5c3484 |
follows. See the source code for the full set of standard entries.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 200 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
"name" is the string to parse, "fun" is the function to call for it, "type"
|
|
Packit |
5c3484 |
indicates what parameters the function takes (among other things), and
|
|
Packit |
5c3484 |
"precedence" sets its operator precedence.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
A NULL for "name" indicates the end of the table, so for example an mpf
|
|
Packit |
5c3484 |
table with nothing but addition could be
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct mpexpr_operator_t table[] = {
|
|
Packit |
5c3484 |
{ "+", (mpexpr_fun_t) mpf_add, MPEXPR_TYPE_BINARY, 190 },
|
|
Packit |
5c3484 |
{ NULL }
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
A special type MPEXPR_TYPE_NEW_TABLE makes it possible to chain from one
|
|
Packit |
5c3484 |
table to another. For example the following would add a "mod" operator to
|
|
Packit |
5c3484 |
the standard mpz table,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct mpexpr_operator_t table[] = {
|
|
Packit |
5c3484 |
{ "mod", (mpexpr_fun_t) mpz_fdiv_r, MPEXPR_TYPE_BINARY, 125 },
|
|
Packit |
5c3484 |
{ (const char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Notice the low precedence on "mod", so that for instance "45+26 mod 7"
|
|
Packit |
5c3484 |
parses as "(45+26)mod7".
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Functions are designated by a precedence of 0. They always occur as
|
|
Packit |
5c3484 |
"foo(expr)" and so have no need for a precedence level. mpq_abs in the
|
|
Packit |
5c3484 |
standard mpq table is
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "abs", (mpexpr_fun_t) mpq_abs, MPEXPR_TYPE_UNARY },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Functions expecting no arguments as in "foo()" can be given with
|
|
Packit |
5c3484 |
MPEXPR_TYPE_0ARY, or actual constants to be parsed as just "foo" are
|
|
Packit |
5c3484 |
MPEXPR_TYPE_CONSTANT. For example if a "void mpf_const_pi(mpf_t f)"
|
|
Packit |
5c3484 |
function existed (which it doesn't) it could be,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "pi", (mpexpr_fun_t) mpf_const_pi, MPEXPR_TYPE_CONSTANT },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Parsing of operator names is done by seeking the table entry with the
|
|
Packit |
5c3484 |
longest matching name. So for instance operators "<" and "<=" exist, and
|
|
Packit |
5c3484 |
when presented with "x <= y" the parser matches "<=" because it's longer.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Parsing of function names, on the other hand, is done by requiring a whole
|
|
Packit |
5c3484 |
alphanumeric word to match. For example presented with "fib2zz(5)" the
|
|
Packit |
5c3484 |
parser will attempt to find a function called "fib2zz". A function "fib"
|
|
Packit |
5c3484 |
wouldn't be used because it doesn't match the whole word.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The flag MPEXPR_TYPE_WHOLEWORD can be ORed into an operator type to override
|
|
Packit |
5c3484 |
the default parsing style. Similarly MPEXPR_TYPE_OPERATOR into a function.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Binary operators are left associative by default, meaning they're evaluated
|
|
Packit |
5c3484 |
from left to right, so for example "1+2+3" is treated as "(1+2)+3".
|
|
Packit |
5c3484 |
MPEXPR_TYPE_RIGHTASSOC can be ORed into the operator type to work from right
|
|
Packit |
5c3484 |
to left as in "1+(2+3)". This is generally what's wanted for
|
|
Packit |
5c3484 |
exponentiation, and for example the standard mpz table has
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "**", (mpexpr_fun_t) mpz_pow_ui,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 220 }
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Unary operators are postfix by default. For example a factorial to be used
|
|
Packit |
5c3484 |
as "123!" might be
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "!", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI, 215 }
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_PREFIX can be ORed into the type to get a prefix operator. For
|
|
Packit |
5c3484 |
instance negation (unary minus) in the standard mpf table is
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "-", (mpexpr_fun_t) mpf_neg,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The same operator can exist as a prefix unary and a binary, or as a prefix
|
|
Packit |
5c3484 |
and postfix unary, simply by putting two entries in the table. While
|
|
Packit |
5c3484 |
parsing the context determines which style is sought. But note that the
|
|
Packit |
5c3484 |
same operator can't be both a postfix unary and a binary, since the parser
|
|
Packit |
5c3484 |
doesn't try to look ahead to decide which ought to be used.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
When there's two entries for an operator, both prefix or both postfix (or
|
|
Packit |
5c3484 |
binary), then the first in the table will be used. This makes it possible
|
|
Packit |
5c3484 |
to override an entry in a standard table, for example to change the function
|
|
Packit |
5c3484 |
it calls, or perhaps its precedence level. The following would change mpz
|
|
Packit |
5c3484 |
division from tdiv to cdiv,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct mpexpr_operator_t table[] = {
|
|
Packit |
5c3484 |
{ "/", (mpexpr_fun_t) mpz_cdiv_q, MPEXPR_TYPE_BINARY, 200 },
|
|
Packit |
5c3484 |
{ "%", (mpexpr_fun_t) mpz_cdiv_r, MPEXPR_TYPE_BINARY, 200 },
|
|
Packit |
5c3484 |
{ (char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The type field indicates what parameters the given function expects. The
|
|
Packit |
5c3484 |
following styles of functions are supported. mpz_t is shown, but of course
|
|
Packit |
5c3484 |
this is mpq_t for mpq_expr_a, mpf_t for mpf_expr_a, etc.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_CONSTANT void func (mpz_t result);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_0ARY void func (mpz_t result);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_0ARY int func (void);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_UNARY void func (mpz_t result, mpz_t op);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_UNARY_UI void func (mpz_t result, unsigned long op);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_UNARY int func (mpz_t op);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_UNARY_UI int func (unsigned long op);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_BINARY void func (mpz_t result, mpz_t op1, mpz_t op2);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_BINARY_UI void func (mpz_t result,
|
|
Packit |
5c3484 |
mpz_t op1, unsigned long op2);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_BINARY int func (mpz_t op1, mpz_t op2);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_BINARY_UI int func (mpz_t op1, unsigned long op2);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
MPEXPR_TYPE_TERNARY void func (mpz_t result,
|
|
Packit |
5c3484 |
mpz_t op1, mpz_t op2, mpz_t op3);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_TERNARY_UI void func (mpz_t result, mpz_t op1, mpz_t op2,
|
|
Packit |
5c3484 |
unsigned long op3);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_TERNARY int func (mpz_t op1, mpz_t op2, mpz_t op3);
|
|
Packit |
5c3484 |
MPEXPR_TYPE_I_TERNARY_UI int func (mpz_t op1, mpz_t op2,
|
|
Packit |
5c3484 |
unsigned long op3);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Notice the pattern of "UI" for the last parameter as an unsigned long, or
|
|
Packit |
5c3484 |
"I" for the result as an "int" return value.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
It's important that the declared type for an operator or function matches
|
|
Packit |
5c3484 |
the function pointer given. Any mismatch will have unpredictable results.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
For binary functions, a further type attribute is MPEXPR_TYPE_PAIRWISE which
|
|
Packit |
5c3484 |
indicates that any number of arguments should be accepted, and evaluated by
|
|
Packit |
5c3484 |
applying the given binary function to them pairwise. This is used by gcd,
|
|
Packit |
5c3484 |
lcm, min and max. For example the standard mpz gcd is
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "gcd", (mpexpr_fun_t) mpz_gcd,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Some special types exist for comparison operators (or functions).
|
|
Packit |
5c3484 |
MPEXPR_TYPE_CMP_LT through MPEXPR_TYPE_CMP_GE expect an MPEXPR_TYPE_I_BINARY
|
|
Packit |
5c3484 |
function, returning positive, negative or zero like mpz_cmp and similar.
|
|
Packit |
5c3484 |
For example the standard mpf "!=" operator is
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "!=", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_CMP_NE, 160 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
But there's no obligation to use these types, for instance the standard mpq
|
|
Packit |
5c3484 |
table just uses a plain MPEXPR_TYPE_I_BINARY and mpq_equal for "==".
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Further special types MPEXPR_TYPE_MIN and MPEXPR_TYPE_MAX exist to implement
|
|
Packit |
5c3484 |
the min and max functions, and they take a function like mpf_cmp similarly.
|
|
Packit |
5c3484 |
The standard mpf max function is
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "max", (mpexpr_fun_t) mpf_cmp,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
These can be used as operators too, for instance the following would be the
|
|
Packit |
5c3484 |
>? operator which is a feature of GNU C++,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ ">?", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX, 175 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Other special types are used to define "(" ")" parentheses, "," function
|
|
Packit |
5c3484 |
argument separator, "!" through "||" logical booleans, ternary "?" ":", and
|
|
Packit |
5c3484 |
the "$" which introduces variables. See the sources for how they should be
|
|
Packit |
5c3484 |
used.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
User definable operator tables will have various uses. For example,
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
- a subset of the C operators, to be rid of infrequently used things
|
|
Packit |
5c3484 |
- a more mathematical syntax like "." for multiply, "^" for powering,
|
|
Packit |
5c3484 |
and "!" for factorial
|
|
Packit |
5c3484 |
- a boolean evaluator with "^" for AND, "v" for OR
|
|
Packit |
5c3484 |
- variables introduced with "%" instead of "$"
|
|
Packit |
5c3484 |
- brackets as "[" and "]" instead of "(" and ")"
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The only fixed parts of the parsing are the treatment of numbers, whitespace
|
|
Packit |
5c3484 |
and the two styles of operator/function name recognition.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
As a final example, the following would be a complete mpz table implementing
|
|
Packit |
5c3484 |
some operators with a more mathematical syntax. Notice there's no need to
|
|
Packit |
5c3484 |
preserve the standard precedence values, anything can be used so long as
|
|
Packit |
5c3484 |
they're in the desired relation to each other. There's also no need to have
|
|
Packit |
5c3484 |
entries in precedence order, but it's convenient to do so to show what comes
|
|
Packit |
5c3484 |
where.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
static const struct mpexpr_operator_t table[] = {
|
|
Packit |
5c3484 |
{ "^", (mpexpr_fun_t) mpz_pow_ui,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 9 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "!", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI, 8 },
|
|
Packit |
5c3484 |
{ "-", (mpexpr_fun_t) mpz_neg,
|
|
Packit |
5c3484 |
MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 7 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 6 },
|
|
Packit |
5c3484 |
{ "/", (mpexpr_fun_t) mpz_fdiv_q, MPEXPR_TYPE_BINARY, 6 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "+", (mpexpr_fun_t) mpz_add, MPEXPR_TYPE_BINARY, 5 },
|
|
Packit |
5c3484 |
{ "-", (mpexpr_fun_t) mpz_sub, MPEXPR_TYPE_BINARY, 5 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "mod", (mpexpr_fun_t) mpz_mod, MPEXPR_TYPE_BINARY, 6 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ ")", NULL, MPEXPR_TYPE_CLOSEPAREN, 4 },
|
|
Packit |
5c3484 |
{ "(", NULL, MPEXPR_TYPE_OPENPAREN, 3 },
|
|
Packit |
5c3484 |
{ ",", NULL, MPEXPR_TYPE_ARGSEP, 2 },
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{ "$", NULL, MPEXPR_TYPE_VARIABLE, 1 },
|
|
Packit |
5c3484 |
{ NULL }
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
INTERNALS
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Operator precedence is implemented using a control and data stack, there's
|
|
Packit |
5c3484 |
no C recursion. When an expression like 1+2*3 is read the "+" is held on
|
|
Packit |
5c3484 |
the control stack and 1 on the data stack until "*" has been parsed and
|
|
Packit |
5c3484 |
applied to 2 and 3. This happens any time a higher precedence operator
|
|
Packit |
5c3484 |
follows a lower one, or when a right-associative operator like "**" is
|
|
Packit |
5c3484 |
repeated.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Parentheses are handled by making "(" a special prefix unary with a low
|
|
Packit |
5c3484 |
precedence so a whole following expression is read. The special operator
|
|
Packit |
5c3484 |
")" knows to discard the pending "(". Function arguments are handled
|
|
Packit |
5c3484 |
similarly, with the function pretending to be a low precedence prefix unary
|
|
Packit |
5c3484 |
operator, and with "," allowed within functions. The same special ")"
|
|
Packit |
5c3484 |
operator recognises a pending function and will invoke it appropriately.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The ternary "? :" operator is also handled using precedences. ":" is one
|
|
Packit |
5c3484 |
level higher than "?", so when a valid a?b:c is parsed the ":" finds a "?"
|
|
Packit |
5c3484 |
on the control stack. It's a parse error for ":" to find anything else.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
FUTURE
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The ternary "?:" operator evaluates the "false" side of its pair, which is
|
|
Packit |
5c3484 |
wasteful, though it ought to be harmless. It'd be better if it could
|
|
Packit |
5c3484 |
evaluate only the "true" side. Similarly for the logical booleans "&&" and
|
|
Packit |
5c3484 |
"||" if they know their result already.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Functions like MPEXPR_TYPE_BINARY could return a status indicating operand
|
|
Packit |
5c3484 |
out of range or whatever, to get an error back through mpz_expr etc. That
|
|
Packit |
5c3484 |
would want to be just an option, since plain mpz_add etc have no such
|
|
Packit |
5c3484 |
return.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Could have assignments like "a = b*c" modifying the input variables.
|
|
Packit |
5c3484 |
Assignment could be an operator attribute, making it expect an lvalue.
|
|
Packit |
5c3484 |
There would want to be a standard table without assignments available
|
|
Packit |
5c3484 |
though, so user input could be safely parsed.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The closing parenthesis table entry could specify the type of open paren it
|
|
Packit |
5c3484 |
expects, so that "(" and ")" could match and "[" and "]" match but not a
|
|
Packit |
5c3484 |
mixture of the two. Currently "[" and "]" can be added, but there's no
|
|
Packit |
5c3484 |
error on writing a mixed expression like "2*(3+4]". Maybe also there could
|
|
Packit |
5c3484 |
be a way to say that functions can only be written with one or the other
|
|
Packit |
5c3484 |
style of parens.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
----------------
|
|
Packit |
5c3484 |
Local variables:
|
|
Packit |
5c3484 |
mode: text
|
|
Packit |
5c3484 |
fill-column: 76
|
|
Packit |
5c3484 |
End:
|