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:
parent
15ea803975
commit
42249c7f31
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=128789
@ -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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user