xref: /netbsd/external/lgpl3/gmp/dist/demos/expr/expr.c (revision f81b1c5b)
14a1767b4Smrg /* mpexpr_evaluate -- shared code for simple expression evaluation
24a1767b4Smrg 
3*f81b1c5bSmrg Copyright 2000-2002, 2004 Free Software Foundation, Inc.
44a1767b4Smrg 
54a1767b4Smrg This file is part of the GNU MP Library.
64a1767b4Smrg 
74a1767b4Smrg The GNU MP Library is free software; you can redistribute it and/or modify
8*f81b1c5bSmrg it under the terms of either:
9*f81b1c5bSmrg 
10*f81b1c5bSmrg   * the GNU Lesser General Public License as published by the Free
11*f81b1c5bSmrg     Software Foundation; either version 3 of the License, or (at your
124a1767b4Smrg     option) any later version.
134a1767b4Smrg 
14*f81b1c5bSmrg or
15*f81b1c5bSmrg 
16*f81b1c5bSmrg   * the GNU General Public License as published by the Free Software
17*f81b1c5bSmrg     Foundation; either version 2 of the License, or (at your option) any
18*f81b1c5bSmrg     later version.
19*f81b1c5bSmrg 
20*f81b1c5bSmrg or both in parallel, as here.
21*f81b1c5bSmrg 
224a1767b4Smrg The GNU MP Library is distributed in the hope that it will be useful, but
234a1767b4Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24*f81b1c5bSmrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25*f81b1c5bSmrg for more details.
264a1767b4Smrg 
27*f81b1c5bSmrg You should have received copies of the GNU General Public License and the
28*f81b1c5bSmrg GNU Lesser General Public License along with the GNU MP Library.  If not,
29*f81b1c5bSmrg see https://www.gnu.org/licenses/.  */
304a1767b4Smrg 
314a1767b4Smrg #include <ctype.h>
324a1767b4Smrg #include <stdio.h>
334a1767b4Smrg #include <string.h>
344a1767b4Smrg 
354a1767b4Smrg #include "gmp.h"
364a1767b4Smrg #include "expr-impl.h"
374a1767b4Smrg 
384a1767b4Smrg 
394a1767b4Smrg /* Change this to "#define TRACE(x) x" to get some traces.  The trace
404a1767b4Smrg    printfs junk up the code a bit, but it's very hard to tell what's going
414a1767b4Smrg    on without them.  Set MPX_TRACE to a suitable output function for the
424a1767b4Smrg    mpz/mpq/mpf being run (if you have the wrong trace function it'll
434a1767b4Smrg    probably segv).  */
444a1767b4Smrg 
454a1767b4Smrg #define TRACE(x)
464a1767b4Smrg #define MPX_TRACE  mpz_trace
474a1767b4Smrg 
484a1767b4Smrg 
494a1767b4Smrg /* A few helper macros copied from gmp-impl.h */
504a1767b4Smrg #define ALLOCATE_FUNC_TYPE(n,type) \
514a1767b4Smrg   ((type *) (*allocate_func) ((n) * sizeof (type)))
524a1767b4Smrg #define ALLOCATE_FUNC_LIMBS(n)   ALLOCATE_FUNC_TYPE (n, mp_limb_t)
534a1767b4Smrg #define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
544a1767b4Smrg   ((type *) (*reallocate_func)                            \
554a1767b4Smrg    (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
564a1767b4Smrg #define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
574a1767b4Smrg   REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
584a1767b4Smrg #define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
594a1767b4Smrg #define FREE_FUNC_LIMBS(p,n)     FREE_FUNC_TYPE (p, n, mp_limb_t)
604a1767b4Smrg #define ASSERT(x)
614a1767b4Smrg 
624a1767b4Smrg 
634a1767b4Smrg 
644a1767b4Smrg /* All the error strings are just for diagnostic traces.  Only the error
654a1767b4Smrg    code is actually returned.  */
664a1767b4Smrg #define ERROR(str,code)                 \
674a1767b4Smrg   {                                     \
684a1767b4Smrg     TRACE (printf ("%s\n", str));       \
694a1767b4Smrg     p->error_code = (code);             \
704a1767b4Smrg     goto done;                          \
714a1767b4Smrg   }
724a1767b4Smrg 
734a1767b4Smrg 
744a1767b4Smrg #define REALLOC(ptr, alloc, incr, type)                         \
754a1767b4Smrg   do {                                                          \
764a1767b4Smrg     int  new_alloc = (alloc) + (incr);                          \
774a1767b4Smrg     ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type);   \
784a1767b4Smrg     (alloc) = new_alloc;                                        \
794a1767b4Smrg   } while (0)
804a1767b4Smrg 
814a1767b4Smrg 
824a1767b4Smrg /* data stack top element */
834a1767b4Smrg #define SP   (p->data_stack + p->data_top)
844a1767b4Smrg 
854a1767b4Smrg /* Make sure there's room for another data element above current top.
864a1767b4Smrg    reallocate_func is fetched for when this macro is used in lookahead(). */
874a1767b4Smrg #define DATA_SPACE()                                                    \
884a1767b4Smrg   do {                                                                  \
894a1767b4Smrg     if (p->data_top + 1 >= p->data_alloc)                               \
904a1767b4Smrg       {                                                                 \
914a1767b4Smrg 	void *(*reallocate_func) (void *, size_t, size_t);              \
924a1767b4Smrg 	mp_get_memory_functions (NULL, &reallocate_func, NULL);         \
934a1767b4Smrg 	TRACE (printf ("grow stack from %d\n", p->data_alloc));         \
944a1767b4Smrg 	REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t);        \
954a1767b4Smrg       }                                                                 \
964a1767b4Smrg     ASSERT (p->data_top + 1 <= p->data_inited);                         \
974a1767b4Smrg     if (p->data_top + 1 == p->data_inited)                              \
984a1767b4Smrg       {                                                                 \
994a1767b4Smrg 	TRACE (printf ("initialize %d\n", p->data_top + 1));            \
1004a1767b4Smrg 	(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec);      \
1014a1767b4Smrg 	p->data_inited++;                                               \
1024a1767b4Smrg       }                                                                 \
1034a1767b4Smrg   } while (0)
1044a1767b4Smrg 
1054a1767b4Smrg #define DATA_PUSH()                             \
1064a1767b4Smrg   do {                                          \
1074a1767b4Smrg     p->data_top++;                              \
1084a1767b4Smrg     ASSERT (p->data_top < p->data_alloc);       \
1094a1767b4Smrg     ASSERT (p->data_top < p->data_inited);      \
1104a1767b4Smrg   } while (0)
1114a1767b4Smrg 
1124a1767b4Smrg /* the last stack entry is never popped, so top>=0 will be true */
1134a1767b4Smrg #define DATA_POP(n)             \
1144a1767b4Smrg   do {                          \
1154a1767b4Smrg     p->data_top -= (n);         \
1164a1767b4Smrg     ASSERT (p->data_top >= 0);  \
1174a1767b4Smrg   } while (0)
1184a1767b4Smrg 
1194a1767b4Smrg 
1204a1767b4Smrg /* lookahead() parses the next token.  Return 1 if successful, with some
1214a1767b4Smrg    extra data.  Return 0 if fail, with reason in p->error_code.
1224a1767b4Smrg 
1234a1767b4Smrg    "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
1244a1767b4Smrg    preferred, or 0 if an operator without is preferred. */
1254a1767b4Smrg 
1264a1767b4Smrg #define TOKEN_EOF         -1   /* no extra data */
1274a1767b4Smrg #define TOKEN_VALUE       -2   /* pushed onto data stack */
1284a1767b4Smrg #define TOKEN_OPERATOR    -3   /* stored in p->token_op */
1294a1767b4Smrg #define TOKEN_FUNCTION    -4   /* stored in p->token_op */
1304a1767b4Smrg 
1314a1767b4Smrg #define TOKEN_NAME(n)                           \
1324a1767b4Smrg   ((n) == TOKEN_EOF ? "TOKEN_EOF"               \
1334a1767b4Smrg    : (n) == TOKEN_VALUE ? "TOKEN_VALUE"         \
1344a1767b4Smrg    : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR"   \
1354a1767b4Smrg    : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION"      \
1364a1767b4Smrg    : "UNKNOWN TOKEN")
1374a1767b4Smrg 
1384a1767b4Smrg /* Functions default to being parsed as whole words, operators to match just
1394a1767b4Smrg    at the start of the string.  The type flags override this. */
1404a1767b4Smrg #define WHOLEWORD(op)                           \
1414a1767b4Smrg   (op->precedence == 0                          \
1424a1767b4Smrg    ? (! (op->type & MPEXPR_TYPE_OPERATOR))      \
1434a1767b4Smrg    :   (op->type & MPEXPR_TYPE_WHOLEWORD))
1444a1767b4Smrg 
1454a1767b4Smrg #define isasciispace(c)   (isascii (c) && isspace (c))
1464a1767b4Smrg 
1474a1767b4Smrg static int
lookahead(struct mpexpr_parse_t * p,int prefix)1484a1767b4Smrg lookahead (struct mpexpr_parse_t *p, int prefix)
1494a1767b4Smrg {
150d25e02daSmrg   const struct mpexpr_operator_t  *op, *op_found;
1514a1767b4Smrg   size_t  oplen, oplen_found, wlen;
1524a1767b4Smrg   int     i;
1534a1767b4Smrg 
1544a1767b4Smrg   /* skip white space */
1554a1767b4Smrg   while (p->elen > 0 && isasciispace (*p->e))
1564a1767b4Smrg     p->e++, p->elen--;
1574a1767b4Smrg 
1584a1767b4Smrg   if (p->elen == 0)
1594a1767b4Smrg     {
1604a1767b4Smrg       TRACE (printf ("lookahead EOF\n"));
1614a1767b4Smrg       p->token = TOKEN_EOF;
1624a1767b4Smrg       return 1;
1634a1767b4Smrg     }
1644a1767b4Smrg 
1654a1767b4Smrg   DATA_SPACE ();
1664a1767b4Smrg 
1674a1767b4Smrg   /* Get extent of whole word. */
1684a1767b4Smrg   for (wlen = 0; wlen < p->elen; wlen++)
1694a1767b4Smrg     if (! isasciicsym (p->e[wlen]))
1704a1767b4Smrg       break;
1714a1767b4Smrg 
1724a1767b4Smrg   TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
1734a1767b4Smrg 		 (int) p->elen, p->e, p->elen, wlen));
1744a1767b4Smrg 
1754a1767b4Smrg   op_found = NULL;
1764a1767b4Smrg   oplen_found = 0;
1774a1767b4Smrg   for (op = p->table; op->name != NULL; op++)
1784a1767b4Smrg     {
1794a1767b4Smrg       if (op->type == MPEXPR_TYPE_NEW_TABLE)
1804a1767b4Smrg 	{
1814a1767b4Smrg 	  printf ("new\n");
1824a1767b4Smrg 	  op = (struct mpexpr_operator_t *) op->name - 1;
1834a1767b4Smrg 	  continue;
1844a1767b4Smrg 	}
1854a1767b4Smrg 
1864a1767b4Smrg       oplen = strlen (op->name);
1874a1767b4Smrg       if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
1884a1767b4Smrg 	     && memcmp (p->e, op->name, oplen) == 0))
1894a1767b4Smrg 	continue;
1904a1767b4Smrg 
1914a1767b4Smrg       /* Shorter matches don't replace longer previous ones. */
1924a1767b4Smrg       if (op_found && oplen < oplen_found)
1934a1767b4Smrg 	continue;
1944a1767b4Smrg 
1954a1767b4Smrg       /* On a match of equal length to a previous one, the old match isn't
1964a1767b4Smrg 	 replaced if it has the preferred prefix, and if it doesn't then
1974a1767b4Smrg 	 it's not replaced if the new one also doesn't.  */
1984a1767b4Smrg       if (op_found && oplen == oplen_found
1994a1767b4Smrg 	  && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
2004a1767b4Smrg 	      || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
2014a1767b4Smrg 	continue;
2024a1767b4Smrg 
2034a1767b4Smrg       /* This is now either the first match seen, or a longer than previous
2044a1767b4Smrg 	 match, or an equal to previous one but with a preferred prefix. */
2054a1767b4Smrg       op_found = op;
2064a1767b4Smrg       oplen_found = oplen;
2074a1767b4Smrg     }
2084a1767b4Smrg 
2094a1767b4Smrg   if (op_found)
2104a1767b4Smrg     {
2114a1767b4Smrg       p->e += oplen_found, p->elen -= oplen_found;
2124a1767b4Smrg 
2134a1767b4Smrg       if (op_found->type == MPEXPR_TYPE_VARIABLE)
2144a1767b4Smrg 	{
2154a1767b4Smrg 	  if (p->elen == 0)
2164a1767b4Smrg 	    ERROR ("end of string expecting a variable",
2174a1767b4Smrg 		   MPEXPR_RESULT_PARSE_ERROR);
2184a1767b4Smrg 	  i = p->e[0] - 'a';
2194a1767b4Smrg 	  if (i < 0 || i >= MPEXPR_VARIABLES)
2204a1767b4Smrg 	    ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
2214a1767b4Smrg 	  goto variable;
2224a1767b4Smrg 	}
2234a1767b4Smrg 
2244a1767b4Smrg       if (op_found->precedence == 0)
2254a1767b4Smrg 	{
2264a1767b4Smrg 	  TRACE (printf ("lookahead function: %s\n", op_found->name));
2274a1767b4Smrg 	  p->token = TOKEN_FUNCTION;
2284a1767b4Smrg 	  p->token_op = op_found;
2294a1767b4Smrg 	  return 1;
2304a1767b4Smrg 	}
2314a1767b4Smrg       else
2324a1767b4Smrg 	{
2334a1767b4Smrg 	  TRACE (printf ("lookahead operator: %s\n", op_found->name));
2344a1767b4Smrg 	  p->token = TOKEN_OPERATOR;
2354a1767b4Smrg 	  p->token_op = op_found;
2364a1767b4Smrg 	  return 1;
2374a1767b4Smrg 	}
2384a1767b4Smrg     }
2394a1767b4Smrg 
2404a1767b4Smrg   oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
2414a1767b4Smrg   if (oplen != 0)
2424a1767b4Smrg     {
2434a1767b4Smrg       p->e += oplen, p->elen -= oplen;
2444a1767b4Smrg       p->token = TOKEN_VALUE;
2454a1767b4Smrg       DATA_PUSH ();
2464a1767b4Smrg       TRACE (MPX_TRACE ("lookahead number", SP));
2474a1767b4Smrg       return 1;
2484a1767b4Smrg     }
2494a1767b4Smrg 
2504a1767b4Smrg   /* Maybe an unprefixed one character variable */
2514a1767b4Smrg   i = p->e[0] - 'a';
2524a1767b4Smrg   if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
2534a1767b4Smrg     {
2544a1767b4Smrg     variable:
2554a1767b4Smrg       p->e++, p->elen--;
2564a1767b4Smrg       if (p->var[i] == NULL)
2574a1767b4Smrg 	ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
2584a1767b4Smrg       TRACE (printf ("lookahead variable: var[%d] = ", i);
2594a1767b4Smrg 	     MPX_TRACE ("", p->var[i]));
2604a1767b4Smrg       p->token = TOKEN_VALUE;
2614a1767b4Smrg       DATA_PUSH ();
2624a1767b4Smrg       (*p->mpX_set) (SP, p->var[i]);
2634a1767b4Smrg       return 1;
2644a1767b4Smrg     }
2654a1767b4Smrg 
2664a1767b4Smrg   ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
2674a1767b4Smrg 
2684a1767b4Smrg  done:
2694a1767b4Smrg   return 0;
2704a1767b4Smrg }
2714a1767b4Smrg 
2724a1767b4Smrg 
2734a1767b4Smrg /* control stack current top element */
2744a1767b4Smrg #define CP   (p->control_stack + p->control_top)
2754a1767b4Smrg 
2764a1767b4Smrg /* make sure there's room for another control element above current top */
2774a1767b4Smrg #define CONTROL_SPACE()                                                    \
2784a1767b4Smrg   do {                                                                     \
2794a1767b4Smrg     if (p->control_top + 1 >= p->control_alloc)                            \
2804a1767b4Smrg       {                                                                    \
2814a1767b4Smrg 	TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
2824a1767b4Smrg 	REALLOC (p->control_stack, p->control_alloc, 20,                   \
2834a1767b4Smrg 		 struct mpexpr_control_t);                                 \
2844a1767b4Smrg       }                                                                    \
2854a1767b4Smrg   } while (0)
2864a1767b4Smrg 
2874a1767b4Smrg /* Push an operator on the control stack, claiming currently to have the
2884a1767b4Smrg    given number of args ready.  Local variable "op" is used in case opptr is
2894a1767b4Smrg    a reference through CP.  */
2904a1767b4Smrg #define CONTROL_PUSH(opptr,args)                        \
2914a1767b4Smrg   do {                                                  \
292d25e02daSmrg     const struct mpexpr_operator_t *op = opptr;		\
2934a1767b4Smrg     struct mpexpr_control_t *cp;                        \
2944a1767b4Smrg     CONTROL_SPACE ();                                   \
2954a1767b4Smrg     p->control_top++;                                   \
2964a1767b4Smrg     ASSERT (p->control_top < p->control_alloc);         \
2974a1767b4Smrg     cp = CP;                                            \
2984a1767b4Smrg     cp->op = op;                                        \
2994a1767b4Smrg     cp->argcount = (args);                              \
3004a1767b4Smrg     TRACE_CONTROL("control stack push:");               \
3014a1767b4Smrg   } while (0)
3024a1767b4Smrg 
3034a1767b4Smrg /* The special operator_done is never popped, so top>=0 will hold. */
3044a1767b4Smrg #define CONTROL_POP()                           \
3054a1767b4Smrg   do {                                          \
3064a1767b4Smrg     p->control_top--;                           \
3074a1767b4Smrg     ASSERT (p->control_top >= 0);               \
3084a1767b4Smrg     TRACE_CONTROL ("control stack pop:");       \
3094a1767b4Smrg   } while (0)
3104a1767b4Smrg 
3114a1767b4Smrg #define TRACE_CONTROL(str)                              \
3124a1767b4Smrg   TRACE ({                                              \
3134a1767b4Smrg     int  i;                                             \
3144a1767b4Smrg     printf ("%s depth %d:", str, p->control_top);       \
3154a1767b4Smrg     for (i = 0; i <= p->control_top; i++)               \
3164a1767b4Smrg       printf (" \"%s\"(%d)",                            \
3174a1767b4Smrg 	      p->control_stack[i].op->name,             \
3184a1767b4Smrg 	      p->control_stack[i].argcount);            \
3194a1767b4Smrg     printf ("\n");                                      \
3204a1767b4Smrg   });
3214a1767b4Smrg 
3224a1767b4Smrg 
3234a1767b4Smrg #define LOOKAHEAD(prefix)               \
3244a1767b4Smrg   do {                                  \
3254a1767b4Smrg     if (! lookahead (p, prefix))        \
3264a1767b4Smrg       goto done;                        \
3274a1767b4Smrg   } while (0)
3284a1767b4Smrg 
3294a1767b4Smrg #define CHECK_UI(n)                                                     \
3304a1767b4Smrg   do {                                                                  \
3314a1767b4Smrg     if (! (*p->mpX_ulong_p) (n))                                        \
3324a1767b4Smrg       ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI);        \
3334a1767b4Smrg   } while (0)
3344a1767b4Smrg 
3354a1767b4Smrg #define CHECK_ARGCOUNT(str,n)                                              \
3364a1767b4Smrg   do {                                                                     \
3374a1767b4Smrg     if (CP->argcount != (n))                                               \
3384a1767b4Smrg       {                                                                    \
3394a1767b4Smrg 	TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
3404a1767b4Smrg 		       str, CP->argcount, n));                             \
3414a1767b4Smrg 	ERROR ("", MPEXPR_RESULT_PARSE_ERROR);                             \
3424a1767b4Smrg       }                                                                    \
3434a1767b4Smrg   } while (0)
3444a1767b4Smrg 
3454a1767b4Smrg 
3464a1767b4Smrg /* There's two basic states here.  In both p->token is the next token.
3474a1767b4Smrg 
3484a1767b4Smrg    "another_expr" is when a whole expression should be parsed.  This means a
3494a1767b4Smrg    literal or variable value possibly followed by an operator, or a function
3504a1767b4Smrg    or prefix operator followed by a further whole expression.
3514a1767b4Smrg 
3524a1767b4Smrg    "another_operator" is when an expression has been parsed and its value is
3534a1767b4Smrg    on the top of the data stack (SP) and an optional further postfix or
3544a1767b4Smrg    infix operator should be parsed.
3554a1767b4Smrg 
3564a1767b4Smrg    In "another_operator" precedences determine whether to push the operator
3574a1767b4Smrg    onto the control stack, or instead go to "apply_control" to reduce the
3584a1767b4Smrg    operator currently on top of the control stack.
3594a1767b4Smrg 
3604a1767b4Smrg    When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
3614a1767b4Smrg    for "another_expr" will seek the prefix form, a LOOKAHEAD() for
3624a1767b4Smrg    "another_operator" will seek the postfix/infix form.  The grammar is
3634a1767b4Smrg    simple enough that the next state is known before reading the next token.
3644a1767b4Smrg 
3654a1767b4Smrg    Argument count checking guards against functions consuming the wrong
3664a1767b4Smrg    number of operands from the data stack.  The same checks are applied to
3674a1767b4Smrg    operators, but will always pass since a UNARY or BINARY will only ever
3684a1767b4Smrg    parse with the correct operands.  */
3694a1767b4Smrg 
3704a1767b4Smrg int
mpexpr_evaluate(struct mpexpr_parse_t * p)3714a1767b4Smrg mpexpr_evaluate (struct mpexpr_parse_t *p)
3724a1767b4Smrg {
3734a1767b4Smrg   void *(*allocate_func) (size_t);
3744a1767b4Smrg   void *(*reallocate_func) (void *, size_t, size_t);
3754a1767b4Smrg   void (*free_func) (void *, size_t);
3764a1767b4Smrg 
3774a1767b4Smrg   mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
3784a1767b4Smrg 
3794a1767b4Smrg   TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
3804a1767b4Smrg 		 p->base, (int) p->elen, p->e));
3814a1767b4Smrg 
3824a1767b4Smrg   /* "done" is a special sentinel at the bottom of the control stack,
3834a1767b4Smrg      precedence -1 is lower than any normal operator.  */
3844a1767b4Smrg   {
385d25e02daSmrg     static const struct mpexpr_operator_t  operator_done
3864a1767b4Smrg       = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
3874a1767b4Smrg 
3884a1767b4Smrg     p->control_alloc = 20;
3894a1767b4Smrg     p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
3904a1767b4Smrg 					   struct mpexpr_control_t);
3914a1767b4Smrg     p->control_top = 0;
3924a1767b4Smrg     CP->op = &operator_done;
3934a1767b4Smrg     CP->argcount = 1;
3944a1767b4Smrg   }
3954a1767b4Smrg 
3964a1767b4Smrg   p->data_inited = 0;
3974a1767b4Smrg   p->data_alloc = 20;
3984a1767b4Smrg   p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
3994a1767b4Smrg   p->data_top = -1;
4004a1767b4Smrg 
4014a1767b4Smrg   p->error_code = MPEXPR_RESULT_OK;
4024a1767b4Smrg 
4034a1767b4Smrg 
4044a1767b4Smrg  another_expr_lookahead:
4054a1767b4Smrg   LOOKAHEAD (MPEXPR_TYPE_PREFIX);
4064a1767b4Smrg   TRACE (printf ("another expr\n"));
4074a1767b4Smrg 
4084a1767b4Smrg   /*another_expr:*/
4094a1767b4Smrg   switch (p->token) {
4104a1767b4Smrg   case TOKEN_VALUE:
4114a1767b4Smrg     goto another_operator_lookahead;
4124a1767b4Smrg 
4134a1767b4Smrg   case TOKEN_OPERATOR:
4144a1767b4Smrg     TRACE (printf ("operator %s\n", p->token_op->name));
4154a1767b4Smrg     if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
4164a1767b4Smrg       ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
4174a1767b4Smrg 
4184a1767b4Smrg     CONTROL_PUSH (p->token_op, 1);
4194a1767b4Smrg     goto another_expr_lookahead;
4204a1767b4Smrg 
4214a1767b4Smrg   case TOKEN_FUNCTION:
4224a1767b4Smrg     CONTROL_PUSH (p->token_op, 1);
4234a1767b4Smrg 
4244a1767b4Smrg     if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
4254a1767b4Smrg       goto apply_control_lookahead;
4264a1767b4Smrg 
4274a1767b4Smrg     LOOKAHEAD (MPEXPR_TYPE_PREFIX);
4284a1767b4Smrg     if (! (p->token == TOKEN_OPERATOR
4294a1767b4Smrg 	   && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
4304a1767b4Smrg       ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
4314a1767b4Smrg 
4324a1767b4Smrg     TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
4334a1767b4Smrg 
4344a1767b4Smrg     if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
4354a1767b4Smrg       {
4364a1767b4Smrg 	LOOKAHEAD (0);
4374a1767b4Smrg 	if (! (p->token == TOKEN_OPERATOR
4384a1767b4Smrg 	       && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
4394a1767b4Smrg 	  ERROR ("expected close paren for 0ary function",
4404a1767b4Smrg 		 MPEXPR_RESULT_PARSE_ERROR);
4414a1767b4Smrg 	goto apply_control_lookahead;
4424a1767b4Smrg       }
4434a1767b4Smrg 
4444a1767b4Smrg     goto another_expr_lookahead;
4454a1767b4Smrg   }
4464a1767b4Smrg   ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
4474a1767b4Smrg 
4484a1767b4Smrg 
4494a1767b4Smrg  another_operator_lookahead:
4504a1767b4Smrg   LOOKAHEAD (0);
4514a1767b4Smrg  another_operator:
4524a1767b4Smrg   TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
4534a1767b4Smrg 
4544a1767b4Smrg   switch (p->token) {
4554a1767b4Smrg   case TOKEN_EOF:
4564a1767b4Smrg     goto apply_control;
4574a1767b4Smrg 
4584a1767b4Smrg   case TOKEN_OPERATOR:
4594a1767b4Smrg     /* The next operator is compared to the one on top of the control stack.
4604a1767b4Smrg        If the next is lower precedence, or the same precedence and not
4614a1767b4Smrg        right-associative, then reduce using the control stack and look at
4624a1767b4Smrg        the next operator again later.  */
4634a1767b4Smrg 
4644a1767b4Smrg #define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype)                 \
4654a1767b4Smrg     ((tprec) < (cprec)                                                  \
4664a1767b4Smrg      || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
4674a1767b4Smrg 
4684a1767b4Smrg     if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
4694a1767b4Smrg 				p->token_op->type,       CP->op->type))
4704a1767b4Smrg       {
4714a1767b4Smrg 	TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
4724a1767b4Smrg 		       p->token_op->name,
4734a1767b4Smrg 		       p->token_op->precedence, CP->op->precedence,
4744a1767b4Smrg 		       p->token_op->type));
4754a1767b4Smrg 	goto apply_control;
4764a1767b4Smrg       }
4774a1767b4Smrg 
4784a1767b4Smrg     /* An argsep is a binary operator, but is never pushed on the control
4794a1767b4Smrg        stack, it just accumulates an extra argument for a function. */
4804a1767b4Smrg     if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
4814a1767b4Smrg       {
4824a1767b4Smrg 	if (CP->op->precedence != 0)
4834a1767b4Smrg 	  ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
4844a1767b4Smrg 
4854a1767b4Smrg 	TRACE (printf ("argsep for function \"%s\"(%d)\n",
4864a1767b4Smrg 		       CP->op->name, CP->argcount));
4874a1767b4Smrg 
4884a1767b4Smrg #define IS_PAIRWISE(type)                                               \
4894a1767b4Smrg 	(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE))  \
4904a1767b4Smrg 	 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
4914a1767b4Smrg 
4924a1767b4Smrg 	if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
4934a1767b4Smrg 	  {
4944a1767b4Smrg 	    TRACE (printf ("    will reduce pairwise now\n"));
4954a1767b4Smrg 	    CP->argcount--;
4964a1767b4Smrg 	    CONTROL_PUSH (CP->op, 2);
4974a1767b4Smrg 	    goto apply_control;
4984a1767b4Smrg 	  }
4994a1767b4Smrg 
5004a1767b4Smrg 	CP->argcount++;
5014a1767b4Smrg 	goto another_expr_lookahead;
5024a1767b4Smrg       }
5034a1767b4Smrg 
5044a1767b4Smrg     switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
5054a1767b4Smrg     case MPEXPR_TYPE_NARY(1):
5064a1767b4Smrg       /* Postfix unary operators can always be applied immediately.  The
5074a1767b4Smrg 	 easiest way to do this is just push it on the control stack and go
5084a1767b4Smrg 	 to the normal control stack reduction code. */
5094a1767b4Smrg 
5104a1767b4Smrg       TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
5114a1767b4Smrg       if (p->token_op->type & MPEXPR_TYPE_PREFIX)
5124a1767b4Smrg 	ERROR ("prefix unary operator used postfix",
5134a1767b4Smrg 	       MPEXPR_RESULT_PARSE_ERROR);
5144a1767b4Smrg       CONTROL_PUSH (p->token_op, 1);
5154a1767b4Smrg       goto apply_control_lookahead;
5164a1767b4Smrg 
5174a1767b4Smrg     case MPEXPR_TYPE_NARY(2):
5184a1767b4Smrg       CONTROL_PUSH (p->token_op, 2);
5194a1767b4Smrg       goto another_expr_lookahead;
5204a1767b4Smrg 
5214a1767b4Smrg     case MPEXPR_TYPE_NARY(3):
5224a1767b4Smrg       CONTROL_PUSH (p->token_op, 1);
5234a1767b4Smrg       goto another_expr_lookahead;
5244a1767b4Smrg     }
5254a1767b4Smrg 
5264a1767b4Smrg     TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
5274a1767b4Smrg 		   CP->op->name, CP->op->type));
5284a1767b4Smrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
5294a1767b4Smrg     break;
5304a1767b4Smrg 
5314a1767b4Smrg   default:
5324a1767b4Smrg     TRACE (printf ("expecting an operator, got token %d", p->token));
5334a1767b4Smrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
5344a1767b4Smrg   }
5354a1767b4Smrg 
5364a1767b4Smrg 
5374a1767b4Smrg  apply_control_lookahead:
5384a1767b4Smrg   LOOKAHEAD (0);
5394a1767b4Smrg  apply_control:
5404a1767b4Smrg   /* Apply the top element CP of the control stack.  Data values are SP,
5414a1767b4Smrg      SP-1, etc.  Result is left as stack top SP after popping consumed
5424a1767b4Smrg      values.
5434a1767b4Smrg 
5444a1767b4Smrg      The use of sp as a duplicate of SP will help compilers that can't
5454a1767b4Smrg      otherwise recognise the various uses of SP as common subexpressions.  */
5464a1767b4Smrg 
5474a1767b4Smrg   TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
5484a1767b4Smrg 		 p->control_top, CP->op->name, CP->op->type, CP->argcount));
5494a1767b4Smrg 
5504a1767b4Smrg   TRACE (printf ("apply 0x%X-ary\n",
5514a1767b4Smrg 		 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
5524a1767b4Smrg   switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
5534a1767b4Smrg   case MPEXPR_TYPE_NARY(0):
5544a1767b4Smrg     {
5554a1767b4Smrg       mpX_ptr  sp;
5564a1767b4Smrg       DATA_SPACE ();
5574a1767b4Smrg       DATA_PUSH ();
5584a1767b4Smrg       sp = SP;
5594a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
5604a1767b4Smrg       case 0:
5614a1767b4Smrg 	(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
5624a1767b4Smrg 	break;
5634a1767b4Smrg       case MPEXPR_TYPE_RESULT_INT:
5644a1767b4Smrg 	(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
5654a1767b4Smrg 	break;
5664a1767b4Smrg       default:
5674a1767b4Smrg 	ERROR ("unrecognised 0ary argument calling style",
5684a1767b4Smrg 	       MPEXPR_RESULT_BAD_TABLE);
5694a1767b4Smrg       }
5704a1767b4Smrg     }
5714a1767b4Smrg     break;
5724a1767b4Smrg 
5734a1767b4Smrg   case MPEXPR_TYPE_NARY(1):
5744a1767b4Smrg     {
5754a1767b4Smrg       mpX_ptr  sp = SP;
5764a1767b4Smrg       CHECK_ARGCOUNT ("unary", 1);
5774a1767b4Smrg       TRACE (MPX_TRACE ("before", sp));
5784a1767b4Smrg 
5794a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
5804a1767b4Smrg       case 0:
5814a1767b4Smrg 	/* not a special */
5824a1767b4Smrg 	break;
5834a1767b4Smrg 
5844a1767b4Smrg       case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
5854a1767b4Smrg 	TRACE (printf ("special done\n"));
5864a1767b4Smrg 	goto done;
5874a1767b4Smrg 
5884a1767b4Smrg       case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
5894a1767b4Smrg 	TRACE (printf ("special logical not\n"));
5904a1767b4Smrg 	(*p->mpX_set_si)
5914a1767b4Smrg 	  (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
5924a1767b4Smrg 	goto apply_control_done;
5934a1767b4Smrg 
5944a1767b4Smrg       case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
5954a1767b4Smrg 	CONTROL_POP ();
5964a1767b4Smrg 	if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
5974a1767b4Smrg 	  {
5984a1767b4Smrg 	    TRACE (printf ("close paren matching open paren\n"));
5994a1767b4Smrg 	    CONTROL_POP ();
6004a1767b4Smrg 	    goto another_operator;
6014a1767b4Smrg 	  }
6024a1767b4Smrg 	if (CP->op->precedence == 0)
6034a1767b4Smrg 	  {
6044a1767b4Smrg 	    TRACE (printf ("close paren for function\n"));
6054a1767b4Smrg 	    goto apply_control;
6064a1767b4Smrg 	  }
6074a1767b4Smrg 	ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
6084a1767b4Smrg 
6094a1767b4Smrg       default:
6104a1767b4Smrg 	TRACE (printf ("unrecognised special unary operator 0x%X",
6114a1767b4Smrg 		       CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
6124a1767b4Smrg 	ERROR ("", MPEXPR_RESULT_BAD_TABLE);
6134a1767b4Smrg       }
6144a1767b4Smrg 
6154a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
6164a1767b4Smrg       case 0:
6174a1767b4Smrg 	(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
6184a1767b4Smrg 	break;
6194a1767b4Smrg       case MPEXPR_TYPE_LAST_UI:
6204a1767b4Smrg 	CHECK_UI (sp);
6214a1767b4Smrg 	(* (mpexpr_fun_unary_ui_t) CP->op->fun)
6224a1767b4Smrg 	  (sp, (*p->mpX_get_ui) (sp));
6234a1767b4Smrg 	break;
6244a1767b4Smrg       case MPEXPR_TYPE_RESULT_INT:
6254a1767b4Smrg 	(*p->mpX_set_si)
6264a1767b4Smrg 	  (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
6274a1767b4Smrg 	break;
6284a1767b4Smrg       case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
6294a1767b4Smrg 	CHECK_UI (sp);
6304a1767b4Smrg 	(*p->mpX_set_si)
6314a1767b4Smrg 	  (sp,
6324a1767b4Smrg 	   (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
6334a1767b4Smrg 	   ((*p->mpX_get_ui) (sp)));
6344a1767b4Smrg 	break;
6354a1767b4Smrg       default:
6364a1767b4Smrg 	ERROR ("unrecognised unary argument calling style",
6374a1767b4Smrg 	       MPEXPR_RESULT_BAD_TABLE);
6384a1767b4Smrg       }
6394a1767b4Smrg     }
6404a1767b4Smrg     break;
6414a1767b4Smrg 
6424a1767b4Smrg   case MPEXPR_TYPE_NARY(2):
6434a1767b4Smrg     {
6444a1767b4Smrg       mpX_ptr  sp;
6454a1767b4Smrg 
6464a1767b4Smrg       /* pairwise functions are allowed to have just one argument */
6474a1767b4Smrg       if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
6484a1767b4Smrg 	  && CP->op->precedence == 0
6494a1767b4Smrg 	  && CP->argcount == 1)
6504a1767b4Smrg 	goto apply_control_done;
6514a1767b4Smrg 
6524a1767b4Smrg       CHECK_ARGCOUNT ("binary", 2);
6534a1767b4Smrg       DATA_POP (1);
6544a1767b4Smrg       sp = SP;
6554a1767b4Smrg       TRACE (MPX_TRACE ("lhs", sp);
6564a1767b4Smrg 	     MPX_TRACE ("rhs", sp+1));
6574a1767b4Smrg 
6584a1767b4Smrg       if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
6594a1767b4Smrg 	{
6604a1767b4Smrg 	  int  type = CP->op->type;
6614a1767b4Smrg 	  int  cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
6624a1767b4Smrg 	    (sp, sp+1);
6634a1767b4Smrg 	  (*p->mpX_set_si)
6644a1767b4Smrg 	    (sp,
6654a1767b4Smrg 	     (long)
6664a1767b4Smrg 	     ((  (cmp  < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
6674a1767b4Smrg 	      | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
6684a1767b4Smrg 	      | ((cmp  > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
6694a1767b4Smrg 	  goto apply_control_done;
6704a1767b4Smrg 	}
6714a1767b4Smrg 
6724a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
6734a1767b4Smrg       case 0:
6744a1767b4Smrg 	/* not a special */
6754a1767b4Smrg 	break;
6764a1767b4Smrg 
6774a1767b4Smrg       case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
6784a1767b4Smrg 	ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
6794a1767b4Smrg 
6804a1767b4Smrg       case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
6814a1767b4Smrg 	TRACE (printf ("special colon\n"));
6824a1767b4Smrg 	CONTROL_POP ();
6834a1767b4Smrg 	if (CP->op->type != MPEXPR_TYPE_QUESTION)
6844a1767b4Smrg 	  ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
6854a1767b4Smrg 
6864a1767b4Smrg 	CP->argcount--;
6874a1767b4Smrg 	DATA_POP (1);
6884a1767b4Smrg 	sp--;
6894a1767b4Smrg 	TRACE (MPX_TRACE ("query", sp);
6904a1767b4Smrg 	       MPX_TRACE ("true",  sp+1);
6914a1767b4Smrg 	       MPX_TRACE ("false", sp+2));
6924a1767b4Smrg 	(*p->mpX_set)
6934a1767b4Smrg 	  (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
6944a1767b4Smrg 	   ? sp+1 : sp+2);
6954a1767b4Smrg 	goto apply_control_done;
6964a1767b4Smrg 
6974a1767b4Smrg       case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
6984a1767b4Smrg 	TRACE (printf ("special logical and\n"));
6994a1767b4Smrg 	(*p->mpX_set_si)
7004a1767b4Smrg 	  (sp,
7014a1767b4Smrg 	   (long)
7024a1767b4Smrg 	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
7034a1767b4Smrg 	    && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
7044a1767b4Smrg 	goto apply_control_done;
7054a1767b4Smrg 
7064a1767b4Smrg       case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
7074a1767b4Smrg 	TRACE (printf ("special logical and\n"));
7084a1767b4Smrg 	(*p->mpX_set_si)
7094a1767b4Smrg 	  (sp,
7104a1767b4Smrg 	   (long)
7114a1767b4Smrg 	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
7124a1767b4Smrg 	    || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
7134a1767b4Smrg 	goto apply_control_done;
7144a1767b4Smrg 
7154a1767b4Smrg       case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
7164a1767b4Smrg 	TRACE (printf ("special max\n"));
7174a1767b4Smrg 	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
7184a1767b4Smrg 	  (*p->mpX_swap) (sp, sp+1);
7194a1767b4Smrg 	goto apply_control_done;
7204a1767b4Smrg       case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
7214a1767b4Smrg 	TRACE (printf ("special min\n"));
7224a1767b4Smrg 	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
7234a1767b4Smrg 	  (*p->mpX_swap) (sp, sp+1);
7244a1767b4Smrg 	goto apply_control_done;
7254a1767b4Smrg 
7264a1767b4Smrg       default:
7274a1767b4Smrg 	ERROR ("unrecognised special binary operator",
7284a1767b4Smrg 	       MPEXPR_RESULT_BAD_TABLE);
7294a1767b4Smrg       }
7304a1767b4Smrg 
7314a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
7324a1767b4Smrg       case 0:
7334a1767b4Smrg 	(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
7344a1767b4Smrg 	break;
7354a1767b4Smrg       case MPEXPR_TYPE_LAST_UI:
7364a1767b4Smrg 	CHECK_UI (sp+1);
7374a1767b4Smrg 	(* (mpexpr_fun_binary_ui_t) CP->op->fun)
7384a1767b4Smrg 	  (sp, sp, (*p->mpX_get_ui) (sp+1));
7394a1767b4Smrg 	break;
7404a1767b4Smrg       case MPEXPR_TYPE_RESULT_INT:
7414a1767b4Smrg 	(*p->mpX_set_si)
7424a1767b4Smrg 	  (sp,
7434a1767b4Smrg 	   (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
7444a1767b4Smrg 	break;
7454a1767b4Smrg       case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
7464a1767b4Smrg 	CHECK_UI (sp+1);
7474a1767b4Smrg 	(*p->mpX_set_si)
7484a1767b4Smrg 	  (sp,
7494a1767b4Smrg 	   (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
7504a1767b4Smrg 	   (sp, (*p->mpX_get_ui) (sp+1)));
7514a1767b4Smrg 	break;
7524a1767b4Smrg       default:
7534a1767b4Smrg 	ERROR ("unrecognised binary argument calling style",
7544a1767b4Smrg 	       MPEXPR_RESULT_BAD_TABLE);
7554a1767b4Smrg       }
7564a1767b4Smrg     }
7574a1767b4Smrg     break;
7584a1767b4Smrg 
7594a1767b4Smrg   case MPEXPR_TYPE_NARY(3):
7604a1767b4Smrg     {
7614a1767b4Smrg       mpX_ptr  sp;
7624a1767b4Smrg 
7634a1767b4Smrg       CHECK_ARGCOUNT ("ternary", 3);
7644a1767b4Smrg       DATA_POP (2);
7654a1767b4Smrg       sp = SP;
7664a1767b4Smrg       TRACE (MPX_TRACE ("arg1", sp);
7674a1767b4Smrg 	     MPX_TRACE ("arg2", sp+1);
7684a1767b4Smrg 	     MPX_TRACE ("arg3", sp+1));
7694a1767b4Smrg 
7704a1767b4Smrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
7714a1767b4Smrg       case 0:
7724a1767b4Smrg 	(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
7734a1767b4Smrg 	break;
7744a1767b4Smrg       case MPEXPR_TYPE_LAST_UI:
7754a1767b4Smrg 	CHECK_UI (sp+2);
7764a1767b4Smrg 	(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
7774a1767b4Smrg 	  (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
7784a1767b4Smrg 	break;
7794a1767b4Smrg       case MPEXPR_TYPE_RESULT_INT:
7804a1767b4Smrg 	(*p->mpX_set_si)
7814a1767b4Smrg 	  (sp,
7824a1767b4Smrg 	   (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
7834a1767b4Smrg 	   (sp, sp+1, sp+2));
7844a1767b4Smrg 	break;
7854a1767b4Smrg       case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
7864a1767b4Smrg 	CHECK_UI (sp+2);
7874a1767b4Smrg 	(*p->mpX_set_si)
7884a1767b4Smrg 	  (sp,
7894a1767b4Smrg 	   (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
7904a1767b4Smrg 	   (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
7914a1767b4Smrg 	break;
7924a1767b4Smrg       default:
7934a1767b4Smrg 	ERROR ("unrecognised binary argument calling style",
7944a1767b4Smrg 	       MPEXPR_RESULT_BAD_TABLE);
7954a1767b4Smrg       }
7964a1767b4Smrg     }
7974a1767b4Smrg     break;
7984a1767b4Smrg 
7994a1767b4Smrg   default:
8004a1767b4Smrg     TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
8014a1767b4Smrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
8024a1767b4Smrg   }
8034a1767b4Smrg 
8044a1767b4Smrg  apply_control_done:
8054a1767b4Smrg   TRACE (MPX_TRACE ("result", SP));
8064a1767b4Smrg   CONTROL_POP ();
8074a1767b4Smrg   goto another_operator;
8084a1767b4Smrg 
8094a1767b4Smrg  done:
8104a1767b4Smrg   if (p->error_code == MPEXPR_RESULT_OK)
8114a1767b4Smrg     {
8124a1767b4Smrg       if (p->data_top != 0)
8134a1767b4Smrg 	{
8144a1767b4Smrg 	  TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
8154a1767b4Smrg 	  p->error_code = MPEXPR_RESULT_PARSE_ERROR;
8164a1767b4Smrg 	}
8174a1767b4Smrg       else
8184a1767b4Smrg 	(*p->mpX_set_or_swap) (p->res, SP);
8194a1767b4Smrg     }
8204a1767b4Smrg 
8214a1767b4Smrg   {
8224a1767b4Smrg     int  i;
8234a1767b4Smrg     for (i = 0; i < p->data_inited; i++)
8244a1767b4Smrg       {
8254a1767b4Smrg 	TRACE (printf ("clear %d\n", i));
8264a1767b4Smrg 	(*p->mpX_clear) (p->data_stack+i);
8274a1767b4Smrg       }
8284a1767b4Smrg   }
8294a1767b4Smrg 
8304a1767b4Smrg   FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
8314a1767b4Smrg   FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
8324a1767b4Smrg 
8334a1767b4Smrg   return p->error_code;
8344a1767b4Smrg }
835