Module Name:    src
Committed By:   rillig
Date:           Tue Jan 19 21:55:20 UTC 2021

Modified Files:
        src/usr.bin/make: cond.c

Log Message:
make(1): remove struct If from evaluation of conditionals

The variant of the .if directive can be stored in the CondParser
directly, instead of pointing to a struct If.

The type CondParser may have to be renamed since the condition is not
only parsed, it is evaluated as well.

No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.242 -r1.243 src/usr.bin/make/cond.c

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.242 src/usr.bin/make/cond.c:1.243
--- src/usr.bin/make/cond.c:1.242	Tue Jan 19 20:51:46 2021
+++ src/usr.bin/make/cond.c	Tue Jan 19 21:55:20 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: cond.c,v 1.242 2021/01/19 20:51:46 rillig Exp $	*/
+/*	$NetBSD: cond.c,v 1.243 2021/01/19 21:55:20 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.242 2021/01/19 20:51:46 rillig Exp $");
+MAKE_RCSID("$NetBSD: cond.c,v 1.243 2021/01/19 21:55:20 rillig Exp $");
 
 /*
  * The parsing of conditional expressions is based on this grammar:
@@ -138,7 +138,18 @@ typedef enum CondResult {
 } CondResult;
 
 typedef struct CondParser {
-	const struct If *if_info; /* Info for current statement */
+
+	/*
+	 * The plain '.if ${VAR}' evaluates to true if the value of the
+	 * expression has length > 0.  The other '.if' variants delegate
+	 * to evalBare instead.
+	 */
+	Boolean plain;
+
+	/* The function to apply on unquoted bare words. */
+	Boolean (*evalBare)(size_t, const char *);
+	Boolean negateEvalBare;
+
 	const char *p;		/* The remaining condition to parse */
 	Token curr;		/* Single push-back token used in parsing */
 
@@ -511,32 +522,11 @@ cleanup:
 	*out_str = str;
 }
 
-struct If {
-	const char *form;	/* Form of if */
-	size_t formlen;		/* Length of form */
-	Boolean doNot;		/* TRUE if default function should be negated */
-	/* The default function to apply on unquoted bare words. */
-	Boolean (*defProc)(size_t, const char *);
-};
-
-/* The different forms of .if directives. */
-static const struct If ifs[] = {
-    { "def",   3, FALSE, FuncDefined },
-    { "ndef",  4, TRUE,  FuncDefined },
-    { "make",  4, FALSE, FuncMake },
-    { "nmake", 5, TRUE,  FuncMake },
-    { "",      0, FALSE, FuncDefined },
-    { NULL,    0, FALSE, NULL }
-};
-enum {
-	PLAIN_IF_INDEX = 4
-};
-
 static Boolean
-If_Eval(const struct If *if_info, const char *arg, size_t arglen)
+If_Eval(const CondParser *par, const char *arg, size_t arglen)
 {
-	Boolean res = if_info->defProc(arglen, arg);
-	return if_info->doNot ? !res : res;
+	Boolean res = par->evalBare(arglen, arg);
+	return par->negateEvalBare ? !res : res;
 }
 
 /*
@@ -560,11 +550,10 @@ EvalNotEmpty(CondParser *par, const char
 	 * the evaluation function from that .if variant, which would test
 	 * whether a variable of the given name were defined. */
 	/* XXX: Whitespace should count as empty, just as in ParseEmptyArg. */
-	if (par->if_info->form[0] == '\0')
+	if (par->plain)
 		return value[0] != '\0';
 
-	/* For the other variants of .ifxxx ${...}, use its default function. */
-	return If_Eval(par->if_info, value, strlen(value));
+	return If_Eval(par, value, strlen(value));
 }
 
 /* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */
@@ -835,7 +824,7 @@ CondParser_LeafToken(CondParser *par, Bo
 	 * after .if must have been taken literally, so the argument cannot
 	 * be empty - even if it contained a variable expansion.
 	 */
-	t = ToToken(!doEval || If_Eval(par->if_info, arg, arglen));
+	t = ToToken(!doEval || If_Eval(par, arg, arglen));
 	free(arg);
 	return t;
 }
@@ -999,7 +988,7 @@ CondParser_Or(CondParser *par, Boolean d
 }
 
 static CondEvalResult
-CondParser_Eval(CondParser *par, Boolean *value)
+CondParser_Eval(CondParser *par, Boolean *out_value)
 {
 	CondResult res;
 
@@ -1012,7 +1001,7 @@ CondParser_Eval(CondParser *par, Boolean
 	if (CondParser_Token(par, FALSE) != TOK_EOF)
 		return COND_INVALID;
 
-	*value = res == CR_TRUE;
+	*out_value = res == CR_TRUE;
 	return COND_PARSE;
 }
 
@@ -1028,7 +1017,8 @@ CondParser_Eval(CondParser *par, Boolean
  *	(*value) is set to the boolean value of the condition
  */
 static CondEvalResult
-CondEvalExpression(const struct If *info, const char *cond, Boolean *value,
+CondEvalExpression(const char *cond, Boolean *out_value, Boolean plain,
+		   Boolean (*evalBare)(size_t, const char *), Boolean negate,
 		   Boolean eprint, Boolean strictLHS)
 {
 	CondParser par;
@@ -1038,12 +1028,14 @@ CondEvalExpression(const struct If *info
 
 	cpp_skip_hspace(&cond);
 
-	par.if_info = info != NULL ? info : ifs + PLAIN_IF_INDEX;
+	par.plain = plain;
+	par.evalBare = evalBare;
+	par.negateEvalBare = negate;
 	par.p = cond;
 	par.curr = TOK_NONE;
 	par.printedError = FALSE;
 
-	rval = CondParser_Eval(&par, value);
+	rval = CondParser_Eval(&par, out_value);
 
 	if (rval == COND_INVALID && eprint && !par.printedError)
 		Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
@@ -1058,7 +1050,8 @@ CondEvalExpression(const struct If *info
 CondEvalResult
 Cond_EvalCondition(const char *cond, Boolean *out_value)
 {
-	return CondEvalExpression(NULL, cond, out_value, FALSE, FALSE);
+	return CondEvalExpression(cond, out_value, TRUE,
+	    FuncDefined, FALSE, FALSE, FALSE);
 }
 
 static Boolean
@@ -1121,7 +1114,9 @@ Cond_EvalLine(const char *line)
 	static enum IfState *cond_states = NULL;
 	static unsigned int cond_states_cap = 128;
 
-	const struct If *ifp;
+	Boolean plain;
+	Boolean (*evalBare)(size_t, const char *);
+	Boolean negate;
 	Boolean isElif;
 	Boolean value;
 	IfState state;
@@ -1205,25 +1200,32 @@ Cond_EvalLine(const char *line)
 	}
 
 	/*
-	 * Figure out what sort of conditional it is -- what its default
-	 * function is, etc. -- by looking in the table of valid "ifs"
+	 * Figure out what sort of conditional it is.
 	 */
 	p += 2;
-	for (ifp = ifs;; ifp++) {
-		if (ifp->form == NULL) {
-			/*
-			 * TODO: Add error message about unknown directive,
-			 * since there is no other known directive that starts
-			 * with 'el' or 'if'.
-			 *
-			 * Example: .elifx 123
-			 */
-			return COND_INVALID;
-		}
-		if (is_token(p, ifp->form, ifp->formlen)) {
-			p += ifp->formlen;
-			break;
-		}
+	plain = FALSE;
+	evalBare = FuncDefined;
+	negate = FALSE;
+	if (*p == 'n') {
+		p++;
+		negate = TRUE;
+	}
+	if (is_token(p, "def", 3)) {		/* .ifdef and .ifndef */
+		p += 3;
+	} else if (is_token(p, "make", 4)) {	/* .ifmake and .ifnmake */
+		p += 4;
+		evalBare = FuncMake;
+	} else if (is_token(p, "", 0) && !negate) {	/* plain .if */
+		plain = TRUE;
+	} else {
+		/*
+		 * TODO: Add error message about unknown directive,
+		 * since there is no other known directive that starts
+		 * with 'el' or 'if'.
+		 *
+		 * Example: .elifx 123
+		 */
+		return COND_INVALID;
 	}
 
 	/* Now we know what sort of 'if' it is... */
@@ -1270,7 +1272,8 @@ Cond_EvalLine(const char *line)
 	}
 
 	/* And evaluate the conditional expression */
-	if (CondEvalExpression(ifp, p, &value, TRUE, TRUE) == COND_INVALID) {
+	if (CondEvalExpression(p, &value, plain, evalBare, negate,
+	    TRUE, TRUE) == COND_INVALID) {
 		/* Syntax error in conditional, error message already output. */
 		/* Skip everything to matching .endif */
 		/* XXX: An extra '.else' is not detected in this case. */

Reply via email to