summaryrefslogtreecommitdiff
path: root/modules/evalparse.c
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2007-01-03 14:44:11 +0000
committerEric Blake <ebb9@byu.net>2007-10-06 07:07:48 -0600
commitb259fc5dd95613b7fcc052027e60046d3d2b3fdc (patch)
treea4c9dd8180484b2aa3599d218ce04c0e5df3fffc /modules/evalparse.c
parent9a8f3bd8964c0b6f64a0ee979cd9bafc44eef6ca (diff)
downloadm4-b259fc5dd95613b7fcc052027e60046d3d2b3fdc.tar.gz
* doc/m4.texinfo (Format, Incr): More merges.
(Eval): Ensure C precedence rules are met. * modules/evalparse.c (BADOP, INVALID_OPERATOR): New enumerators. (not_term, logical_not_term): Delete; these are same precedence as other unary operators. (equality_term): New; these are lower precedence than relational operators. (eval_lex, simple_term, m4_evaluate): Recognize forbidden C operators for better error messages. (logical_or_term, logical_and_term): Short-circuit out the error of division by zero. (unary_term): Allow consecutive unary operators. * modules/m4.c (int2numb, numb2int): Delete; these potentially truncate bits. (numb_not, numb_eor, numb_ior, numb_and): Update callers. * modules/mpeval.c (reduce1, reduce2): Protect macros better. * NEWS: Document this change.
Diffstat (limited to 'modules/evalparse.c')
-rw-r--r--modules/evalparse.c282
1 files changed, 151 insertions, 131 deletions
diff --git a/modules/evalparse.c b/modules/evalparse.c
index 2871eaa0..a88bdbf5 100644
--- a/modules/evalparse.c
+++ b/modules/evalparse.c
@@ -1,5 +1,5 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2001, 2006
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2001, 2006, 2007
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,7 @@
typedef enum eval_token
{
- ERROR,
+ ERROR, BADOP,
PLUS, MINUS,
EXPONENT,
TIMES, DIVIDE, MODULO, RATIO,
@@ -62,6 +62,7 @@ typedef enum eval_error
SYNTAX_ERROR,
UNKNOWN_INPUT,
EXCESS_INPUT,
+ INVALID_OPERATOR,
DIVIDE_ZERO,
MODULO_ZERO
}
@@ -72,8 +73,7 @@ static eval_error logical_and_term (m4 *, eval_token, number *);
static eval_error or_term (m4 *, eval_token, number *);
static eval_error xor_term (m4 *, eval_token, number *);
static eval_error and_term (m4 *, eval_token, number *);
-static eval_error not_term (m4 *, eval_token, number *);
-static eval_error logical_not_term (m4 *, eval_token, number *);
+static eval_error equality_term (m4 *, eval_token, number *);
static eval_error cmp_term (m4 *, eval_token, number *);
static eval_error shift_term (m4 *, eval_token, number *);
static eval_error add_term (m4 *, eval_token, number *);
@@ -107,7 +107,9 @@ eval_undo (void)
eval_text = last_text;
}
-/* VAL is numerical value, if any. */
+/* VAL is numerical value, if any. Recognize C assignment operators,
+ even though we cannot support them, to issue better error
+ messages. */
static eval_token
eval_lex (number *val)
@@ -159,7 +161,7 @@ eval_lex (number *val)
else
base = 10;
- numb_set_si(val,0);
+ numb_set_si (val, 0);
for (; *eval_text; eval_text++)
{
if (isdigit (*eval_text))
@@ -176,17 +178,17 @@ eval_lex (number *val)
{ /* (*val) = (*val) * base; */
number xbase;
- numb_init(xbase);
- numb_set_si(&xbase,base);
- numb_times(*val,xbase);
- numb_fini(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);
+ numb_init (xdigit);
+ numb_set_si (&xdigit, digit);
+ numb_plus (*val, xdigit);
+ numb_fini (xdigit);
}
}
return NUMBER;
@@ -195,8 +197,12 @@ eval_lex (number *val)
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 == '*')
@@ -204,26 +210,33 @@ eval_lex (number *val)
eval_text++;
return EXPONENT;
}
- else
- return TIMES;
+ 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 ':':
- return RATIO;
+ return RATIO; /* FIXME - this clashes with supporting ?:. */
case '=':
if (*eval_text == '=')
- eval_text++;
- return EQ;
+ {
+ eval_text++;
+ return EQ;
+ }
+ return BADOP;
case '!':
if (*eval_text == '=')
{
eval_text++;
return NOTEQ;
}
- else
- return LNOT;
+ return LNOT;
case '>':
if (*eval_text == '=')
{
@@ -232,7 +245,8 @@ eval_lex (number *val)
}
else if (*eval_text == '>')
{
- eval_text++;
+ if (*eval_text++ == '=')
+ return BADOP;
return RSHIFT;
}
else
@@ -245,12 +259,15 @@ eval_lex (number *val)
}
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;
@@ -260,16 +277,18 @@ eval_lex (number *val)
eval_text++;
return LAND;
}
- else
- return AND;
+ else if (*eval_text == '=')
+ return BADOP;
+ return AND;
case '|':
if (*eval_text == '|')
{
eval_text++;
return LOR;
}
- else
- return OR;
+ else if (*eval_text == '=')
+ return BADOP;
+ return OR;
case '(':
return LEFTP;
case ')':
@@ -289,19 +308,24 @@ logical_or_term (m4 *context, eval_token et, number *v1)
if ((er = logical_and_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == LOR)
{
et = eval_lex (&v2);
if (et == ERROR)
return UNKNOWN_INPUT;
- if ((er = logical_and_term (context, et, &v2)) != NO_ERROR)
+ /* Implement short-circuiting of valid syntax. */
+ 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))
+ numb_set (*v1, numb_ONE);
+ else
return er;
-
- numb_lior(*v1,v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -318,19 +342,24 @@ logical_and_term (m4 *context, eval_token et, number *v1)
if ((er = or_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == LAND)
{
et = eval_lex (&v2);
if (et == ERROR)
return UNKNOWN_INPUT;
- if ((er = or_term (context, et, &v2)) != NO_ERROR)
+ /* Implement short-circuiting of valid syntax. */
+ 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))
+ numb_set (*v1, numb_ZERO);
+ else
return er;
-
- numb_land(*v1,v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -347,7 +376,7 @@ or_term (m4 *context, eval_token et, number *v1)
if ((er = xor_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == OR)
{
et = eval_lex (&v2);
@@ -357,9 +386,9 @@ or_term (m4 *context, eval_token et, number *v1)
if ((er = xor_term (context, et, &v2)) != NO_ERROR)
return er;
- numb_ior(context, v1, &v2);
+ numb_ior (context, v1, &v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -376,7 +405,7 @@ xor_term (m4 *context, eval_token et, number *v1)
if ((er = and_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == XOR)
{
et = eval_lex (&v2);
@@ -386,9 +415,9 @@ xor_term (m4 *context, eval_token et, number *v1)
if ((er = and_term (context, et, &v2)) != NO_ERROR)
return er;
- numb_eor(context, v1, &v2);
+ numb_eor (context, v1, &v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -402,22 +431,22 @@ and_term (m4 *context, eval_token et, number *v1)
number v2;
eval_error er;
- if ((er = not_term (context, et, v1)) != NO_ERROR)
+ if ((er = equality_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == AND)
{
et = eval_lex (&v2);
if (et == ERROR)
return UNKNOWN_INPUT;
- if ((er = not_term (context, et, &v2)) != NO_ERROR)
+ if ((er = equality_term (context, et, &v2)) != NO_ERROR)
return er;
- numb_and(context, v1, &v2);
+ numb_and (context, v1, &v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -426,46 +455,35 @@ and_term (m4 *context, eval_token et, number *v1)
}
static eval_error
-not_term (m4 *context, eval_token et, number *v1)
+equality_term (m4 *context, eval_token et, number *v1)
{
+ eval_token op;
+ number v2;
eval_error er;
- if (et == NOT)
- {
- et = eval_lex (v1);
- if (et == ERROR)
- return UNKNOWN_INPUT;
-
- if ((er = not_term (context, et, v1)) != NO_ERROR)
- return er;
- numb_not(context, v1);
- }
- else
- if ((er = logical_not_term (context, et, v1)) != NO_ERROR)
- return er;
-
- return NO_ERROR;
-}
-
-static eval_error
-logical_not_term (m4 *context, eval_token et, number *v1)
-{
- eval_error er;
+ if ((er = cmp_term (context, et, v1)) != NO_ERROR)
+ return er;
- if (et == LNOT)
+ numb_init (v2);
+ 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 (context, et, v1)) != NO_ERROR)
+ if ((er = cmp_term (context, et, &v2)) != NO_ERROR)
return er;
- numb_lnot(*v1);
+
+ if (op == EQ)
+ numb_eq (*v1, v2);
+ else
+ numb_ne (*v1, v2);
}
- else
- if ((er = cmp_term (context, et, v1)) != NO_ERROR)
- return er;
+ numb_fini (v2);
+ if (op == ERROR)
+ return UNKNOWN_INPUT;
+ eval_undo ();
return NO_ERROR;
}
@@ -479,9 +497,8 @@ cmp_term (m4 *context, eval_token et, number *v1)
if ((er = shift_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
- while ((op = eval_lex (&v2)) == EQ || op == NOTEQ
- || op == GT || op == GTEQ
+ numb_init (v2);
+ while ((op = eval_lex (&v2)) == GT || op == GTEQ
|| op == LS || op == LSEQ)
{
@@ -494,28 +511,20 @@ cmp_term (m4 *context, eval_token et, number *v1)
switch (op)
{
- case EQ:
- numb_eq(*v1,v2);
- break;
-
- case NOTEQ:
- numb_ne(*v1,v2);
- break;
-
case GT:
- numb_gt(*v1,v2);
+ numb_gt (*v1, v2);
break;
case GTEQ:
- numb_ge(*v1,v2);
+ numb_ge (*v1, v2);
break;
case LS:
- numb_lt(*v1,v2);
+ numb_lt (*v1, v2);
break;
case LSEQ:
- numb_le(*v1,v2);
+ numb_le (*v1, v2);
break;
default:
@@ -523,7 +532,7 @@ cmp_term (m4 *context, eval_token et, number *v1)
abort ();
}
}
- numb_fini(v2);
+ numb_fini (v2);
if (op == ERROR)
return UNKNOWN_INPUT;
@@ -541,7 +550,7 @@ shift_term (m4 *context, eval_token et, number *v1)
if ((er = add_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT)
{
@@ -555,11 +564,11 @@ shift_term (m4 *context, eval_token et, number *v1)
switch (op)
{
case LSHIFT:
- numb_lshift(context, v1, &v2);
+ numb_lshift (context, v1, &v2);
break;
case RSHIFT:
- numb_rshift(context, v1, &v2);
+ numb_rshift (context, v1, &v2);
break;
default:
@@ -567,7 +576,7 @@ shift_term (m4 *context, eval_token et, number *v1)
abort ();
}
}
- numb_fini(v2);
+ numb_fini (v2);
if (op == ERROR)
return UNKNOWN_INPUT;
@@ -585,7 +594,7 @@ add_term (m4 *context, eval_token et, number *v1)
if ((er = mult_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while ((op = eval_lex (&v2)) == PLUS || op == MINUS)
{
et = eval_lex (&v2);
@@ -595,13 +604,12 @@ add_term (m4 *context, eval_token et, number *v1)
if ((er = mult_term (context, et, &v2)) != NO_ERROR)
return er;
- if (op == PLUS) {
- numb_plus(*v1,v2);
- } else {
- numb_minus(*v1,v2);
- }
+ if (op == PLUS)
+ numb_plus (*v1, v2);
+ else
+ numb_minus (*v1, v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (op == ERROR)
return UNKNOWN_INPUT;
@@ -619,7 +627,7 @@ mult_term (m4 *context, eval_token et, number *v1)
if ((er = exp_term (context, et, v1)) != NO_ERROR)
return er;
- numb_init(v2);
+ numb_init (v2);
while (op = eval_lex (&v2),
op == TIMES
|| op == DIVIDE
@@ -636,31 +644,28 @@ mult_term (m4 *context, eval_token et, number *v1)
switch (op)
{
case TIMES:
- numb_times(*v1,v2);
+ numb_times (*v1, v2);
break;
case DIVIDE:
- if (numb_zerop(v2))
+ if (numb_zerop (v2))
return DIVIDE_ZERO;
- else {
+ else
numb_divide(v1, &v2);
- }
break;
case RATIO:
- if (numb_zerop(v2))
+ if (numb_zerop (v2))
return DIVIDE_ZERO;
- else {
- numb_ratio(*v1,v2);
- }
+ else
+ numb_ratio (*v1, v2);
break;
case MODULO:
- if (numb_zerop(v2))
+ if (numb_zerop (v2))
return MODULO_ZERO;
- else {
- numb_modulo(context, v1, &v2);
- }
+ else
+ numb_modulo (context, v1, &v2);
break;
default:
@@ -668,7 +673,7 @@ mult_term (m4 *context, eval_token et, number *v1)
abort ();
}
}
- numb_fini(v2);
+ numb_fini (v2);
if (op == ERROR)
return UNKNOWN_INPUT;
@@ -685,9 +690,9 @@ exp_term (m4 *context, eval_token et, number *v1)
if ((er = unary_term (context, et, v1)) != NO_ERROR)
return er;
- memcpy(&result, v1, sizeof(number));
+ memcpy (&result, v1, sizeof(number));
- numb_init(v2);
+ numb_init (v2);
while ((et = eval_lex (&v2)) == EXPONENT)
{
et = eval_lex (&v2);
@@ -697,9 +702,9 @@ exp_term (m4 *context, eval_token et, number *v1)
if ((er = exp_term (context, et, &v2)) != NO_ERROR)
return er;
- numb_pow(v1, &v2);
+ numb_pow (v1, &v2);
}
- numb_fini(v2);
+ numb_fini (v2);
if (et == ERROR)
return UNKNOWN_INPUT;
@@ -713,17 +718,21 @@ unary_term (m4 *context, eval_token et, number *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 (context, et2, v1)) != NO_ERROR)
+ if ((er = unary_term (context, et2, v1)) != NO_ERROR)
return er;
if (et == MINUS)
numb_negate(*v1);
+ else if (et == NOT)
+ numb_not (context, v1);
+ else if (et == LNOT)
+ numb_lnot (*v1);
}
else
if ((er = simple_term (context, et, v1)) != NO_ERROR)
@@ -760,6 +769,9 @@ simple_term (m4 *context, eval_token et, number *v1)
case NUMBER:
break;
+ case BADOP:
+ return INVALID_OPERATOR;
+
default:
return SYNTAX_ERROR;
}
@@ -782,7 +794,7 @@ m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv)
if (radix <= 1 || radix > 36)
{
m4_error (context, 0, 0, _("%s: radix out of range: %d"),
- M4ARG(0), radix);
+ M4ARG (0), radix);
return;
}
@@ -791,23 +803,29 @@ m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv)
if (min <= 0)
{
- m4_error (context, 0, 0, _("%s: negative width: %d"), M4ARG(0), min);
+ m4_error (context, 0, 0, _("%s: negative width: %d"), M4ARG (0), min);
return;
}
numb_initialise ();
eval_init_lex (M4ARG (1));
- numb_init(val);
+ numb_init (val);
et = eval_lex (&val);
err = logical_or_term (context, et, &val);
if (err == NO_ERROR && *eval_text != '\0')
- err = EXCESS_INPUT;
+ {
+ if (eval_lex (&val) == BADOP)
+ err = INVALID_OPERATOR;
+ else
+ err = EXCESS_INPUT;
+ }
switch (err)
{
case NO_ERROR:
+ numb_obstack (obs, val, radix, min);
break;
case MISSING_RIGHT:
@@ -829,6 +847,11 @@ m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv)
M4ARG (1));
break;
+ case INVALID_OPERATOR:
+ 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),
M4ARG (1));
@@ -844,9 +867,6 @@ m4_evaluate (m4 *context, m4_obstack *obs, int argc, m4_symbol_value **argv)
abort ();
}
- if (err == NO_ERROR)
- numb_obstack (obs, val, radix, min);
-
numb_fini (val);
}