Upload Tizen:Base source
[external/gmp.git] / demos / expr / expr.c
1 /* mpexpr_evaluate -- shared code for simple expression evaluation
2
3 Copyright 2000, 2001, 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 the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
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
136 static int
137 lookahead (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
359 int
360 mpexpr_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 }