m4-commit
[Top][All Lists]
Advanced

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

Changes to m4/src/Attic/eval.c,v [branch-1_4]


From: Eric Blake
Subject: Changes to m4/src/Attic/eval.c,v [branch-1_4]
Date: Sat, 06 Jan 2007 19:56:13 +0000

CVSROOT:        /sources/m4
Module name:    m4
Branch:         branch-1_4
Changes by:     Eric Blake <ericb>      07/01/06 19:56:11

Index: src/eval.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/eval.c,v
retrieving revision 1.1.1.1.2.7
retrieving revision 1.1.1.1.2.8
diff -u -b -r1.1.1.1.2.7 -r1.1.1.1.2.8
--- src/eval.c  1 Nov 2006 22:29:08 -0000       1.1.1.1.2.7
+++ src/eval.c  6 Jan 2007 19:56:11 -0000       1.1.1.1.2.8
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
 
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007
    Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,7 @@
 /* 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 ().  For POSIX semantics of the "eval" macro, the type
-   eval_t must be a 32-bit signed integer.  */
+   is evaluate ().  */
 
 #include "m4.h"
 
@@ -31,7 +30,7 @@
 
 typedef enum eval_token
   {
-    ERROR,
+    ERROR, BADOP,
     PLUS, MINUS,
     EXPONENT,
     TIMES, DIVIDE, MODULO,
@@ -49,29 +48,33 @@
 typedef enum eval_error
   {
     NO_ERROR,
-    MISSING_RIGHT,
+    DIVIDE_ZERO,
+    MODULO_ZERO,
+    NEGATIVE_EXPONENT,
+    /* All errors prior to SYNTAX_ERROR can be ignored in a dead
+       branch of && and ||.  All errors after are just more details
+       about a syntax error.  */
     SYNTAX_ERROR,
+    MISSING_RIGHT,
     UNKNOWN_INPUT,
     EXCESS_INPUT,
-    DIVIDE_ZERO,
-    MODULO_ZERO
+    INVALID_OPERATOR
   }
 eval_error;
 
-static eval_error logical_or_term (eval_token, eval_t *);
-static eval_error logical_and_term (eval_token, eval_t *);
-static eval_error or_term (eval_token, eval_t *);
-static eval_error xor_term (eval_token, eval_t *);
-static eval_error and_term (eval_token, eval_t *);
-static eval_error not_term (eval_token, eval_t *);
-static eval_error logical_not_term (eval_token, eval_t *);
-static eval_error cmp_term (eval_token, eval_t *);
-static eval_error shift_term (eval_token, eval_t *);
-static eval_error add_term (eval_token, eval_t *);
-static eval_error mult_term (eval_token, eval_t *);
-static eval_error exp_term (eval_token, eval_t *);
-static eval_error unary_term (eval_token, eval_t *);
-static eval_error simple_term (eval_token, eval_t *);
+static eval_error logical_or_term (eval_token, int32_t *);
+static eval_error logical_and_term (eval_token, int32_t *);
+static eval_error or_term (eval_token, int32_t *);
+static eval_error xor_term (eval_token, int32_t *);
+static eval_error and_term (eval_token, int32_t *);
+static eval_error equality_term (eval_token, int32_t *);
+static eval_error cmp_term (eval_token, int32_t *);
+static eval_error shift_term (eval_token, int32_t *);
+static eval_error add_term (eval_token, int32_t *);
+static eval_error mult_term (eval_token, int32_t *);
+static eval_error exp_term (eval_token, int32_t *);
+static eval_error unary_term (eval_token, int32_t *);
+static eval_error simple_term (eval_token, int32_t *);
 
 /*--------------------.
 | Lexical functions.  |
@@ -100,7 +103,7 @@
 /* VAL is numerical value, if any.  */
 
 static eval_token
-eval_lex (eval_t *val)
+eval_lex (int32_t *val)
 {
   while (isspace (to_uchar (*eval_text)))
     eval_text++;
@@ -149,7 +152,8 @@
       else
        base = 10;
 
-      (*val) = 0;
+      /* FIXME - this calculation can overflow.  Consider xstrtol.  */
+      *val = 0;
       for (; *eval_text; eval_text++)
        {
          if (isdigit (to_uchar (*eval_text)))
@@ -173,7 +177,7 @@
          else if (digit >= base)
            break;
          else
-           (*val) = (*val) * base + digit;
+           *val = *val * base + digit;
        }
       return NUMBER;
     }
@@ -181,8 +185,12 @@
   switch (*eval_text++)
     {
     case '+':
+      if (*eval_text == '+' || *eval_text == '=')
+       return BADOP;
       return PLUS;
     case '-':
+      if (*eval_text == '-' || *eval_text == '=')
+       return BADOP;
       return MINUS;
     case '*':
       if (*eval_text == '*')
@@ -190,23 +198,30 @@
          eval_text++;
          return EXPONENT;
        }
-      else
+      else if (*eval_text == '=')
+       return BADOP;
        return TIMES;
     case '/':
+      if (*eval_text == '=')
+       return BADOP;
       return DIVIDE;
     case '%':
+      if (*eval_text == '=')
+       return BADOP;
       return MODULO;
     case '=':
       if (*eval_text == '=')
+       {
        eval_text++;
       return EQ;
+       }
+      return BADOP;
     case '!':
       if (*eval_text == '=')
        {
          eval_text++;
          return NOTEQ;
        }
-      else
        return LNOT;
     case '>':
       if (*eval_text == '=')
@@ -216,10 +231,10 @@
        }
       else if (*eval_text == '>')
        {
-         eval_text++;
+         if (*++eval_text == '=')
+           return BADOP;
          return RSHIFT;
        }
-      else
        return GT;
     case '<':
       if (*eval_text == '=')
@@ -229,12 +244,14 @@
        }
       else if (*eval_text == '<')
        {
-         eval_text++;
+         if (*++eval_text == '=')
+           return BADOP;
          return LSHIFT;
        }
-      else
        return LS;
     case '^':
+      if (*eval_text == '=')
+       return BADOP;
       return XOR;
     case '~':
       return NOT;
@@ -244,7 +261,8 @@
          eval_text++;
          return LAND;
        }
-      else
+      else if (*eval_text == '=')
+       return BADOP;
        return AND;
     case '|':
       if (*eval_text == '|')
@@ -252,7 +270,8 @@
          eval_text++;
          return LOR;
        }
-      else
+      else if (*eval_text == '=')
+       return BADOP;
        return OR;
     case '(':
       return LEFTP;
@@ -268,7 +287,7 @@
 `---------------------------------------*/
 
 bool
-evaluate (const char *expr, eval_t *val)
+evaluate (const char *expr, int32_t *val)
 {
   eval_token et;
   eval_error err;
@@ -278,7 +297,12 @@
   err = logical_or_term (et, val);
 
   if (err == NO_ERROR && *eval_text != '\0')
+    {
+      if (eval_lex (val) == BADOP)
+       err = INVALID_OPERATOR;
+      else
     err = EXCESS_INPUT;
+    }
 
   switch (err)
     {
@@ -306,6 +330,12 @@
                "bad expression in eval (excess input): %s", expr));
       break;
 
+    case INVALID_OPERATOR:
+      M4ERROR ((warning_status, 0,
+               "invalid operator in eval: %s", expr));
+      retcode = EXIT_FAILURE;
+      break;
+
     case DIVIDE_ZERO:
       M4ERROR ((warning_status, 0,
                "divide by zero in eval: %s", expr));
@@ -316,6 +346,11 @@
                "modulo by zero in eval: %s", expr));
       break;
 
+    case NEGATIVE_EXPONENT:
+      M4ERROR ((warning_status, 0,
+               "negative exponent in eval: %s", expr));
+      break;
+
     default:
       M4ERROR ((warning_status, 0,
                "INTERNAL ERROR: bad error code in evaluate ()"));
@@ -330,9 +365,9 @@
 `---------------------------*/
 
 static eval_error
-logical_or_term (eval_token et, eval_t *v1)
+logical_or_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = logical_and_term (et, v1)) != NO_ERROR)
@@ -344,10 +379,14 @@
       if (et == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = logical_and_term (et, &v2)) != NO_ERROR)
-       return er;
-
+      /* Implement short-circuiting of valid syntax.  */
+      er = logical_and_term (et, &v2);
+      if (er == NO_ERROR)
       *v1 = *v1 || v2;
+      else if (*v1 != 0 && er < SYNTAX_ERROR)
+       *v1 = 1;
+      else
+       return er;
     }
   if (et == ERROR)
     return UNKNOWN_INPUT;
@@ -357,9 +396,9 @@
 }
 
 static eval_error
-logical_and_term (eval_token et, eval_t *v1)
+logical_and_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = or_term (et, v1)) != NO_ERROR)
@@ -371,10 +410,14 @@
       if (et == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = or_term (et, &v2)) != NO_ERROR)
-       return er;
-
+      /* Implement short-circuiting of valid syntax.  */
+      er = or_term (et, &v2);
+      if (er == NO_ERROR)
       *v1 = *v1 && v2;
+      else if (*v1 == 0 && er < SYNTAX_ERROR)
+       ; /* v1 is already 0 */
+      else
+       return er;
     }
   if (et == ERROR)
     return UNKNOWN_INPUT;
@@ -384,9 +427,9 @@
 }
 
 static eval_error
-or_term (eval_token et, eval_t *v1)
+or_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = xor_term (et, v1)) != NO_ERROR)
@@ -401,7 +444,7 @@
       if ((er = xor_term (et, &v2)) != NO_ERROR)
        return er;
 
-      *v1 = *v1 | v2;
+      *v1 |= v2;
     }
   if (et == ERROR)
     return UNKNOWN_INPUT;
@@ -411,9 +454,9 @@
 }
 
 static eval_error
-xor_term (eval_token et, eval_t *v1)
+xor_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = and_term (et, v1)) != NO_ERROR)
@@ -428,7 +471,7 @@
       if ((er = and_term (et, &v2)) != NO_ERROR)
        return er;
 
-      *v1 = *v1 ^ v2;
+      *v1 ^= v2;
     }
   if (et == ERROR)
     return UNKNOWN_INPUT;
@@ -438,12 +481,12 @@
 }
 
 static eval_error
-and_term (eval_token et, eval_t *v1)
+and_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
-  if ((er = not_term (et, v1)) != NO_ERROR)
+  if ((er = equality_term (et, v1)) != NO_ERROR)
     return er;
 
   while ((et = eval_lex (&v2)) == AND)
@@ -452,10 +495,10 @@
       if (et == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = not_term (et, &v2)) != NO_ERROR)
+      if ((er = equality_term (et, &v2)) != NO_ERROR)
        return er;
 
-      *v1 = *v1 & v2;
+      *v1 &= v2;
     }
   if (et == ERROR)
     return UNKNOWN_INPUT;
@@ -465,61 +508,43 @@
 }
 
 static eval_error
-not_term (eval_token et, eval_t *v1)
+equality_term (eval_token et, int32_t *v1)
 {
+  eval_token op;
+  int32_t v2;
   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;
-      *v1 = ~*v1;
-    }
-  else
-    if ((er = logical_not_term (et, v1)) != NO_ERROR)
+  if ((er = cmp_term (et, v1)) != NO_ERROR)
       return er;
 
-  return NO_ERROR;
-}
-
-static eval_error
-logical_not_term (eval_token et, eval_t *v1)
-{
-  eval_error er;
-
-  if (et == LNOT)
+  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ)
     {
-      et = eval_lex (v1);
+      et = eval_lex (&v2);
       if (et == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = logical_not_term (et, v1)) != NO_ERROR)
+      if ((er = cmp_term (et, &v2)) != NO_ERROR)
        return er;
-      *v1 = !*v1;
+      *v1 = (op == EQ) == (*v1 == v2);
     }
-  else
-    if ((er = cmp_term (et, v1)) != NO_ERROR)
-      return er;
+  if (op == ERROR)
+    return UNKNOWN_INPUT;
 
+  eval_undo ();
   return NO_ERROR;
 }
 
 static eval_error
-cmp_term (eval_token et, eval_t *v1)
+cmp_term (eval_token et, int32_t *v1)
 {
   eval_token op;
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = shift_term (et, v1)) != NO_ERROR)
     return er;
 
-  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ
-        || op == GT || op == GTEQ
+  while ((op = eval_lex (&v2)) == GT || op == GTEQ
         || op == LS || op == LSEQ)
     {
 
@@ -532,14 +557,6 @@
 
       switch (op)
        {
-       case EQ:
-         *v1 = *v1 == v2;
-         break;
-
-       case NOTEQ:
-         *v1 = *v1 != v2;
-         break;
-
        case GT:
          *v1 = *v1 > v2;
          break;
@@ -570,10 +587,11 @@
 }
 
 static eval_error
-shift_term (eval_token et, eval_t *v1)
+shift_term (eval_token et, int32_t *v1)
 {
   eval_token op;
-  eval_t v2;
+  int32_t v2;
+  uint32_t u1;
   eval_error er;
 
   if ((er = add_term (et, v1)) != NO_ERROR)
@@ -589,20 +607,24 @@
       if ((er = add_term (et, &v2)) != NO_ERROR)
        return er;
 
-      /* Shifting by a negative number, or by greater than the width, is
-        undefined in C, but POSIX requires eval to operate on 32-bit signed
-        numbers.  Explicitly mask the right argument to ensure defined
-        behavior.  */
+      /* Minimize undefined C behavior (shifting by a negative number,
+        shifting by the width or greater, left shift overflow, or
+        right shift of a negative number).  Implement Java 32-bit
+        wrap-around semantics.  This code assumes that the
+        implementation-defined overflow when casting unsigned to
+        signed is a silent twos-complement wrap-around.  */
       switch (op)
        {
        case LSHIFT:
-         *v1 = *v1 << (v2 & 0x1f);
+         u1 = *v1;
+         u1 <<= (uint32_t) (v2 & 0x1f);
+         *v1 = u1;
          break;
 
        case RSHIFT:
-         /* This assumes 2's-complement with sign-extension, since shifting
-            a negative number right is implementation-defined in C.  */
-         *v1 = *v1 >> (v2 & 0x1f);
+         u1 = *v1 < 0 ? ~*v1 : *v1;
+         u1 >>= (uint32_t) (v2 & 0x1f);
+         *v1 = *v1 < 0 ? ~u1 : u1;
          break;
 
        default:
@@ -619,10 +641,10 @@
 }
 
 static eval_error
-add_term (eval_token et, eval_t *v1)
+add_term (eval_token et, int32_t *v1)
 {
   eval_token op;
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = mult_term (et, v1)) != NO_ERROR)
@@ -637,10 +659,14 @@
       if ((er = mult_term (et, &v2)) != NO_ERROR)
        return er;
 
+      /* Minimize undefined C behavior on overflow.  This code assumes
+        that the implementation-defined overflow when casting
+        unsigned to signed is a silent twos-complement
+        wrap-around.  */
       if (op == PLUS)
-       *v1 = *v1 + v2;
+       *v1 = (int32_t) ((uint32_t) *v1 + (uint32_t) v2);
       else
-       *v1 = *v1 - v2;
+       *v1 = (int32_t) ((uint32_t) *v1 - (uint32_t) v2);
     }
   if (op == ERROR)
     return UNKNOWN_INPUT;
@@ -650,10 +676,10 @@
 }
 
 static eval_error
-mult_term (eval_token et, eval_t *v1)
+mult_term (eval_token et, int32_t *v1)
 {
   eval_token op;
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   if ((er = exp_term (et, v1)) != NO_ERROR)
@@ -668,10 +694,14 @@
       if ((er = exp_term (et, &v2)) != NO_ERROR)
        return er;
 
+      /* Minimize undefined C behavior on overflow.  This code assumes
+        that the implementation-defined overflow when casting
+        unsigned to signed is a silent twos-complement
+        wrap-around.  */
       switch (op)
        {
        case TIMES:
-         *v1 = *v1 * v2;
+         *v1 = (int32_t) ((uint32_t) *v1 * (uint32_t) v2);
          break;
 
        case DIVIDE:
@@ -679,9 +709,9 @@
            return DIVIDE_ZERO;
          else if (v2 == -1)
            /* Avoid the x86 SIGFPE on INT_MIN / -1.  */
-           *v1 = -*v1;
+           *v1 = (int32_t) -(uint32_t) *v1;
          else
-           *v1 = *v1 / v2;
+           *v1 = (int32_t) ((uint32_t) *v1 / (uint32_t) v2);
          break;
 
        case MODULO:
@@ -691,7 +721,7 @@
            /* Avoid the x86 SIGFPE on INT_MIN % -1.  */
            *v1 = 0;
          else
-           *v1 = *v1 % v2;
+           *v1 %= v2;
          break;
 
        default:
@@ -708,15 +738,14 @@
 }
 
 static eval_error
-exp_term (eval_token et, eval_t *v1)
+exp_term (eval_token et, int32_t *v1)
 {
-  register eval_t result;
-  eval_t v2;
+  uint32_t result;
+  int32_t v2;
   eval_error er;
 
   if ((er = unary_term (et, v1)) != NO_ERROR)
     return er;
-  result = *v1;
 
   while ((et = eval_lex (&v2)) == EXPONENT)
     {
@@ -727,9 +756,17 @@
       if ((er = exp_term (et, &v2)) != NO_ERROR)
        return er;
 
+      /* Minimize undefined C behavior on overflow.  This code assumes
+        that the implementation-defined overflow when casting
+        unsigned to signed is a silent twos-complement
+        wrap-around.  */
       result = 1;
+      if (v2 < 0)
+       return NEGATIVE_EXPONENT;
+      if (*v1 == 0 && v2 == 0)
+       return DIVIDE_ZERO;
       while (v2-- > 0)
-       result *= *v1;
+       result *= (uint32_t) *v1;
       *v1 = result;
     }
   if (et == ERROR)
@@ -740,34 +777,41 @@
 }
 
 static eval_error
-unary_term (eval_token et, eval_t *v1)
+unary_term (eval_token et, int32_t *v1)
 {
   eval_token et2 = et;
   eval_error er;
 
-  if (et == PLUS || et == MINUS)
+  if (et == PLUS || et == MINUS || et == NOT || et == LNOT)
     {
       et2 = eval_lex (v1);
       if (et2 == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = simple_term (et2, v1)) != NO_ERROR)
+      if ((er = unary_term (et2, v1)) != NO_ERROR)
        return er;
 
+      /* Minimize undefined C behavior on overflow.  This code assumes
+        that the implementation-defined overflow when casting
+        unsigned to signed is a silent twos-complement
+        wrap-around.  */
       if (et == MINUS)
-       *v1 = -*v1;
+       *v1 = (int32_t) -(uint32_t) *v1;
+      else if (et == NOT)
+       *v1 = ~*v1;
+      else if (et == LNOT)
+       *v1 = *v1 == 0 ? 1 : 0;
     }
-  else
-    if ((er = simple_term (et, v1)) != NO_ERROR)
+  else if ((er = simple_term (et, v1)) != NO_ERROR)
       return er;
 
   return NO_ERROR;
 }
 
 static eval_error
-simple_term (eval_token et, eval_t *v1)
+simple_term (eval_token et, int32_t *v1)
 {
-  eval_t v2;
+  int32_t v2;
   eval_error er;
 
   switch (et)
@@ -792,6 +836,9 @@
     case NUMBER:
       break;
 
+    case BADOP:
+      return INVALID_OPERATOR;
+
     default:
       return SYNTAX_ERROR;
     }




reply via email to

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