[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     ! 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>