~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to gmp3/demos/expr/expr.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

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