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>