[Top][All Lists]
[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;
}