github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/demos/expr/expr.c (about)

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