Module Name:    src
Committed By:   rillig
Date:           Tue Jan 19 18:18:43 UTC 2021

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

Log Message:
make(1): condense code for parsing and evaluating conditionals


To generate a diff of this commit:
cvs rdiff -u -r1.238 -r1.239 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.238 src/usr.bin/make/cond.c:1.239
--- src/usr.bin/make/cond.c:1.238	Tue Jan 19 18:13:37 2021
+++ src/usr.bin/make/cond.c	Tue Jan 19 18:18:43 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: cond.c,v 1.238 2021/01/19 18:13:37 rillig Exp $	*/
+/*	$NetBSD: cond.c,v 1.239 2021/01/19 18:18:43 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -95,43 +95,39 @@
 #include "dir.h"
 
 /*	"@(#)cond.c	8.2 (Berkeley) 1/2/94"	*/
-MAKE_RCSID("$NetBSD: cond.c,v 1.238 2021/01/19 18:13:37 rillig Exp $");
+MAKE_RCSID("$NetBSD: cond.c,v 1.239 2021/01/19 18:18:43 rillig Exp $");
 
 /*
  * The parsing of conditional expressions is based on this grammar:
- *	E -> F || E
- *	E -> F
- *	F -> T && F
- *	F -> T
- *	T -> defined(variable)
- *	T -> make(target)
- *	T -> exists(file)
- *	T -> empty(varspec)
- *	T -> target(name)
- *	T -> commands(name)
- *	T -> symbol
- *	T -> $(varspec) op value
- *	T -> $(varspec) == "string"
- *	T -> $(varspec) != "string"
- *	T -> "string"
- *	T -> ( E )
- *	T -> ! T
- *	op -> == | != | > | < | >= | <=
+ *	Or -> And '||' Or
+ *	Or -> And
+ *	And -> Term '&&' And
+ *	And -> Term
+ *	Term -> Function '(' Argument ')'
+ *	Term -> Leaf Operator Leaf
+ *	Term -> Leaf
+ *	Term -> '(' Or ')'
+ *	Term -> '!' Term
+ *	Leaf -> "string"
+ *	Leaf -> Number
+ *	Leaf -> VariableExpression
+ *	Leaf -> Symbol
+ *	Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
  *
- * 'symbol' is some other symbol to which the default function is applied.
+ * 'Symbol' is an unquoted string literal to which the default function is
+ * applied.
  *
  * The tokens are scanned by CondToken, which returns:
- *	TOK_AND		for '&' or '&&'
- *	TOK_OR		for '|' or '||'
+ *	TOK_AND		for '&&'
+ *	TOK_OR		for '||'
  *	TOK_NOT		for '!'
  *	TOK_LPAREN	for '('
  *	TOK_RPAREN	for ')'
+ *
  * Other terminal symbols are evaluated using either the default function or
  * the function given in the terminal, they return either TOK_TRUE or
  * TOK_FALSE.
  *
- * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons.
- *
  * All non-terminal functions (CondParser_Expr, CondParser_Factor and
  * CondParser_Term) return either TOK_FALSE, TOK_TRUE, or TOK_ERROR on error.
  */
@@ -154,7 +150,7 @@ typedef struct CondParser {
 	Boolean printedError;
 } CondParser;
 
-static Token CondParser_Expr(CondParser *par, Boolean);
+static Token CondParser_Or(CondParser *par, Boolean);
 
 static unsigned int cond_depth = 0;	/* current .if nesting level */
 static unsigned int cond_min_depth = 0;	/* depth at makefile open */
@@ -909,11 +905,10 @@ CondParser_Token(CondParser *par, Boolea
 }
 
 /*
- * Parse a single term in the expression. This consists of a terminal symbol
- * or TOK_NOT and a term (not including the binary operators):
- *
- *	T -> defined(variable) | make(target) | exists(file) | symbol
- *	T -> ! T | ( E )
+ * Term -> '(' Or ')'
+ * Term -> '!' Term
+ * Term -> Leaf Operator Leaf
+ * Term -> Leaf
  *
  * Results:
  *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
@@ -928,113 +923,82 @@ CondParser_Term(CondParser *par, Boolean
 		return t;
 
 	if (t == TOK_LPAREN) {
-		/*
-		 * T -> ( E )
-		 */
-		t = CondParser_Expr(par, doEval);
-		if (t != TOK_ERROR) {
-			if (CondParser_Token(par, doEval) != TOK_RPAREN) {
-				t = TOK_ERROR;
-			}
-		}
-	} else if (t == TOK_NOT) {
+		t = CondParser_Or(par, doEval);
+		if (t == TOK_ERROR)
+			return TOK_ERROR;
+		if (CondParser_Token(par, doEval) != TOK_RPAREN)
+			return TOK_ERROR;
+		return t;
+	}
+
+	if (t == TOK_NOT) {
 		t = CondParser_Term(par, doEval);
-		if (t == TOK_TRUE) {
+		if (t == TOK_TRUE)
 			t = TOK_FALSE;
-		} else if (t == TOK_FALSE) {
+		else if (t == TOK_FALSE)
 			t = TOK_TRUE;
-		}
-	} else
-		return TOK_ERROR;
+		return t;
+	}
 
-	assert(t == TOK_TRUE || t == TOK_FALSE || t == TOK_ERROR);
-	return t;
+	return TOK_ERROR;
 }
 
 /*
- * Parse a conjunctive factor (nice name, wot?)
- *
- *	F -> T && F | T
+ * And -> Term '&&' And
+ * And -> Term
  *
  * Results:
  *	TOK_TRUE, TOK_FALSE or TOK_ERROR
  */
 static Token
-CondParser_Factor(CondParser *par, Boolean doEval)
+CondParser_And(CondParser *par, Boolean doEval)
 {
-	Token l, o;
+	Token res, op;
 
-	l = CondParser_Term(par, doEval);
-	if (l != TOK_ERROR) {
-		o = CondParser_Token(par, doEval);
+	res = CondParser_Term(par, doEval);
+	if (res == TOK_ERROR)
+		return TOK_ERROR;
 
-		if (o == TOK_AND) {
-			/*
-			 * F -> T && F
-			 *
-			 * If T is TOK_FALSE, the whole thing will be
-			 * TOK_FALSE, but we have to parse the r.h.s. anyway
-			 * (to throw it away). If T is TOK_TRUE, the result
-			 * is the r.h.s., be it a TOK_ERROR or not.
-			 */
-			if (l == TOK_TRUE) {
-				l = CondParser_Factor(par, doEval);
-			} else {
-				if (CondParser_Factor(par, FALSE) == TOK_ERROR)
-					return TOK_ERROR;
-			}
-		} else {
-			/*
-			 * F -> T
-			 */
-			CondParser_PushBack(par, o);
-		}
+	op = CondParser_Token(par, doEval);
+	if (op == TOK_AND) {
+		if (res == TOK_TRUE)
+			return CondParser_And(par, doEval);
+		if (CondParser_And(par, FALSE) == TOK_ERROR)
+			return TOK_ERROR;
+		return res;
 	}
-	return l;
+
+	CondParser_PushBack(par, op);
+	return res;
 }
 
 /*
- * Main expression production.
- *
- *	E -> F || E | F
+ * Or -> And '||' Or
+ * Or -> And
  *
  * Results:
  *	TOK_TRUE, TOK_FALSE or TOK_ERROR.
  */
 static Token
-CondParser_Expr(CondParser *par, Boolean doEval)
+CondParser_Or(CondParser *par, Boolean doEval)
 {
-	Token l, o;
+	Token res, op;
 
-	l = CondParser_Factor(par, doEval);
-	if (l != TOK_ERROR) {
-		o = CondParser_Token(par, doEval);
+	res = CondParser_And(par, doEval);
+	if (res == TOK_ERROR)
+		return TOK_ERROR;
 
-		if (o == TOK_OR) {
-			/*
-			 * E -> F || E
-			 *
-			 * A similar thing occurs for ||, except that here
-			 * we make sure the l.h.s. is TOK_FALSE before we
-			 * bother to evaluate the r.h.s. Once again, if l
-			 * is TOK_FALSE, the result is the r.h.s. and once
-			 * again if l is TOK_TRUE, we parse the r.h.s. to
-			 * throw it away.
-			 */
-			if (l == TOK_FALSE) {
-				l = CondParser_Expr(par, doEval);
-			} else {
-				if (CondParser_Expr(par, FALSE) == TOK_ERROR)
-					return TOK_ERROR;
-			}
-		} else {
-			/*
-			 * E -> F
-			 */
-			CondParser_PushBack(par, o);
-		}
+	op = CondParser_Token(par, doEval);
+	if (op == TOK_OR) {
+		if (res == TOK_FALSE)
+			return CondParser_Or(par, doEval);
+		if (CondParser_Or(par, FALSE) == TOK_ERROR)
+			return TOK_ERROR;
+		return res;
 	}
-	return l;
+
+	CondParser_PushBack(par, op);
+	return res;
 }
 
 static CondEvalResult
@@ -1044,7 +1008,7 @@ CondParser_Eval(CondParser *par, Boolean
 
 	DEBUG1(COND, "CondParser_Eval: %s\n", par->p);
 
-	res = CondParser_Expr(par, TRUE);
+	res = CondParser_Or(par, TRUE);
 	if (res != TOK_FALSE && res != TOK_TRUE)
 		return COND_INVALID;
 

Reply via email to