Home | History | Annotate | Line # | Download | only in expr
      1      1.1  mrg /* mpexpr_evaluate -- shared code for simple expression evaluation
      2      1.1  mrg 
      3  1.1.1.3  mrg Copyright 2000-2002, 2004 Free Software Foundation, Inc.
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU MP Library.
      6      1.1  mrg 
      7      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
      8  1.1.1.3  mrg it under the terms of either:
      9  1.1.1.3  mrg 
     10  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     11  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     12  1.1.1.3  mrg     option) any later version.
     13  1.1.1.3  mrg 
     14  1.1.1.3  mrg or
     15  1.1.1.3  mrg 
     16  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     17  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     18  1.1.1.3  mrg     later version.
     19  1.1.1.3  mrg 
     20  1.1.1.3  mrg or both in parallel, as here.
     21      1.1  mrg 
     22      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     23      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     24  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     25  1.1.1.3  mrg for more details.
     26      1.1  mrg 
     27  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     28  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     29  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     30      1.1  mrg 
     31      1.1  mrg #include <ctype.h>
     32      1.1  mrg #include <stdio.h>
     33      1.1  mrg #include <string.h>
     34      1.1  mrg 
     35      1.1  mrg #include "gmp.h"
     36      1.1  mrg #include "expr-impl.h"
     37      1.1  mrg 
     38      1.1  mrg 
     39      1.1  mrg /* Change this to "#define TRACE(x) x" to get some traces.  The trace
     40      1.1  mrg    printfs junk up the code a bit, but it's very hard to tell what's going
     41      1.1  mrg    on without them.  Set MPX_TRACE to a suitable output function for the
     42      1.1  mrg    mpz/mpq/mpf being run (if you have the wrong trace function it'll
     43      1.1  mrg    probably segv).  */
     44      1.1  mrg 
     45      1.1  mrg #define TRACE(x)
     46      1.1  mrg #define MPX_TRACE  mpz_trace
     47      1.1  mrg 
     48      1.1  mrg 
     49      1.1  mrg /* A few helper macros copied from gmp-impl.h */
     50      1.1  mrg #define ALLOCATE_FUNC_TYPE(n,type) \
     51      1.1  mrg   ((type *) (*allocate_func) ((n) * sizeof (type)))
     52      1.1  mrg #define ALLOCATE_FUNC_LIMBS(n)   ALLOCATE_FUNC_TYPE (n, mp_limb_t)
     53      1.1  mrg #define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
     54      1.1  mrg   ((type *) (*reallocate_func)                            \
     55      1.1  mrg    (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
     56      1.1  mrg #define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
     57      1.1  mrg   REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
     58      1.1  mrg #define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
     59      1.1  mrg #define FREE_FUNC_LIMBS(p,n)     FREE_FUNC_TYPE (p, n, mp_limb_t)
     60      1.1  mrg #define ASSERT(x)
     61      1.1  mrg 
     62      1.1  mrg 
     63      1.1  mrg 
     64      1.1  mrg /* All the error strings are just for diagnostic traces.  Only the error
     65      1.1  mrg    code is actually returned.  */
     66      1.1  mrg #define ERROR(str,code)                 \
     67      1.1  mrg   {                                     \
     68      1.1  mrg     TRACE (printf ("%s\n", str));       \
     69      1.1  mrg     p->error_code = (code);             \
     70      1.1  mrg     goto done;                          \
     71      1.1  mrg   }
     72      1.1  mrg 
     73      1.1  mrg 
     74      1.1  mrg #define REALLOC(ptr, alloc, incr, type)                         \
     75      1.1  mrg   do {                                                          \
     76      1.1  mrg     int  new_alloc = (alloc) + (incr);                          \
     77      1.1  mrg     ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type);   \
     78      1.1  mrg     (alloc) = new_alloc;                                        \
     79      1.1  mrg   } while (0)
     80      1.1  mrg 
     81      1.1  mrg 
     82      1.1  mrg /* data stack top element */
     83      1.1  mrg #define SP   (p->data_stack + p->data_top)
     84      1.1  mrg 
     85      1.1  mrg /* Make sure there's room for another data element above current top.
     86      1.1  mrg    reallocate_func is fetched for when this macro is used in lookahead(). */
     87      1.1  mrg #define DATA_SPACE()                                                    \
     88      1.1  mrg   do {                                                                  \
     89      1.1  mrg     if (p->data_top + 1 >= p->data_alloc)                               \
     90      1.1  mrg       {                                                                 \
     91      1.1  mrg 	void *(*reallocate_func) (void *, size_t, size_t);              \
     92      1.1  mrg 	mp_get_memory_functions (NULL, &reallocate_func, NULL);         \
     93      1.1  mrg 	TRACE (printf ("grow stack from %d\n", p->data_alloc));         \
     94      1.1  mrg 	REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t);        \
     95      1.1  mrg       }                                                                 \
     96      1.1  mrg     ASSERT (p->data_top + 1 <= p->data_inited);                         \
     97      1.1  mrg     if (p->data_top + 1 == p->data_inited)                              \
     98      1.1  mrg       {                                                                 \
     99      1.1  mrg 	TRACE (printf ("initialize %d\n", p->data_top + 1));            \
    100      1.1  mrg 	(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec);      \
    101      1.1  mrg 	p->data_inited++;                                               \
    102      1.1  mrg       }                                                                 \
    103      1.1  mrg   } while (0)
    104      1.1  mrg 
    105      1.1  mrg #define DATA_PUSH()                             \
    106      1.1  mrg   do {                                          \
    107      1.1  mrg     p->data_top++;                              \
    108      1.1  mrg     ASSERT (p->data_top < p->data_alloc);       \
    109      1.1  mrg     ASSERT (p->data_top < p->data_inited);      \
    110      1.1  mrg   } while (0)
    111      1.1  mrg 
    112      1.1  mrg /* the last stack entry is never popped, so top>=0 will be true */
    113      1.1  mrg #define DATA_POP(n)             \
    114      1.1  mrg   do {                          \
    115      1.1  mrg     p->data_top -= (n);         \
    116      1.1  mrg     ASSERT (p->data_top >= 0);  \
    117      1.1  mrg   } while (0)
    118      1.1  mrg 
    119      1.1  mrg 
    120      1.1  mrg /* lookahead() parses the next token.  Return 1 if successful, with some
    121      1.1  mrg    extra data.  Return 0 if fail, with reason in p->error_code.
    122      1.1  mrg 
    123      1.1  mrg    "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
    124      1.1  mrg    preferred, or 0 if an operator without is preferred. */
    125      1.1  mrg 
    126      1.1  mrg #define TOKEN_EOF         -1   /* no extra data */
    127      1.1  mrg #define TOKEN_VALUE       -2   /* pushed onto data stack */
    128      1.1  mrg #define TOKEN_OPERATOR    -3   /* stored in p->token_op */
    129      1.1  mrg #define TOKEN_FUNCTION    -4   /* stored in p->token_op */
    130      1.1  mrg 
    131      1.1  mrg #define TOKEN_NAME(n)                           \
    132      1.1  mrg   ((n) == TOKEN_EOF ? "TOKEN_EOF"               \
    133      1.1  mrg    : (n) == TOKEN_VALUE ? "TOKEN_VALUE"         \
    134      1.1  mrg    : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR"   \
    135      1.1  mrg    : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION"      \
    136      1.1  mrg    : "UNKNOWN TOKEN")
    137      1.1  mrg 
    138      1.1  mrg /* Functions default to being parsed as whole words, operators to match just
    139      1.1  mrg    at the start of the string.  The type flags override this. */
    140      1.1  mrg #define WHOLEWORD(op)                           \
    141      1.1  mrg   (op->precedence == 0                          \
    142      1.1  mrg    ? (! (op->type & MPEXPR_TYPE_OPERATOR))      \
    143      1.1  mrg    :   (op->type & MPEXPR_TYPE_WHOLEWORD))
    144      1.1  mrg 
    145      1.1  mrg #define isasciispace(c)   (isascii (c) && isspace (c))
    146      1.1  mrg 
    147      1.1  mrg static int
    148      1.1  mrg lookahead (struct mpexpr_parse_t *p, int prefix)
    149      1.1  mrg {
    150  1.1.1.2  mrg   const struct mpexpr_operator_t  *op, *op_found;
    151      1.1  mrg   size_t  oplen, oplen_found, wlen;
    152      1.1  mrg   int     i;
    153      1.1  mrg 
    154      1.1  mrg   /* skip white space */
    155      1.1  mrg   while (p->elen > 0 && isasciispace (*p->e))
    156      1.1  mrg     p->e++, p->elen--;
    157      1.1  mrg 
    158      1.1  mrg   if (p->elen == 0)
    159      1.1  mrg     {
    160      1.1  mrg       TRACE (printf ("lookahead EOF\n"));
    161      1.1  mrg       p->token = TOKEN_EOF;
    162      1.1  mrg       return 1;
    163      1.1  mrg     }
    164      1.1  mrg 
    165      1.1  mrg   DATA_SPACE ();
    166      1.1  mrg 
    167      1.1  mrg   /* Get extent of whole word. */
    168      1.1  mrg   for (wlen = 0; wlen < p->elen; wlen++)
    169      1.1  mrg     if (! isasciicsym (p->e[wlen]))
    170      1.1  mrg       break;
    171      1.1  mrg 
    172      1.1  mrg   TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
    173      1.1  mrg 		 (int) p->elen, p->e, p->elen, wlen));
    174      1.1  mrg 
    175      1.1  mrg   op_found = NULL;
    176      1.1  mrg   oplen_found = 0;
    177      1.1  mrg   for (op = p->table; op->name != NULL; op++)
    178      1.1  mrg     {
    179      1.1  mrg       if (op->type == MPEXPR_TYPE_NEW_TABLE)
    180      1.1  mrg 	{
    181      1.1  mrg 	  printf ("new\n");
    182      1.1  mrg 	  op = (struct mpexpr_operator_t *) op->name - 1;
    183      1.1  mrg 	  continue;
    184      1.1  mrg 	}
    185      1.1  mrg 
    186      1.1  mrg       oplen = strlen (op->name);
    187      1.1  mrg       if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
    188      1.1  mrg 	     && memcmp (p->e, op->name, oplen) == 0))
    189      1.1  mrg 	continue;
    190      1.1  mrg 
    191      1.1  mrg       /* Shorter matches don't replace longer previous ones. */
    192      1.1  mrg       if (op_found && oplen < oplen_found)
    193      1.1  mrg 	continue;
    194      1.1  mrg 
    195      1.1  mrg       /* On a match of equal length to a previous one, the old match isn't
    196      1.1  mrg 	 replaced if it has the preferred prefix, and if it doesn't then
    197      1.1  mrg 	 it's not replaced if the new one also doesn't.  */
    198      1.1  mrg       if (op_found && oplen == oplen_found
    199      1.1  mrg 	  && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
    200      1.1  mrg 	      || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
    201      1.1  mrg 	continue;
    202      1.1  mrg 
    203      1.1  mrg       /* This is now either the first match seen, or a longer than previous
    204      1.1  mrg 	 match, or an equal to previous one but with a preferred prefix. */
    205      1.1  mrg       op_found = op;
    206      1.1  mrg       oplen_found = oplen;
    207      1.1  mrg     }
    208      1.1  mrg 
    209      1.1  mrg   if (op_found)
    210      1.1  mrg     {
    211      1.1  mrg       p->e += oplen_found, p->elen -= oplen_found;
    212      1.1  mrg 
    213      1.1  mrg       if (op_found->type == MPEXPR_TYPE_VARIABLE)
    214      1.1  mrg 	{
    215      1.1  mrg 	  if (p->elen == 0)
    216      1.1  mrg 	    ERROR ("end of string expecting a variable",
    217      1.1  mrg 		   MPEXPR_RESULT_PARSE_ERROR);
    218      1.1  mrg 	  i = p->e[0] - 'a';
    219      1.1  mrg 	  if (i < 0 || i >= MPEXPR_VARIABLES)
    220      1.1  mrg 	    ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
    221      1.1  mrg 	  goto variable;
    222      1.1  mrg 	}
    223      1.1  mrg 
    224      1.1  mrg       if (op_found->precedence == 0)
    225      1.1  mrg 	{
    226      1.1  mrg 	  TRACE (printf ("lookahead function: %s\n", op_found->name));
    227      1.1  mrg 	  p->token = TOKEN_FUNCTION;
    228      1.1  mrg 	  p->token_op = op_found;
    229      1.1  mrg 	  return 1;
    230      1.1  mrg 	}
    231      1.1  mrg       else
    232      1.1  mrg 	{
    233      1.1  mrg 	  TRACE (printf ("lookahead operator: %s\n", op_found->name));
    234      1.1  mrg 	  p->token = TOKEN_OPERATOR;
    235      1.1  mrg 	  p->token_op = op_found;
    236      1.1  mrg 	  return 1;
    237      1.1  mrg 	}
    238      1.1  mrg     }
    239      1.1  mrg 
    240      1.1  mrg   oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
    241      1.1  mrg   if (oplen != 0)
    242      1.1  mrg     {
    243      1.1  mrg       p->e += oplen, p->elen -= oplen;
    244      1.1  mrg       p->token = TOKEN_VALUE;
    245      1.1  mrg       DATA_PUSH ();
    246      1.1  mrg       TRACE (MPX_TRACE ("lookahead number", SP));
    247      1.1  mrg       return 1;
    248      1.1  mrg     }
    249      1.1  mrg 
    250      1.1  mrg   /* Maybe an unprefixed one character variable */
    251      1.1  mrg   i = p->e[0] - 'a';
    252      1.1  mrg   if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
    253      1.1  mrg     {
    254      1.1  mrg     variable:
    255      1.1  mrg       p->e++, p->elen--;
    256      1.1  mrg       if (p->var[i] == NULL)
    257      1.1  mrg 	ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
    258      1.1  mrg       TRACE (printf ("lookahead variable: var[%d] = ", i);
    259      1.1  mrg 	     MPX_TRACE ("", p->var[i]));
    260      1.1  mrg       p->token = TOKEN_VALUE;
    261      1.1  mrg       DATA_PUSH ();
    262      1.1  mrg       (*p->mpX_set) (SP, p->var[i]);
    263      1.1  mrg       return 1;
    264      1.1  mrg     }
    265      1.1  mrg 
    266      1.1  mrg   ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
    267      1.1  mrg 
    268      1.1  mrg  done:
    269      1.1  mrg   return 0;
    270      1.1  mrg }
    271      1.1  mrg 
    272      1.1  mrg 
    273      1.1  mrg /* control stack current top element */
    274      1.1  mrg #define CP   (p->control_stack + p->control_top)
    275      1.1  mrg 
    276      1.1  mrg /* make sure there's room for another control element above current top */
    277      1.1  mrg #define CONTROL_SPACE()                                                    \
    278      1.1  mrg   do {                                                                     \
    279      1.1  mrg     if (p->control_top + 1 >= p->control_alloc)                            \
    280      1.1  mrg       {                                                                    \
    281      1.1  mrg 	TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
    282      1.1  mrg 	REALLOC (p->control_stack, p->control_alloc, 20,                   \
    283      1.1  mrg 		 struct mpexpr_control_t);                                 \
    284      1.1  mrg       }                                                                    \
    285      1.1  mrg   } while (0)
    286      1.1  mrg 
    287      1.1  mrg /* Push an operator on the control stack, claiming currently to have the
    288      1.1  mrg    given number of args ready.  Local variable "op" is used in case opptr is
    289      1.1  mrg    a reference through CP.  */
    290      1.1  mrg #define CONTROL_PUSH(opptr,args)                        \
    291      1.1  mrg   do {                                                  \
    292  1.1.1.2  mrg     const struct mpexpr_operator_t *op = opptr;		\
    293      1.1  mrg     struct mpexpr_control_t *cp;                        \
    294      1.1  mrg     CONTROL_SPACE ();                                   \
    295      1.1  mrg     p->control_top++;                                   \
    296      1.1  mrg     ASSERT (p->control_top < p->control_alloc);         \
    297      1.1  mrg     cp = CP;                                            \
    298      1.1  mrg     cp->op = op;                                        \
    299      1.1  mrg     cp->argcount = (args);                              \
    300      1.1  mrg     TRACE_CONTROL("control stack push:");               \
    301      1.1  mrg   } while (0)
    302      1.1  mrg 
    303      1.1  mrg /* The special operator_done is never popped, so top>=0 will hold. */
    304      1.1  mrg #define CONTROL_POP()                           \
    305      1.1  mrg   do {                                          \
    306      1.1  mrg     p->control_top--;                           \
    307      1.1  mrg     ASSERT (p->control_top >= 0);               \
    308      1.1  mrg     TRACE_CONTROL ("control stack pop:");       \
    309      1.1  mrg   } while (0)
    310      1.1  mrg 
    311      1.1  mrg #define TRACE_CONTROL(str)                              \
    312      1.1  mrg   TRACE ({                                              \
    313      1.1  mrg     int  i;                                             \
    314      1.1  mrg     printf ("%s depth %d:", str, p->control_top);       \
    315      1.1  mrg     for (i = 0; i <= p->control_top; i++)               \
    316      1.1  mrg       printf (" \"%s\"(%d)",                            \
    317      1.1  mrg 	      p->control_stack[i].op->name,             \
    318      1.1  mrg 	      p->control_stack[i].argcount);            \
    319      1.1  mrg     printf ("\n");                                      \
    320      1.1  mrg   });
    321      1.1  mrg 
    322      1.1  mrg 
    323      1.1  mrg #define LOOKAHEAD(prefix)               \
    324      1.1  mrg   do {                                  \
    325      1.1  mrg     if (! lookahead (p, prefix))        \
    326      1.1  mrg       goto done;                        \
    327      1.1  mrg   } while (0)
    328      1.1  mrg 
    329      1.1  mrg #define CHECK_UI(n)                                                     \
    330      1.1  mrg   do {                                                                  \
    331      1.1  mrg     if (! (*p->mpX_ulong_p) (n))                                        \
    332      1.1  mrg       ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI);        \
    333      1.1  mrg   } while (0)
    334      1.1  mrg 
    335      1.1  mrg #define CHECK_ARGCOUNT(str,n)                                              \
    336      1.1  mrg   do {                                                                     \
    337      1.1  mrg     if (CP->argcount != (n))                                               \
    338      1.1  mrg       {                                                                    \
    339      1.1  mrg 	TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
    340      1.1  mrg 		       str, CP->argcount, n));                             \
    341      1.1  mrg 	ERROR ("", MPEXPR_RESULT_PARSE_ERROR);                             \
    342      1.1  mrg       }                                                                    \
    343      1.1  mrg   } while (0)
    344      1.1  mrg 
    345      1.1  mrg 
    346      1.1  mrg /* There's two basic states here.  In both p->token is the next token.
    347      1.1  mrg 
    348      1.1  mrg    "another_expr" is when a whole expression should be parsed.  This means a
    349      1.1  mrg    literal or variable value possibly followed by an operator, or a function
    350      1.1  mrg    or prefix operator followed by a further whole expression.
    351      1.1  mrg 
    352      1.1  mrg    "another_operator" is when an expression has been parsed and its value is
    353      1.1  mrg    on the top of the data stack (SP) and an optional further postfix or
    354      1.1  mrg    infix operator should be parsed.
    355      1.1  mrg 
    356      1.1  mrg    In "another_operator" precedences determine whether to push the operator
    357      1.1  mrg    onto the control stack, or instead go to "apply_control" to reduce the
    358      1.1  mrg    operator currently on top of the control stack.
    359      1.1  mrg 
    360      1.1  mrg    When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
    361      1.1  mrg    for "another_expr" will seek the prefix form, a LOOKAHEAD() for
    362      1.1  mrg    "another_operator" will seek the postfix/infix form.  The grammar is
    363      1.1  mrg    simple enough that the next state is known before reading the next token.
    364      1.1  mrg 
    365      1.1  mrg    Argument count checking guards against functions consuming the wrong
    366      1.1  mrg    number of operands from the data stack.  The same checks are applied to
    367      1.1  mrg    operators, but will always pass since a UNARY or BINARY will only ever
    368      1.1  mrg    parse with the correct operands.  */
    369      1.1  mrg 
    370      1.1  mrg int
    371      1.1  mrg mpexpr_evaluate (struct mpexpr_parse_t *p)
    372      1.1  mrg {
    373      1.1  mrg   void *(*allocate_func) (size_t);
    374      1.1  mrg   void *(*reallocate_func) (void *, size_t, size_t);
    375      1.1  mrg   void (*free_func) (void *, size_t);
    376      1.1  mrg 
    377      1.1  mrg   mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
    378      1.1  mrg 
    379      1.1  mrg   TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
    380      1.1  mrg 		 p->base, (int) p->elen, p->e));
    381      1.1  mrg 
    382      1.1  mrg   /* "done" is a special sentinel at the bottom of the control stack,
    383      1.1  mrg      precedence -1 is lower than any normal operator.  */
    384      1.1  mrg   {
    385  1.1.1.2  mrg     static const struct mpexpr_operator_t  operator_done
    386      1.1  mrg       = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
    387      1.1  mrg 
    388      1.1  mrg     p->control_alloc = 20;
    389      1.1  mrg     p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
    390      1.1  mrg 					   struct mpexpr_control_t);
    391      1.1  mrg     p->control_top = 0;
    392      1.1  mrg     CP->op = &operator_done;
    393      1.1  mrg     CP->argcount = 1;
    394      1.1  mrg   }
    395      1.1  mrg 
    396      1.1  mrg   p->data_inited = 0;
    397      1.1  mrg   p->data_alloc = 20;
    398      1.1  mrg   p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
    399      1.1  mrg   p->data_top = -1;
    400      1.1  mrg 
    401      1.1  mrg   p->error_code = MPEXPR_RESULT_OK;
    402      1.1  mrg 
    403      1.1  mrg 
    404      1.1  mrg  another_expr_lookahead:
    405      1.1  mrg   LOOKAHEAD (MPEXPR_TYPE_PREFIX);
    406      1.1  mrg   TRACE (printf ("another expr\n"));
    407      1.1  mrg 
    408      1.1  mrg   /*another_expr:*/
    409      1.1  mrg   switch (p->token) {
    410      1.1  mrg   case TOKEN_VALUE:
    411      1.1  mrg     goto another_operator_lookahead;
    412      1.1  mrg 
    413      1.1  mrg   case TOKEN_OPERATOR:
    414      1.1  mrg     TRACE (printf ("operator %s\n", p->token_op->name));
    415      1.1  mrg     if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
    416      1.1  mrg       ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
    417      1.1  mrg 
    418      1.1  mrg     CONTROL_PUSH (p->token_op, 1);
    419      1.1  mrg     goto another_expr_lookahead;
    420      1.1  mrg 
    421      1.1  mrg   case TOKEN_FUNCTION:
    422      1.1  mrg     CONTROL_PUSH (p->token_op, 1);
    423      1.1  mrg 
    424      1.1  mrg     if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
    425      1.1  mrg       goto apply_control_lookahead;
    426      1.1  mrg 
    427      1.1  mrg     LOOKAHEAD (MPEXPR_TYPE_PREFIX);
    428      1.1  mrg     if (! (p->token == TOKEN_OPERATOR
    429      1.1  mrg 	   && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
    430      1.1  mrg       ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
    431      1.1  mrg 
    432      1.1  mrg     TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
    433      1.1  mrg 
    434      1.1  mrg     if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
    435      1.1  mrg       {
    436      1.1  mrg 	LOOKAHEAD (0);
    437      1.1  mrg 	if (! (p->token == TOKEN_OPERATOR
    438      1.1  mrg 	       && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
    439      1.1  mrg 	  ERROR ("expected close paren for 0ary function",
    440      1.1  mrg 		 MPEXPR_RESULT_PARSE_ERROR);
    441      1.1  mrg 	goto apply_control_lookahead;
    442      1.1  mrg       }
    443      1.1  mrg 
    444      1.1  mrg     goto another_expr_lookahead;
    445      1.1  mrg   }
    446      1.1  mrg   ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
    447      1.1  mrg 
    448      1.1  mrg 
    449      1.1  mrg  another_operator_lookahead:
    450      1.1  mrg   LOOKAHEAD (0);
    451      1.1  mrg  another_operator:
    452      1.1  mrg   TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
    453      1.1  mrg 
    454      1.1  mrg   switch (p->token) {
    455      1.1  mrg   case TOKEN_EOF:
    456      1.1  mrg     goto apply_control;
    457      1.1  mrg 
    458      1.1  mrg   case TOKEN_OPERATOR:
    459      1.1  mrg     /* The next operator is compared to the one on top of the control stack.
    460      1.1  mrg        If the next is lower precedence, or the same precedence and not
    461      1.1  mrg        right-associative, then reduce using the control stack and look at
    462      1.1  mrg        the next operator again later.  */
    463      1.1  mrg 
    464      1.1  mrg #define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype)                 \
    465      1.1  mrg     ((tprec) < (cprec)                                                  \
    466      1.1  mrg      || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
    467      1.1  mrg 
    468      1.1  mrg     if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
    469      1.1  mrg 				p->token_op->type,       CP->op->type))
    470      1.1  mrg       {
    471      1.1  mrg 	TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
    472      1.1  mrg 		       p->token_op->name,
    473      1.1  mrg 		       p->token_op->precedence, CP->op->precedence,
    474      1.1  mrg 		       p->token_op->type));
    475      1.1  mrg 	goto apply_control;
    476      1.1  mrg       }
    477      1.1  mrg 
    478      1.1  mrg     /* An argsep is a binary operator, but is never pushed on the control
    479      1.1  mrg        stack, it just accumulates an extra argument for a function. */
    480      1.1  mrg     if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
    481      1.1  mrg       {
    482      1.1  mrg 	if (CP->op->precedence != 0)
    483      1.1  mrg 	  ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
    484      1.1  mrg 
    485      1.1  mrg 	TRACE (printf ("argsep for function \"%s\"(%d)\n",
    486      1.1  mrg 		       CP->op->name, CP->argcount));
    487      1.1  mrg 
    488      1.1  mrg #define IS_PAIRWISE(type)                                               \
    489      1.1  mrg 	(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE))  \
    490      1.1  mrg 	 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
    491      1.1  mrg 
    492      1.1  mrg 	if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
    493      1.1  mrg 	  {
    494      1.1  mrg 	    TRACE (printf ("    will reduce pairwise now\n"));
    495      1.1  mrg 	    CP->argcount--;
    496      1.1  mrg 	    CONTROL_PUSH (CP->op, 2);
    497      1.1  mrg 	    goto apply_control;
    498      1.1  mrg 	  }
    499      1.1  mrg 
    500      1.1  mrg 	CP->argcount++;
    501      1.1  mrg 	goto another_expr_lookahead;
    502      1.1  mrg       }
    503      1.1  mrg 
    504      1.1  mrg     switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
    505      1.1  mrg     case MPEXPR_TYPE_NARY(1):
    506      1.1  mrg       /* Postfix unary operators can always be applied immediately.  The
    507      1.1  mrg 	 easiest way to do this is just push it on the control stack and go
    508      1.1  mrg 	 to the normal control stack reduction code. */
    509      1.1  mrg 
    510      1.1  mrg       TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
    511      1.1  mrg       if (p->token_op->type & MPEXPR_TYPE_PREFIX)
    512      1.1  mrg 	ERROR ("prefix unary operator used postfix",
    513      1.1  mrg 	       MPEXPR_RESULT_PARSE_ERROR);
    514      1.1  mrg       CONTROL_PUSH (p->token_op, 1);
    515      1.1  mrg       goto apply_control_lookahead;
    516      1.1  mrg 
    517      1.1  mrg     case MPEXPR_TYPE_NARY(2):
    518      1.1  mrg       CONTROL_PUSH (p->token_op, 2);
    519      1.1  mrg       goto another_expr_lookahead;
    520      1.1  mrg 
    521      1.1  mrg     case MPEXPR_TYPE_NARY(3):
    522      1.1  mrg       CONTROL_PUSH (p->token_op, 1);
    523      1.1  mrg       goto another_expr_lookahead;
    524      1.1  mrg     }
    525      1.1  mrg 
    526      1.1  mrg     TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
    527      1.1  mrg 		   CP->op->name, CP->op->type));
    528      1.1  mrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
    529      1.1  mrg     break;
    530      1.1  mrg 
    531      1.1  mrg   default:
    532      1.1  mrg     TRACE (printf ("expecting an operator, got token %d", p->token));
    533      1.1  mrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
    534      1.1  mrg   }
    535      1.1  mrg 
    536      1.1  mrg 
    537      1.1  mrg  apply_control_lookahead:
    538      1.1  mrg   LOOKAHEAD (0);
    539      1.1  mrg  apply_control:
    540      1.1  mrg   /* Apply the top element CP of the control stack.  Data values are SP,
    541      1.1  mrg      SP-1, etc.  Result is left as stack top SP after popping consumed
    542      1.1  mrg      values.
    543      1.1  mrg 
    544      1.1  mrg      The use of sp as a duplicate of SP will help compilers that can't
    545      1.1  mrg      otherwise recognise the various uses of SP as common subexpressions.  */
    546      1.1  mrg 
    547      1.1  mrg   TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
    548      1.1  mrg 		 p->control_top, CP->op->name, CP->op->type, CP->argcount));
    549      1.1  mrg 
    550      1.1  mrg   TRACE (printf ("apply 0x%X-ary\n",
    551      1.1  mrg 		 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
    552      1.1  mrg   switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
    553      1.1  mrg   case MPEXPR_TYPE_NARY(0):
    554      1.1  mrg     {
    555      1.1  mrg       mpX_ptr  sp;
    556      1.1  mrg       DATA_SPACE ();
    557      1.1  mrg       DATA_PUSH ();
    558      1.1  mrg       sp = SP;
    559      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
    560      1.1  mrg       case 0:
    561      1.1  mrg 	(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
    562      1.1  mrg 	break;
    563      1.1  mrg       case MPEXPR_TYPE_RESULT_INT:
    564      1.1  mrg 	(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
    565      1.1  mrg 	break;
    566      1.1  mrg       default:
    567      1.1  mrg 	ERROR ("unrecognised 0ary argument calling style",
    568      1.1  mrg 	       MPEXPR_RESULT_BAD_TABLE);
    569      1.1  mrg       }
    570      1.1  mrg     }
    571      1.1  mrg     break;
    572      1.1  mrg 
    573      1.1  mrg   case MPEXPR_TYPE_NARY(1):
    574      1.1  mrg     {
    575      1.1  mrg       mpX_ptr  sp = SP;
    576      1.1  mrg       CHECK_ARGCOUNT ("unary", 1);
    577      1.1  mrg       TRACE (MPX_TRACE ("before", sp));
    578      1.1  mrg 
    579      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
    580      1.1  mrg       case 0:
    581      1.1  mrg 	/* not a special */
    582      1.1  mrg 	break;
    583      1.1  mrg 
    584      1.1  mrg       case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
    585      1.1  mrg 	TRACE (printf ("special done\n"));
    586      1.1  mrg 	goto done;
    587      1.1  mrg 
    588      1.1  mrg       case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
    589      1.1  mrg 	TRACE (printf ("special logical not\n"));
    590      1.1  mrg 	(*p->mpX_set_si)
    591      1.1  mrg 	  (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
    592      1.1  mrg 	goto apply_control_done;
    593      1.1  mrg 
    594      1.1  mrg       case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
    595      1.1  mrg 	CONTROL_POP ();
    596      1.1  mrg 	if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
    597      1.1  mrg 	  {
    598      1.1  mrg 	    TRACE (printf ("close paren matching open paren\n"));
    599      1.1  mrg 	    CONTROL_POP ();
    600      1.1  mrg 	    goto another_operator;
    601      1.1  mrg 	  }
    602      1.1  mrg 	if (CP->op->precedence == 0)
    603      1.1  mrg 	  {
    604      1.1  mrg 	    TRACE (printf ("close paren for function\n"));
    605      1.1  mrg 	    goto apply_control;
    606      1.1  mrg 	  }
    607      1.1  mrg 	ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
    608      1.1  mrg 
    609      1.1  mrg       default:
    610      1.1  mrg 	TRACE (printf ("unrecognised special unary operator 0x%X",
    611      1.1  mrg 		       CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
    612      1.1  mrg 	ERROR ("", MPEXPR_RESULT_BAD_TABLE);
    613      1.1  mrg       }
    614      1.1  mrg 
    615      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
    616      1.1  mrg       case 0:
    617      1.1  mrg 	(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
    618      1.1  mrg 	break;
    619      1.1  mrg       case MPEXPR_TYPE_LAST_UI:
    620      1.1  mrg 	CHECK_UI (sp);
    621      1.1  mrg 	(* (mpexpr_fun_unary_ui_t) CP->op->fun)
    622      1.1  mrg 	  (sp, (*p->mpX_get_ui) (sp));
    623      1.1  mrg 	break;
    624      1.1  mrg       case MPEXPR_TYPE_RESULT_INT:
    625      1.1  mrg 	(*p->mpX_set_si)
    626      1.1  mrg 	  (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
    627      1.1  mrg 	break;
    628      1.1  mrg       case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
    629      1.1  mrg 	CHECK_UI (sp);
    630      1.1  mrg 	(*p->mpX_set_si)
    631      1.1  mrg 	  (sp,
    632      1.1  mrg 	   (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
    633      1.1  mrg 	   ((*p->mpX_get_ui) (sp)));
    634      1.1  mrg 	break;
    635      1.1  mrg       default:
    636      1.1  mrg 	ERROR ("unrecognised unary argument calling style",
    637      1.1  mrg 	       MPEXPR_RESULT_BAD_TABLE);
    638      1.1  mrg       }
    639      1.1  mrg     }
    640      1.1  mrg     break;
    641      1.1  mrg 
    642      1.1  mrg   case MPEXPR_TYPE_NARY(2):
    643      1.1  mrg     {
    644      1.1  mrg       mpX_ptr  sp;
    645      1.1  mrg 
    646      1.1  mrg       /* pairwise functions are allowed to have just one argument */
    647      1.1  mrg       if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
    648      1.1  mrg 	  && CP->op->precedence == 0
    649      1.1  mrg 	  && CP->argcount == 1)
    650      1.1  mrg 	goto apply_control_done;
    651      1.1  mrg 
    652      1.1  mrg       CHECK_ARGCOUNT ("binary", 2);
    653      1.1  mrg       DATA_POP (1);
    654      1.1  mrg       sp = SP;
    655      1.1  mrg       TRACE (MPX_TRACE ("lhs", sp);
    656      1.1  mrg 	     MPX_TRACE ("rhs", sp+1));
    657      1.1  mrg 
    658      1.1  mrg       if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
    659      1.1  mrg 	{
    660      1.1  mrg 	  int  type = CP->op->type;
    661      1.1  mrg 	  int  cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
    662      1.1  mrg 	    (sp, sp+1);
    663      1.1  mrg 	  (*p->mpX_set_si)
    664      1.1  mrg 	    (sp,
    665      1.1  mrg 	     (long)
    666      1.1  mrg 	     ((  (cmp  < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
    667      1.1  mrg 	      | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
    668      1.1  mrg 	      | ((cmp  > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
    669      1.1  mrg 	  goto apply_control_done;
    670      1.1  mrg 	}
    671      1.1  mrg 
    672      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
    673      1.1  mrg       case 0:
    674      1.1  mrg 	/* not a special */
    675      1.1  mrg 	break;
    676      1.1  mrg 
    677      1.1  mrg       case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
    678      1.1  mrg 	ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
    679      1.1  mrg 
    680      1.1  mrg       case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
    681      1.1  mrg 	TRACE (printf ("special colon\n"));
    682      1.1  mrg 	CONTROL_POP ();
    683      1.1  mrg 	if (CP->op->type != MPEXPR_TYPE_QUESTION)
    684      1.1  mrg 	  ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
    685      1.1  mrg 
    686      1.1  mrg 	CP->argcount--;
    687      1.1  mrg 	DATA_POP (1);
    688      1.1  mrg 	sp--;
    689      1.1  mrg 	TRACE (MPX_TRACE ("query", sp);
    690      1.1  mrg 	       MPX_TRACE ("true",  sp+1);
    691      1.1  mrg 	       MPX_TRACE ("false", sp+2));
    692      1.1  mrg 	(*p->mpX_set)
    693      1.1  mrg 	  (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
    694      1.1  mrg 	   ? sp+1 : sp+2);
    695      1.1  mrg 	goto apply_control_done;
    696      1.1  mrg 
    697      1.1  mrg       case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
    698      1.1  mrg 	TRACE (printf ("special logical and\n"));
    699      1.1  mrg 	(*p->mpX_set_si)
    700      1.1  mrg 	  (sp,
    701      1.1  mrg 	   (long)
    702      1.1  mrg 	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
    703      1.1  mrg 	    && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
    704      1.1  mrg 	goto apply_control_done;
    705      1.1  mrg 
    706      1.1  mrg       case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
    707      1.1  mrg 	TRACE (printf ("special logical and\n"));
    708      1.1  mrg 	(*p->mpX_set_si)
    709      1.1  mrg 	  (sp,
    710      1.1  mrg 	   (long)
    711      1.1  mrg 	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
    712      1.1  mrg 	    || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
    713      1.1  mrg 	goto apply_control_done;
    714      1.1  mrg 
    715      1.1  mrg       case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
    716      1.1  mrg 	TRACE (printf ("special max\n"));
    717      1.1  mrg 	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
    718      1.1  mrg 	  (*p->mpX_swap) (sp, sp+1);
    719      1.1  mrg 	goto apply_control_done;
    720      1.1  mrg       case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
    721      1.1  mrg 	TRACE (printf ("special min\n"));
    722      1.1  mrg 	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
    723      1.1  mrg 	  (*p->mpX_swap) (sp, sp+1);
    724      1.1  mrg 	goto apply_control_done;
    725      1.1  mrg 
    726      1.1  mrg       default:
    727      1.1  mrg 	ERROR ("unrecognised special binary operator",
    728      1.1  mrg 	       MPEXPR_RESULT_BAD_TABLE);
    729      1.1  mrg       }
    730      1.1  mrg 
    731      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
    732      1.1  mrg       case 0:
    733      1.1  mrg 	(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
    734      1.1  mrg 	break;
    735      1.1  mrg       case MPEXPR_TYPE_LAST_UI:
    736      1.1  mrg 	CHECK_UI (sp+1);
    737      1.1  mrg 	(* (mpexpr_fun_binary_ui_t) CP->op->fun)
    738      1.1  mrg 	  (sp, sp, (*p->mpX_get_ui) (sp+1));
    739      1.1  mrg 	break;
    740      1.1  mrg       case MPEXPR_TYPE_RESULT_INT:
    741      1.1  mrg 	(*p->mpX_set_si)
    742      1.1  mrg 	  (sp,
    743      1.1  mrg 	   (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
    744      1.1  mrg 	break;
    745      1.1  mrg       case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
    746      1.1  mrg 	CHECK_UI (sp+1);
    747      1.1  mrg 	(*p->mpX_set_si)
    748      1.1  mrg 	  (sp,
    749      1.1  mrg 	   (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
    750      1.1  mrg 	   (sp, (*p->mpX_get_ui) (sp+1)));
    751      1.1  mrg 	break;
    752      1.1  mrg       default:
    753      1.1  mrg 	ERROR ("unrecognised binary argument calling style",
    754      1.1  mrg 	       MPEXPR_RESULT_BAD_TABLE);
    755      1.1  mrg       }
    756      1.1  mrg     }
    757      1.1  mrg     break;
    758      1.1  mrg 
    759      1.1  mrg   case MPEXPR_TYPE_NARY(3):
    760      1.1  mrg     {
    761      1.1  mrg       mpX_ptr  sp;
    762      1.1  mrg 
    763      1.1  mrg       CHECK_ARGCOUNT ("ternary", 3);
    764      1.1  mrg       DATA_POP (2);
    765      1.1  mrg       sp = SP;
    766      1.1  mrg       TRACE (MPX_TRACE ("arg1", sp);
    767      1.1  mrg 	     MPX_TRACE ("arg2", sp+1);
    768      1.1  mrg 	     MPX_TRACE ("arg3", sp+1));
    769      1.1  mrg 
    770      1.1  mrg       switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
    771      1.1  mrg       case 0:
    772      1.1  mrg 	(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
    773      1.1  mrg 	break;
    774      1.1  mrg       case MPEXPR_TYPE_LAST_UI:
    775      1.1  mrg 	CHECK_UI (sp+2);
    776      1.1  mrg 	(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
    777      1.1  mrg 	  (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
    778      1.1  mrg 	break;
    779      1.1  mrg       case MPEXPR_TYPE_RESULT_INT:
    780      1.1  mrg 	(*p->mpX_set_si)
    781      1.1  mrg 	  (sp,
    782      1.1  mrg 	   (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
    783      1.1  mrg 	   (sp, sp+1, sp+2));
    784      1.1  mrg 	break;
    785      1.1  mrg       case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
    786      1.1  mrg 	CHECK_UI (sp+2);
    787      1.1  mrg 	(*p->mpX_set_si)
    788      1.1  mrg 	  (sp,
    789      1.1  mrg 	   (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
    790      1.1  mrg 	   (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
    791      1.1  mrg 	break;
    792      1.1  mrg       default:
    793      1.1  mrg 	ERROR ("unrecognised binary argument calling style",
    794      1.1  mrg 	       MPEXPR_RESULT_BAD_TABLE);
    795      1.1  mrg       }
    796      1.1  mrg     }
    797      1.1  mrg     break;
    798      1.1  mrg 
    799      1.1  mrg   default:
    800      1.1  mrg     TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
    801      1.1  mrg     ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
    802      1.1  mrg   }
    803      1.1  mrg 
    804      1.1  mrg  apply_control_done:
    805      1.1  mrg   TRACE (MPX_TRACE ("result", SP));
    806      1.1  mrg   CONTROL_POP ();
    807      1.1  mrg   goto another_operator;
    808      1.1  mrg 
    809      1.1  mrg  done:
    810      1.1  mrg   if (p->error_code == MPEXPR_RESULT_OK)
    811      1.1  mrg     {
    812      1.1  mrg       if (p->data_top != 0)
    813      1.1  mrg 	{
    814      1.1  mrg 	  TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
    815      1.1  mrg 	  p->error_code = MPEXPR_RESULT_PARSE_ERROR;
    816      1.1  mrg 	}
    817      1.1  mrg       else
    818      1.1  mrg 	(*p->mpX_set_or_swap) (p->res, SP);
    819      1.1  mrg     }
    820      1.1  mrg 
    821      1.1  mrg   {
    822      1.1  mrg     int  i;
    823      1.1  mrg     for (i = 0; i < p->data_inited; i++)
    824      1.1  mrg       {
    825      1.1  mrg 	TRACE (printf ("clear %d\n", i));
    826      1.1  mrg 	(*p->mpX_clear) (p->data_stack+i);
    827      1.1  mrg       }
    828      1.1  mrg   }
    829      1.1  mrg 
    830      1.1  mrg   FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
    831      1.1  mrg   FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
    832      1.1  mrg 
    833      1.1  mrg   return p->error_code;
    834      1.1  mrg }
    835