From 11da511c784eca003deb90c23570f0873954e0de Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Sat, 18 Nov 2023 06:11:09 -0600 Subject: Initial commit. --- gmp-6.3.0/demos/expr/expr.c | 834 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 834 insertions(+) create mode 100644 gmp-6.3.0/demos/expr/expr.c (limited to 'gmp-6.3.0/demos/expr/expr.c') 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 +#include +#include + +#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; +} -- cgit v1.2.3