summaryrefslogtreecommitdiffstats
path: root/usr.bin/m4/expr.c
diff options
context:
space:
mode:
authorsmkelly <smkelly@FreeBSD.org>2004-05-01 03:59:43 +0000
committersmkelly <smkelly@FreeBSD.org>2004-05-01 03:59:43 +0000
commit507ac98289cc78d63e169ec6862a844b6ab135db (patch)
tree021df9e6a5e80412007dec1022b1c84c40fc8452 /usr.bin/m4/expr.c
parent1728b4c285810523867f88a01ef98521a624b866 (diff)
downloadFreeBSD-src-507ac98289cc78d63e169ec6862a844b6ab135db.zip
FreeBSD-src-507ac98289cc78d63e169ec6862a844b6ab135db.tar.gz
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
Diffstat (limited to 'usr.bin/m4/expr.c')
-rw-r--r--usr.bin/m4/expr.c327
1 files changed, 173 insertions, 154 deletions
diff --git a/usr.bin/m4/expr.c b/usr.bin/m4/expr.c
index 6e20b7a..2c0284b 100644
--- a/usr.bin/m4/expr.c
+++ b/usr.bin/m4/expr.c
@@ -67,31 +67,24 @@ __FBSDID("$FreeBSD$");
* query : lor
* | lor "?" query ":" query
* lor : land { "||" land }
- * land : not { "&&" not }
- * not : eqrel
- * | '!' not
- * eqrel : shift { eqrelop shift }
- * shift : primary { shop primary }
- * primary : term { addop term }
- * term : exp { mulop exp }
- * exp : unary { expop unary }
+ * land : bor { "&&" bor }
+ * bor : xor { "|" xor }
+ * xor : band { "^" eqrel }
+ * band : eqrel { "&" eqrel }
+ * eqrel : nerel { ("==" | "!=") nerel }
+ * nerel : shift { ("<" | ">" | "<=" | ">=") shift }
+ * shift : primary { ("<<" | ">>") primary }
+ * primary : term { ("+" | "-") term }
+ * term : exp { ("*" | "/" | "%") exp }
+ * exp : unary { "**" unary }
* unary : factor
- * | unop unary
+ * | ("+" | "-" | "~" | "!") unary
* factor : constant
* | "(" query ")"
* constant: num
* | "'" CHAR "'"
* num : DIGIT
* | DIGIT num
- * shop : "<<"
- * | ">>"
- * eqrel : "="
- * | "=="
- * | "!="
- * | "<"
- * | ">"
- * | "<="
- * | ">="
*
*
* 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 *where;
-static int query(void);
-static int lor(void);
-static int land(void);
-static int not(void);
-static int eqrel(void);
-static int shift(void);
-static int primary(void);
-static int term(void);
-static int exp(void);
-static int unary(void);
-static int factor(void);
-static int constant(void);
-static int num(void);
-static int geteqrel(void);
+static int query(int mayeval);
+static int lor(int mayeval);
+static int land(int mayeval);
+static int bor(int mayeval);
+static int xor(int mayeval);
+static int band(int mayeval);
+static int eqrel(int mayeval);
+static int nerel(int mayeval);
+static int shift(int mayeval);
+static int primary(int mayeval);
+static int term(int mayeval);
+static int exp(int mayeval);
+static int unary(int mayeval);
+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 void experr(const char *);
@@ -156,7 +152,7 @@ expr(const char *expbuf)
if (setjmp(expjump) != 0)
return FALSE;
- rval = query();
+ rval = query(1);
if (skipws() == EOS)
return rval;
@@ -168,21 +164,21 @@ expr(const char *expbuf)
* query : lor | lor '?' query ':' query
*/
static int
-query(void)
+query(int mayeval)
{
int result, true_val, false_val;
- result = lor();
+ result = lor(mayeval);
if (skipws() != '?') {
ungetch();
return result;
}
- true_val = query();
+ true_val = query(result);
if (skipws() != ':')
- experr("bad query");
+ experr("bad query: missing \":\"");
- false_val = query();
+ false_val = query(!result);
return result ? true_val : false_val;
}
@@ -190,15 +186,19 @@ query(void)
* lor : land { '||' land }
*/
static int
-lor(void)
+lor(int mayeval)
{
int c, vl, vr;
- vl = land();
+ vl = land(mayeval);
while ((c = skipws()) == '|') {
- if (getch() != '|')
+ if (getch() != '|') {
ungetch();
- vr = land();
+ break;
+ }
+ if (vl != 0)
+ mayeval = 0;
+ vr = land(mayeval);
vl = vl || vr;
}
@@ -210,15 +210,19 @@ lor(void)
* land : not { '&&' not }
*/
static int
-land(void)
+land(int mayeval)
{
int c, vl, vr;
- vl = not();
+ vl = bor(mayeval);
while ((c = skipws()) == '&') {
- if (getch() != '&')
+ if (getch() != '&') {
ungetch();
- vr = not();
+ break;
+ }
+ if (vl == 0)
+ mayeval = 0;
+ vr = bor(mayeval);
vl = vl && vr;
}
@@ -227,74 +231,131 @@ land(void)
}
/*
- * not : eqrel | '!' not
+ * bor : xor { "|" xor }
*/
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();
- val = not();
- return !val;
+ if (cr == '|')
+ break;
+ vr = xor(mayeval);
+ vl |= vr;
}
+ ungetch();
+ return (vl);
+}
- if (c == '!')
- ungetch();
+/*
+ * xor : band { "^" band }
+ */
+static int
+xor(int mayeval)
+{
+ int vl, vr, c;
+
+ vl = band(mayeval);
+ while ((c = skipws()) == '^') {
+ vr = band(mayeval);
+ vl ^= vr;
+ }
ungetch();
- return eqrel();
+ return (vl);
}
/*
- * eqrel : shift { eqrelop shift }
+ * band : eqrel { "&" eqrel }
*/
static int
-eqrel(void)
+band(int mayeval)
{
- int vl, vr, op;
+ int c, cr, vl, vr;
- vl = shift();
- while ((op = geteqrel()) != -1) {
- vr = shift();
+ vl = eqrel(mayeval);
+ while ((c = skipws()) == '&') {
+ cr = getch();
+ ungetch();
+ if (cr == '&')
+ break;
+ vr = eqrel(mayeval);
+ vl &= vr;
+ }
+ ungetch();
+ return vl;
+}
- switch (op) {
+/*
+ * eqrel : nerel { ("==" | "!=" ) nerel }
+ */
+static int
+eqrel(int mayeval)
+{
+ int vl, vr, c, cr;
- case EQL:
+ vl = nerel(mayeval);
+ while ((c = skipws()) == '!' || c == '=') {
+ if ((cr = getch()) != '=') {
+ ungetch();
+ break;
+ }
+ vr = nerel(mayeval);
+ switch (c) {
+ case '=':
vl = (vl == vr);
break;
- case NEQ:
+ case '!':
vl = (vl != vr);
break;
+ }
+ }
+ ungetch();
+ return vl;
+}
- case LEQ:
- vl = (vl <= vr);
- break;
- case LSS:
- vl = (vl < vr);
- break;
- case GTR:
- vl = (vl > vr);
+/*
+ * 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 GEQ:
- vl = (vl >= vr);
+ case '>':
+ vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
break;
}
}
+ ungetch();
return vl;
}
/*
- * shift : primary { shop primary }
+ * shift : primary { ("<<" | ">>") primary }
*/
static int
-shift(void)
+shift(int mayeval)
{
int vl, vr, c;
- vl = primary();
+ vl = primary(mayeval);
while (((c = skipws()) == '<' || c == '>') && getch() == c) {
- vr = primary();
+ vr = primary(mayeval);
if (c == '<')
vl <<= vr;
@@ -309,16 +370,16 @@ shift(void)
}
/*
- * primary : term { addop term }
+ * primary : term { ("+" | "-") term }
*/
static int
-primary(void)
+primary(int mayeval)
{
int c, vl, vr;
- vl = term();
+ vl = term(mayeval);
while ((c = skipws()) == '+' || c == '-') {
- vr = term();
+ vr = term(mayeval);
if (c == '+')
vl += vr;
@@ -331,29 +392,33 @@ primary(void)
}
/*
- * <term> := <exp> { <mulop> <exp> }
+ * term : exp { ("*" | "/" | "%") exp }
*/
static int
-term(void)
+term(int mayeval)
{
int c, vl, vr;
- vl = exp();
+ vl = exp(mayeval);
while ((c = skipws()) == '*' || c == '/' || c == '%') {
- vr = exp();
+ vr = exp(mayeval);
switch (c) {
case '*':
vl *= vr;
break;
case '/':
- if (vr == 0)
+ if (!mayeval)
+ /* short-circuit */;
+ else if (vr == 0)
errx(1, "division by zero in eval.");
else
vl /= vr;
break;
case '%':
- if (vr == 0)
+ if (!mayeval)
+ /* short-circuit */;
+ else if (vr == 0)
errx(1, "modulo zero in eval.");
else
vl %= vr;
@@ -365,24 +430,20 @@ term(void)
}
/*
- * <term> := <unary> { <expop> <unary> }
+ * exp : unary { "**" exp }
*/
static int
-exp(void)
+exp(int mayeval)
{
int c, vl, vr, n;
- vl = unary();
- switch (c = skipws()) {
-
- case '*':
+ vl = unary(mayeval);
+ while ((c = skipws()) == '*') {
if (getch() != '*') {
ungetch();
break;
}
-
- case '^':
- vr = exp();
+ vr = unary(mayeval);
n = 1;
while (vr-- > 0)
n *= vl;
@@ -394,15 +455,15 @@ exp(void)
}
/*
- * unary : factor | unop unary
+ * unary : factor | ("+" | "-" | "~" | "!") unary
*/
static int
-unary(void)
+unary(int mayeval)
{
int val, c;
- if ((c = skipws()) == '+' || c == '-' || c == '~') {
- val = unary();
+ if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
+ val = unary(mayeval);
switch (c) {
case '+':
@@ -411,30 +472,32 @@ unary(void)
return -val;
case '~':
return ~val;
+ case '!':
+ return !val;
}
}
ungetch();
- return factor();
+ return factor(mayeval);
}
/*
* factor : constant | '(' query ')'
*/
static int
-factor(void)
+factor(int mayeval)
{
int val;
if (skipws() == '(') {
- val = query();
+ val = query(mayeval);
if (skipws() != ')')
- experr("bad factor");
+ experr("bad factor: missing \")\"");
return val;
}
ungetch();
- return constant();
+ return constant(mayeval);
}
/*
@@ -442,7 +505,7 @@ factor(void)
* Note: constant() handles multi-byte constants
*/
static int
-constant(void)
+constant(int mayeval)
{
int i;
int value;
@@ -451,7 +514,7 @@ constant(void)
if (skipws() != '\'') {
ungetch();
- return num();
+ return num(mayeval);
}
for (i = 0; i < (ssize_t)sizeof(int); i++) {
if ((c = getch()) == '\'') {
@@ -469,7 +532,7 @@ constant(void)
case '6':
case '7':
ungetch();
- c = num();
+ c = num(mayeval);
break;
case 'n':
c = 012;
@@ -503,7 +566,7 @@ constant(void)
* num : digit | num digit
*/
static int
-num(void)
+num(int mayeval)
{
int rval, c, base;
int ndig;
@@ -558,50 +621,6 @@ bad_digit:
}
/*
- * 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.
*/
static int
OpenPOWER on IntegriCloud