1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-23 07:31:31 +00:00

Fix m4 to properly handle bitwise operators &, ^, and |. Fix operator

precedence. Add short-circuit evaluation.

PR:		bin/60914
Reviewed by:	petef
Discussed with:	jeff, petef
This commit is contained in:
Sean Kelly 2004-05-01 03:59:43 +00:00
parent 15ea803975
commit 42249c7f31
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=128789

View File

@ -67,31 +67,24 @@ __FBSDID("$FreeBSD$");
* query : lor * query : lor
* | lor "?" query ":" query * | lor "?" query ":" query
* lor : land { "||" land } * lor : land { "||" land }
* land : not { "&&" not } * land : bor { "&&" bor }
* not : eqrel * bor : xor { "|" xor }
* | '!' not * xor : band { "^" eqrel }
* eqrel : shift { eqrelop shift } * band : eqrel { "&" eqrel }
* shift : primary { shop primary } * eqrel : nerel { ("==" | "!=") nerel }
* primary : term { addop term } * nerel : shift { ("<" | ">" | "<=" | ">=") shift }
* term : exp { mulop exp } * shift : primary { ("<<" | ">>") primary }
* exp : unary { expop unary } * primary : term { ("+" | "-") term }
* term : exp { ("*" | "/" | "%") exp }
* exp : unary { "**" unary }
* unary : factor * unary : factor
* | unop unary * | ("+" | "-" | "~" | "!") unary
* factor : constant * factor : constant
* | "(" query ")" * | "(" query ")"
* constant: num * constant: num
* | "'" CHAR "'" * | "'" CHAR "'"
* num : DIGIT * num : DIGIT
* | DIGIT num * | DIGIT num
* shop : "<<"
* | ">>"
* eqrel : "="
* | "=="
* | "!="
* | "<"
* | ">"
* | "<="
* | ">="
* *
* *
* This expression evaluator is lifted from a public-domain * This expression evaluator is lifted from a public-domain
@ -115,20 +108,23 @@ __FBSDID("$FreeBSD$");
static const char *nxtch; /* Parser scan pointer */ static const char *nxtch; /* Parser scan pointer */
static const char *where; static const char *where;
static int query(void); static int query(int mayeval);
static int lor(void); static int lor(int mayeval);
static int land(void); static int land(int mayeval);
static int not(void); static int bor(int mayeval);
static int eqrel(void); static int xor(int mayeval);
static int shift(void); static int band(int mayeval);
static int primary(void); static int eqrel(int mayeval);
static int term(void); static int nerel(int mayeval);
static int exp(void); static int shift(int mayeval);
static int unary(void); static int primary(int mayeval);
static int factor(void); static int term(int mayeval);
static int constant(void); static int exp(int mayeval);
static int num(void); static int unary(int mayeval);
static int geteqrel(void); static int factor(int mayeval);
static int constant(int mayeval);
static int num(int mayeval);
static int geteqrel(int mayeval);
static int skipws(void); static int skipws(void);
static void experr(const char *); static void experr(const char *);
@ -156,7 +152,7 @@ expr(const char *expbuf)
if (setjmp(expjump) != 0) if (setjmp(expjump) != 0)
return FALSE; return FALSE;
rval = query(); rval = query(1);
if (skipws() == EOS) if (skipws() == EOS)
return rval; return rval;
@ -168,21 +164,21 @@ expr(const char *expbuf)
* query : lor | lor '?' query ':' query * query : lor | lor '?' query ':' query
*/ */
static int static int
query(void) query(int mayeval)
{ {
int result, true_val, false_val; int result, true_val, false_val;
result = lor(); result = lor(mayeval);
if (skipws() != '?') { if (skipws() != '?') {
ungetch(); ungetch();
return result; return result;
} }
true_val = query(); true_val = query(result);
if (skipws() != ':') if (skipws() != ':')
experr("bad query"); experr("bad query: missing \":\"");
false_val = query(); false_val = query(!result);
return result ? true_val : false_val; return result ? true_val : false_val;
} }
@ -190,15 +186,19 @@ query(void)
* lor : land { '||' land } * lor : land { '||' land }
*/ */
static int static int
lor(void) lor(int mayeval)
{ {
int c, vl, vr; int c, vl, vr;
vl = land(); vl = land(mayeval);
while ((c = skipws()) == '|') { while ((c = skipws()) == '|') {
if (getch() != '|') if (getch() != '|') {
ungetch(); ungetch();
vr = land(); break;
}
if (vl != 0)
mayeval = 0;
vr = land(mayeval);
vl = vl || vr; vl = vl || vr;
} }
@ -210,15 +210,19 @@ lor(void)
* land : not { '&&' not } * land : not { '&&' not }
*/ */
static int static int
land(void) land(int mayeval)
{ {
int c, vl, vr; int c, vl, vr;
vl = not(); vl = bor(mayeval);
while ((c = skipws()) == '&') { while ((c = skipws()) == '&') {
if (getch() != '&') if (getch() != '&') {
ungetch(); ungetch();
vr = not(); break;
}
if (vl == 0)
mayeval = 0;
vr = bor(mayeval);
vl = vl && vr; vl = vl && vr;
} }
@ -227,74 +231,131 @@ land(void)
} }
/* /*
* not : eqrel | '!' not * bor : xor { "|" xor }
*/ */
static int static int
not(void) bor(int mayeval)
{ {
int val, c; int vl, vr, c, cr;
if ((c = skipws()) == '!' && getch() != '=') { vl = xor(mayeval);
while ((c = skipws()) == '|') {
cr = getch();
ungetch(); ungetch();
val = not(); if (cr == '|')
return !val; break;
vr = xor(mayeval);
vl |= vr;
} }
if (c == '!')
ungetch();
ungetch(); ungetch();
return eqrel(); return (vl);
} }
/* /*
* eqrel : shift { eqrelop shift } * xor : band { "^" band }
*/ */
static int static int
eqrel(void) xor(int mayeval)
{ {
int vl, vr, op; int vl, vr, c;
vl = shift(); vl = band(mayeval);
while ((op = geteqrel()) != -1) { while ((c = skipws()) == '^') {
vr = shift(); vr = band(mayeval);
vl ^= vr;
switch (op) {
case EQL:
vl = (vl == vr);
break;
case NEQ:
vl = (vl != vr);
break;
case LEQ:
vl = (vl <= vr);
break;
case LSS:
vl = (vl < vr);
break;
case GTR:
vl = (vl > vr);
break;
case GEQ:
vl = (vl >= vr);
break;
}
} }
ungetch();
return (vl);
}
/*
* band : eqrel { "&" eqrel }
*/
static int
band(int mayeval)
{
int c, cr, vl, vr;
vl = eqrel(mayeval);
while ((c = skipws()) == '&') {
cr = getch();
ungetch();
if (cr == '&')
break;
vr = eqrel(mayeval);
vl &= vr;
}
ungetch();
return vl; return vl;
} }
/* /*
* shift : primary { shop primary } * eqrel : nerel { ("==" | "!=" ) nerel }
*/ */
static int static int
shift(void) eqrel(int mayeval)
{
int vl, vr, c, cr;
vl = nerel(mayeval);
while ((c = skipws()) == '!' || c == '=') {
if ((cr = getch()) != '=') {
ungetch();
break;
}
vr = nerel(mayeval);
switch (c) {
case '=':
vl = (vl == vr);
break;
case '!':
vl = (vl != vr);
break;
}
}
ungetch();
return vl;
}
/*
* nerel : shift { ("<=" | ">=" | "<" | ">") shift }
*/
static int
nerel(int mayeval)
{
int vl, vr, c, cr;
vl = shift(mayeval);
while ((c = skipws()) == '<' || c == '>') {
if ((cr = getch()) != '=') {
ungetch();
cr = '\0';
}
vr = shift(mayeval);
switch (c) {
case '<':
vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
break;
case '>':
vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
break;
}
}
ungetch();
return vl;
}
/*
* shift : primary { ("<<" | ">>") primary }
*/
static int
shift(int mayeval)
{ {
int vl, vr, c; int vl, vr, c;
vl = primary(); vl = primary(mayeval);
while (((c = skipws()) == '<' || c == '>') && getch() == c) { while (((c = skipws()) == '<' || c == '>') && getch() == c) {
vr = primary(); vr = primary(mayeval);
if (c == '<') if (c == '<')
vl <<= vr; vl <<= vr;
@ -309,16 +370,16 @@ shift(void)
} }
/* /*
* primary : term { addop term } * primary : term { ("+" | "-") term }
*/ */
static int static int
primary(void) primary(int mayeval)
{ {
int c, vl, vr; int c, vl, vr;
vl = term(); vl = term(mayeval);
while ((c = skipws()) == '+' || c == '-') { while ((c = skipws()) == '+' || c == '-') {
vr = term(); vr = term(mayeval);
if (c == '+') if (c == '+')
vl += vr; vl += vr;
@ -331,29 +392,33 @@ primary(void)
} }
/* /*
* <term> := <exp> { <mulop> <exp> } * term : exp { ("*" | "/" | "%") exp }
*/ */
static int static int
term(void) term(int mayeval)
{ {
int c, vl, vr; int c, vl, vr;
vl = exp(); vl = exp(mayeval);
while ((c = skipws()) == '*' || c == '/' || c == '%') { while ((c = skipws()) == '*' || c == '/' || c == '%') {
vr = exp(); vr = exp(mayeval);
switch (c) { switch (c) {
case '*': case '*':
vl *= vr; vl *= vr;
break; break;
case '/': case '/':
if (vr == 0) if (!mayeval)
/* short-circuit */;
else if (vr == 0)
errx(1, "division by zero in eval."); errx(1, "division by zero in eval.");
else else
vl /= vr; vl /= vr;
break; break;
case '%': case '%':
if (vr == 0) if (!mayeval)
/* short-circuit */;
else if (vr == 0)
errx(1, "modulo zero in eval."); errx(1, "modulo zero in eval.");
else else
vl %= vr; vl %= vr;
@ -365,24 +430,20 @@ term(void)
} }
/* /*
* <term> := <unary> { <expop> <unary> } * exp : unary { "**" exp }
*/ */
static int static int
exp(void) exp(int mayeval)
{ {
int c, vl, vr, n; int c, vl, vr, n;
vl = unary(); vl = unary(mayeval);
switch (c = skipws()) { while ((c = skipws()) == '*') {
case '*':
if (getch() != '*') { if (getch() != '*') {
ungetch(); ungetch();
break; break;
} }
vr = unary(mayeval);
case '^':
vr = exp();
n = 1; n = 1;
while (vr-- > 0) while (vr-- > 0)
n *= vl; n *= vl;
@ -394,15 +455,15 @@ exp(void)
} }
/* /*
* unary : factor | unop unary * unary : factor | ("+" | "-" | "~" | "!") unary
*/ */
static int static int
unary(void) unary(int mayeval)
{ {
int val, c; int val, c;
if ((c = skipws()) == '+' || c == '-' || c == '~') { if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
val = unary(); val = unary(mayeval);
switch (c) { switch (c) {
case '+': case '+':
@ -411,30 +472,32 @@ unary(void)
return -val; return -val;
case '~': case '~':
return ~val; return ~val;
case '!':
return !val;
} }
} }
ungetch(); ungetch();
return factor(); return factor(mayeval);
} }
/* /*
* factor : constant | '(' query ')' * factor : constant | '(' query ')'
*/ */
static int static int
factor(void) factor(int mayeval)
{ {
int val; int val;
if (skipws() == '(') { if (skipws() == '(') {
val = query(); val = query(mayeval);
if (skipws() != ')') if (skipws() != ')')
experr("bad factor"); experr("bad factor: missing \")\"");
return val; return val;
} }
ungetch(); ungetch();
return constant(); return constant(mayeval);
} }
/* /*
@ -442,7 +505,7 @@ factor(void)
* Note: constant() handles multi-byte constants * Note: constant() handles multi-byte constants
*/ */
static int static int
constant(void) constant(int mayeval)
{ {
int i; int i;
int value; int value;
@ -451,7 +514,7 @@ constant(void)
if (skipws() != '\'') { if (skipws() != '\'') {
ungetch(); ungetch();
return num(); return num(mayeval);
} }
for (i = 0; i < (ssize_t)sizeof(int); i++) { for (i = 0; i < (ssize_t)sizeof(int); i++) {
if ((c = getch()) == '\'') { if ((c = getch()) == '\'') {
@ -469,7 +532,7 @@ constant(void)
case '6': case '6':
case '7': case '7':
ungetch(); ungetch();
c = num(); c = num(mayeval);
break; break;
case 'n': case 'n':
c = 012; c = 012;
@ -503,7 +566,7 @@ constant(void)
* num : digit | num digit * num : digit | num digit
*/ */
static int static int
num(void) num(int mayeval)
{ {
int rval, c, base; int rval, c, base;
int ndig; int ndig;
@ -557,50 +620,6 @@ num(void)
return rval; return rval;
} }
/*
* eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
*/
static int
geteqrel(void)
{
int c1, c2;
c1 = skipws();
c2 = getch();
switch (c1) {
case '=':
if (c2 != '=')
ungetch();
return EQL;
case '!':
if (c2 == '=')
return NEQ;
ungetch();
ungetch();
return -1;
case '<':
if (c2 == '=')
return LEQ;
ungetch();
return LSS;
case '>':
if (c2 == '=')
return GEQ;
ungetch();
return GTR;
default:
ungetch();
ungetch();
return -1;
}
}
/* /*
* Skip over any white space and return terminating char. * Skip over any white space and return terminating char.
*/ */