m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

FYI: 16-gary-refactor-eval-mpeval-and-gmp.patch


From: Gary V. Vaughan
Subject: FYI: 16-gary-refactor-eval-mpeval-and-gmp.patch
Date: Thu, 20 Sep 2001 23:12:47 +0100
User-agent: Mutt/1.3.22.1i

This doesn't address some of the outstanding issues I raised in the
GMP thread earlier... but finishes the refactoring and file
reorganisation I started with my 2000-11-29 changes to (then)
evalmp.c, numb.c and numb.h.

I believe I have addressed the following comments (from the sources)
too:

-   FIXME: it makes no sense to me, since anyway both `modules' own
-   their copy of `m4_do_eval': why don't we just also use a macro for
-   that part instead of a function pointer? --akim.  */

Good call.  Infact there is no need to have a separate m4_do_eval and
m4_evaluate, so I combined these while I was at it.

-  /* FIXME: Huh?  What's these `if' and `return' doing here?  Makes no
-     sense to me. Furthermore, then what is the point of returning a
-     bool (m4_evaluate) if we just ignore it? --akim */

Dunno.  I'm dumb ;-)

The stupidities you observed were due to the incomplete factoring I
started last year (see ChangeLog for 2000-11-29).

Cheers,
        Gary.

Index: ChangeLog
from  Gary V. Vaughan  <address@hidden>

        * m4/evalparse.c: Moved to...
        * modules/evalparse.c:  ...here.  This code is shared between
        modules/mpeval.c and modules/m4.c, so there is no need to pollute
        the libm4 API with its details.  Moderately rewritten to interface
        into its clients more simply.
        * m4/eval.c: Deleted.  Migrated functionality to...
        * modules/m4.c: ...here.
        (builtin_eval):  Implemented in terms of the new interface style.
        * modules/mpeval.c (builtin_mpeval): Ditto.
        * m4/m4module.h: Removed references to the former m4/eval.c.
        * m4/Makefile.am (libm4_la_SOURCES):  Removed eval.c.
        (EXTRA_libm4_la_SOURCES): Deleted.
        * modules/Makefile.am (EXTRA_m4_la_SOURCES): Reference evalparse.c.
        (EXTRA_mpeval_la_SOURCES): Reference evalparse.c.

2001-09-20  Akim Demaille  <address@hidden>
Index: m4/Makefile.am
===================================================================
RCS file: /cvsroot/m4/m4/m4/Makefile.am,v
retrieving revision 1.11
diff -u -p -u -r1.11 Makefile.am
--- m4/Makefile.am 2001/09/06 20:13:12 1.11
+++ m4/Makefile.am 2001/09/20 21:53:39
@@ -36,10 +36,9 @@ EXTRA_HEADERS        = system-h.in gnu-obstack.
 EXTRA_DIST = $(EXTRA_HEADERS) obstack.c
 
 lib_LTLIBRARIES                = libm4.la
-libm4_la_SOURCES       = builtin.c debug.c error.c eval.c hash.c \
+libm4_la_SOURCES       = builtin.c debug.c error.c hash.c \
                          input.c ltdl.c macro.c module.c output.c \
                          path.c regex.c symtab.c utility.c
-EXTRA_libm4_la_SOURCES = evalparse.c
 libm4_la_LIBADD                = @LTLIBOBJS@ @LIBADD_DL@
 
 module.o module.lo: $(srcdir)/module.c pathconf.h
Index: m4/eval.c
===================================================================
RCS file: eval.c
diff -N eval.c
--- m4/eval.c Thu Sep 20 17:53:45 2001
+++ /dev/null   Sat Apr 14 20:46:23 2001
@@ -1,152 +0,0 @@
-/* GNU m4 -- A simple macro processor
-   Copyright 1995, 1998 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307  USA
-*/
-
-/* This file contains the functions to evaluate integer or multiple
- * precision expressions for the "eval" macro.
- */
-
-#if HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "m4private.h"
-
-/* number should be at least 32 bits.  */
-/* use GNU long long int if available */
-#if defined(SIZEOF_LONG_LONG_INT) && SIZEOF_LONG_LONG_INT > 0
-typedef long long int number;
-typedef unsigned long long int unumber;
-#else
-typedef long int number;
-typedef unsigned long int unumber;
-#endif
-
-#define int2numb(i) ((number)(i))
-#define numb2int(n) ((n))
-
-#define numb_set(ans,x) ((ans) = x)
-#define numb_set_si(ans,si) (*(ans) = int2numb(si))
-
-#define numb_init(x) x=((number)0)
-#define numb_fini(x)
-
-#define numb_decr(n) (n) -= 1
-
-#define numb_ZERO ((number)0)
-#define numb_ONE  ((number)1)
-
-#define numb_zerop(x)     ((x) == numb_ZERO)
-#define numb_positivep(x) ((x) >  numb_ZERO)
-#define numb_negativep(x) ((x) <  numb_ZERO)
-
-
-#define numb_eq(x,y) ((x) = ((x) == (y)))
-#define numb_ne(x,y) ((x) = ((x) != (y)))
-#define numb_lt(x,y) ((x) = ((x) <  (y)))
-#define numb_le(x,y) ((x) = ((x) <= (y)))
-#define numb_gt(x,y) ((x) = ((x) >  (y)))
-#define numb_ge(x,y) ((x) = ((x) >= (y)))
-
-#define numb_lnot(x)   ((x) = (! (x)))
-#define numb_lior(x,y) ((x) = ((x) || (y)))
-#define numb_land(x,y) ((x) = ((x) && (y)))
-
-#define numb_not(x)   (*(x) = int2numb(~numb2int(*(x))))
-#define numb_eor(x,y) (*(x) = int2numb(numb2int(*(x)) ^ numb2int(*(y))))
-#define numb_ior(x,y) (*(x) = int2numb(numb2int(*(x)) | numb2int(*(y))))
-#define numb_and(x,y) (*(x) = int2numb(numb2int(*(x)) & numb2int(*(y))))
-
-#define numb_plus(x,y)  ((x) = ((x) + (y)))
-#define numb_minus(x,y) ((x) = ((x) - (y)))
-#define numb_negate(x)  ((x) = (- (x)))
-
-#define numb_times(x,y)  ((x) = ((x) * (y)))
-#define numb_ratio(x,y)  ((x) = ((x) / ((y))))
-#define numb_divide(x,y) (*(x) = (*(x) / (*(y))))
-#define numb_modulo(x,y) (*(x) = (*(x) % *(y)))
-#define numb_invert(x)   ((x) = 1 / (x))
-
-#define numb_lshift(x,y) (*(x) = (*(x) << *(y)))
-#define numb_rshift(x,y) (*(x) = (*(x) >> *(y)))
-
-static void
-numb_initialise(void)
-{
-  ;
-}
-
-
-/* Digits for number to ascii conversions.  */
-static char const ntoa_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-
-
-/* The function ntoa () converts VALUE to a signed ascii representation in
-   radix RADIX.  */
-static const char *
-ntoa (number value, int radix)
-{
-  boolean negative;
-  unumber uvalue;
-  static char str[256];
-  register char *s = &str[sizeof str];
-
-  *--s = '\0';
-
-  if (value < 0)
-    {
-      negative = TRUE;
-      uvalue = (unumber) -value;
-    }
-  else
-    {
-      negative = FALSE;
-      uvalue = (unumber) value;
-    }
-
-  do
-    {
-      *--s = ntoa_digits[uvalue % radix];
-      uvalue /= radix;
-    }
-  while (uvalue > 0);
-
-  if (negative)
-    *--s = '-';
-  return s;
-}
-
-static void
-numb_obstack(struct obstack *obs, const number value,
-            const int radix, int min)
-{
-  const char *s = ntoa (value, radix);
-
-  if (*s == '-')
-    {
-      obstack_1grow (obs, '-');
-      min--;
-      s++;
-    }
-  for (min -= strlen (s); --min >= 0;)
-    obstack_1grow (obs, '0');
-
-  obstack_grow (obs, s, strlen (s));
-}
-
-#include "evalparse.c"
Index: m4/evalparse.c
===================================================================
RCS file: evalparse.c
diff -N evalparse.c
--- m4/evalparse.c Thu Sep 20 17:53:45 2001
+++ /dev/null   Sat Apr 14 20:46:23 2001
@@ -1,906 +0,0 @@
-/* GNU m4 -- A simple macro processor
-   Copyright 1989, 1990, 1991, 1992, 1993, 1994, 2001
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307  USA
-*/
-
-/* This file contains the functions to evaluate integer expressions
-   for the "eval" macro.  It is a little, fairly self-contained
-   module, with its own scanner, and a recursive descent parser.  The
-   only entry point is evaluate ().
-
-   It has been carefully written to be also used for the GMP module,
-   mpeval: any actual operation performed on numbers is abstracted by
-   a set of macro definitions.  For plain `eval', `number' is some
-   long int type, and `numb_*' manipulates those long ints, while when
-   using GMP, `number' is typedef'd to `mpq_t' (the arbritrary
-   precision fractional numbers type of GMP), and `numb_*' are mapped
-   to GMP functions.
-
-   There is only one entry point, `m4_do_eval', a single function for
-   both `eval' and `mpeval', but which is given a function pointer to
-   either `m4_evaluate' (for plain `eval'), and `m4_mp_evaluate' (for
-   GMP `mpeval').
-
-   This allows to factor the `user interface' of `eval' and `mpeval',
-   i.e., sanity checks on the input arguments.
-
-   FIXME: it makes no sense to me, since anyway both `modules' own
-   their copy of `m4_do_eval': why don't we just also use a macro for
-   that part instead of a function pointer? --akim.  */
-
-/* Evaluates token types.  */
-
-#include <ctype.h>
-
-typedef enum eval_token
-  {
-    ERROR,
-    PLUS, MINUS,
-    EXPONENT,
-    TIMES, DIVIDE, MODULO, RATIO,
-    EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
-    LSHIFT, RSHIFT,
-    LNOT, LAND, LOR,
-    NOT, AND, OR, XOR,
-    LEFTP, RIGHTP,
-    NUMBER, EOTEXT
-  }
-eval_token;
-
-/* Error types.  */
-
-typedef enum eval_error
-  {
-    NO_ERROR,
-    MISSING_RIGHT,
-    SYNTAX_ERROR,
-    UNKNOWN_INPUT,
-    EXCESS_INPUT,
-    DIVIDE_ZERO,
-    MODULO_ZERO
-  }
-eval_error;
-
-static eval_error logical_or_term   (eval_token, number *);
-static eval_error logical_and_term  (eval_token, number *);
-static eval_error or_term          (eval_token, number *);
-static eval_error xor_term         (eval_token, number *);
-static eval_error and_term         (eval_token, number *);
-static eval_error not_term         (eval_token, number *);
-static eval_error logical_not_term  (eval_token, number *);
-static eval_error cmp_term         (eval_token, number *);
-static eval_error shift_term       (eval_token, number *);
-static eval_error add_term         (eval_token, number *);
-static eval_error mult_term        (eval_token, number *);
-static eval_error exp_term         (eval_token, number *);
-static eval_error unary_term       (eval_token, number *);
-static eval_error simple_term      (eval_token, number *);
-static void      numb_pow          (number *x, const number *y);
-
-
-
-/* --- LEXICAL FUNCTIONS --- */
-
-/* Pointer to next character of input text.  */
-static const unsigned char *eval_text;
-
-/* Value of eval_text, from before last call of eval_lex ().  This is so we
-   can back up, if we have read too much.  */
-static const unsigned char *last_text;
-
-static void
-eval_init_lex (const unsigned char *text)
-{
-  eval_text = text;
-  last_text = NULL;
-}
-
-static void
-eval_undo (void)
-{
-  eval_text = last_text;
-}
-
-/* VAL is numerical value, if any.  */
-
-static eval_token
-eval_lex (number *val)
-{
-  while (isspace (*eval_text))
-    eval_text++;
-
-  last_text = eval_text;
-
-  if (*eval_text == '\0')
-    return EOTEXT;
-
-  if (isdigit (*eval_text))
-    {
-      int base, digit;
-
-      if (*eval_text == '0')
-       {
-         eval_text++;
-         switch (*eval_text)
-           {
-           case 'x':
-           case 'X':
-             base = 16;
-             eval_text++;
-             break;
-
-           case 'b':
-           case 'B':
-             base = 2;
-             eval_text++;
-             break;
-
-           case 'r':
-           case 'R':
-             base = 0;
-             eval_text++;
-             while (isdigit (*eval_text) && base <= 36)
-               base = 10 * base + *eval_text++ - '0';
-             if (base == 0 || base > 36 || *eval_text != ':')
-               return ERROR;
-             eval_text++;
-             break;
-
-           default:
-             base = 8;
-           }
-       }
-      else
-       base = 10;
-
-      numb_set_si(val,0);
-      for (; *eval_text; eval_text++)
-       {
-         if (isdigit (*eval_text))
-           digit = *eval_text - '0';
-         else if (islower (*eval_text))
-           digit = *eval_text - 'a' + 10;
-         else if (isupper (*eval_text))
-           digit = *eval_text - 'A' + 10;
-         else
-           break;
-
-         if (digit >= base)
-           break;
-
-         { /* (*val) = (*val) * base; */
-           number xbase;
-           numb_init(xbase);
-           numb_set_si(&xbase,base);
-           numb_times(*val,xbase);
-           numb_fini(xbase);
-         }
-         { /* (*val) = (*val) + digit; */
-           number xdigit;
-           numb_init(xdigit);
-           numb_set_si(&xdigit,digit);
-           numb_plus(*val,xdigit);
-           numb_fini(xdigit);
-         }
-       }
-      return NUMBER;
-    }
-
-  switch (*eval_text++)
-    {
-    case '+':
-      return PLUS;
-    case '-':
-      return MINUS;
-    case '*':
-      if (*eval_text == '*')
-       {
-         eval_text++;
-         return EXPONENT;
-       }
-      else
-       return TIMES;
-    case '/':
-      return DIVIDE;
-    case '%':
-      return MODULO;
-    case ':':
-      return RATIO;
-    case '=':
-      if (*eval_text == '=')
-       eval_text++;
-      return EQ;
-    case '!':
-      if (*eval_text == '=')
-       {
-         eval_text++;
-         return NOTEQ;
-       }
-      else
-       return LNOT;
-    case '>':
-      if (*eval_text == '=')
-       {
-         eval_text++;
-         return GTEQ;
-       }
-      else if (*eval_text == '>')
-       {
-         eval_text++;
-         return RSHIFT;
-       }
-      else
-       return GT;
-    case '<':
-      if (*eval_text == '=')
-       {
-         eval_text++;
-         return LSEQ;
-       }
-      else if (*eval_text == '<')
-       {
-         eval_text++;
-         return LSHIFT;
-       }
-      else
-       return LS;
-    case '^':
-      return XOR;
-    case '~':
-      return NOT;
-    case '&':
-      if (*eval_text == '&')
-       {
-         eval_text++;
-         return LAND;
-       }
-      else
-       return AND;
-    case '|':
-      if (*eval_text == '|')
-       {
-         eval_text++;
-         return LOR;
-       }
-      else
-       return OR;
-    case '(':
-      return LEFTP;
-    case ')':
-      return RIGHTP;
-    default:
-      return ERROR;
-    }
-}
-
-/* Main entry point, called from "eval".  */
-boolean
-m4_evaluate (struct obstack *obs, const char *expr, const int radix, int min)
-{
-  number val;
-  eval_token et;
-  eval_error err;
-
-  numb_initialise();
-  eval_init_lex (expr);
-
-  numb_init(val);
-  et = eval_lex (&val);
-  err = logical_or_term (et, &val);
-
-  if (err == NO_ERROR && *eval_text != '\0')
-    err = EXCESS_INPUT;
-
-  switch (err)
-    {
-    case NO_ERROR:
-      break;
-
-    case MISSING_RIGHT:
-      M4ERROR ((warning_status, 0,
-               _("Bad expression in eval (missing right parenthesis): %s"),
-               expr));
-      break;
-
-    case SYNTAX_ERROR:
-      M4ERROR ((warning_status, 0,
-               _("Bad expression in eval: %s"), expr));
-      break;
-
-    case UNKNOWN_INPUT:
-      M4ERROR ((warning_status, 0,
-               _("Bad expression in eval (bad input): %s"), expr));
-      break;
-
-    case EXCESS_INPUT:
-      M4ERROR ((warning_status, 0,
-               _("Bad expression in eval (excess input): %s"), expr));
-      break;
-
-    case DIVIDE_ZERO:
-      M4ERROR ((warning_status, 0,
-               _("Divide by zero in eval: %s"), expr));
-      break;
-
-    case MODULO_ZERO:
-      M4ERROR ((warning_status, 0,
-               _("Modulo by zero in eval: %s"), expr));
-      break;
-
-    default:
-      M4ERROR ((warning_status, 0,
-               _("INTERNAL ERROR: Bad error code in evaluate ()")));
-      abort ();
-    }
-
-  if (err == NO_ERROR)
-    numb_obstack(obs, val, radix, min);
-
-  numb_fini(val);
-  return (boolean) (err != NO_ERROR);
-}
-
-/* Recursive descent parser.  */
-static eval_error
-logical_or_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  if ((er = logical_and_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == LOR)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = logical_and_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_lior(*v1,v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-logical_and_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  if ((er = or_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == LAND)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = or_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_land(*v1,v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-or_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  if ((er = xor_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == OR)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = xor_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_ior(v1, (const number *)&v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-xor_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  if ((er = and_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == XOR)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = and_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_eor(v1, (const number *)&v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-and_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  if ((er = not_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == AND)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = not_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_and(v1, (const number *)&v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-not_term (eval_token et, number *v1)
-{
-  eval_error er;
-
-  if (et == NOT)
-    {
-      et = eval_lex (v1);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = not_term (et, v1)) != NO_ERROR)
-       return er;
-      numb_not(v1);
-    }
-  else
-    if ((er = logical_not_term (et, v1)) != NO_ERROR)
-      return er;
-
-  return NO_ERROR;
-}
-
-static eval_error
-logical_not_term (eval_token et, number *v1)
-{
-  eval_error er;
-
-  if (et == LNOT)
-    {
-      et = eval_lex (v1);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = logical_not_term (et, v1)) != NO_ERROR)
-       return er;
-      numb_lnot(*v1);
-    }
-  else
-    if ((er = cmp_term (et, v1)) != NO_ERROR)
-      return er;
-
-  return NO_ERROR;
-}
-
-static eval_error
-cmp_term (eval_token et, number *v1)
-{
-  eval_token op;
-  number v2;
-  eval_error er;
-
-  if ((er = shift_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ
-        || op == GT || op == GTEQ
-        || op == LS || op == LSEQ)
-    {
-
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = shift_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      switch (op)
-       {
-       case EQ:
-         numb_eq(*v1,v2);
-         break;
-
-       case NOTEQ:
-         numb_ne(*v1,v2);
-         break;
-
-       case GT:
-         numb_gt(*v1,v2);
-         break;
-
-       case GTEQ:
-         numb_ge(*v1,v2);
-         break;
-
-       case LS:
-         numb_lt(*v1,v2);
-         break;
-
-       case LSEQ:
-         numb_le(*v1,v2);
-         break;
-
-       default:
-         M4ERROR ((warning_status, 0, _("\
-INTERNAL ERROR: Bad comparison operator in cmp_term ()")));
-         abort ();
-       }
-    }
-  numb_fini(v2);
-  if (op == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-shift_term (eval_token et, number *v1)
-{
-  eval_token op;
-  number v2;
-  eval_error er;
-
-  if ((er = add_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT)
-    {
-
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = add_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      switch (op)
-       {
-       case LSHIFT:
-         numb_lshift(v1, (const number *)&v2);
-         break;
-
-       case RSHIFT:
-         numb_rshift(v1, (const number *)&v2);
-         break;
-
-       default:
-         M4ERROR ((warning_status, 0, _("\
-INTERNAL ERROR: Bad shift operator in shift_term ()")));
-         abort ();
-       }
-    }
-  numb_fini(v2);
-  if (op == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-add_term (eval_token et, number *v1)
-{
-  eval_token op;
-  number v2;
-  eval_error er;
-
-  if ((er = mult_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((op = eval_lex (&v2)) == PLUS || op == MINUS)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = mult_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      if (op == PLUS) {
-       numb_plus(*v1,v2);
-      } else {
-       numb_minus(*v1,v2);
-      }
-    }
-  numb_fini(v2);
-  if (op == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-mult_term (eval_token et, number *v1)
-{
-  eval_token op;
-  number v2;
-  eval_error er;
-
-  if ((er = exp_term (et, v1)) != NO_ERROR)
-    return er;
-
-  numb_init(v2);
-  while ((op = eval_lex (&v2)) == TIMES || op == DIVIDE || op == MODULO || op 
== RATIO)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = exp_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      switch (op)
-       {
-       case TIMES:
-         numb_times(*v1,v2);
-         break;
-
-       case DIVIDE:
-         if (numb_zerop(v2))
-           return DIVIDE_ZERO;
-         else {
-           numb_divide(v1, (const number *)&v2);
-         }
-         break;
-
-       case RATIO:
-         if (numb_zerop(v2))
-           return DIVIDE_ZERO;
-         else {
-           numb_ratio(*v1,v2);
-         }
-         break;
-
-       case MODULO:
-         if (numb_zerop(v2))
-           return MODULO_ZERO;
-         else {
-           numb_modulo(v1, (const number *)&v2);
-         }
-         break;
-
-       default:
-         M4ERROR ((warning_status, 0,
-                   _("INTERNAL ERROR: Bad operator in mult_term ()")));
-         abort ();
-       }
-    }
-  numb_fini(v2);
-  if (op == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-exp_term (eval_token et, number *v1)
-{
-  number result;
-  number v2;
-  eval_error er;
-
-  if ((er = unary_term (et, v1)) != NO_ERROR)
-    return er;
-  memcpy(&result, v1, sizeof(number));
-
-  numb_init(v2);
-  while ((et = eval_lex (&v2)) == EXPONENT)
-    {
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = exp_term (et, &v2)) != NO_ERROR)
-       return er;
-
-      numb_pow(v1, (const number *)&v2);
-    }
-  numb_fini(v2);
-  if (et == ERROR)
-    return UNKNOWN_INPUT;
-
-  eval_undo ();
-  return NO_ERROR;
-}
-
-static eval_error
-unary_term (eval_token et, number *v1)
-{
-  eval_token et2 = et;
-  eval_error er;
-
-  if (et == PLUS || et == MINUS)
-    {
-      et2 = eval_lex (v1);
-      if (et2 == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = simple_term (et2, v1)) != NO_ERROR)
-       return er;
-
-      if (et == MINUS)
-       numb_negate(*v1);
-    }
-  else
-    if ((er = simple_term (et, v1)) != NO_ERROR)
-      return er;
-
-  return NO_ERROR;
-}
-
-static eval_error
-simple_term (eval_token et, number *v1)
-{
-  number v2;
-  eval_error er;
-
-  switch (et)
-    {
-    case LEFTP:
-      et = eval_lex (v1);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if ((er = logical_or_term (et, v1)) != NO_ERROR)
-       return er;
-
-      et = eval_lex (&v2);
-      if (et == ERROR)
-       return UNKNOWN_INPUT;
-
-      if (et != RIGHTP)
-       return MISSING_RIGHT;
-
-      break;
-
-    case NUMBER:
-      break;
-
-    default:
-      return SYNTAX_ERROR;
-    }
-  return NO_ERROR;
-}
-
-void
-m4_do_eval (struct obstack *obs,
-           int argc, m4_symbol **argv, m4_eval_func func)
-{
-  int radix = 10;
-  int min = 1;
-
-  if (m4_bad_argc (argv[0], argc, 2, 4))
-    return;
-
-  if (argc >= 3 && !m4_numeric_arg (argv[0], M4ARG (2), &radix))
-    return;
-
-  if (radix <= 1 || radix > 36)
-    {
-      M4ERROR ((warning_status, 0,
-               _("Radix in eval out of range (radix = %d)"), radix));
-      return;
-    }
-
-  if (argc >= 4 && !m4_numeric_arg (argv[0], M4ARG (3), &min))
-    return;
-  if (min <= 0)
-    {
-      M4ERROR ((warning_status, 0,
-               _("Negative width to eval")));
-      return;
-    }
-
-  /* FIXME: Huh?  What's these `if' and `return' doing here?  Makes no
-     sense to me. Furthermore, then what is the point of returning a
-     bool (m4_evaluate) if we just ignore it? --akim */
-  if ((*func) (obs, M4ARG (1), radix, min))
-    return;
-}
-
-static void
-numb_pow (number *x, const number *y)
-{
-  /* y should be integral */
-
-  number ans, yy;
-
-  numb_init(ans);
-  numb_set_si(&ans,1);
-
-  numb_init(yy);
-  numb_set(yy,*y);
-
-  if (numb_negativep(yy)) {
-    numb_invert(*x);
-    numb_negate(yy);
-  }
-
-  while (numb_positivep(yy)) {
-    numb_times(ans,*x);
-    numb_decr(yy);
-  }
-  numb_set(*x,ans);
-
-  numb_fini(ans);
-  numb_fini(yy);
-}
Index: m4/m4module.h
===================================================================
RCS file: /cvsroot/m4/m4/m4/m4module.h,v
retrieving revision 1.29
diff -u -p -u -r1.29 m4module.h
--- m4/m4module.h 2001/09/20 03:48:05 1.29
+++ m4/m4module.h 2001/09/20 21:53:40
@@ -452,17 +452,7 @@ extern int m4_dump_symbol (const char *n
 extern void m4_dump_symbols (struct m4_dump_symbol_data *data, int argc, 
m4_symbol **argv, boolean complain);
 
 
-
 
-/* --- EXPRESSION EVALUATION --- */
-
-typedef boolean (*m4_eval_func) (struct obstack *obs,
-                               const char *expr, const int radix, int min);
-
-extern boolean m4_evaluate (struct obstack *obs,
-                                     const char *, const int radix, int min);
-extern void m4_do_eval (struct obstack *obs, int argc, m4_symbol **argv, 
m4_eval_func func);
-
 #define obstack_chunk_alloc    xmalloc
 #define obstack_chunk_free     xfree
 
Index: modules/Makefile.am
===================================================================
RCS file: /cvsroot/m4/m4/modules/Makefile.am,v
retrieving revision 1.14
diff -u -p -u -r1.14 Makefile.am
--- modules/Makefile.am 2001/09/20 08:49:31 1.14
+++ modules/Makefile.am 2001/09/20 21:53:42
@@ -50,12 +50,14 @@ gnu_la_LDFLAGS = -module
 load_la_SOURCES = load.c
 load_la_LDFLAGS = -module
 
-m4_la_SOURCES = m4.c
-m4_la_LDFLAGS = -module
+m4_la_SOURCES          = m4.c
+EXTRA_m4_la_SOURCES    = evalparse.c
+m4_la_LDFLAGS          = -module
 
-mpeval_la_SOURCES = mpeval.c
-mpeval_la_LDFLAGS = -module
-mpeval_la_LIBADD = -lgmp
+mpeval_la_SOURCES      = mpeval.c
+EXTRA_mpeval_la_SOURCES        = evalparse.c
+mpeval_la_LDFLAGS      = -module
+mpeval_la_LIBADD       = -lgmp
 
 traditional_la_SOURCES = traditional.c
 traditional_la_LDFLAGS = -module
Index: modules/evalparse.c
===================================================================
RCS file: evalparse.c
diff -N evalparse.c
--- /dev/null   Sat Apr 14 20:46:23 2001
+++ modules/evalparse.c Thu Sep 20 17:53:42 2001
@@ -0,0 +1,884 @@
+/* GNU m4 -- A simple macro processor
+   Copyright 1989, 1990, 1991, 1992, 1993, 1994, 2001
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307  USA
+*/
+
+/* This file contains the functions to evaluate integer expressions
+   for the "eval" and "evalmp" builtins.  It is a little, fairly
+   self-contained module, with its own scanner, and a recursive descent
+   parser.
+
+   It has been carefully factored for use from the GMP module builtin,
+   mpeval: any actual operation performed on numbers is abstracted by
+   a set of macro definitions.  For plain `eval', `number' is some
+   long int type, and `numb_*' manipulate those long ints.  When
+   using GMP, `number' is typedef'd to `mpq_t' (the arbritrary
+   precision fractional numbers type of GMP), and `numb_*' are mapped
+   to GMP functions.
+
+   There is only one entry point, `m4_evaluate', a single function for
+   both `eval' and `mpeval', but which is redefined appropriately when
+   this file is #included into its clients.  */
+
+#include <ctype.h>
+
+typedef enum eval_token
+  {
+    ERROR,
+    PLUS, MINUS,
+    EXPONENT,
+    TIMES, DIVIDE, MODULO, RATIO,
+    EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
+    LSHIFT, RSHIFT,
+    LNOT, LAND, LOR,
+    NOT, AND, OR, XOR,
+    LEFTP, RIGHTP,
+    NUMBER, EOTEXT
+  }
+eval_token;
+
+/* Error types.  */
+
+typedef enum eval_error
+  {
+    NO_ERROR,
+    MISSING_RIGHT,
+    SYNTAX_ERROR,
+    UNKNOWN_INPUT,
+    EXCESS_INPUT,
+    DIVIDE_ZERO,
+    MODULO_ZERO
+  }
+eval_error;
+
+static eval_error logical_or_term   (eval_token, number *);
+static eval_error logical_and_term  (eval_token, number *);
+static eval_error or_term          (eval_token, number *);
+static eval_error xor_term         (eval_token, number *);
+static eval_error and_term         (eval_token, number *);
+static eval_error not_term         (eval_token, number *);
+static eval_error logical_not_term  (eval_token, number *);
+static eval_error cmp_term         (eval_token, number *);
+static eval_error shift_term       (eval_token, number *);
+static eval_error add_term         (eval_token, number *);
+static eval_error mult_term        (eval_token, number *);
+static eval_error exp_term         (eval_token, number *);
+static eval_error unary_term       (eval_token, number *);
+static eval_error simple_term      (eval_token, number *);
+static void      numb_pow          (number *x, const number *y);
+
+
+
+/* --- LEXICAL FUNCTIONS --- */
+
+/* Pointer to next character of input text.  */
+static const unsigned char *eval_text;
+
+/* Value of eval_text, from before last call of eval_lex ().  This is so we
+   can back up, if we have read too much.  */
+static const unsigned char *last_text;
+
+static void
+eval_init_lex (const unsigned char *text)
+{
+  eval_text = text;
+  last_text = NULL;
+}
+
+static void
+eval_undo (void)
+{
+  eval_text = last_text;
+}
+
+/* VAL is numerical value, if any.  */
+
+static eval_token
+eval_lex (number *val)
+{
+  while (isspace (*eval_text))
+    eval_text++;
+
+  last_text = eval_text;
+
+  if (*eval_text == '\0')
+    return EOTEXT;
+
+  if (isdigit (*eval_text))
+    {
+      int base, digit;
+
+      if (*eval_text == '0')
+       {
+         eval_text++;
+         switch (*eval_text)
+           {
+           case 'x':
+           case 'X':
+             base = 16;
+             eval_text++;
+             break;
+
+           case 'b':
+           case 'B':
+             base = 2;
+             eval_text++;
+             break;
+
+           case 'r':
+           case 'R':
+             base = 0;
+             eval_text++;
+             while (isdigit (*eval_text) && base <= 36)
+               base = 10 * base + *eval_text++ - '0';
+             if (base == 0 || base > 36 || *eval_text != ':')
+               return ERROR;
+             eval_text++;
+             break;
+
+           default:
+             base = 8;
+           }
+       }
+      else
+       base = 10;
+
+      numb_set_si(val,0);
+      for (; *eval_text; eval_text++)
+       {
+         if (isdigit (*eval_text))
+           digit = *eval_text - '0';
+         else if (islower (*eval_text))
+           digit = *eval_text - 'a' + 10;
+         else if (isupper (*eval_text))
+           digit = *eval_text - 'A' + 10;
+         else
+           break;
+
+         if (digit >= base)
+           break;
+
+         { /* (*val) = (*val) * base; */
+           number xbase;
+           numb_init(xbase);
+           numb_set_si(&xbase,base);
+           numb_times(*val,xbase);
+           numb_fini(xbase);
+         }
+         { /* (*val) = (*val) + digit; */
+           number xdigit;
+           numb_init(xdigit);
+           numb_set_si(&xdigit,digit);
+           numb_plus(*val,xdigit);
+           numb_fini(xdigit);
+         }
+       }
+      return NUMBER;
+    }
+
+  switch (*eval_text++)
+    {
+    case '+':
+      return PLUS;
+    case '-':
+      return MINUS;
+    case '*':
+      if (*eval_text == '*')
+       {
+         eval_text++;
+         return EXPONENT;
+       }
+      else
+       return TIMES;
+    case '/':
+      return DIVIDE;
+    case '%':
+      return MODULO;
+    case ':':
+      return RATIO;
+    case '=':
+      if (*eval_text == '=')
+       eval_text++;
+      return EQ;
+    case '!':
+      if (*eval_text == '=')
+       {
+         eval_text++;
+         return NOTEQ;
+       }
+      else
+       return LNOT;
+    case '>':
+      if (*eval_text == '=')
+       {
+         eval_text++;
+         return GTEQ;
+       }
+      else if (*eval_text == '>')
+       {
+         eval_text++;
+         return RSHIFT;
+       }
+      else
+       return GT;
+    case '<':
+      if (*eval_text == '=')
+       {
+         eval_text++;
+         return LSEQ;
+       }
+      else if (*eval_text == '<')
+       {
+         eval_text++;
+         return LSHIFT;
+       }
+      else
+       return LS;
+    case '^':
+      return XOR;
+    case '~':
+      return NOT;
+    case '&':
+      if (*eval_text == '&')
+       {
+         eval_text++;
+         return LAND;
+       }
+      else
+       return AND;
+    case '|':
+      if (*eval_text == '|')
+       {
+         eval_text++;
+         return LOR;
+       }
+      else
+       return OR;
+    case '(':
+      return LEFTP;
+    case ')':
+      return RIGHTP;
+    default:
+      return ERROR;
+    }
+}
+
+/* Recursive descent parser.  */
+static eval_error
+logical_or_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = logical_and_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == LOR)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = logical_and_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_lior(*v1,v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+logical_and_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = or_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == LAND)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = or_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_land(*v1,v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+or_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = xor_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == OR)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = xor_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_ior(v1, (const number *)&v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+xor_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = and_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == XOR)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = and_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_eor(v1, (const number *)&v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+and_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = not_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == AND)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = not_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_and(v1, (const number *)&v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+not_term (eval_token et, number *v1)
+{
+  eval_error er;
+
+  if (et == NOT)
+    {
+      et = eval_lex (v1);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = not_term (et, v1)) != NO_ERROR)
+       return er;
+      numb_not(v1);
+    }
+  else
+    if ((er = logical_not_term (et, v1)) != NO_ERROR)
+      return er;
+
+  return NO_ERROR;
+}
+
+static eval_error
+logical_not_term (eval_token et, number *v1)
+{
+  eval_error er;
+
+  if (et == LNOT)
+    {
+      et = eval_lex (v1);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = logical_not_term (et, v1)) != NO_ERROR)
+       return er;
+      numb_lnot(*v1);
+    }
+  else
+    if ((er = cmp_term (et, v1)) != NO_ERROR)
+      return er;
+
+  return NO_ERROR;
+}
+
+static eval_error
+cmp_term (eval_token et, number *v1)
+{
+  eval_token op;
+  number v2;
+  eval_error er;
+
+  if ((er = shift_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ
+        || op == GT || op == GTEQ
+        || op == LS || op == LSEQ)
+    {
+
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = shift_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      switch (op)
+       {
+       case EQ:
+         numb_eq(*v1,v2);
+         break;
+
+       case NOTEQ:
+         numb_ne(*v1,v2);
+         break;
+
+       case GT:
+         numb_gt(*v1,v2);
+         break;
+
+       case GTEQ:
+         numb_ge(*v1,v2);
+         break;
+
+       case LS:
+         numb_lt(*v1,v2);
+         break;
+
+       case LSEQ:
+         numb_le(*v1,v2);
+         break;
+
+       default:
+         M4ERROR ((warning_status, 0, _("\
+INTERNAL ERROR: Bad comparison operator in cmp_term ()")));
+         abort ();
+       }
+    }
+  numb_fini(v2);
+  if (op == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+shift_term (eval_token et, number *v1)
+{
+  eval_token op;
+  number v2;
+  eval_error er;
+
+  if ((er = add_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT)
+    {
+
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = add_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      switch (op)
+       {
+       case LSHIFT:
+         numb_lshift(v1, (const number *)&v2);
+         break;
+
+       case RSHIFT:
+         numb_rshift(v1, (const number *)&v2);
+         break;
+
+       default:
+         M4ERROR ((warning_status, 0, _("\
+INTERNAL ERROR: Bad shift operator in shift_term ()")));
+         abort ();
+       }
+    }
+  numb_fini(v2);
+  if (op == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+add_term (eval_token et, number *v1)
+{
+  eval_token op;
+  number v2;
+  eval_error er;
+
+  if ((er = mult_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((op = eval_lex (&v2)) == PLUS || op == MINUS)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = mult_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      if (op == PLUS) {
+       numb_plus(*v1,v2);
+      } else {
+       numb_minus(*v1,v2);
+      }
+    }
+  numb_fini(v2);
+  if (op == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+mult_term (eval_token et, number *v1)
+{
+  eval_token op;
+  number v2;
+  eval_error er;
+
+  if ((er = exp_term (et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init(v2);
+  while ((op = eval_lex (&v2)) == TIMES || op == DIVIDE || op == MODULO || op 
== RATIO)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = exp_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      switch (op)
+       {
+       case TIMES:
+         numb_times(*v1,v2);
+         break;
+
+       case DIVIDE:
+         if (numb_zerop(v2))
+           return DIVIDE_ZERO;
+         else {
+           numb_divide(v1, (const number *)&v2);
+         }
+         break;
+
+       case RATIO:
+         if (numb_zerop(v2))
+           return DIVIDE_ZERO;
+         else {
+           numb_ratio(*v1,v2);
+         }
+         break;
+
+       case MODULO:
+         if (numb_zerop(v2))
+           return MODULO_ZERO;
+         else {
+           numb_modulo(v1, (const number *)&v2);
+         }
+         break;
+
+       default:
+         M4ERROR ((warning_status, 0,
+                   _("INTERNAL ERROR: Bad operator in mult_term ()")));
+         abort ();
+       }
+    }
+  numb_fini(v2);
+  if (op == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+exp_term (eval_token et, number *v1)
+{
+  number result;
+  number v2;
+  eval_error er;
+
+  if ((er = unary_term (et, v1)) != NO_ERROR)
+    return er;
+  memcpy(&result, v1, sizeof(number));
+
+  numb_init(v2);
+  while ((et = eval_lex (&v2)) == EXPONENT)
+    {
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = exp_term (et, &v2)) != NO_ERROR)
+       return er;
+
+      numb_pow(v1, (const number *)&v2);
+    }
+  numb_fini(v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+unary_term (eval_token et, number *v1)
+{
+  eval_token et2 = et;
+  eval_error er;
+
+  if (et == PLUS || et == MINUS)
+    {
+      et2 = eval_lex (v1);
+      if (et2 == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = simple_term (et2, v1)) != NO_ERROR)
+       return er;
+
+      if (et == MINUS)
+       numb_negate(*v1);
+    }
+  else
+    if ((er = simple_term (et, v1)) != NO_ERROR)
+      return er;
+
+  return NO_ERROR;
+}
+
+static eval_error
+simple_term (eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  switch (et)
+    {
+    case LEFTP:
+      et = eval_lex (v1);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = logical_or_term (et, v1)) != NO_ERROR)
+       return er;
+
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if (et != RIGHTP)
+       return MISSING_RIGHT;
+
+      break;
+
+    case NUMBER:
+      break;
+
+    default:
+      return SYNTAX_ERROR;
+    }
+  return NO_ERROR;
+}
+
+/* Main entry point, called from "eval" and "mpeval" builtins.  */
+void
+m4_evaluate (struct obstack *obs, int argc, m4_symbol **argv)
+{
+  int          radix   = 10;
+  int          min     = 1;
+  number       val;
+  eval_token   et;
+  eval_error   err;
+
+  if (m4_bad_argc (argv[0], argc, 2, 4))
+    return;
+
+  if (argc >= 3 && !m4_numeric_arg (argv[0], M4ARG (2), &radix))
+    return;
+
+  if (radix <= 1 || radix > 36)
+    {
+      M4ERROR ((warning_status, 0,
+               _("Radix in eval out of range (radix = %d)"), radix));
+      return;
+    }
+
+  if (argc >= 4 && !m4_numeric_arg (argv[0], M4ARG (3), &min))
+    return;
+
+  if (min <= 0)
+    {
+      M4ERROR ((warning_status, 0,
+               _("Negative width to eval")));
+      return;
+    }
+
+  numb_initialise ();
+  eval_init_lex (M4ARG (1));
+
+  numb_init(val);
+  et = eval_lex (&val);
+  err = logical_or_term (et, &val);
+
+  if (err == NO_ERROR && *eval_text != '\0')
+    err = EXCESS_INPUT;
+
+  switch (err)
+    {
+    case NO_ERROR:
+      break;
+
+    case MISSING_RIGHT:
+      M4ERROR ((warning_status, 0,
+               _("Bad expression in eval (missing right parenthesis): %s"),
+               M4ARG (1)));
+      break;
+
+    case SYNTAX_ERROR:
+      M4ERROR ((warning_status, 0,
+               _("Bad expression in eval: %s"), M4ARG (1)));
+      break;
+
+    case UNKNOWN_INPUT:
+      M4ERROR ((warning_status, 0,
+               _("Bad expression in eval (bad input): %s"), M4ARG (1)));
+      break;
+
+    case EXCESS_INPUT:
+      M4ERROR ((warning_status, 0,
+               _("Bad expression in eval (excess input): %s"), M4ARG (1)));
+      break;
+
+    case DIVIDE_ZERO:
+      M4ERROR ((warning_status, 0,
+               _("Divide by zero in eval: %s"), M4ARG (1)));
+      break;
+
+    case MODULO_ZERO:
+      M4ERROR ((warning_status, 0,
+               _("Modulo by zero in eval: %s"), M4ARG (1)));
+      break;
+
+    default:
+      M4ERROR ((warning_status, 0,
+               _("INTERNAL ERROR: Bad error code in evaluate ()")));
+      abort ();
+    }
+
+  if (err == NO_ERROR)
+    numb_obstack(obs, val, radix, min);
+
+  numb_fini(val);
+}
+
+static void
+numb_pow (number *x, const number *y)
+{
+  /* y should be integral */
+
+  number ans, yy;
+
+  numb_init(ans);
+  numb_set_si(&ans,1);
+
+  numb_init(yy);
+  numb_set(yy,*y);
+
+  if (numb_negativep(yy)) {
+    numb_invert(*x);
+    numb_negate(yy);
+  }
+
+  while (numb_positivep(yy)) {
+    numb_times(ans,*x);
+    numb_decr(yy);
+  }
+  numb_set(*x,ans);
+
+  numb_fini(ans);
+  numb_fini(yy);
+}
Index: modules/m4.c
===================================================================
RCS file: /cvsroot/m4/m4/modules/m4.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 m4.c
--- modules/m4.c 2001/09/20 03:48:05 1.22
+++ modules/m4.c 2001/09/20 21:53:45
@@ -81,6 +81,25 @@ extern int errno;
        BUILTIN(undefine,       FALSE,  TRUE  ) \
        BUILTIN(undivert,       FALSE,  FALSE )
 
+
+#if defined(SIZEOF_LONG_LONG_INT) && SIZEOF_LONG_LONG_INT > 0
+/* Use GNU long long int if available.  */
+typedef long long int number;
+typedef unsigned long long int unumber;
+#else
+typedef long int number;
+typedef unsigned long int unumber;
+#endif
+
+
+static void    include         (int argc, m4_symbol **argv, boolean silent);
+static int     set_trace       (const char *name, m4_symbol *symbol,
+                                void *data);
+static const char *ntoa                (number value, int radix);
+static void    numb_obstack    (struct obstack *obs, const number value,
+                                const int radix, int min);
+
+
 /* Generate prototypes for each builtin handler function. */
 #define BUILTIN(handler, macros,  blind)       M4BUILTIN(handler)
   builtin_functions
@@ -403,14 +422,6 @@ M4BUILTIN_HANDLER (sysval)
 }
 
 
-/* This section contains the top level code for the "eval" builtin.  The
-   actual work is done in the function m4_evaluate (), which lives in
-   eval.c.  */
-M4BUILTIN_HANDLER (eval)
-{
-  m4_do_eval(obs, argc, argv, m4_evaluate);
-}
-
 M4BUILTIN_HANDLER (incr)
 {
   int value;
@@ -647,9 +658,6 @@ M4BUILTIN_HANDLER (m4wrap)
    tracing of a macro.  It disables tracing if DATA is NULL, otherwise it
    enable tracing.  */
 static int
-set_trace (const char *name, m4_symbol *symbol, void *data);
-
-static int
 set_trace (const char *name, m4_symbol *symbol, void *data)
 {
   M4_SYMBOL_TRACED (symbol) = (boolean) (data != NULL);
@@ -811,3 +819,125 @@ M4BUILTIN_HANDLER (translit)
        }
     }
 }
+
+
+
+/* The rest of this  file contains the functions to evaluate integer
+ * expressions for the "eval" macro.  `number' should be at least 32 bits.
+ */
+#define int2numb(i) ((number)(i))
+#define numb2int(n) ((n))
+
+#define numb_set(ans,x) ((ans) = x)
+#define numb_set_si(ans,si) (*(ans) = int2numb(si))
+
+#define numb_init(x) x=((number)0)
+#define numb_fini(x)
+
+#define numb_decr(n) (n) -= 1
+
+#define numb_ZERO ((number)0)
+#define numb_ONE  ((number)1)
+
+#define numb_zerop(x)     ((x) == numb_ZERO)
+#define numb_positivep(x) ((x) >  numb_ZERO)
+#define numb_negativep(x) ((x) <  numb_ZERO)
+
+#define numb_eq(x,y) ((x) = ((x) == (y)))
+#define numb_ne(x,y) ((x) = ((x) != (y)))
+#define numb_lt(x,y) ((x) = ((x) <  (y)))
+#define numb_le(x,y) ((x) = ((x) <= (y)))
+#define numb_gt(x,y) ((x) = ((x) >  (y)))
+#define numb_ge(x,y) ((x) = ((x) >= (y)))
+
+#define numb_lnot(x)   ((x) = (! (x)))
+#define numb_lior(x,y) ((x) = ((x) || (y)))
+#define numb_land(x,y) ((x) = ((x) && (y)))
+
+#define numb_not(x)   (*(x) = int2numb(~numb2int(*(x))))
+#define numb_eor(x,y) (*(x) = int2numb(numb2int(*(x)) ^ numb2int(*(y))))
+#define numb_ior(x,y) (*(x) = int2numb(numb2int(*(x)) | numb2int(*(y))))
+#define numb_and(x,y) (*(x) = int2numb(numb2int(*(x)) & numb2int(*(y))))
+
+#define numb_plus(x,y)  ((x) = ((x) + (y)))
+#define numb_minus(x,y) ((x) = ((x) - (y)))
+#define numb_negate(x)  ((x) = (- (x)))
+
+#define numb_times(x,y)  ((x) = ((x) * (y)))
+#define numb_ratio(x,y)  ((x) = ((x) / ((y))))
+#define numb_divide(x,y) (*(x) = (*(x) / (*(y))))
+#define numb_modulo(x,y) (*(x) = (*(x) % *(y)))
+#define numb_invert(x)   ((x) = 1 / (x))
+
+#define numb_lshift(x,y) (*(x) = (*(x) << *(y)))
+#define numb_rshift(x,y) (*(x) = (*(x) >> *(y)))
+
+
+/* The function ntoa () converts VALUE to a signed ascii representation in
+   radix RADIX.  */
+static const char *
+ntoa (number value, int radix)
+{
+  /* Digits for number to ascii conversions.  */
+  static char const ntoa_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+  boolean negative;
+  unumber uvalue;
+  static char str[256];
+  char *s = &str[sizeof str];
+
+  *--s = '\0';
+
+  if (value < 0)
+    {
+      negative = TRUE;
+      uvalue = (unumber) -value;
+    }
+  else
+    {
+      negative = FALSE;
+      uvalue = (unumber) value;
+    }
+
+  do
+    {
+      *--s = ntoa_digits[uvalue % radix];
+      uvalue /= radix;
+    }
+  while (uvalue > 0);
+
+  if (negative)
+    *--s = '-';
+  return s;
+}
+
+static void
+numb_obstack(struct obstack *obs, const number value,
+            const int radix, int min)
+{
+  const char *s = ntoa (value, radix);
+
+  if (*s == '-')
+    {
+      obstack_1grow (obs, '-');
+      min--;
+      s++;
+    }
+  for (min -= strlen (s); --min >= 0;)
+    obstack_1grow (obs, '0');
+
+  obstack_grow (obs, s, strlen (s));
+}
+
+
+static void
+numb_initialise (void)
+{
+  ;
+}
+
+/* This macro defines the top level code for the "eval" builtin.  The
+   actual work is done in the function m4_evaluate (), which lives in
+   evalparse.c.  */
+#define m4_evaluate    builtin_eval
+#include "evalparse.c"
Index: modules/mpeval.c
===================================================================
RCS file: /cvsroot/m4/m4/modules/mpeval.c,v
retrieving revision 1.7
diff -u -p -u -r1.7 mpeval.c
--- modules/mpeval.c 2001/09/20 08:49:31 1.7
+++ modules/mpeval.c 2001/09/20 21:53:45
@@ -105,8 +105,6 @@ m4_macro m4_macro_table[] =
 /* number should be at least 32 bits.  */
 typedef mpq_t number;
 
-extern boolean m4_mp_evaluate (struct obstack *obs, const char *,
-                              const int radix, int min);
 static void numb_initialise (void);
 static void numb_obstack (struct obstack *obs, const number value,
                          const int radix, int min);
@@ -122,16 +120,6 @@ static void numb_lshift (number *x, cons
 static void numb_rshift (number *x, const number *y);
 
 
-
-/**
- * mpeval(EXPRESSION)
- **/
-M4BUILTIN_HANDLER (mpeval)
-{
-  m4_do_eval (obs, argc, argv, m4_mp_evaluate);
-}
-
-
 static number numb_ZERO;
 static number numb_ONE;
 
@@ -413,7 +401,8 @@ numb_rshift (number * x, const number * 
   mpq2mpz (yy, *y, NOISY);
 
   mpz_init (res);
-  {                            /* bug: need to determine if y is too big or 
negative */
+  {
+    /* FIXME: bug - need to determine if y is too big or negative */
     long int exp = mpz_get_si (yy);
     if (exp >= 0)
       {
@@ -432,5 +421,5 @@ numb_rshift (number * x, const number * 
   mpz_clear (res);
 }
 
-#define m4_evaluate m4_mp_evaluate
+#define m4_evaluate    builtin_mpeval
 #include "evalparse.c"

-- 
  ())_. Gary V. Vaughan     gary@(oranda.demon.co.uk|gnu.org)
  ( '/  Research Scientist  http://www.oranda.demon.co.uk       ,_())____
  / )=  GNU Hacker          http://www.gnu.org/software/libtool  \'      `&
`(_~)_  Tech' Author        http://sources.redhat.com/autobook   =`---d__/



reply via email to

[Prev in Thread] Current Thread [Next in Thread]