1 /* mpexpr_evaluate -- shared code for simple expression evaluation
3 Copyright 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
5 This file is part of the GNU MP Library.
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
25 #include "expr-impl.h"
28 /* Change this to "#define TRACE(x) x" to get some traces. The trace
29 printfs junk up the code a bit, but it's very hard to tell what's going
30 on without them. Set MPX_TRACE to a suitable output function for the
31 mpz/mpq/mpf being run (if you have the wrong trace function it'll
35 #define MPX_TRACE mpz_trace
38 /* A few helper macros copied from gmp-impl.h */
39 #define ALLOCATE_FUNC_TYPE(n,type) \
40 ((type *) (*allocate_func) ((n) * sizeof (type)))
41 #define ALLOCATE_FUNC_LIMBS(n) ALLOCATE_FUNC_TYPE (n, mp_limb_t)
42 #define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
43 ((type *) (*reallocate_func) \
44 (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
45 #define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
46 REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
47 #define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
48 #define FREE_FUNC_LIMBS(p,n) FREE_FUNC_TYPE (p, n, mp_limb_t)
53 /* All the error strings are just for diagnostic traces. Only the error
54 code is actually returned. */
55 #define ERROR(str,code) \
57 TRACE (printf ("%s\n", str)); \
58 p->error_code = (code); \
63 #define REALLOC(ptr, alloc, incr, type) \
65 int new_alloc = (alloc) + (incr); \
66 ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type); \
67 (alloc) = new_alloc; \
71 /* data stack top element */
72 #define SP (p->data_stack + p->data_top)
74 /* Make sure there's room for another data element above current top.
75 reallocate_func is fetched for when this macro is used in lookahead(). */
76 #define DATA_SPACE() \
78 if (p->data_top + 1 >= p->data_alloc) \
80 void *(*reallocate_func) (void *, size_t, size_t); \
81 mp_get_memory_functions (NULL, &reallocate_func, NULL); \
82 TRACE (printf ("grow stack from %d\n", p->data_alloc)); \
83 REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t); \
85 ASSERT (p->data_top + 1 <= p->data_inited); \
86 if (p->data_top + 1 == p->data_inited) \
88 TRACE (printf ("initialize %d\n", p->data_top + 1)); \
89 (*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec); \
97 ASSERT (p->data_top < p->data_alloc); \
98 ASSERT (p->data_top < p->data_inited); \
101 /* the last stack entry is never popped, so top>=0 will be true */
102 #define DATA_POP(n) \
104 p->data_top -= (n); \
105 ASSERT (p->data_top >= 0); \
109 /* lookahead() parses the next token. Return 1 if successful, with some
110 extra data. Return 0 if fail, with reason in p->error_code.
112 "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
113 preferred, or 0 if an operator without is preferred. */
115 #define TOKEN_EOF -1 /* no extra data */
116 #define TOKEN_VALUE -2 /* pushed onto data stack */
117 #define TOKEN_OPERATOR -3 /* stored in p->token_op */
118 #define TOKEN_FUNCTION -4 /* stored in p->token_op */
120 #define TOKEN_NAME(n) \
121 ((n) == TOKEN_EOF ? "TOKEN_EOF" \
122 : (n) == TOKEN_VALUE ? "TOKEN_VALUE" \
123 : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR" \
124 : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION" \
127 /* Functions default to being parsed as whole words, operators to match just
128 at the start of the string. The type flags override this. */
129 #define WHOLEWORD(op) \
130 (op->precedence == 0 \
131 ? (! (op->type & MPEXPR_TYPE_OPERATOR)) \
132 : (op->type & MPEXPR_TYPE_WHOLEWORD))
134 #define isasciispace(c) (isascii (c) && isspace (c))
137 lookahead (struct mpexpr_parse_t *p, int prefix)
139 __gmp_const struct mpexpr_operator_t *op, *op_found;
140 size_t oplen, oplen_found, wlen;
143 /* skip white space */
144 while (p->elen > 0 && isasciispace (*p->e))
149 TRACE (printf ("lookahead EOF\n"));
150 p->token = TOKEN_EOF;
156 /* Get extent of whole word. */
157 for (wlen = 0; wlen < p->elen; wlen++)
158 if (! isasciicsym (p->e[wlen]))
161 TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
162 (int) p->elen, p->e, p->elen, wlen));
166 for (op = p->table; op->name != NULL; op++)
168 if (op->type == MPEXPR_TYPE_NEW_TABLE)
171 op = (struct mpexpr_operator_t *) op->name - 1;
175 oplen = strlen (op->name);
176 if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
177 && memcmp (p->e, op->name, oplen) == 0))
180 /* Shorter matches don't replace longer previous ones. */
181 if (op_found && oplen < oplen_found)
184 /* On a match of equal length to a previous one, the old match isn't
185 replaced if it has the preferred prefix, and if it doesn't then
186 it's not replaced if the new one also doesn't. */
187 if (op_found && oplen == oplen_found
188 && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
189 || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
192 /* This is now either the first match seen, or a longer than previous
193 match, or an equal to previous one but with a preferred prefix. */
200 p->e += oplen_found, p->elen -= oplen_found;
202 if (op_found->type == MPEXPR_TYPE_VARIABLE)
205 ERROR ("end of string expecting a variable",
206 MPEXPR_RESULT_PARSE_ERROR);
208 if (i < 0 || i >= MPEXPR_VARIABLES)
209 ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
213 if (op_found->precedence == 0)
215 TRACE (printf ("lookahead function: %s\n", op_found->name));
216 p->token = TOKEN_FUNCTION;
217 p->token_op = op_found;
222 TRACE (printf ("lookahead operator: %s\n", op_found->name));
223 p->token = TOKEN_OPERATOR;
224 p->token_op = op_found;
229 oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
232 p->e += oplen, p->elen -= oplen;
233 p->token = TOKEN_VALUE;
235 TRACE (MPX_TRACE ("lookahead number", SP));
239 /* Maybe an unprefixed one character variable */
241 if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
245 if (p->var[i] == NULL)
246 ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
247 TRACE (printf ("lookahead variable: var[%d] = ", i);
248 MPX_TRACE ("", p->var[i]));
249 p->token = TOKEN_VALUE;
251 (*p->mpX_set) (SP, p->var[i]);
255 ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
262 /* control stack current top element */
263 #define CP (p->control_stack + p->control_top)
265 /* make sure there's room for another control element above current top */
266 #define CONTROL_SPACE() \
268 if (p->control_top + 1 >= p->control_alloc) \
270 TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
271 REALLOC (p->control_stack, p->control_alloc, 20, \
272 struct mpexpr_control_t); \
276 /* Push an operator on the control stack, claiming currently to have the
277 given number of args ready. Local variable "op" is used in case opptr is
278 a reference through CP. */
279 #define CONTROL_PUSH(opptr,args) \
281 __gmp_const struct mpexpr_operator_t *op = opptr; \
282 struct mpexpr_control_t *cp; \
285 ASSERT (p->control_top < p->control_alloc); \
288 cp->argcount = (args); \
289 TRACE_CONTROL("control stack push:"); \
292 /* The special operator_done is never popped, so top>=0 will hold. */
293 #define CONTROL_POP() \
296 ASSERT (p->control_top >= 0); \
297 TRACE_CONTROL ("control stack pop:"); \
300 #define TRACE_CONTROL(str) \
303 printf ("%s depth %d:", str, p->control_top); \
304 for (i = 0; i <= p->control_top; i++) \
305 printf (" \"%s\"(%d)", \
306 p->control_stack[i].op->name, \
307 p->control_stack[i].argcount); \
312 #define LOOKAHEAD(prefix) \
314 if (! lookahead (p, prefix)) \
318 #define CHECK_UI(n) \
320 if (! (*p->mpX_ulong_p) (n)) \
321 ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI); \
324 #define CHECK_ARGCOUNT(str,n) \
326 if (CP->argcount != (n)) \
328 TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
329 str, CP->argcount, n)); \
330 ERROR ("", MPEXPR_RESULT_PARSE_ERROR); \
335 /* There's two basic states here. In both p->token is the next token.
337 "another_expr" is when a whole expression should be parsed. This means a
338 literal or variable value possibly followed by an operator, or a function
339 or prefix operator followed by a further whole expression.
341 "another_operator" is when an expression has been parsed and its value is
342 on the top of the data stack (SP) and an optional further postfix or
343 infix operator should be parsed.
345 In "another_operator" precedences determine whether to push the operator
346 onto the control stack, or instead go to "apply_control" to reduce the
347 operator currently on top of the control stack.
349 When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
350 for "another_expr" will seek the prefix form, a LOOKAHEAD() for
351 "another_operator" will seek the postfix/infix form. The grammar is
352 simple enough that the next state is known before reading the next token.
354 Argument count checking guards against functions consuming the wrong
355 number of operands from the data stack. The same checks are applied to
356 operators, but will always pass since a UNARY or BINARY will only ever
357 parse with the correct operands. */
360 mpexpr_evaluate (struct mpexpr_parse_t *p)
362 void *(*allocate_func) (size_t);
363 void *(*reallocate_func) (void *, size_t, size_t);
364 void (*free_func) (void *, size_t);
366 mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
368 TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
369 p->base, (int) p->elen, p->e));
371 /* "done" is a special sentinel at the bottom of the control stack,
372 precedence -1 is lower than any normal operator. */
374 static __gmp_const struct mpexpr_operator_t operator_done
375 = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
377 p->control_alloc = 20;
378 p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
379 struct mpexpr_control_t);
381 CP->op = &operator_done;
387 p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
390 p->error_code = MPEXPR_RESULT_OK;
393 another_expr_lookahead:
394 LOOKAHEAD (MPEXPR_TYPE_PREFIX);
395 TRACE (printf ("another expr\n"));
400 goto another_operator_lookahead;
403 TRACE (printf ("operator %s\n", p->token_op->name));
404 if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
405 ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
407 CONTROL_PUSH (p->token_op, 1);
408 goto another_expr_lookahead;
411 CONTROL_PUSH (p->token_op, 1);
413 if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
414 goto apply_control_lookahead;
416 LOOKAHEAD (MPEXPR_TYPE_PREFIX);
417 if (! (p->token == TOKEN_OPERATOR
418 && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
419 ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
421 TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
423 if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
426 if (! (p->token == TOKEN_OPERATOR
427 && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
428 ERROR ("expected close paren for 0ary function",
429 MPEXPR_RESULT_PARSE_ERROR);
430 goto apply_control_lookahead;
433 goto another_expr_lookahead;
435 ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
438 another_operator_lookahead:
441 TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
448 /* The next operator is compared to the one on top of the control stack.
449 If the next is lower precedence, or the same precedence and not
450 right-associative, then reduce using the control stack and look at
451 the next operator again later. */
453 #define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype) \
455 || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
457 if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
458 p->token_op->type, CP->op->type))
460 TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
462 p->token_op->precedence, CP->op->precedence,
467 /* An argsep is a binary operator, but is never pushed on the control
468 stack, it just accumulates an extra argument for a function. */
469 if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
471 if (CP->op->precedence != 0)
472 ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
474 TRACE (printf ("argsep for function \"%s\"(%d)\n",
475 CP->op->name, CP->argcount));
477 #define IS_PAIRWISE(type) \
478 (((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE)) \
479 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
481 if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
483 TRACE (printf (" will reduce pairwise now\n"));
485 CONTROL_PUSH (CP->op, 2);
490 goto another_expr_lookahead;
493 switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
494 case MPEXPR_TYPE_NARY(1):
495 /* Postfix unary operators can always be applied immediately. The
496 easiest way to do this is just push it on the control stack and go
497 to the normal control stack reduction code. */
499 TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
500 if (p->token_op->type & MPEXPR_TYPE_PREFIX)
501 ERROR ("prefix unary operator used postfix",
502 MPEXPR_RESULT_PARSE_ERROR);
503 CONTROL_PUSH (p->token_op, 1);
504 goto apply_control_lookahead;
506 case MPEXPR_TYPE_NARY(2):
507 CONTROL_PUSH (p->token_op, 2);
508 goto another_expr_lookahead;
510 case MPEXPR_TYPE_NARY(3):
511 CONTROL_PUSH (p->token_op, 1);
512 goto another_expr_lookahead;
515 TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
516 CP->op->name, CP->op->type));
517 ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
521 TRACE (printf ("expecting an operator, got token %d", p->token));
522 ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
526 apply_control_lookahead:
529 /* Apply the top element CP of the control stack. Data values are SP,
530 SP-1, etc. Result is left as stack top SP after popping consumed
533 The use of sp as a duplicate of SP will help compilers that can't
534 otherwise recognise the various uses of SP as common subexpressions. */
536 TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
537 p->control_top, CP->op->name, CP->op->type, CP->argcount));
539 TRACE (printf ("apply 0x%X-ary\n",
540 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
541 switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
542 case MPEXPR_TYPE_NARY(0):
548 switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
550 (* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
552 case MPEXPR_TYPE_RESULT_INT:
553 (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
556 ERROR ("unrecognised 0ary argument calling style",
557 MPEXPR_RESULT_BAD_TABLE);
562 case MPEXPR_TYPE_NARY(1):
565 CHECK_ARGCOUNT ("unary", 1);
566 TRACE (MPX_TRACE ("before", sp));
568 switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
573 case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
574 TRACE (printf ("special done\n"));
577 case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
578 TRACE (printf ("special logical not\n"));
580 (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
581 goto apply_control_done;
583 case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
585 if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
587 TRACE (printf ("close paren matching open paren\n"));
589 goto another_operator;
591 if (CP->op->precedence == 0)
593 TRACE (printf ("close paren for function\n"));
596 ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
599 TRACE (printf ("unrecognised special unary operator 0x%X",
600 CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
601 ERROR ("", MPEXPR_RESULT_BAD_TABLE);
604 switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
606 (* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
608 case MPEXPR_TYPE_LAST_UI:
610 (* (mpexpr_fun_unary_ui_t) CP->op->fun)
611 (sp, (*p->mpX_get_ui) (sp));
613 case MPEXPR_TYPE_RESULT_INT:
615 (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
617 case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
621 (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
622 ((*p->mpX_get_ui) (sp)));
625 ERROR ("unrecognised unary argument calling style",
626 MPEXPR_RESULT_BAD_TABLE);
631 case MPEXPR_TYPE_NARY(2):
635 /* pairwise functions are allowed to have just one argument */
636 if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
637 && CP->op->precedence == 0
638 && CP->argcount == 1)
639 goto apply_control_done;
641 CHECK_ARGCOUNT ("binary", 2);
644 TRACE (MPX_TRACE ("lhs", sp);
645 MPX_TRACE ("rhs", sp+1));
647 if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
649 int type = CP->op->type;
650 int cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
655 (( (cmp < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
656 | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
657 | ((cmp > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
658 goto apply_control_done;
661 switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
666 case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
667 ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
669 case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
670 TRACE (printf ("special colon\n"));
672 if (CP->op->type != MPEXPR_TYPE_QUESTION)
673 ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
678 TRACE (MPX_TRACE ("query", sp);
679 MPX_TRACE ("true", sp+1);
680 MPX_TRACE ("false", sp+2));
682 (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
684 goto apply_control_done;
686 case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
687 TRACE (printf ("special logical and\n"));
691 ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
692 && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
693 goto apply_control_done;
695 case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
696 TRACE (printf ("special logical and\n"));
700 ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
701 || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
702 goto apply_control_done;
704 case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
705 TRACE (printf ("special max\n"));
706 if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
707 (*p->mpX_swap) (sp, sp+1);
708 goto apply_control_done;
709 case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
710 TRACE (printf ("special min\n"));
711 if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
712 (*p->mpX_swap) (sp, sp+1);
713 goto apply_control_done;
716 ERROR ("unrecognised special binary operator",
717 MPEXPR_RESULT_BAD_TABLE);
720 switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
722 (* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
724 case MPEXPR_TYPE_LAST_UI:
726 (* (mpexpr_fun_binary_ui_t) CP->op->fun)
727 (sp, sp, (*p->mpX_get_ui) (sp+1));
729 case MPEXPR_TYPE_RESULT_INT:
732 (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
734 case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
738 (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
739 (sp, (*p->mpX_get_ui) (sp+1)));
742 ERROR ("unrecognised binary argument calling style",
743 MPEXPR_RESULT_BAD_TABLE);
748 case MPEXPR_TYPE_NARY(3):
752 CHECK_ARGCOUNT ("ternary", 3);
755 TRACE (MPX_TRACE ("arg1", sp);
756 MPX_TRACE ("arg2", sp+1);
757 MPX_TRACE ("arg3", sp+1));
759 switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
761 (* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
763 case MPEXPR_TYPE_LAST_UI:
765 (* (mpexpr_fun_ternary_ui_t) CP->op->fun)
766 (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
768 case MPEXPR_TYPE_RESULT_INT:
771 (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
774 case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
778 (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
779 (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
782 ERROR ("unrecognised binary argument calling style",
783 MPEXPR_RESULT_BAD_TABLE);
789 TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
790 ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
794 TRACE (MPX_TRACE ("result", SP));
796 goto another_operator;
799 if (p->error_code == MPEXPR_RESULT_OK)
801 if (p->data_top != 0)
803 TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
804 p->error_code = MPEXPR_RESULT_PARSE_ERROR;
807 (*p->mpX_set_or_swap) (p->res, SP);
812 for (i = 0; i < p->data_inited; i++)
814 TRACE (printf ("clear %d\n", i));
815 (*p->mpX_clear) (p->data_stack+i);
819 FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
820 FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
822 return p->error_code;