aboutsummaryrefslogtreecommitdiff
path: root/gmp-6.3.0/demos/expr/expr.c
diff options
context:
space:
mode:
authorDuncan Wilkie <antigravityd@gmail.com>2023-11-18 06:11:09 -0600
committerDuncan Wilkie <antigravityd@gmail.com>2023-11-18 06:11:09 -0600
commit11da511c784eca003deb90c23570f0873954e0de (patch)
treee14fdd3d5d6345956d67e79ae771d0633d28362b /gmp-6.3.0/demos/expr/expr.c
Initial commit.
Diffstat (limited to 'gmp-6.3.0/demos/expr/expr.c')
-rw-r--r--gmp-6.3.0/demos/expr/expr.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/gmp-6.3.0/demos/expr/expr.c b/gmp-6.3.0/demos/expr/expr.c
new file mode 100644
index 0000000..42dd796
--- /dev/null
+++ b/gmp-6.3.0/demos/expr/expr.c
@@ -0,0 +1,834 @@
+/* mpexpr_evaluate -- shared code for simple expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+or
+
+ * the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library. If not,
+see https://www.gnu.org/licenses/. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. The trace
+ printfs junk up the code a bit, but it's very hard to tell what's going
+ on without them. Set MPX_TRACE to a suitable output function for the
+ mpz/mpq/mpf being run (if you have the wrong trace function it'll
+ probably segv). */
+
+#define TRACE(x)
+#define MPX_TRACE mpz_trace
+
+
+/* A few helper macros copied from gmp-impl.h */
+#define ALLOCATE_FUNC_TYPE(n,type) \
+ ((type *) (*allocate_func) ((n) * sizeof (type)))
+#define ALLOCATE_FUNC_LIMBS(n) ALLOCATE_FUNC_TYPE (n, mp_limb_t)
+#define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
+ ((type *) (*reallocate_func) \
+ (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
+#define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
+ REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
+#define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
+#define FREE_FUNC_LIMBS(p,n) FREE_FUNC_TYPE (p, n, mp_limb_t)
+#define ASSERT(x)
+
+
+
+/* All the error strings are just for diagnostic traces. Only the error
+ code is actually returned. */
+#define ERROR(str,code) \
+ { \
+ TRACE (printf ("%s\n", str)); \
+ p->error_code = (code); \
+ goto done; \
+ }
+
+
+#define REALLOC(ptr, alloc, incr, type) \
+ do { \
+ int new_alloc = (alloc) + (incr); \
+ ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type); \
+ (alloc) = new_alloc; \
+ } while (0)
+
+
+/* data stack top element */
+#define SP (p->data_stack + p->data_top)
+
+/* Make sure there's room for another data element above current top.
+ reallocate_func is fetched for when this macro is used in lookahead(). */
+#define DATA_SPACE() \
+ do { \
+ if (p->data_top + 1 >= p->data_alloc) \
+ { \
+ void *(*reallocate_func) (void *, size_t, size_t); \
+ mp_get_memory_functions (NULL, &reallocate_func, NULL); \
+ TRACE (printf ("grow stack from %d\n", p->data_alloc)); \
+ REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t); \
+ } \
+ ASSERT (p->data_top + 1 <= p->data_inited); \
+ if (p->data_top + 1 == p->data_inited) \
+ { \
+ TRACE (printf ("initialize %d\n", p->data_top + 1)); \
+ (*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec); \
+ p->data_inited++; \
+ } \
+ } while (0)
+
+#define DATA_PUSH() \
+ do { \
+ p->data_top++; \
+ ASSERT (p->data_top < p->data_alloc); \
+ ASSERT (p->data_top < p->data_inited); \
+ } while (0)
+
+/* the last stack entry is never popped, so top>=0 will be true */
+#define DATA_POP(n) \
+ do { \
+ p->data_top -= (n); \
+ ASSERT (p->data_top >= 0); \
+ } while (0)
+
+
+/* lookahead() parses the next token. Return 1 if successful, with some
+ extra data. Return 0 if fail, with reason in p->error_code.
+
+ "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
+ preferred, or 0 if an operator without is preferred. */
+
+#define TOKEN_EOF -1 /* no extra data */
+#define TOKEN_VALUE -2 /* pushed onto data stack */
+#define TOKEN_OPERATOR -3 /* stored in p->token_op */
+#define TOKEN_FUNCTION -4 /* stored in p->token_op */
+
+#define TOKEN_NAME(n) \
+ ((n) == TOKEN_EOF ? "TOKEN_EOF" \
+ : (n) == TOKEN_VALUE ? "TOKEN_VALUE" \
+ : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR" \
+ : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION" \
+ : "UNKNOWN TOKEN")
+
+/* Functions default to being parsed as whole words, operators to match just
+ at the start of the string. The type flags override this. */
+#define WHOLEWORD(op) \
+ (op->precedence == 0 \
+ ? (! (op->type & MPEXPR_TYPE_OPERATOR)) \
+ : (op->type & MPEXPR_TYPE_WHOLEWORD))
+
+#define isasciispace(c) (isascii (c) && isspace (c))
+
+static int
+lookahead (struct mpexpr_parse_t *p, int prefix)
+{
+ const struct mpexpr_operator_t *op, *op_found;
+ size_t oplen, oplen_found, wlen;
+ int i;
+
+ /* skip white space */
+ while (p->elen > 0 && isasciispace (*p->e))
+ p->e++, p->elen--;
+
+ if (p->elen == 0)
+ {
+ TRACE (printf ("lookahead EOF\n"));
+ p->token = TOKEN_EOF;
+ return 1;
+ }
+
+ DATA_SPACE ();
+
+ /* Get extent of whole word. */
+ for (wlen = 0; wlen < p->elen; wlen++)
+ if (! isasciicsym (p->e[wlen]))
+ break;
+
+ TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
+ (int) p->elen, p->e, p->elen, wlen));
+
+ op_found = NULL;
+ oplen_found = 0;
+ for (op = p->table; op->name != NULL; op++)
+ {
+ if (op->type == MPEXPR_TYPE_NEW_TABLE)
+ {
+ printf ("new\n");
+ op = (struct mpexpr_operator_t *) op->name - 1;
+ continue;
+ }
+
+ oplen = strlen (op->name);
+ if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
+ && memcmp (p->e, op->name, oplen) == 0))
+ continue;
+
+ /* Shorter matches don't replace longer previous ones. */
+ if (op_found && oplen < oplen_found)
+ continue;
+
+ /* On a match of equal length to a previous one, the old match isn't
+ replaced if it has the preferred prefix, and if it doesn't then
+ it's not replaced if the new one also doesn't. */
+ if (op_found && oplen == oplen_found
+ && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
+ || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
+ continue;
+
+ /* This is now either the first match seen, or a longer than previous
+ match, or an equal to previous one but with a preferred prefix. */
+ op_found = op;
+ oplen_found = oplen;
+ }
+
+ if (op_found)
+ {
+ p->e += oplen_found, p->elen -= oplen_found;
+
+ if (op_found->type == MPEXPR_TYPE_VARIABLE)
+ {
+ if (p->elen == 0)
+ ERROR ("end of string expecting a variable",
+ MPEXPR_RESULT_PARSE_ERROR);
+ i = p->e[0] - 'a';
+ if (i < 0 || i >= MPEXPR_VARIABLES)
+ ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
+ goto variable;
+ }
+
+ if (op_found->precedence == 0)
+ {
+ TRACE (printf ("lookahead function: %s\n", op_found->name));
+ p->token = TOKEN_FUNCTION;
+ p->token_op = op_found;
+ return 1;
+ }
+ else
+ {
+ TRACE (printf ("lookahead operator: %s\n", op_found->name));
+ p->token = TOKEN_OPERATOR;
+ p->token_op = op_found;
+ return 1;
+ }
+ }
+
+ oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
+ if (oplen != 0)
+ {
+ p->e += oplen, p->elen -= oplen;
+ p->token = TOKEN_VALUE;
+ DATA_PUSH ();
+ TRACE (MPX_TRACE ("lookahead number", SP));
+ return 1;
+ }
+
+ /* Maybe an unprefixed one character variable */
+ i = p->e[0] - 'a';
+ if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
+ {
+ variable:
+ p->e++, p->elen--;
+ if (p->var[i] == NULL)
+ ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
+ TRACE (printf ("lookahead variable: var[%d] = ", i);
+ MPX_TRACE ("", p->var[i]));
+ p->token = TOKEN_VALUE;
+ DATA_PUSH ();
+ (*p->mpX_set) (SP, p->var[i]);
+ return 1;
+ }
+
+ ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
+
+ done:
+ return 0;
+}
+
+
+/* control stack current top element */
+#define CP (p->control_stack + p->control_top)
+
+/* make sure there's room for another control element above current top */
+#define CONTROL_SPACE() \
+ do { \
+ if (p->control_top + 1 >= p->control_alloc) \
+ { \
+ TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
+ REALLOC (p->control_stack, p->control_alloc, 20, \
+ struct mpexpr_control_t); \
+ } \
+ } while (0)
+
+/* Push an operator on the control stack, claiming currently to have the
+ given number of args ready. Local variable "op" is used in case opptr is
+ a reference through CP. */
+#define CONTROL_PUSH(opptr,args) \
+ do { \
+ const struct mpexpr_operator_t *op = opptr; \
+ struct mpexpr_control_t *cp; \
+ CONTROL_SPACE (); \
+ p->control_top++; \
+ ASSERT (p->control_top < p->control_alloc); \
+ cp = CP; \
+ cp->op = op; \
+ cp->argcount = (args); \
+ TRACE_CONTROL("control stack push:"); \
+ } while (0)
+
+/* The special operator_done is never popped, so top>=0 will hold. */
+#define CONTROL_POP() \
+ do { \
+ p->control_top--; \
+ ASSERT (p->control_top >= 0); \
+ TRACE_CONTROL ("control stack pop:"); \
+ } while (0)
+
+#define TRACE_CONTROL(str) \
+ TRACE ({ \
+ int i; \
+ printf ("%s depth %d:", str, p->control_top); \
+ for (i = 0; i <= p->control_top; i++) \
+ printf (" \"%s\"(%d)", \
+ p->control_stack[i].op->name, \
+ p->control_stack[i].argcount); \
+ printf ("\n"); \
+ });
+
+
+#define LOOKAHEAD(prefix) \
+ do { \
+ if (! lookahead (p, prefix)) \
+ goto done; \
+ } while (0)
+
+#define CHECK_UI(n) \
+ do { \
+ if (! (*p->mpX_ulong_p) (n)) \
+ ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI); \
+ } while (0)
+
+#define CHECK_ARGCOUNT(str,n) \
+ do { \
+ if (CP->argcount != (n)) \
+ { \
+ TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
+ str, CP->argcount, n)); \
+ ERROR ("", MPEXPR_RESULT_PARSE_ERROR); \
+ } \
+ } while (0)
+
+
+/* There's two basic states here. In both p->token is the next token.
+
+ "another_expr" is when a whole expression should be parsed. This means a
+ literal or variable value possibly followed by an operator, or a function
+ or prefix operator followed by a further whole expression.
+
+ "another_operator" is when an expression has been parsed and its value is
+ on the top of the data stack (SP) and an optional further postfix or
+ infix operator should be parsed.
+
+ In "another_operator" precedences determine whether to push the operator
+ onto the control stack, or instead go to "apply_control" to reduce the
+ operator currently on top of the control stack.
+
+ When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
+ for "another_expr" will seek the prefix form, a LOOKAHEAD() for
+ "another_operator" will seek the postfix/infix form. The grammar is
+ simple enough that the next state is known before reading the next token.
+
+ Argument count checking guards against functions consuming the wrong
+ number of operands from the data stack. The same checks are applied to
+ operators, but will always pass since a UNARY or BINARY will only ever
+ parse with the correct operands. */
+
+int
+mpexpr_evaluate (struct mpexpr_parse_t *p)
+{
+ void *(*allocate_func) (size_t);
+ void *(*reallocate_func) (void *, size_t, size_t);
+ void (*free_func) (void *, size_t);
+
+ mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
+
+ TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
+ p->base, (int) p->elen, p->e));
+
+ /* "done" is a special sentinel at the bottom of the control stack,
+ precedence -1 is lower than any normal operator. */
+ {
+ static const struct mpexpr_operator_t operator_done
+ = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
+
+ p->control_alloc = 20;
+ p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
+ struct mpexpr_control_t);
+ p->control_top = 0;
+ CP->op = &operator_done;
+ CP->argcount = 1;
+ }
+
+ p->data_inited = 0;
+ p->data_alloc = 20;
+ p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
+ p->data_top = -1;
+
+ p->error_code = MPEXPR_RESULT_OK;
+
+
+ another_expr_lookahead:
+ LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+ TRACE (printf ("another expr\n"));
+
+ /*another_expr:*/
+ switch (p->token) {
+ case TOKEN_VALUE:
+ goto another_operator_lookahead;
+
+ case TOKEN_OPERATOR:
+ TRACE (printf ("operator %s\n", p->token_op->name));
+ if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
+ ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
+
+ CONTROL_PUSH (p->token_op, 1);
+ goto another_expr_lookahead;
+
+ case TOKEN_FUNCTION:
+ CONTROL_PUSH (p->token_op, 1);
+
+ if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
+ goto apply_control_lookahead;
+
+ LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+ if (! (p->token == TOKEN_OPERATOR
+ && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
+ ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
+
+ TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
+
+ if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
+ {
+ LOOKAHEAD (0);
+ if (! (p->token == TOKEN_OPERATOR
+ && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
+ ERROR ("expected close paren for 0ary function",
+ MPEXPR_RESULT_PARSE_ERROR);
+ goto apply_control_lookahead;
+ }
+
+ goto another_expr_lookahead;
+ }
+ ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
+
+
+ another_operator_lookahead:
+ LOOKAHEAD (0);
+ another_operator:
+ TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
+
+ switch (p->token) {
+ case TOKEN_EOF:
+ goto apply_control;
+
+ case TOKEN_OPERATOR:
+ /* The next operator is compared to the one on top of the control stack.
+ If the next is lower precedence, or the same precedence and not
+ right-associative, then reduce using the control stack and look at
+ the next operator again later. */
+
+#define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype) \
+ ((tprec) < (cprec) \
+ || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
+
+ if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
+ p->token_op->type, CP->op->type))
+ {
+ TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
+ p->token_op->name,
+ p->token_op->precedence, CP->op->precedence,
+ p->token_op->type));
+ goto apply_control;
+ }
+
+ /* An argsep is a binary operator, but is never pushed on the control
+ stack, it just accumulates an extra argument for a function. */
+ if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
+ {
+ if (CP->op->precedence != 0)
+ ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
+
+ TRACE (printf ("argsep for function \"%s\"(%d)\n",
+ CP->op->name, CP->argcount));
+
+#define IS_PAIRWISE(type) \
+ (((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE)) \
+ == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
+
+ if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
+ {
+ TRACE (printf (" will reduce pairwise now\n"));
+ CP->argcount--;
+ CONTROL_PUSH (CP->op, 2);
+ goto apply_control;
+ }
+
+ CP->argcount++;
+ goto another_expr_lookahead;
+ }
+
+ switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+ case MPEXPR_TYPE_NARY(1):
+ /* Postfix unary operators can always be applied immediately. The
+ easiest way to do this is just push it on the control stack and go
+ to the normal control stack reduction code. */
+
+ TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
+ if (p->token_op->type & MPEXPR_TYPE_PREFIX)
+ ERROR ("prefix unary operator used postfix",
+ MPEXPR_RESULT_PARSE_ERROR);
+ CONTROL_PUSH (p->token_op, 1);
+ goto apply_control_lookahead;
+
+ case MPEXPR_TYPE_NARY(2):
+ CONTROL_PUSH (p->token_op, 2);
+ goto another_expr_lookahead;
+
+ case MPEXPR_TYPE_NARY(3):
+ CONTROL_PUSH (p->token_op, 1);
+ goto another_expr_lookahead;
+ }
+
+ TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
+ CP->op->name, CP->op->type));
+ ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+ break;
+
+ default:
+ TRACE (printf ("expecting an operator, got token %d", p->token));
+ ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+ }
+
+
+ apply_control_lookahead:
+ LOOKAHEAD (0);
+ apply_control:
+ /* Apply the top element CP of the control stack. Data values are SP,
+ SP-1, etc. Result is left as stack top SP after popping consumed
+ values.
+
+ The use of sp as a duplicate of SP will help compilers that can't
+ otherwise recognise the various uses of SP as common subexpressions. */
+
+ TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
+ p->control_top, CP->op->name, CP->op->type, CP->argcount));
+
+ TRACE (printf ("apply 0x%X-ary\n",
+ CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
+ switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+ case MPEXPR_TYPE_NARY(0):
+ {
+ mpX_ptr sp;
+ DATA_SPACE ();
+ DATA_PUSH ();
+ sp = SP;
+ switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+ case 0:
+ (* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
+ break;
+ case MPEXPR_TYPE_RESULT_INT:
+ (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
+ break;
+ default:
+ ERROR ("unrecognised 0ary argument calling style",
+ MPEXPR_RESULT_BAD_TABLE);
+ }
+ }
+ break;
+
+ case MPEXPR_TYPE_NARY(1):
+ {
+ mpX_ptr sp = SP;
+ CHECK_ARGCOUNT ("unary", 1);
+ TRACE (MPX_TRACE ("before", sp));
+
+ switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+ case 0:
+ /* not a special */
+ break;
+
+ case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special done\n"));
+ goto done;
+
+ case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special logical not\n"));
+ (*p->mpX_set_si)
+ (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
+ goto apply_control_done;
+
+ case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
+ CONTROL_POP ();
+ if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
+ {
+ TRACE (printf ("close paren matching open paren\n"));
+ CONTROL_POP ();
+ goto another_operator;
+ }
+ if (CP->op->precedence == 0)
+ {
+ TRACE (printf ("close paren for function\n"));
+ goto apply_control;
+ }
+ ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
+
+ default:
+ TRACE (printf ("unrecognised special unary operator 0x%X",
+ CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
+ ERROR ("", MPEXPR_RESULT_BAD_TABLE);
+ }
+
+ switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+ case 0:
+ (* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
+ break;
+ case MPEXPR_TYPE_LAST_UI:
+ CHECK_UI (sp);
+ (* (mpexpr_fun_unary_ui_t) CP->op->fun)
+ (sp, (*p->mpX_get_ui) (sp));
+ break;
+ case MPEXPR_TYPE_RESULT_INT:
+ (*p->mpX_set_si)
+ (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
+ break;
+ case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
+ CHECK_UI (sp);
+ (*p->mpX_set_si)
+ (sp,
+ (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
+ ((*p->mpX_get_ui) (sp)));
+ break;
+ default:
+ ERROR ("unrecognised unary argument calling style",
+ MPEXPR_RESULT_BAD_TABLE);
+ }
+ }
+ break;
+
+ case MPEXPR_TYPE_NARY(2):
+ {
+ mpX_ptr sp;
+
+ /* pairwise functions are allowed to have just one argument */
+ if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
+ && CP->op->precedence == 0
+ && CP->argcount == 1)
+ goto apply_control_done;
+
+ CHECK_ARGCOUNT ("binary", 2);
+ DATA_POP (1);
+ sp = SP;
+ TRACE (MPX_TRACE ("lhs", sp);
+ MPX_TRACE ("rhs", sp+1));
+
+ if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
+ {
+ int type = CP->op->type;
+ int cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
+ (sp, sp+1);
+ (*p->mpX_set_si)
+ (sp,
+ (long)
+ (( (cmp < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
+ | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
+ | ((cmp > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
+ goto apply_control_done;
+ }
+
+ switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+ case 0:
+ /* not a special */
+ break;
+
+ case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
+ ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
+
+ case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special colon\n"));
+ CONTROL_POP ();
+ if (CP->op->type != MPEXPR_TYPE_QUESTION)
+ ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
+
+ CP->argcount--;
+ DATA_POP (1);
+ sp--;
+ TRACE (MPX_TRACE ("query", sp);
+ MPX_TRACE ("true", sp+1);
+ MPX_TRACE ("false", sp+2));
+ (*p->mpX_set)
+ (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+ ? sp+1 : sp+2);
+ goto apply_control_done;
+
+ case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special logical and\n"));
+ (*p->mpX_set_si)
+ (sp,
+ (long)
+ ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+ && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+ goto apply_control_done;
+
+ case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special logical and\n"));
+ (*p->mpX_set_si)
+ (sp,
+ (long)
+ ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+ || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+ goto apply_control_done;
+
+ case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special max\n"));
+ if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
+ (*p->mpX_swap) (sp, sp+1);
+ goto apply_control_done;
+ case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
+ TRACE (printf ("special min\n"));
+ if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
+ (*p->mpX_swap) (sp, sp+1);
+ goto apply_control_done;
+
+ default:
+ ERROR ("unrecognised special binary operator",
+ MPEXPR_RESULT_BAD_TABLE);
+ }
+
+ switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+ case 0:
+ (* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
+ break;
+ case MPEXPR_TYPE_LAST_UI:
+ CHECK_UI (sp+1);
+ (* (mpexpr_fun_binary_ui_t) CP->op->fun)
+ (sp, sp, (*p->mpX_get_ui) (sp+1));
+ break;
+ case MPEXPR_TYPE_RESULT_INT:
+ (*p->mpX_set_si)
+ (sp,
+ (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
+ break;
+ case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+ CHECK_UI (sp+1);
+ (*p->mpX_set_si)
+ (sp,
+ (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
+ (sp, (*p->mpX_get_ui) (sp+1)));
+ break;
+ default:
+ ERROR ("unrecognised binary argument calling style",
+ MPEXPR_RESULT_BAD_TABLE);
+ }
+ }
+ break;
+
+ case MPEXPR_TYPE_NARY(3):
+ {
+ mpX_ptr sp;
+
+ CHECK_ARGCOUNT ("ternary", 3);
+ DATA_POP (2);
+ sp = SP;
+ TRACE (MPX_TRACE ("arg1", sp);
+ MPX_TRACE ("arg2", sp+1);
+ MPX_TRACE ("arg3", sp+1));
+
+ switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+ case 0:
+ (* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
+ break;
+ case MPEXPR_TYPE_LAST_UI:
+ CHECK_UI (sp+2);
+ (* (mpexpr_fun_ternary_ui_t) CP->op->fun)
+ (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
+ break;
+ case MPEXPR_TYPE_RESULT_INT:
+ (*p->mpX_set_si)
+ (sp,
+ (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
+ (sp, sp+1, sp+2));
+ break;
+ case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+ CHECK_UI (sp+2);
+ (*p->mpX_set_si)
+ (sp,
+ (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
+ (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
+ break;
+ default:
+ ERROR ("unrecognised binary argument calling style",
+ MPEXPR_RESULT_BAD_TABLE);
+ }
+ }
+ break;
+
+ default:
+ TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
+ ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+ }
+
+ apply_control_done:
+ TRACE (MPX_TRACE ("result", SP));
+ CONTROL_POP ();
+ goto another_operator;
+
+ done:
+ if (p->error_code == MPEXPR_RESULT_OK)
+ {
+ if (p->data_top != 0)
+ {
+ TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
+ p->error_code = MPEXPR_RESULT_PARSE_ERROR;
+ }
+ else
+ (*p->mpX_set_or_swap) (p->res, SP);
+ }
+
+ {
+ int i;
+ for (i = 0; i < p->data_inited; i++)
+ {
+ TRACE (printf ("clear %d\n", i));
+ (*p->mpX_clear) (p->data_stack+i);
+ }
+ }
+
+ FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
+ FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
+
+ return p->error_code;
+}