Module Name: src Committed By: rillig Date: Thu Jan 21 23:25:08 UTC 2021
Modified Files: src/usr.bin/make: cond.c src/usr.bin/make/unit-tests: cond-cmp-numeric-eq.exp cond-cmp-numeric.exp cond-cmp-string.exp cond-token-plain.exp Log Message: make(1): fix debug output for comparison operators in conditionals This produces fewer warnings than before, but these were edge cases that probably didn't matter in practice. The "Malformaed conditional" is still generated, the set of accepted conditionals is still the same. To generate a diff of this commit: cvs rdiff -u -r1.250 -r1.251 src/usr.bin/make/cond.c cvs rdiff -u -r1.3 -r1.4 src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp \ src/usr.bin/make/unit-tests/cond-cmp-numeric.exp cvs rdiff -u -r1.9 -r1.10 src/usr.bin/make/unit-tests/cond-cmp-string.exp cvs rdiff -u -r1.7 -r1.8 src/usr.bin/make/unit-tests/cond-token-plain.exp Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/cond.c diff -u src/usr.bin/make/cond.c:1.250 src/usr.bin/make/cond.c:1.251 --- src/usr.bin/make/cond.c:1.250 Thu Jan 21 23:06:06 2021 +++ src/usr.bin/make/cond.c Thu Jan 21 23:25:08 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: cond.c,v 1.250 2021/01/21 23:06:06 rillig Exp $ */ +/* $NetBSD: cond.c,v 1.251 2021/01/21 23:25:08 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -95,7 +95,7 @@ #include "dir.h" /* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */ -MAKE_RCSID("$NetBSD: cond.c,v 1.250 2021/01/21 23:06:06 rillig Exp $"); +MAKE_RCSID("$NetBSD: cond.c,v 1.251 2021/01/21 23:25:08 rillig Exp $"); /* * The parsing of conditional expressions is based on this grammar: @@ -137,6 +137,10 @@ typedef enum CondResult { CR_FALSE, CR_TRUE, CR_ERROR } CondResult; +typedef enum ComparisonOp { + LT, LE, GT, GE, EQ, NE +} ComparisonOp; + typedef struct CondParser { /* @@ -167,6 +171,8 @@ static CondResult CondParser_Or(CondPars static unsigned int cond_depth = 0; /* current .if nesting level */ static unsigned int cond_min_depth = 0; /* depth at makefile open */ +static const char *opname[] = { "<", "<=", ">", ">=", "==", "!=" }; + /* * Indicate when we should be strict about lhs of comparisons. * In strict mode, the lhs must be a variable expression or a string literal @@ -575,65 +581,90 @@ EvalNotEmpty(CondParser *par, const char } /* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */ -static Token -EvalCompareNum(double lhs, const char *op, double rhs) +static Boolean +EvalCompareNum(double lhs, ComparisonOp op, double rhs) { - /* FIXME: %2.s is cheated and produces wrong output. */ - DEBUG3(COND, "lhs = %f, rhs = %f, op = %.2s\n", lhs, rhs, op); + DEBUG3(COND, "lhs = %f, rhs = %f, op = %.2s\n", lhs, rhs, opname[op]); - switch (op[0]) { - case '!': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, "Unknown operator"); - /* The PARSE_FATAL follows in CondEvalExpression. */ - return TOK_ERROR; - } - return ToToken(lhs != rhs); - case '=': - if (op[1] != '=') { - Parse_Error(PARSE_WARNING, "Unknown operator"); - /* The PARSE_FATAL follows in CondEvalExpression. */ - return TOK_ERROR; - } - return ToToken(lhs == rhs); - case '<': - return ToToken(op[1] == '=' ? lhs <= rhs : lhs < rhs); - case '>': - return ToToken(op[1] == '=' ? lhs >= rhs : lhs > rhs); + switch (op) { + case LT: + return lhs < rhs; + case LE: + return lhs <= rhs; + case GT: + return lhs > rhs; + case GE: + return lhs >= rhs; + case NE: + return lhs != rhs; + default: + return lhs == rhs; } - return TOK_ERROR; } static Token -EvalCompareStr(const char *lhs, const char *op, const char *rhs) +EvalCompareStr(const char *lhs, ComparisonOp op, const char *rhs) { - if (!((op[0] == '!' || op[0] == '=') && op[1] == '=')) { + if (op != EQ && op != NE) { Parse_Error(PARSE_WARNING, - "String comparison operator " - "must be either == or !="); + "String comparison operator must be either == or !="); /* The PARSE_FATAL follows in CondEvalExpression. */ return TOK_ERROR; } - /* FIXME: %2.s is cheated and produces wrong output. */ - DEBUG3(COND, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, rhs, op); - return ToToken((*op == '=') == (strcmp(lhs, rhs) == 0)); + DEBUG3(COND, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", + lhs, rhs, opname[op]); + return ToToken((op == EQ) == (strcmp(lhs, rhs) == 0)); } /* Evaluate a comparison, such as "${VAR} == 12345". */ static Token -EvalCompare(const char *lhs, Boolean lhsQuoted, const char *op, +EvalCompare(const char *lhs, Boolean lhsQuoted, ComparisonOp op, const char *rhs, Boolean rhsQuoted) { double left, right; if (!rhsQuoted && !lhsQuoted) if (TryParseNumber(lhs, &left) && TryParseNumber(rhs, &right)) - return EvalCompareNum(left, op, right); + return ToToken(EvalCompareNum(left, op, right)); return EvalCompareStr(lhs, op, rhs); } +static Boolean +CondParser_ComparisonOp(CondParser *par, ComparisonOp *out_op) +{ + const char *p = par->p; + + if (p[0] == '<' && p[1] == '=') { + *out_op = LE; + goto length_2; + } else if (p[0] == '<') { + *out_op = LT; + goto length_1; + } else if (p[0] == '>' && p[1] == '=') { + *out_op = GE; + goto length_2; + } else if (p[0] == '>') { + *out_op = GT; + goto length_1; + } else if (p[0] == '=' && p[1] == '=') { + *out_op = EQ; + goto length_2; + } else if (p[0] == '!' && p[1] == '=') { + *out_op = NE; + goto length_2; + } + return FALSE; + +length_2: + par->p = p + 2; + return TRUE; +length_1: + par->p = p + 1; + return TRUE; +} + /* * Parse a comparison condition such as: * @@ -647,7 +678,7 @@ CondParser_Comparison(CondParser *par, B { Token t = TOK_ERROR; FStr lhs, rhs; - const char *op; + ComparisonOp op; Boolean lhsQuoted, rhsQuoted; /* @@ -660,18 +691,7 @@ CondParser_Comparison(CondParser *par, B CondParser_SkipWhitespace(par); - op = par->p; - switch (par->p[0]) { - case '!': - case '=': - case '<': - case '>': - if (par->p[1] == '=') - par->p += 2; - else - par->p++; - break; - default: + if (!CondParser_ComparisonOp(par, &op)) { /* Unknown operator, compare against an empty string or 0. */ t = ToToken(doEval && EvalNotEmpty(par, lhs.str, lhsQuoted)); goto done_lhs; Index: src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp diff -u src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp:1.3 src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp:1.4 --- src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp:1.3 Sun Nov 8 21:47:59 2020 +++ src/usr.bin/make/unit-tests/cond-cmp-numeric-eq.exp Thu Jan 21 23:25:08 2021 @@ -1,4 +1,3 @@ -make: "cond-cmp-numeric-eq.mk" line 67: warning: Unknown operator make: "cond-cmp-numeric-eq.mk" line 67: Malformed conditional (!(12345 = 12345)) make: "cond-cmp-numeric-eq.mk" line 74: Malformed conditional (!(12345 === 12345)) make: Fatal errors encountered -- cannot continue Index: src/usr.bin/make/unit-tests/cond-cmp-numeric.exp diff -u src/usr.bin/make/unit-tests/cond-cmp-numeric.exp:1.3 src/usr.bin/make/unit-tests/cond-cmp-numeric.exp:1.4 --- src/usr.bin/make/unit-tests/cond-cmp-numeric.exp:1.3 Sun Nov 8 22:56:16 2020 +++ src/usr.bin/make/unit-tests/cond-cmp-numeric.exp Thu Jan 21 23:25:08 2021 @@ -7,8 +7,6 @@ make: "cond-cmp-numeric.mk" line 16: Mal CondParser_Eval: !(${:UNaN} == NaN) lhs = "NaN", rhs = "NaN", op = == CondParser_Eval: 123 ! 123 -lhs = 123.000000, rhs = 123.000000, op = ! -make: "cond-cmp-numeric.mk" line 34: warning: Unknown operator make: "cond-cmp-numeric.mk" line 34: Malformed conditional (123 ! 123) make: Fatal errors encountered -- cannot continue make: stopped in unit-tests Index: src/usr.bin/make/unit-tests/cond-cmp-string.exp diff -u src/usr.bin/make/unit-tests/cond-cmp-string.exp:1.9 src/usr.bin/make/unit-tests/cond-cmp-string.exp:1.10 --- src/usr.bin/make/unit-tests/cond-cmp-string.exp:1.9 Tue Jan 19 19:54:57 2021 +++ src/usr.bin/make/unit-tests/cond-cmp-string.exp Thu Jan 21 23:25:08 2021 @@ -1,6 +1,5 @@ make: "cond-cmp-string.mk" line 18: Malformed conditional (str != str) make: "cond-cmp-string.mk" line 42: Malformed conditional ("string" != "str""ing") -make: "cond-cmp-string.mk" line 49: warning: String comparison operator must be either == or != make: "cond-cmp-string.mk" line 49: Malformed conditional (!("value" = "value")) make: "cond-cmp-string.mk" line 56: Malformed conditional (!("value" === "value")) make: "cond-cmp-string.mk" line 113: warning: String comparison operator must be either == or != Index: src/usr.bin/make/unit-tests/cond-token-plain.exp diff -u src/usr.bin/make/unit-tests/cond-token-plain.exp:1.7 src/usr.bin/make/unit-tests/cond-token-plain.exp:1.8 --- src/usr.bin/make/unit-tests/cond-token-plain.exp:1.7 Thu Jan 21 14:08:09 2021 +++ src/usr.bin/make/unit-tests/cond-token-plain.exp Thu Jan 21 23:25:08 2021 @@ -18,9 +18,9 @@ lhs = "yes", rhs = "yes", op = != CondParser_Eval: ${UNDEF:Uundefined}!=undefined lhs = "undefined", rhs = "undefined", op = != CondParser_Eval: ${UNDEF:U12345}>12345 -lhs = 12345.000000, rhs = 12345.000000, op = >1 +lhs = 12345.000000, rhs = 12345.000000, op = > CondParser_Eval: ${UNDEF:U12345}<12345 -lhs = 12345.000000, rhs = 12345.000000, op = <1 +lhs = 12345.000000, rhs = 12345.000000, op = < CondParser_Eval: (${UNDEF:U0})||0 CondParser_Eval: ${:Uvar}&&name != "var&&name" lhs = "var&&name", rhs = "var&&name", op = !=