m4-commit
[Top][All Lists]
Advanced

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

Changes to m4/modules/evalparse.c,v


From: Eric Blake
Subject: Changes to m4/modules/evalparse.c,v
Date: Sat, 06 Jan 2007 19:56:55 +0000

CVSROOT:        /sources/m4
Module name:    m4
Changes by:     Eric Blake <ericb>      07/01/06 19:56:54

Index: modules/evalparse.c
===================================================================
RCS file: /sources/m4/m4/modules/evalparse.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- modules/evalparse.c 3 Jan 2007 14:44:11 -0000       1.15
+++ modules/evalparse.c 6 Jan 2007 19:56:54 -0000       1.16
@@ -45,10 +45,11 @@
     EXPONENT,
     TIMES, DIVIDE, MODULO, RATIO,
     EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
-    LSHIFT, RSHIFT,
+    LSHIFT, RSHIFT, URSHIFT,
     LNOT, LAND, LOR,
     NOT, AND, OR, XOR,
     LEFTP, RIGHTP,
+    QUESTION, COLON, COMMA,
     NUMBER, EOTEXT
   }
 eval_token;
@@ -58,16 +59,23 @@
 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,
+    MISSING_COLON,
     UNKNOWN_INPUT,
     EXCESS_INPUT,
-    INVALID_OPERATOR,
-    DIVIDE_ZERO,
-    MODULO_ZERO
+    INVALID_OPERATOR
   }
 eval_error;
 
+static eval_error comma_term           (m4 *, eval_token, number *);
+static eval_error condition_term       (m4 *, eval_token, number *);
 static eval_error logical_or_term   (m4 *, eval_token, number *);
 static eval_error logical_and_term  (m4 *, eval_token, number *);
 static eval_error or_term          (m4 *, eval_token, number *);
@@ -81,21 +89,21 @@
 static eval_error exp_term         (m4 *, eval_token, number *);
 static eval_error unary_term       (m4 *, eval_token, number *);
 static eval_error simple_term      (m4 *, eval_token, number *);
-static void      numb_pow          (number *x, number *y);
+static eval_error numb_pow             (number *, number *);
 
 
 
 /* --- LEXICAL FUNCTIONS --- */
 
 /* Pointer to next character of input text.  */
-static const unsigned char *eval_text;
+static const 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 const char *last_text;
 
 static void
-eval_init_lex (const unsigned char *text)
+eval_init_lex (const char *text)
 {
   eval_text = text;
   last_text = NULL;
@@ -114,7 +122,7 @@
 static eval_token
 eval_lex (number *val)
 {
-  while (isspace (*eval_text))
+  while (isspace (to_uchar (*eval_text)))
     eval_text++;
 
   last_text = eval_text;
@@ -122,7 +130,7 @@
   if (*eval_text == '\0')
     return EOTEXT;
 
-  if (isdigit (*eval_text))
+  if (isdigit (to_uchar (*eval_text)))
     {
       int base, digit;
 
@@ -147,7 +155,7 @@
            case 'R':
              base = 0;
              eval_text++;
-             while (isdigit (*eval_text) && base <= 36)
+             while (isdigit (to_uchar (*eval_text)) && base <= 36)
                base = 10 * base + *eval_text++ - '0';
              if (base == 0 || base > 36 || *eval_text != ':')
                return ERROR;
@@ -164,27 +172,37 @@
       numb_set_si (val, 0);
       for (; *eval_text; eval_text++)
        {
-         if (isdigit (*eval_text))
+         if (isdigit (to_uchar (*eval_text)))
            digit = *eval_text - '0';
-         else if (islower (*eval_text))
+         else if (islower (to_uchar (*eval_text)))
            digit = *eval_text - 'a' + 10;
-         else if (isupper (*eval_text))
+         else if (isupper (to_uchar (*eval_text)))
            digit = *eval_text - 'A' + 10;
          else
            break;
 
-         if (digit >= base)
+         if (base == 1)
+           {
+             if (digit == 1)
+               numb_incr (*val);
+             else if (digit == 0 && numb_zerop (*val))
+               continue;
+             else
            break;
-
-         { /* (*val) = (*val) * base; */
+           }
+         else if (digit >= base)
+           break;
+         else
+           {
            number xbase;
+             number xdigit;
+
+             /* (*val) = (*val) * base; */
            numb_init (xbase);
            numb_set_si (&xbase, base);
            numb_times (*val, xbase);
            numb_fini (xbase);
-         }
-         { /* (*val) = (*val) + digit; */
-           number xdigit;
+             /* (*val) = (*val) + digit; */
            numb_init (xdigit);
            numb_set_si (&xdigit, digit);
            numb_plus (*val, xdigit);
@@ -221,8 +239,8 @@
       if (*eval_text == '=')
        return BADOP;
       return MODULO;
-    case ':':
-      return RATIO; /* FIXME - this clashes with supporting ?:.  */
+    case '\\':
+      return RATIO;
     case '=':
       if (*eval_text == '=')
        {
@@ -245,8 +263,14 @@
        }
       else if (*eval_text == '>')
        {
-         if (*eval_text++ == '=')
+         eval_text++;
+         if (*eval_text == '=')
            return BADOP;
+         else if (*eval_text == '>')
+           {
+             eval_text++;
+             return URSHIFT;
+           }
          return RSHIFT;
        }
       else
@@ -259,7 +283,7 @@
        }
       else if (*eval_text == '<')
        {
-         if (*eval_text++ == '=')
+         if (*++eval_text == '=')
            return BADOP;
          return LSHIFT;
        }
@@ -293,6 +317,12 @@
       return LEFTP;
     case ')':
       return RIGHTP;
+    case '?':
+      return QUESTION;
+    case ':':
+      return COLON;
+    case ',':
+      return COMMA;
     default:
       return ERROR;
     }
@@ -300,6 +330,90 @@
 
 /* Recursive descent parser.  */
 static eval_error
+comma_term (m4 *context, eval_token et, number *v1)
+{
+  number v2;
+  eval_error er;
+
+  if ((er = condition_term (context, et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init (v2);
+  while ((et = eval_lex (&v2)) == COMMA)
+    {
+      /* Unless XCU ERN 137 is approved, eval must reject this in
+        POSIX mode.  */
+      numb_extension (context);
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      if ((er = condition_term (context, et, &v2)) != NO_ERROR)
+       return er;
+      numb_set (*v1, v2);
+    }
+  numb_fini (v2);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
+condition_term (m4 *context, eval_token et, number *v1)
+{
+  number v2;
+  number v3;
+  eval_error er;
+
+  if ((er = logical_or_term (context, et, v1)) != NO_ERROR)
+    return er;
+
+  numb_init (v2);
+  numb_init (v3);
+  if ((et = eval_lex (&v2)) == QUESTION)
+    {
+      /* Unless XCU ERN 137 is approved, eval must reject this in
+        POSIX mode.  */
+      numb_extension (context);
+      et = eval_lex (&v2);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      /* Implement short-circuiting of valid syntax.  */
+      er = comma_term (context, et, &v2);
+      if (er != NO_ERROR
+         && !(numb_zerop (*v1) && er < SYNTAX_ERROR))
+       return er;
+
+      et = eval_lex (&v3);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+      if (et != COLON)
+       return MISSING_COLON;
+
+      et = eval_lex (&v3);
+      if (et == ERROR)
+       return UNKNOWN_INPUT;
+
+      er = condition_term (context, et, &v3);
+      if (er != NO_ERROR
+         && !(! numb_zerop (*v1) && er < SYNTAX_ERROR))
+       return er;
+
+      numb_set (*v1, ! numb_zerop (*v1) ? v2 : v3);
+    }
+  numb_fini (v2);
+  numb_fini (v3);
+  if (et == ERROR)
+    return UNKNOWN_INPUT;
+
+  eval_undo ();
+  return NO_ERROR;
+}
+
+static eval_error
 logical_or_term (m4 *context, eval_token et, number *v1)
 {
   number v2;
@@ -319,8 +433,7 @@
       er = logical_and_term (context, et, &v2);
       if (er == NO_ERROR)
        numb_lior (*v1, v2);
-      else if (! numb_zerop (*v1)
-              && (er == DIVIDE_ZERO || er == MODULO_ZERO))
+      else if (! numb_zerop (*v1) && er < SYNTAX_ERROR)
        numb_set (*v1, numb_ONE);
       else
        return er;
@@ -353,8 +466,7 @@
       er = or_term (context, et, &v2);
       if (er == NO_ERROR)
        numb_land (*v1, v2);
-      else if (numb_zerop (*v1)
-              && (er == DIVIDE_ZERO || er == MODULO_ZERO))
+      else if (numb_zerop (*v1) && er < SYNTAX_ERROR)
        numb_set (*v1, numb_ZERO);
       else
        return er;
@@ -551,7 +663,7 @@
     return er;
 
   numb_init (v2);
-  while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT)
+  while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT || op == URSHIFT)
     {
 
       et = eval_lex (&v2);
@@ -571,6 +683,10 @@
          numb_rshift (context, v1, &v2);
          break;
 
+       case URSHIFT:
+         numb_urshift (context, v1, &v2);
+         break;
+
        default:
          assert (!"INTERNAL ERROR: bad shift operator in shift_term ()");
          abort ();
@@ -684,13 +800,11 @@
 static eval_error
 exp_term (m4 *context, eval_token et, number *v1)
 {
-  number result;
   number v2;
   eval_error er;
 
   if ((er = unary_term (context, et, v1)) != NO_ERROR)
     return er;
-  memcpy (&result, v1, sizeof(number));
 
   numb_init (v2);
   while ((et = eval_lex (&v2)) == EXPONENT)
@@ -702,7 +816,8 @@
       if ((er = exp_term (context, et, &v2)) != NO_ERROR)
        return er;
 
-      numb_pow (v1, &v2);
+      if ((er = numb_pow (v1, &v2)) != NO_ERROR)
+       return er;
     }
   numb_fini (v2);
   if (et == ERROR)
@@ -734,8 +849,7 @@
       else if (et == LNOT)
        numb_lnot (*v1);
     }
-  else
-    if ((er = simple_term (context, et, v1)) != NO_ERROR)
+  else if ((er = simple_term (context, et, v1)) != NO_ERROR)
       return er;
 
   return NO_ERROR;
@@ -754,7 +868,7 @@
       if (et == ERROR)
        return UNKNOWN_INPUT;
 
-      if ((er = logical_or_term (context, et, v1)) != NO_ERROR)
+      if ((er = comma_term (context, et, v1)) != NO_ERROR)
        return er;
 
       et = eval_lex (&v2);
@@ -786,14 +900,14 @@
   int          min     = 1;
   number       val;
   eval_token   et;
-  eval_error   err;
+  eval_error   err     = NO_ERROR;
 
-  if (argc >= 3 && !m4_numeric_arg (context, argc, argv, 2, &radix))
+  if (*M4ARG (2) && !m4_numeric_arg (context, argc, argv, 2, &radix))
     return;
 
-  if (radix <= 1 || radix > 36)
+  if (radix < 1 || radix > 36)
     {
-      m4_error (context, 0, 0, _("%s: radix out of range: %d"),
+      m4_warn (context, 0, _("%s: radix out of range: %d"),
                M4ARG (0), radix);
       return;
     }
@@ -801,9 +915,9 @@
   if (argc >= 4 && !m4_numeric_arg (context, argc, argv, 3, &min))
     return;
 
-  if (min <= 0)
+  if (min < 0)
     {
-      m4_error (context, 0, 0, _("%s: negative width: %d"), M4ARG (0), min);
+      m4_warn (context, 0, _("%s: negative width: %d"), M4ARG (0), min);
       return;
     }
 
@@ -812,7 +926,13 @@
 
   numb_init (val);
   et = eval_lex (&val);
-  err = logical_or_term (context, et, &val);
+  if (et == EOTEXT)
+    {
+      m4_warn (context, 0, _("%s: empty string treated as zero"), M4ARG (0));
+      numb_set (val, numb_ZERO);
+    }
+  else
+    err = comma_term (context, et, &val);
 
   if (err == NO_ERROR && *eval_text != '\0')
     {
@@ -829,36 +949,47 @@
       break;
 
     case MISSING_RIGHT:
-      m4_error (context, 0, 0, _("%s: missing right parenthesis: %s"),
+      m4_warn (context, 0, _("%s: missing right parenthesis: %s"),
+              M4ARG (0), M4ARG (1));
+      break;
+
+    case MISSING_COLON:
+      m4_warn (context, 0, _("%s: missing colon: %s"),
                M4ARG (0), M4ARG (1));
       break;
 
     case SYNTAX_ERROR:
-      m4_error (context, 0, 0, _("%s: bad expression: %s"),
+      m4_warn (context, 0, _("%s: bad expression: %s"),
                M4ARG (0), M4ARG (1));
       break;
 
     case UNKNOWN_INPUT:
-      m4_error (context, 0, 0, _("%s: bad input: %s"), M4ARG (0), M4ARG (1));
+      m4_warn (context, 0, _("%s: bad input: %s"), M4ARG (0), M4ARG (1));
       break;
 
     case EXCESS_INPUT:
-      m4_error (context, 0, 0, _("%s: excess input: %s"), M4ARG (0),
+      m4_warn (context, 0, _("%s: excess input: %s"), M4ARG (0),
                M4ARG (1));
       break;
 
     case INVALID_OPERATOR:
+      /* POSIX requires an error here, unless XCU ERN 137 is approved.  */
       m4_error (context, 0, 0, _("%s: invalid operator: %s"), M4ARG (0),
                M4ARG (1));
       break;
 
     case DIVIDE_ZERO:
-      m4_error (context, 0, 0, _("%s: divide by zero: %s"), M4ARG (0),
+      m4_warn (context, 0, _("%s: divide by zero: %s"), M4ARG (0),
                M4ARG (1));
       break;
 
     case MODULO_ZERO:
-      m4_error (context, 0, 0, _("%s: modulo by zero: %s"), M4ARG (0),
+      m4_warn (context, 0, _("%s: modulo by zero: %s"), M4ARG (0),
+              M4ARG (1));
+      break;
+
+    case NEGATIVE_EXPONENT:
+      m4_warn (context, 0, _("%s: negative exponent: %s"), M4ARG (0),
                M4ARG (1));
       break;
 
@@ -870,7 +1001,7 @@
   numb_fini (val);
 }
 
-static void
+static eval_error
 numb_pow (number *x, number *y)
 {
   /* y should be integral */
@@ -880,13 +1011,16 @@
   numb_init (ans);
   numb_set_si (&ans, 1);
 
+  if (numb_zerop (*x) && numb_zerop (*y))
+    return DIVIDE_ZERO;
+
   numb_init (yy);
   numb_set (yy, *y);
 
   if (numb_negativep (yy))
     {
-      numb_invert (*x);
       numb_negate (yy);
+      numb_invert (*x);
     }
 
   while (numb_positivep (yy))
@@ -898,4 +1032,5 @@
 
   numb_fini (ans);
   numb_fini (yy);
+  return NO_ERROR;
 }




reply via email to

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