Blame demos/expr/expr.c

Packit 5c3484
/* mpexpr_evaluate -- shared code for simple expression evaluation
Packit 5c3484
Packit 5c3484
Copyright 2000-2002, 2004 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <ctype.h>
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <string.h>
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "expr-impl.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Change this to "#define TRACE(x) x" to get some traces.  The trace
Packit 5c3484
   printfs junk up the code a bit, but it's very hard to tell what's going
Packit 5c3484
   on without them.  Set MPX_TRACE to a suitable output function for the
Packit 5c3484
   mpz/mpq/mpf being run (if you have the wrong trace function it'll
Packit 5c3484
   probably segv).  */
Packit 5c3484
Packit 5c3484
#define TRACE(x)
Packit 5c3484
#define MPX_TRACE  mpz_trace
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* A few helper macros copied from gmp-impl.h */
Packit 5c3484
#define ALLOCATE_FUNC_TYPE(n,type) \
Packit 5c3484
  ((type *) (*allocate_func) ((n) * sizeof (type)))
Packit 5c3484
#define ALLOCATE_FUNC_LIMBS(n)   ALLOCATE_FUNC_TYPE (n, mp_limb_t)
Packit 5c3484
#define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
Packit 5c3484
  ((type *) (*reallocate_func)                            \
Packit 5c3484
   (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
Packit 5c3484
#define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
Packit 5c3484
  REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
Packit 5c3484
#define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
Packit 5c3484
#define FREE_FUNC_LIMBS(p,n)     FREE_FUNC_TYPE (p, n, mp_limb_t)
Packit 5c3484
#define ASSERT(x)
Packit 5c3484
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* All the error strings are just for diagnostic traces.  Only the error
Packit 5c3484
   code is actually returned.  */
Packit 5c3484
#define ERROR(str,code)                 \
Packit 5c3484
  {                                     \
Packit 5c3484
    TRACE (printf ("%s\n", str));       \
Packit 5c3484
    p->error_code = (code);             \
Packit 5c3484
    goto done;                          \
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
Packit 5c3484
#define REALLOC(ptr, alloc, incr, type)                         \
Packit 5c3484
  do {                                                          \
Packit 5c3484
    int  new_alloc = (alloc) + (incr);                          \
Packit 5c3484
    ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type);   \
Packit 5c3484
    (alloc) = new_alloc;                                        \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* data stack top element */
Packit 5c3484
#define SP   (p->data_stack + p->data_top)
Packit 5c3484
Packit 5c3484
/* Make sure there's room for another data element above current top.
Packit 5c3484
   reallocate_func is fetched for when this macro is used in lookahead(). */
Packit 5c3484
#define DATA_SPACE()                                                    \
Packit 5c3484
  do {                                                                  \
Packit 5c3484
    if (p->data_top + 1 >= p->data_alloc)                               \
Packit 5c3484
      {                                                                 \
Packit 5c3484
	void *(*reallocate_func) (void *, size_t, size_t);              \
Packit 5c3484
	mp_get_memory_functions (NULL, &reallocate_func, NULL);         \
Packit 5c3484
	TRACE (printf ("grow stack from %d\n", p->data_alloc));         \
Packit 5c3484
	REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t);        \
Packit 5c3484
      }                                                                 \
Packit 5c3484
    ASSERT (p->data_top + 1 <= p->data_inited);                         \
Packit 5c3484
    if (p->data_top + 1 == p->data_inited)                              \
Packit 5c3484
      {                                                                 \
Packit 5c3484
	TRACE (printf ("initialize %d\n", p->data_top + 1));            \
Packit 5c3484
	(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec);      \
Packit 5c3484
	p->data_inited++;                                               \
Packit 5c3484
      }                                                                 \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
#define DATA_PUSH()                             \
Packit 5c3484
  do {                                          \
Packit 5c3484
    p->data_top++;                              \
Packit 5c3484
    ASSERT (p->data_top < p->data_alloc);       \
Packit 5c3484
    ASSERT (p->data_top < p->data_inited);      \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
/* the last stack entry is never popped, so top>=0 will be true */
Packit 5c3484
#define DATA_POP(n)             \
Packit 5c3484
  do {                          \
Packit 5c3484
    p->data_top -= (n);         \
Packit 5c3484
    ASSERT (p->data_top >= 0);  \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* lookahead() parses the next token.  Return 1 if successful, with some
Packit 5c3484
   extra data.  Return 0 if fail, with reason in p->error_code.
Packit 5c3484
Packit 5c3484
   "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
Packit 5c3484
   preferred, or 0 if an operator without is preferred. */
Packit 5c3484
Packit 5c3484
#define TOKEN_EOF         -1   /* no extra data */
Packit 5c3484
#define TOKEN_VALUE       -2   /* pushed onto data stack */
Packit 5c3484
#define TOKEN_OPERATOR    -3   /* stored in p->token_op */
Packit 5c3484
#define TOKEN_FUNCTION    -4   /* stored in p->token_op */
Packit 5c3484
Packit 5c3484
#define TOKEN_NAME(n)                           \
Packit 5c3484
  ((n) == TOKEN_EOF ? "TOKEN_EOF"               \
Packit 5c3484
   : (n) == TOKEN_VALUE ? "TOKEN_VALUE"         \
Packit 5c3484
   : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR"   \
Packit 5c3484
   : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION"      \
Packit 5c3484
   : "UNKNOWN TOKEN")
Packit 5c3484
Packit 5c3484
/* Functions default to being parsed as whole words, operators to match just
Packit 5c3484
   at the start of the string.  The type flags override this. */
Packit 5c3484
#define WHOLEWORD(op)                           \
Packit 5c3484
  (op->precedence == 0                          \
Packit 5c3484
   ? (! (op->type & MPEXPR_TYPE_OPERATOR))      \
Packit 5c3484
   :   (op->type & MPEXPR_TYPE_WHOLEWORD))
Packit 5c3484
Packit 5c3484
#define isasciispace(c)   (isascii (c) && isspace (c))
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
lookahead (struct mpexpr_parse_t *p, int prefix)
Packit 5c3484
{
Packit 5c3484
  const struct mpexpr_operator_t  *op, *op_found;
Packit 5c3484
  size_t  oplen, oplen_found, wlen;
Packit 5c3484
  int     i;
Packit 5c3484
Packit 5c3484
  /* skip white space */
Packit 5c3484
  while (p->elen > 0 && isasciispace (*p->e))
Packit 5c3484
    p->e++, p->elen--;
Packit 5c3484
Packit 5c3484
  if (p->elen == 0)
Packit 5c3484
    {
Packit 5c3484
      TRACE (printf ("lookahead EOF\n"));
Packit 5c3484
      p->token = TOKEN_EOF;
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  DATA_SPACE ();
Packit 5c3484
Packit 5c3484
  /* Get extent of whole word. */
Packit 5c3484
  for (wlen = 0; wlen < p->elen; wlen++)
Packit 5c3484
    if (! isasciicsym (p->e[wlen]))
Packit 5c3484
      break;
Packit 5c3484
Packit 5c3484
  TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
Packit 5c3484
		 (int) p->elen, p->e, p->elen, wlen));
Packit 5c3484
Packit 5c3484
  op_found = NULL;
Packit 5c3484
  oplen_found = 0;
Packit 5c3484
  for (op = p->table; op->name != NULL; op++)
Packit 5c3484
    {
Packit 5c3484
      if (op->type == MPEXPR_TYPE_NEW_TABLE)
Packit 5c3484
	{
Packit 5c3484
	  printf ("new\n");
Packit 5c3484
	  op = (struct mpexpr_operator_t *) op->name - 1;
Packit 5c3484
	  continue;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      oplen = strlen (op->name);
Packit 5c3484
      if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
Packit 5c3484
	     && memcmp (p->e, op->name, oplen) == 0))
Packit 5c3484
	continue;
Packit 5c3484
Packit 5c3484
      /* Shorter matches don't replace longer previous ones. */
Packit 5c3484
      if (op_found && oplen < oplen_found)
Packit 5c3484
	continue;
Packit 5c3484
Packit 5c3484
      /* On a match of equal length to a previous one, the old match isn't
Packit 5c3484
	 replaced if it has the preferred prefix, and if it doesn't then
Packit 5c3484
	 it's not replaced if the new one also doesn't.  */
Packit 5c3484
      if (op_found && oplen == oplen_found
Packit 5c3484
	  && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
Packit 5c3484
	      || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
Packit 5c3484
	continue;
Packit 5c3484
Packit 5c3484
      /* This is now either the first match seen, or a longer than previous
Packit 5c3484
	 match, or an equal to previous one but with a preferred prefix. */
Packit 5c3484
      op_found = op;
Packit 5c3484
      oplen_found = oplen;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (op_found)
Packit 5c3484
    {
Packit 5c3484
      p->e += oplen_found, p->elen -= oplen_found;
Packit 5c3484
Packit 5c3484
      if (op_found->type == MPEXPR_TYPE_VARIABLE)
Packit 5c3484
	{
Packit 5c3484
	  if (p->elen == 0)
Packit 5c3484
	    ERROR ("end of string expecting a variable",
Packit 5c3484
		   MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
	  i = p->e[0] - 'a';
Packit 5c3484
	  if (i < 0 || i >= MPEXPR_VARIABLES)
Packit 5c3484
	    ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
Packit 5c3484
	  goto variable;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (op_found->precedence == 0)
Packit 5c3484
	{
Packit 5c3484
	  TRACE (printf ("lookahead function: %s\n", op_found->name));
Packit 5c3484
	  p->token = TOKEN_FUNCTION;
Packit 5c3484
	  p->token_op = op_found;
Packit 5c3484
	  return 1;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  TRACE (printf ("lookahead operator: %s\n", op_found->name));
Packit 5c3484
	  p->token = TOKEN_OPERATOR;
Packit 5c3484
	  p->token_op = op_found;
Packit 5c3484
	  return 1;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
Packit 5c3484
  if (oplen != 0)
Packit 5c3484
    {
Packit 5c3484
      p->e += oplen, p->elen -= oplen;
Packit 5c3484
      p->token = TOKEN_VALUE;
Packit 5c3484
      DATA_PUSH ();
Packit 5c3484
      TRACE (MPX_TRACE ("lookahead number", SP));
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Maybe an unprefixed one character variable */
Packit 5c3484
  i = p->e[0] - 'a';
Packit 5c3484
  if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
Packit 5c3484
    {
Packit 5c3484
    variable:
Packit 5c3484
      p->e++, p->elen--;
Packit 5c3484
      if (p->var[i] == NULL)
Packit 5c3484
	ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
Packit 5c3484
      TRACE (printf ("lookahead variable: var[%d] = ", i);
Packit 5c3484
	     MPX_TRACE ("", p->var[i]));
Packit 5c3484
      p->token = TOKEN_VALUE;
Packit 5c3484
      DATA_PUSH ();
Packit 5c3484
      (*p->mpX_set) (SP, p->var[i]);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
 done:
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* control stack current top element */
Packit 5c3484
#define CP   (p->control_stack + p->control_top)
Packit 5c3484
Packit 5c3484
/* make sure there's room for another control element above current top */
Packit 5c3484
#define CONTROL_SPACE()                                                    \
Packit 5c3484
  do {                                                                     \
Packit 5c3484
    if (p->control_top + 1 >= p->control_alloc)                            \
Packit 5c3484
      {                                                                    \
Packit 5c3484
	TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
Packit 5c3484
	REALLOC (p->control_stack, p->control_alloc, 20,                   \
Packit 5c3484
		 struct mpexpr_control_t);                                 \
Packit 5c3484
      }                                                                    \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
/* Push an operator on the control stack, claiming currently to have the
Packit 5c3484
   given number of args ready.  Local variable "op" is used in case opptr is
Packit 5c3484
   a reference through CP.  */
Packit 5c3484
#define CONTROL_PUSH(opptr,args)                        \
Packit 5c3484
  do {                                                  \
Packit 5c3484
    const struct mpexpr_operator_t *op = opptr;		\
Packit 5c3484
    struct mpexpr_control_t *cp;                        \
Packit 5c3484
    CONTROL_SPACE ();                                   \
Packit 5c3484
    p->control_top++;                                   \
Packit 5c3484
    ASSERT (p->control_top < p->control_alloc);         \
Packit 5c3484
    cp = CP;                                            \
Packit 5c3484
    cp->op = op;                                        \
Packit 5c3484
    cp->argcount = (args);                              \
Packit 5c3484
    TRACE_CONTROL("control stack push:");               \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
/* The special operator_done is never popped, so top>=0 will hold. */
Packit 5c3484
#define CONTROL_POP()                           \
Packit 5c3484
  do {                                          \
Packit 5c3484
    p->control_top--;                           \
Packit 5c3484
    ASSERT (p->control_top >= 0);               \
Packit 5c3484
    TRACE_CONTROL ("control stack pop:");       \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
#define TRACE_CONTROL(str)                              \
Packit 5c3484
  TRACE ({                                              \
Packit 5c3484
    int  i;                                             \
Packit 5c3484
    printf ("%s depth %d:", str, p->control_top);       \
Packit 5c3484
    for (i = 0; i <= p->control_top; i++)               \
Packit 5c3484
      printf (" \"%s\"(%d)",                            \
Packit 5c3484
	      p->control_stack[i].op->name,             \
Packit 5c3484
	      p->control_stack[i].argcount);            \
Packit 5c3484
    printf ("\n");                                      \
Packit 5c3484
  });
Packit 5c3484
Packit 5c3484
Packit 5c3484
#define LOOKAHEAD(prefix)               \
Packit 5c3484
  do {                                  \
Packit 5c3484
    if (! lookahead (p, prefix))        \
Packit 5c3484
      goto done;                        \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
#define CHECK_UI(n)                                                     \
Packit 5c3484
  do {                                                                  \
Packit 5c3484
    if (! (*p->mpX_ulong_p) (n))                                        \
Packit 5c3484
      ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI);        \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
#define CHECK_ARGCOUNT(str,n)                                              \
Packit 5c3484
  do {                                                                     \
Packit 5c3484
    if (CP->argcount != (n))                                               \
Packit 5c3484
      {                                                                    \
Packit 5c3484
	TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
Packit 5c3484
		       str, CP->argcount, n));                             \
Packit 5c3484
	ERROR ("", MPEXPR_RESULT_PARSE_ERROR);                             \
Packit 5c3484
      }                                                                    \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* There's two basic states here.  In both p->token is the next token.
Packit 5c3484
Packit 5c3484
   "another_expr" is when a whole expression should be parsed.  This means a
Packit 5c3484
   literal or variable value possibly followed by an operator, or a function
Packit 5c3484
   or prefix operator followed by a further whole expression.
Packit 5c3484
Packit 5c3484
   "another_operator" is when an expression has been parsed and its value is
Packit 5c3484
   on the top of the data stack (SP) and an optional further postfix or
Packit 5c3484
   infix operator should be parsed.
Packit 5c3484
Packit 5c3484
   In "another_operator" precedences determine whether to push the operator
Packit 5c3484
   onto the control stack, or instead go to "apply_control" to reduce the
Packit 5c3484
   operator currently on top of the control stack.
Packit 5c3484
Packit 5c3484
   When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
Packit 5c3484
   for "another_expr" will seek the prefix form, a LOOKAHEAD() for
Packit 5c3484
   "another_operator" will seek the postfix/infix form.  The grammar is
Packit 5c3484
   simple enough that the next state is known before reading the next token.
Packit 5c3484
Packit 5c3484
   Argument count checking guards against functions consuming the wrong
Packit 5c3484
   number of operands from the data stack.  The same checks are applied to
Packit 5c3484
   operators, but will always pass since a UNARY or BINARY will only ever
Packit 5c3484
   parse with the correct operands.  */
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
mpexpr_evaluate (struct mpexpr_parse_t *p)
Packit 5c3484
{
Packit 5c3484
  void *(*allocate_func) (size_t);
Packit 5c3484
  void *(*reallocate_func) (void *, size_t, size_t);
Packit 5c3484
  void (*free_func) (void *, size_t);
Packit 5c3484
Packit 5c3484
  mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
Packit 5c3484
Packit 5c3484
  TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
Packit 5c3484
		 p->base, (int) p->elen, p->e));
Packit 5c3484
Packit 5c3484
  /* "done" is a special sentinel at the bottom of the control stack,
Packit 5c3484
     precedence -1 is lower than any normal operator.  */
Packit 5c3484
  {
Packit 5c3484
    static const struct mpexpr_operator_t  operator_done
Packit 5c3484
      = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
Packit 5c3484
Packit 5c3484
    p->control_alloc = 20;
Packit 5c3484
    p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
Packit 5c3484
					   struct mpexpr_control_t);
Packit 5c3484
    p->control_top = 0;
Packit 5c3484
    CP->op = &operator_done;
Packit 5c3484
    CP->argcount = 1;
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
  p->data_inited = 0;
Packit 5c3484
  p->data_alloc = 20;
Packit 5c3484
  p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
Packit 5c3484
  p->data_top = -1;
Packit 5c3484
Packit 5c3484
  p->error_code = MPEXPR_RESULT_OK;
Packit 5c3484
Packit 5c3484
Packit 5c3484
 another_expr_lookahead:
Packit 5c3484
  LOOKAHEAD (MPEXPR_TYPE_PREFIX);
Packit 5c3484
  TRACE (printf ("another expr\n"));
Packit 5c3484
Packit 5c3484
  /*another_expr:*/
Packit 5c3484
  switch (p->token) {
Packit 5c3484
  case TOKEN_VALUE:
Packit 5c3484
    goto another_operator_lookahead;
Packit 5c3484
Packit 5c3484
  case TOKEN_OPERATOR:
Packit 5c3484
    TRACE (printf ("operator %s\n", p->token_op->name));
Packit 5c3484
    if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
Packit 5c3484
      ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
    CONTROL_PUSH (p->token_op, 1);
Packit 5c3484
    goto another_expr_lookahead;
Packit 5c3484
Packit 5c3484
  case TOKEN_FUNCTION:
Packit 5c3484
    CONTROL_PUSH (p->token_op, 1);
Packit 5c3484
Packit 5c3484
    if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
Packit 5c3484
      goto apply_control_lookahead;
Packit 5c3484
Packit 5c3484
    LOOKAHEAD (MPEXPR_TYPE_PREFIX);
Packit 5c3484
    if (! (p->token == TOKEN_OPERATOR
Packit 5c3484
	   && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
Packit 5c3484
      ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
    TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
Packit 5c3484
Packit 5c3484
    if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
Packit 5c3484
      {
Packit 5c3484
	LOOKAHEAD (0);
Packit 5c3484
	if (! (p->token == TOKEN_OPERATOR
Packit 5c3484
	       && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
Packit 5c3484
	  ERROR ("expected close paren for 0ary function",
Packit 5c3484
		 MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
	goto apply_control_lookahead;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    goto another_expr_lookahead;
Packit 5c3484
  }
Packit 5c3484
  ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
Packit 5c3484
 another_operator_lookahead:
Packit 5c3484
  LOOKAHEAD (0);
Packit 5c3484
 another_operator:
Packit 5c3484
  TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
Packit 5c3484
Packit 5c3484
  switch (p->token) {
Packit 5c3484
  case TOKEN_EOF:
Packit 5c3484
    goto apply_control;
Packit 5c3484
Packit 5c3484
  case TOKEN_OPERATOR:
Packit 5c3484
    /* The next operator is compared to the one on top of the control stack.
Packit 5c3484
       If the next is lower precedence, or the same precedence and not
Packit 5c3484
       right-associative, then reduce using the control stack and look at
Packit 5c3484
       the next operator again later.  */
Packit 5c3484
Packit 5c3484
#define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype)                 \
Packit 5c3484
    ((tprec) < (cprec)                                                  \
Packit 5c3484
     || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
Packit 5c3484
Packit 5c3484
    if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
Packit 5c3484
				p->token_op->type,       CP->op->type))
Packit 5c3484
      {
Packit 5c3484
	TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
Packit 5c3484
		       p->token_op->name,
Packit 5c3484
		       p->token_op->precedence, CP->op->precedence,
Packit 5c3484
		       p->token_op->type));
Packit 5c3484
	goto apply_control;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    /* An argsep is a binary operator, but is never pushed on the control
Packit 5c3484
       stack, it just accumulates an extra argument for a function. */
Packit 5c3484
    if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
Packit 5c3484
      {
Packit 5c3484
	if (CP->op->precedence != 0)
Packit 5c3484
	  ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
	TRACE (printf ("argsep for function \"%s\"(%d)\n",
Packit 5c3484
		       CP->op->name, CP->argcount));
Packit 5c3484
Packit 5c3484
#define IS_PAIRWISE(type)                                               \
Packit 5c3484
	(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE))  \
Packit 5c3484
	 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
Packit 5c3484
Packit 5c3484
	if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
Packit 5c3484
	  {
Packit 5c3484
	    TRACE (printf ("    will reduce pairwise now\n"));
Packit 5c3484
	    CP->argcount--;
Packit 5c3484
	    CONTROL_PUSH (CP->op, 2);
Packit 5c3484
	    goto apply_control;
Packit 5c3484
	  }
Packit 5c3484
Packit 5c3484
	CP->argcount++;
Packit 5c3484
	goto another_expr_lookahead;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
Packit 5c3484
    case MPEXPR_TYPE_NARY(1):
Packit 5c3484
      /* Postfix unary operators can always be applied immediately.  The
Packit 5c3484
	 easiest way to do this is just push it on the control stack and go
Packit 5c3484
	 to the normal control stack reduction code. */
Packit 5c3484
Packit 5c3484
      TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
Packit 5c3484
      if (p->token_op->type & MPEXPR_TYPE_PREFIX)
Packit 5c3484
	ERROR ("prefix unary operator used postfix",
Packit 5c3484
	       MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
      CONTROL_PUSH (p->token_op, 1);
Packit 5c3484
      goto apply_control_lookahead;
Packit 5c3484
Packit 5c3484
    case MPEXPR_TYPE_NARY(2):
Packit 5c3484
      CONTROL_PUSH (p->token_op, 2);
Packit 5c3484
      goto another_expr_lookahead;
Packit 5c3484
Packit 5c3484
    case MPEXPR_TYPE_NARY(3):
Packit 5c3484
      CONTROL_PUSH (p->token_op, 1);
Packit 5c3484
      goto another_expr_lookahead;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
    TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
Packit 5c3484
		   CP->op->name, CP->op->type));
Packit 5c3484
    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
    break;
Packit 5c3484
Packit 5c3484
  default:
Packit 5c3484
    TRACE (printf ("expecting an operator, got token %d", p->token));
Packit 5c3484
    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
Packit 5c3484
 apply_control_lookahead:
Packit 5c3484
  LOOKAHEAD (0);
Packit 5c3484
 apply_control:
Packit 5c3484
  /* Apply the top element CP of the control stack.  Data values are SP,
Packit 5c3484
     SP-1, etc.  Result is left as stack top SP after popping consumed
Packit 5c3484
     values.
Packit 5c3484
Packit 5c3484
     The use of sp as a duplicate of SP will help compilers that can't
Packit 5c3484
     otherwise recognise the various uses of SP as common subexpressions.  */
Packit 5c3484
Packit 5c3484
  TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
Packit 5c3484
		 p->control_top, CP->op->name, CP->op->type, CP->argcount));
Packit 5c3484
Packit 5c3484
  TRACE (printf ("apply 0x%X-ary\n",
Packit 5c3484
		 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
Packit 5c3484
  switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
Packit 5c3484
  case MPEXPR_TYPE_NARY(0):
Packit 5c3484
    {
Packit 5c3484
      mpX_ptr  sp;
Packit 5c3484
      DATA_SPACE ();
Packit 5c3484
      DATA_PUSH ();
Packit 5c3484
      sp = SP;
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
Packit 5c3484
      case 0:
Packit 5c3484
	(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
Packit 5c3484
	break;
Packit 5c3484
      default:
Packit 5c3484
	ERROR ("unrecognised 0ary argument calling style",
Packit 5c3484
	       MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
    }
Packit 5c3484
    break;
Packit 5c3484
Packit 5c3484
  case MPEXPR_TYPE_NARY(1):
Packit 5c3484
    {
Packit 5c3484
      mpX_ptr  sp = SP;
Packit 5c3484
      CHECK_ARGCOUNT ("unary", 1);
Packit 5c3484
      TRACE (MPX_TRACE ("before", sp));
Packit 5c3484
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
Packit 5c3484
      case 0:
Packit 5c3484
	/* not a special */
Packit 5c3484
	break;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special done\n"));
Packit 5c3484
	goto done;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special logical not\n"));
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	CONTROL_POP ();
Packit 5c3484
	if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
Packit 5c3484
	  {
Packit 5c3484
	    TRACE (printf ("close paren matching open paren\n"));
Packit 5c3484
	    CONTROL_POP ();
Packit 5c3484
	    goto another_operator;
Packit 5c3484
	  }
Packit 5c3484
	if (CP->op->precedence == 0)
Packit 5c3484
	  {
Packit 5c3484
	    TRACE (printf ("close paren for function\n"));
Packit 5c3484
	    goto apply_control;
Packit 5c3484
	  }
Packit 5c3484
	ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
      default:
Packit 5c3484
	TRACE (printf ("unrecognised special unary operator 0x%X",
Packit 5c3484
		       CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
Packit 5c3484
	ERROR ("", MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
Packit 5c3484
      case 0:
Packit 5c3484
	(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_LAST_UI:
Packit 5c3484
	CHECK_UI (sp);
Packit 5c3484
	(* (mpexpr_fun_unary_ui_t) CP->op->fun)
Packit 5c3484
	  (sp, (*p->mpX_get_ui) (sp));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
Packit 5c3484
	CHECK_UI (sp);
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
Packit 5c3484
	   ((*p->mpX_get_ui) (sp)));
Packit 5c3484
	break;
Packit 5c3484
      default:
Packit 5c3484
	ERROR ("unrecognised unary argument calling style",
Packit 5c3484
	       MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
    }
Packit 5c3484
    break;
Packit 5c3484
Packit 5c3484
  case MPEXPR_TYPE_NARY(2):
Packit 5c3484
    {
Packit 5c3484
      mpX_ptr  sp;
Packit 5c3484
Packit 5c3484
      /* pairwise functions are allowed to have just one argument */
Packit 5c3484
      if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
Packit 5c3484
	  && CP->op->precedence == 0
Packit 5c3484
	  && CP->argcount == 1)
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      CHECK_ARGCOUNT ("binary", 2);
Packit 5c3484
      DATA_POP (1);
Packit 5c3484
      sp = SP;
Packit 5c3484
      TRACE (MPX_TRACE ("lhs", sp);
Packit 5c3484
	     MPX_TRACE ("rhs", sp+1));
Packit 5c3484
Packit 5c3484
      if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
Packit 5c3484
	{
Packit 5c3484
	  int  type = CP->op->type;
Packit 5c3484
	  int  cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
Packit 5c3484
	    (sp, sp+1);
Packit 5c3484
	  (*p->mpX_set_si)
Packit 5c3484
	    (sp,
Packit 5c3484
	     (long)
Packit 5c3484
	     ((  (cmp  < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
Packit 5c3484
	      | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
Packit 5c3484
	      | ((cmp  > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
Packit 5c3484
	  goto apply_control_done;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
Packit 5c3484
      case 0:
Packit 5c3484
	/* not a special */
Packit 5c3484
	break;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special colon\n"));
Packit 5c3484
	CONTROL_POP ();
Packit 5c3484
	if (CP->op->type != MPEXPR_TYPE_QUESTION)
Packit 5c3484
	  ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
Packit 5c3484
	CP->argcount--;
Packit 5c3484
	DATA_POP (1);
Packit 5c3484
	sp--;
Packit 5c3484
	TRACE (MPX_TRACE ("query", sp);
Packit 5c3484
	       MPX_TRACE ("true",  sp+1);
Packit 5c3484
	       MPX_TRACE ("false", sp+2));
Packit 5c3484
	(*p->mpX_set)
Packit 5c3484
	  (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
Packit 5c3484
	   ? sp+1 : sp+2);
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special logical and\n"));
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long)
Packit 5c3484
	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
Packit 5c3484
	    && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special logical and\n"));
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long)
Packit 5c3484
	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
Packit 5c3484
	    || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special max\n"));
Packit 5c3484
	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
Packit 5c3484
	  (*p->mpX_swap) (sp, sp+1);
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
      case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
Packit 5c3484
	TRACE (printf ("special min\n"));
Packit 5c3484
	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
Packit 5c3484
	  (*p->mpX_swap) (sp, sp+1);
Packit 5c3484
	goto apply_control_done;
Packit 5c3484
Packit 5c3484
      default:
Packit 5c3484
	ERROR ("unrecognised special binary operator",
Packit 5c3484
	       MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
Packit 5c3484
      case 0:
Packit 5c3484
	(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_LAST_UI:
Packit 5c3484
	CHECK_UI (sp+1);
Packit 5c3484
	(* (mpexpr_fun_binary_ui_t) CP->op->fun)
Packit 5c3484
	  (sp, sp, (*p->mpX_get_ui) (sp+1));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	CHECK_UI (sp+1);
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
Packit 5c3484
	   (sp, (*p->mpX_get_ui) (sp+1)));
Packit 5c3484
	break;
Packit 5c3484
      default:
Packit 5c3484
	ERROR ("unrecognised binary argument calling style",
Packit 5c3484
	       MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
    }
Packit 5c3484
    break;
Packit 5c3484
Packit 5c3484
  case MPEXPR_TYPE_NARY(3):
Packit 5c3484
    {
Packit 5c3484
      mpX_ptr  sp;
Packit 5c3484
Packit 5c3484
      CHECK_ARGCOUNT ("ternary", 3);
Packit 5c3484
      DATA_POP (2);
Packit 5c3484
      sp = SP;
Packit 5c3484
      TRACE (MPX_TRACE ("arg1", sp);
Packit 5c3484
	     MPX_TRACE ("arg2", sp+1);
Packit 5c3484
	     MPX_TRACE ("arg3", sp+1));
Packit 5c3484
Packit 5c3484
      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
Packit 5c3484
      case 0:
Packit 5c3484
	(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_LAST_UI:
Packit 5c3484
	CHECK_UI (sp+2);
Packit 5c3484
	(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
Packit 5c3484
	  (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
Packit 5c3484
	   (sp, sp+1, sp+2));
Packit 5c3484
	break;
Packit 5c3484
      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
Packit 5c3484
	CHECK_UI (sp+2);
Packit 5c3484
	(*p->mpX_set_si)
Packit 5c3484
	  (sp,
Packit 5c3484
	   (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
Packit 5c3484
	   (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
Packit 5c3484
	break;
Packit 5c3484
      default:
Packit 5c3484
	ERROR ("unrecognised binary argument calling style",
Packit 5c3484
	       MPEXPR_RESULT_BAD_TABLE);
Packit 5c3484
      }
Packit 5c3484
    }
Packit 5c3484
    break;
Packit 5c3484
Packit 5c3484
  default:
Packit 5c3484
    TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
Packit 5c3484
    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
 apply_control_done:
Packit 5c3484
  TRACE (MPX_TRACE ("result", SP));
Packit 5c3484
  CONTROL_POP ();
Packit 5c3484
  goto another_operator;
Packit 5c3484
Packit 5c3484
 done:
Packit 5c3484
  if (p->error_code == MPEXPR_RESULT_OK)
Packit 5c3484
    {
Packit 5c3484
      if (p->data_top != 0)
Packit 5c3484
	{
Packit 5c3484
	  TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
Packit 5c3484
	  p->error_code = MPEXPR_RESULT_PARSE_ERROR;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	(*p->mpX_set_or_swap) (p->res, SP);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  {
Packit 5c3484
    int  i;
Packit 5c3484
    for (i = 0; i < p->data_inited; i++)
Packit 5c3484
      {
Packit 5c3484
	TRACE (printf ("clear %d\n", i));
Packit 5c3484
	(*p->mpX_clear) (p->data_stack+i);
Packit 5c3484
      }
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
  FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
Packit 5c3484
  FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
Packit 5c3484
Packit 5c3484
  return p->error_code;
Packit 5c3484
}