[BACK]Return to README CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / demos / expr

Annotation of OpenXM_contrib/gmp/demos/expr/README, Revision 1.1

1.1     ! ohara       1: Copyright 2001 Free Software Foundation, Inc.
        !             2:
        !             3: This file is part of the GNU MP Library.
        !             4:
        !             5: The GNU MP Library is free software; you can redistribute it and/or modify
        !             6: it under the terms of the GNU Lesser General Public License as published by
        !             7: the Free Software Foundation; either version 2.1 of the License, or (at your
        !             8: option) any later version.
        !             9:
        !            10: The GNU MP Library is distributed in the hope that it will be useful, but
        !            11: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            13: License for more details.
        !            14:
        !            15: You should have received a copy of the GNU Lesser General Public License
        !            16: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
        !            17: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
        !            18: 02111-1307, USA.
        !            19:
        !            20:
        !            21:
        !            22:
        !            23:
        !            24:
        !            25:                     GMP EXPRESSION EVALUATION
        !            26:                     -------------------------
        !            27:
        !            28:
        !            29:
        !            30: THIS CODE IS PRELIMINARY AND MAY BE SUBJECT TO INCOMPATIBLE CHANGES IN
        !            31: FUTURE VERSIONS OF GMP.
        !            32:
        !            33:
        !            34:
        !            35: The files in this directory implement a simple scheme of string based
        !            36: expression parsing and evaluation, supporting mpz, mpq, mpf and mpfr.
        !            37:
        !            38: This will be slower than direct GMP library calls, but may be convenient in
        !            39: various circumstances, such as while prototyping, or for letting a user
        !            40: enter values in symbolic form.  "2**5723-7" for example is a lot easier to
        !            41: enter or maintain than the equivalent written out in decimal.
        !            42:
        !            43:
        !            44:
        !            45: BUILDING
        !            46:
        !            47: Nothing in this directory is a normal part of libgmp, and nothing is built
        !            48: or installed, but various Makefile rules are available to compile
        !            49: everything.
        !            50:
        !            51: All the functions are available through a little library (there's no shared
        !            52: library since upward binary compatibility is not guaranteed).
        !            53:
        !            54:        make libexpr.a
        !            55:
        !            56: In a program, prototypes are available using
        !            57:
        !            58:        #include "expr.h"
        !            59:
        !            60: run-expr.c is a sample program doing evaluations from the command line.
        !            61:
        !            62:        make run-expr
        !            63:        ./run-expr '1+2*3'
        !            64:
        !            65: t-expr.c is self-test program, it prints nothing if successful.
        !            66:
        !            67:        make t-expr
        !            68:        ./t-expr
        !            69:
        !            70: The expr*.c sources don't depend on gmp-impl.h and can be compiled with just
        !            71: a standard installed GMP.  This isn't true of t-expr though, since it uses
        !            72: some of the internal tests/libtests.la.
        !            73:
        !            74:
        !            75:
        !            76: OPTIONAL MPFR
        !            77:
        !            78: The mpfr support in libexpr.a is built if GMP is configured with
        !            79: --enable-mpfr.  Programs must include mpfr.h before expr.h to get the extra
        !            80: prototypes,
        !            81:
        !            82:         #include "mpfr.h"
        !            83:         #include "expr.h"
        !            84:
        !            85: If the expr sources are being compiled outside a GMP build tree, then change
        !            86: HAVE_MPFR in expr-impl.h if necessary to indicate whether mpfr is available.
        !            87: exprfr.c and exprfra.c are the C files providing mpfr support.
        !            88:
        !            89:
        !            90:
        !            91:
        !            92: SIMPLE USAGE
        !            93:
        !            94: int mpz_expr (mpz_t res, int base, const char *e, ...);
        !            95: int mpq_expr (mpq_t res, int base, const char *e, ...);
        !            96: int mpf_expr (mpf_t res, int base, const char *e, ...);
        !            97: int mpfr_expr (mpfr_t res, int base, const char *e, ...);
        !            98:
        !            99: These functions evaluate simple arithmetic expressions.  For example,
        !           100:
        !           101:        mpz_expr (result, 0, "123+456", NULL);
        !           102:
        !           103: Numbers are parsed by mpz_expr and mpq_expr the same as mpz_set_str with the
        !           104: given base.  mpf_expr and mpfr_expr follow mpf_set_str and mpfr_set_str
        !           105: respectively, but supporting an "0x" prefix for hex when base==0.
        !           106:
        !           107:        mpz_expr (result, 0, "0xAAAA * 0x5555", NULL);
        !           108:
        !           109: White space, as indicated by <ctype.h> isspace(), is ignored except for the
        !           110: purpose of separating tokens.
        !           111:
        !           112: Variables can be included in expressions by putting them in the varargs list
        !           113: after the string.  "a", "b", "c" etc in the expression string designate
        !           114: those values.  For example,
        !           115:
        !           116:         mpq_t  foo, bar;
        !           117:         ...
        !           118:        mpq_expr (q, 10, "2/3 + 1/a + b/2", foo, bar, NULL);
        !           119:
        !           120: Here "a" will be the value from foo and "b" from bar.  Up to 26 variables
        !           121: can be included this way.  The NULL must be present to indicate the end of
        !           122: the list.
        !           123:
        !           124: Variables can also be written "$a", "$b" etc.  This is necessary when using
        !           125: bases greater than 10 since plain "a", "b" etc will otherwise be interpreted
        !           126: as numbers.  For example,
        !           127:
        !           128:         mpf_t  quux;
        !           129:         mpf_expr (f, 16, "F00F@-6 * $a", quux, NULL);
        !           130:
        !           131: All the standard C operators are available, with the usual precedences, plus
        !           132: "**" for exponentiation at the highest precedence (and right associative).
        !           133:
        !           134:         Operators      Precedence
        !           135:          **              220
        !           136:          ~ ! - (unary)   210
        !           137:          * / %           200
        !           138:          + -             190
        !           139:          << >>           180
        !           140:          <= < >= >       170
        !           141:          == !=           160
        !           142:          &               150
        !           143:          ^               140
        !           144:          |               130
        !           145:          &&              120
        !           146:          ||              110
        !           147:          ? :             100/101
        !           148:
        !           149: Currently only mpz_expr has the bitwise ~ % & ^ and | operators.  The
        !           150: precedence numbers are of interest in the advanced usage described below.
        !           151:
        !           152: Various functions are available too.  For example,
        !           153:
        !           154:         mpz_expr (res, 10, "gcd(123,456,789) * abs(a)", var, NULL);
        !           155:
        !           156: The following is the full set of functions,
        !           157:
        !           158:         mpz_expr
        !           159:             abs bin clrbit cmp cmpabs congruent_p divisible_p even_p fib fac
        !           160:             gcd hamdist invert jacobi kronecker lcm lucnum max min nextprime
        !           161:             odd_p perfect_power_p perfect_square_p popcount powm
        !           162:             probab_prime_p root scan0 scan1 setbit sgn sqrt
        !           163:
        !           164:         mpq_expr
        !           165:             abs, cmp, den, max, min, num, sgn
        !           166:
        !           167:         mpf_expr
        !           168:             abs, ceil, cmp, eq, floor, integer_p, max, min, reldiff, sgn,
        !           169:             sqrt, trunc
        !           170:
        !           171:         mpfr_expr
        !           172:             abs, agm, ceil, cmp, cos, eq, exp, floor, inf_p, log, max, min,
        !           173:             nan_p, number_p, reldiff, sgn, sin, sqrt, trunc
        !           174:
        !           175: In addition mpfr_expr has constants "log2" and "pi".  For example,
        !           176:
        !           177:        mpfr_expr (res, 0, "2 * pi - log2", NULL);
        !           178:
        !           179: All these are the same as the GMP library functions, except that min and max
        !           180: don't exist in the library.  Note also that min, max, gcd and lcm take any
        !           181: number of arguments, not just two.
        !           182:
        !           183:
        !           184: mpf_expr and mpfr_expr do all calculations to the precision of the
        !           185: destination variable.  mpfr_expr rounds using GMP_RNDZ (but this can be
        !           186: changed at build time in expr-impl.h).
        !           187:
        !           188:
        !           189: Expression parsing can succeed or fail.  The return value indicates this,
        !           190: and will be one of the following
        !           191:
        !           192:        MPEXPR_RESULT_OK
        !           193:        MPEXPR_RESULT_BAD_VARIABLE
        !           194:        MPEXPR_RESULT_BAD_TABLE
        !           195:        MPEXPR_RESULT_PARSE_ERROR
        !           196:        MPEXPR_RESULT_NOT_UI
        !           197:
        !           198: BAD_VARIABLE is when a variable is referenced that hasn't been provided.
        !           199: For example if "c" is used when only two parameters have been passed.
        !           200: BAD_TABLE is applicable to the advanced usage described below.
        !           201:
        !           202: PARSE_ERROR is a general syntax error, returned for any mal-formed input
        !           203: string.
        !           204:
        !           205: NOT_UI is returned when an attempt is made to use an operand that's bigger
        !           206: than an "unsigned long" with a function that's restricted to that range.
        !           207: For example "fib" is mpz_fib_ui and only accepts an "unsigned long".
        !           208:
        !           209:
        !           210:
        !           211:
        !           212: ADVANCED USAGE
        !           213:
        !           214: int mpz_expr_a (const struct mpexpr_operator_t *table,
        !           215:                 mpz_ptr res, int base, const char *e, size_t elen,
        !           216:                 mpz_srcptr var[26])
        !           217: int mpq_expr_a (const struct mpexpr_operator_t *table,
        !           218:                 mpq_ptr res, int base, const char *e, size_t elen,
        !           219:                 mpq_srcptr var[26])
        !           220: int mpf_expr_a (const struct mpexpr_operator_t *table,
        !           221:                 mpf_ptr res, int base, unsigned long prec,
        !           222:                 const char *e, size_t elen,
        !           223:                 mpf_srcptr var[26])
        !           224: int mpfr_expr_a (const struct mpexpr_operator_t *table,
        !           225:                  mpfr_ptr res, int base, unsigned long prec,
        !           226:                  const char *e, size_t elen,
        !           227:                  mpfr_srcptr var[26])
        !           228:
        !           229: These functions are an advanced interface to expression parsing.
        !           230:
        !           231: The string is taken as pointer and length.  This makes it possible to parse
        !           232: an expression in the middle of somewhere without copying and null
        !           233: terminating it.
        !           234:
        !           235: Variables are an array of 26 pointers to the appropriate operands, or NULL
        !           236: for variables that are not available.  Any combination of variables can be
        !           237: given, for example just "x" and "y" (var[23] and var[24]) could be set.
        !           238:
        !           239: Operators and functions are specified with a table.  This makes it possible
        !           240: to provide additional operators or functions, or to completely change the
        !           241: syntax.  The standard tables used by the simple functions above are
        !           242: available as
        !           243:
        !           244:        const struct mpexpr_operator_t * const mpz_expr_standard_table;
        !           245:        const struct mpexpr_operator_t * const mpq_expr_standard_table;
        !           246:        const struct mpexpr_operator_t * const mpf_expr_standard_table;
        !           247:        const struct mpexpr_operator_t * const mpfr_expr_standard_table;
        !           248:
        !           249: struct mpexpr_operator_t is the following
        !           250:
        !           251:        struct mpexpr_operator_t {
        !           252:          const char    *name;
        !           253:          mpexpr_fun_t  fun;
        !           254:          int           type;
        !           255:          int           precedence;
        !           256:        };
        !           257:
        !           258:         typedef void (*mpexpr_fun_t) (void);
        !           259:
        !           260: As an example, the standard mpz_expr table entry for multiplication is as
        !           261: follows.  See the source code for the full set of standard entries.
        !           262:
        !           263:        { "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 200 },
        !           264:
        !           265: "name" is the string to parse, "fun" is the function to call for it, "type"
        !           266: indicates what parameters the function takes (among other things), and
        !           267: "precedence" sets its operator precedence.
        !           268:
        !           269: A NULL for "name" indicates the end of the table, so for example an mpf
        !           270: table with nothing but addition could be
        !           271:
        !           272:         struct mpexpr_operator_t  table[] = {
        !           273:           { "+", (mpexpr_fun_t) mpf_add, MPEXPR_TYPE_BINARY, 190 },
        !           274:           { NULL }
        !           275:         };
        !           276:
        !           277: A special type MPEXPR_TYPE_NEW_TABLE makes it possible to chain from one
        !           278: table to another.  For example the following would add a "mod" operator to
        !           279: the standard mpz table,
        !           280:
        !           281:         struct mpexpr_operator_t  table[] = {
        !           282:         { "mod", (mpexpr_fun_t) mpz_fdiv_r, MPEXPR_TYPE_BINARY, 125 },
        !           283:         { (const char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
        !           284:         };
        !           285:
        !           286: Notice the low precedence on "mod", so that for instance "45+26 mod 7"
        !           287: parses as "(45+26)mod7".
        !           288:
        !           289:
        !           290: Functions are designated by a precedence of 0.  They always occur as
        !           291: "foo(expr)" and so have no need for a precedence level.  mpq_abs in the
        !           292: standard mpq table is
        !           293:
        !           294:        { "abs", (mpexpr_fun_t) mpq_abs, MPEXPR_TYPE_UNARY },
        !           295:
        !           296: Functions expecting no arguments as in "foo()" can be given with
        !           297: MPEXPR_TYPE_0ARY, or actual constants to be parsed as just "foo" are
        !           298: MPEXPR_TYPE_CONSTANT.  For example if a "void mpf_const_pi(mpf_t f)"
        !           299: function existed (which it doesn't) it could be,
        !           300:
        !           301:        { "pi", (mpexpr_fun_t) mpf_const_pi, MPEXPR_TYPE_CONSTANT },
        !           302:
        !           303:
        !           304: Parsing of operator names is done by seeking the table entry with the
        !           305: longest matching name.  So for instance operators "<" and "<=" exist, and
        !           306: when presented with "x <= y" the parser matches "<=" because it's longer.
        !           307:
        !           308: Parsing of function names, on the other hand, is done by requiring a whole
        !           309: alphanumeric word to match.  For example presented with "fib2zz(5)" the
        !           310: parser will attempt to find a function called "fib2zz".  A function "fib"
        !           311: wouldn't be used because it doesn't match the whole word.
        !           312:
        !           313: The flag MPEXPR_TYPE_WHOLEWORD can be ORed into an operator type to override
        !           314: the default parsing style.  Similarly MPEXPR_TYPE_OPERATOR into a function.
        !           315:
        !           316:
        !           317: Binary operators are left associative by default, meaning they're evaluated
        !           318: from left to right, so for example "1+2+3" is treated as "(1+2)+3".
        !           319: MPEXPR_TYPE_RIGHTASSOC can be ORed into the operator type to work from right
        !           320: to left as in "1+(2+3)".  This is generally what's wanted for
        !           321: exponentiation, and for example the standard mpz table has
        !           322:
        !           323:         { "**", (mpexpr_fun_t) mpz_pow_ui,
        !           324:           MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 220 }
        !           325:
        !           326: Unary operators are postfix by default.  For example a factorial to be used
        !           327: as "123!" might be
        !           328:
        !           329:        { "!", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI, 215 }
        !           330:
        !           331: MPEXPR_TYPE_PREFIX can be ORed into the type to get a prefix operator.  For
        !           332: instance negation (unary minus) in the standard mpf table is
        !           333:
        !           334:        { "-", (mpexpr_fun_t) mpf_neg,
        !           335:           MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 },
        !           336:
        !           337:
        !           338: The same operator can exist as a prefix unary and a binary, or as a prefix
        !           339: and postfix unary, simply by putting two entries in the table.  While
        !           340: parsing the context determines which style is sought.  But note that the
        !           341: same operator can't be both a postfix unary and a binary, since the parser
        !           342: doesn't try to look ahead to decide which ought to be used.
        !           343:
        !           344: When there's two entries for an operator, both prefix or both postfix (or
        !           345: binary), then the first in the table will be used.  This makes it possible
        !           346: to override an entry in a standard table, for example to change the function
        !           347: it calls, or perhaps its precedence level.  The following would change mpz
        !           348: division from tdiv to cdiv,
        !           349:
        !           350:         struct mpexpr_operator_t  table[] = {
        !           351:           { "/", (mpexpr_fun_t) mpz_cdiv_q, MPEXPR_TYPE_BINARY, 200 },
        !           352:           { "%", (mpexpr_fun_t) mpz_cdiv_r, MPEXPR_TYPE_BINARY, 200 },
        !           353:           { (char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
        !           354:         };
        !           355:
        !           356:
        !           357: The type field indicates what parameters the given function expects.  The
        !           358: following styles of functions are supported.  mpz_t is shown, but of course
        !           359: this is mpq_t for mpq_expr_a, mpf_t for mpf_expr_a, etc.
        !           360:
        !           361:     MPEXPR_TYPE_CONSTANT     void func (mpz_t result);
        !           362:
        !           363:     MPEXPR_TYPE_0ARY         void func (mpz_t result);
        !           364:     MPEXPR_TYPE_I_0ARY       int func (void);
        !           365:
        !           366:     MPEXPR_TYPE_UNARY        void func (mpz_t result, mpz_t op);
        !           367:     MPEXPR_TYPE_UNARY_UI     void func (mpz_t result, unsigned long op);
        !           368:     MPEXPR_TYPE_I_UNARY      int func (mpz_t op);
        !           369:     MPEXPR_TYPE_I_UNARY_UI   int func (unsigned long op);
        !           370:
        !           371:     MPEXPR_TYPE_BINARY       void func (mpz_t result, mpz_t op1, mpz_t op2);
        !           372:     MPEXPR_TYPE_BINARY_UI    void func (mpz_t result,
        !           373:                                         mpz_t op1, unsigned long op2);
        !           374:     MPEXPR_TYPE_I_BINARY     int func (mpz_t op1, mpz_t op2);
        !           375:     MPEXPR_TYPE_I_BINARY_UI  int func (mpz_t op1, unsigned long op2);
        !           376:
        !           377:     MPEXPR_TYPE_TERNARY      void func (mpz_t result,
        !           378:                                         mpz_t op1, mpz_t op2, mpz_t op3);
        !           379:     MPEXPR_TYPE_TERNARY_UI   void func (mpz_t result, mpz_t op1, mpz_t op2,
        !           380:                                         unsigned long op3);
        !           381:     MPEXPR_TYPE_I_TERNARY    int func (mpz_t op1, mpz_t op2, mpz_t op3);
        !           382:     MPEXPR_TYPE_I_TERNARY_UI int func (mpz_t op1, mpz_t op2,
        !           383:                                        unsigned long op3);
        !           384:
        !           385: Notice the pattern of "UI" for the last parameter as an unsigned long, or
        !           386: "I" for the result as an "int" return value.
        !           387:
        !           388: It's important that the declared type for an operator or function matches
        !           389: the function pointer given.  Any mismatch will have unpredictable results.
        !           390:
        !           391: For binary functions, a further type attribute is MPEXPR_TYPE_PAIRWISE which
        !           392: indicates that any number of arguments should be accepted, and evaluated by
        !           393: applying the given binary function to them pairwise.  This is used by gcd,
        !           394: lcm, min and max.  For example the standard mpz gcd is
        !           395:
        !           396:        { "gcd", (mpexpr_fun_t) mpz_gcd,
        !           397:          MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE },
        !           398:
        !           399: Some special types exist for comparison operators (or functions).
        !           400: MPEXPR_TYPE_CMP_LT through MPEXPR_TYPE_CMP_GE expect an MPEXPR_TYPE_I_BINARY
        !           401: function, returning positive, negative or zero like mpz_cmp and similar.
        !           402: For example the standard mpf "!=" operator is
        !           403:
        !           404:        { "!=", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_CMP_NE, 160 },
        !           405:
        !           406: But there's no obligation to use these types, for instance the standard mpq
        !           407: table just uses a plain MPEXPR_TYPE_I_BINARY and mpq_equal for "==".
        !           408:
        !           409: Further special types MPEXPR_TYPE_MIN and MPEXPR_TYPE_MAX exist to implement
        !           410: the min and max functions, and they take a function like mpf_cmp similarly.
        !           411: The standard mpf max function is
        !           412:
        !           413:        { "max",  (mpexpr_fun_t) mpf_cmp,
        !           414:           MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
        !           415:
        !           416: These can be used as operators too, for instance the following would be the
        !           417: >? operator which is a feature of GNU C++,
        !           418:
        !           419:        { ">?", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX, 175 },
        !           420:
        !           421: Other special types are used to define "(" ")" parentheses, "," function
        !           422: argument separator, "!" through "||" logical booleans, ternary "?"  ":", and
        !           423: the "$" which introduces variables.  See the sources for how they should be
        !           424: used.
        !           425:
        !           426:
        !           427: User definable operator tables will have various uses.  For example,
        !           428:
        !           429:   - a subset of the C operators, to be rid of infrequently used things
        !           430:   - a more mathematical syntax like "." for multiply, "^" for powering,
        !           431:     and "!" for factorial
        !           432:   - a boolean evaluator with "^" for AND, "v" for OR
        !           433:   - variables introduced with "%" instead of "$"
        !           434:   - brackets as "[" and "]" instead of "(" and ")"
        !           435:   - new mpfr operators ^+^ or _+_ which round in a particular direction
        !           436:
        !           437: The only fixed parts of the parsing are the treatment of numbers, whitespace
        !           438: and the two styles of operator/function name recognition.
        !           439:
        !           440: As a final example, the following would be a complete mpz table implementing
        !           441: some operators with a more mathematical syntax.  Notice there's no need to
        !           442: preserve the standard precedence values, anything can be used so long as
        !           443: they're in the desired relation to each other.  There's also no need to have
        !           444: entries in precedence order, but it's convenient to do so to show what comes
        !           445: where.
        !           446:
        !           447:         static const struct mpexpr_operator_t  table[] = {
        !           448:          { "^",   (mpexpr_fun_t) mpz_pow_ui,
        !           449:             MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,           9 },
        !           450:
        !           451:           { "!",   (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI,   8 },
        !           452:           { "-",   (mpexpr_fun_t) mpz_neg,
        !           453:             MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                   7 },
        !           454:
        !           455:           { "*",   (mpexpr_fun_t) mpz_mul,    MPEXPR_TYPE_BINARY,     6 },
        !           456:           { "/",   (mpexpr_fun_t) mpz_fdiv_q, MPEXPR_TYPE_BINARY,     6 },
        !           457:
        !           458:           { "+",   (mpexpr_fun_t) mpz_add,    MPEXPR_TYPE_BINARY,     5 },
        !           459:           { "-",   (mpexpr_fun_t) mpz_sub,    MPEXPR_TYPE_BINARY,     5 },
        !           460:
        !           461:           { "mod", (mpexpr_fun_t) mpz_mod,    MPEXPR_TYPE_BINARY,     6 },
        !           462:
        !           463:           { ")",   NULL,                      MPEXPR_TYPE_CLOSEPAREN, 4 },
        !           464:           { "(",   NULL,                      MPEXPR_TYPE_OPENPAREN,  3 },
        !           465:           { ",",   NULL,                      MPEXPR_TYPE_ARGSEP,     2 },
        !           466:
        !           467:           { "$",   NULL,                      MPEXPR_TYPE_VARIABLE,   1 },
        !           468:           { NULL }
        !           469:         };
        !           470:
        !           471:
        !           472:
        !           473:
        !           474: INTERNALS
        !           475:
        !           476: Operator precedence is implemented using a control and data stack, there's
        !           477: no C recursion.  When an expression like 1+2*3 is read the "+" is held on
        !           478: the control stack and 1 on the data stack until "*" has been parsed and
        !           479: applied to 2 and 3.  This happens any time a higher precedence operator
        !           480: follows a lower one, or when a right-associative operator like "**" is
        !           481: repeated.
        !           482:
        !           483: Parentheses are handled by making "(" a special prefix unary with a low
        !           484: precedence so a whole following expression is read.  The special operator
        !           485: ")" knows to discard the pending "(".  Function arguments are handled
        !           486: similarly, with the function pretending to be a low precedence prefix unary
        !           487: operator, and with "," allowed within functions.  The same special ")"
        !           488: operator recognises a pending function and will invoke it appropriately.
        !           489:
        !           490: The ternary "? :" operator is also handled using precedences.  ":" is one
        !           491: level higher than "?", so when a valid a?b:c is parsed the ":" finds a "?"
        !           492: on the control stack.  It's a parse error for ":" to find anything else.
        !           493:
        !           494:
        !           495:
        !           496: FUTURE
        !           497:
        !           498: The ternary "?:" operator evaluates the "false" side of its pair, which is
        !           499: wasteful, though it ought to be harmless.  It'd be better if it could
        !           500: evaluate only the "true" side.  Similarly for the logical booleans "&&" and
        !           501: "||" if they know their result already.
        !           502:
        !           503: Functions like MPEXPR_TYPE_BINARY could return a status indicating operand
        !           504: out of range or whatever, to get an error back through mpz_expr etc.  That
        !           505: would want to be just an option, since plain mpz_add etc have no such
        !           506: return.
        !           507:
        !           508: Could have assignments like "a = b*c" modifying the input variables.
        !           509: Assignment could be an operator attribute, making it expect an lvalue.
        !           510: There would want to be a standard table without assignments available
        !           511: though, so user input could be safely parsed.
        !           512:
        !           513: The closing parethesis table entry could specify the type of open paren it
        !           514: expects, so that "(" and ")" could match and "[" and "]" match but not a
        !           515: mixture of the two.  Currently "[" and "]" can be added, but there's no
        !           516: error on writing a mixed expression like "2*(3+4]".  Maybe also there could
        !           517: be a way to say that functions can only be written with one or the other
        !           518: style of parens.
        !           519:
        !           520:
        !           521:
        !           522: ----------------
        !           523: Local variables:
        !           524: mode: text
        !           525: fill-column: 76
        !           526: End:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>