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