Blame demos/expr/README

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: