[BACK]Return to expr.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / demos / expr

Annotation of OpenXM_contrib/gmp/demos/expr/expr.c, Revision 1.1.1.1

1.1       ohara       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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>