Module Name:    src
Committed By:   rillig
Date:           Sat Mar 15 09:33:02 UTC 2025

Modified Files:
        src/bin/expr: expr.y

Log Message:
expr: extract expression evaluation functions from the grammar


To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/bin/expr/expr.y

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/expr/expr.y
diff -u src/bin/expr/expr.y:1.47 src/bin/expr/expr.y:1.48
--- src/bin/expr/expr.y:1.47	Fri Mar 14 21:48:10 2025
+++ src/bin/expr/expr.y	Sat Mar 15 09:33:02 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: expr.y,v 1.47 2025/03/14 21:48:10 rillig Exp $ */
+/* $NetBSD: expr.y,v 1.48 2025/03/15 09:33:02 rillig Exp $ */
 
 /*_
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
 %{
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: expr.y,v 1.47 2025/03/14 21:48:10 rillig Exp $");
+__RCSID("$NetBSD: expr.y,v 1.48 2025/03/15 09:33:02 rillig Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -53,7 +53,9 @@ static void yyerror(const char *, ...) _
 static int yylex(void);
 static int is_zero_or_null(const char *);
 static int is_integer(const char *);
-static int64_t perform_arith_op(const char *, const char *, const char *);
+static const char *eval_arith(const char *, const char *, const char *);
+static int eval_compare(const char *, const char *, const char *);
+static const char *eval_match(const char *, const char *);
 
 #define YYSTYPE	const char *
 
@@ -70,154 +72,37 @@ static int64_t perform_arith_op(const ch
 
 %%
 
-exp:	expr = {
+exp:	expr {
 		(void) printf("%s\n", $1);
 		return (is_zero_or_null($1));
 		}
 	;
 
 expr:	item { $$ = $1; }
-	| expr SPEC_OR expr = {
-		/*
-		 * Return evaluation of first expression if it is neither
-		 * an empty string nor zero; otherwise, returns the evaluation
-		 * of second expression.
-		 */
+	| expr SPEC_OR expr {
 		if (!is_zero_or_null($1))
 			$$ = $1;
 		else
 			$$ = $3;
 		}
-	| expr SPEC_AND expr = {
-		/*
-		 * Returns the evaluation of first expr if neither expression
-		 * evaluates to an empty string or zero; otherwise, returns
-		 * zero.
-		 */
+	| expr SPEC_AND expr {
 		if (!is_zero_or_null($1) && !is_zero_or_null($3))
 			$$ = $1;
 		else
 			$$ = "0";
 		}
-	| expr SPEC_REG expr = {
-		/*
-		 * The ``:'' operator matches first expr against the second,
-		 * which must be a regular expression.
-		 */
-		regex_t rp;
-		regmatch_t rm[2];
-		int eval;
-
-		/* compile regular expression */
-		if ((eval = regcomp(&rp, $3, REG_BASIC)) != 0) {
-			char errbuf[256];
-			(void)regerror(eval, &rp, errbuf, sizeof(errbuf));
-			yyerror("%s", errbuf);
-			/* NOT REACHED */
-		}
-		
-		/* compare string against pattern --  remember that patterns 
-		   are anchored to the beginning of the line */
-		if (regexec(&rp, $1, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
-			char *val;
-			if (rm[1].rm_so >= 0) {
-				(void) asprintf(&val, "%.*s",
-					(int) (rm[1].rm_eo - rm[1].rm_so),
-					$1 + rm[1].rm_so);
-			} else {
-				(void) asprintf(&val, "%d",
-					(int)(rm[0].rm_eo - rm[0].rm_so));
-			}
-			if (val == NULL)
-				err(1, NULL);
-			$$ = val;
-		} else {
-			if (rp.re_nsub == 0) {
-				$$ = "0";
-			} else {
-				$$ = "";
-			}
-		}
-
+	| expr SPEC_REG expr {
+		$$ = eval_match($1, $3);
 		}
-	| expr ADD_SUB_OPERATOR expr = {
-		/* Returns the results of addition, subtraction */
-		char *val;
-		int64_t res;
-		
-		res = perform_arith_op($1, $2, $3);
-		(void) asprintf(&val, "%lld", (long long int) res);
-		if (val == NULL)
-			err(1, NULL);
-		$$ = val;
+	| expr ADD_SUB_OPERATOR expr {
+		$$ = eval_arith($1, $2, $3);
                 }
 
-	| expr MUL_DIV_MOD_OPERATOR expr = {
-		/* 
-		 * Returns the results of multiply, divide or remainder of 
-		 * numeric-valued arguments.
-		 */
-		char *val;
-		int64_t res;
-
-		res = perform_arith_op($1, $2, $3);
-		(void) asprintf(&val, "%lld", (long long int) res);
-		if (val == NULL)
-			err(1, NULL);
-		$$ = val;
-
+	| expr MUL_DIV_MOD_OPERATOR expr {
+		$$ = eval_arith($1, $2, $3);
 		}
-	| expr COMPARE expr = {
-		/*
-		 * Returns the results of integer comparison if both arguments
-		 * are integers; otherwise, returns the results of string
-		 * comparison using the locale-specific collation sequence.
-		 * The result of each comparison is 1 if the specified relation
-		 * is true, or 0 if the relation is false.
-		 */
-
-		int64_t l, r;
-		int res;
-
-		res = 0;
-
-		/*
-		 * Slight hack to avoid differences in the compare code
-		 * between string and numeric compare.
-		 */
-		if (is_integer($1) && is_integer($3)) {
-			/* numeric comparison */
-			l = strtoll($1, NULL, 10);
-			r = strtoll($3, NULL, 10);
-		} else {
-			/* string comparison */
-			l = strcoll($1, $3);
-			r = 0;
-		}
-
-		switch($2[0]) {	
-		case '=': /* equal */
-			res = (l == r);
-			break;
-		case '>': /* greater or greater-equal */
-			if ($2[1] == '=')
-				res = (l >= r);
-			else
-				res = (l > r);
-			break;
-		case '<': /* lower or lower-equal */
-			if ($2[1] == '=')
-				res = (l <= r);
-			else
-				res = (l < r);
-			break;
-		case '!': /* not equal */
-			/* the check if this is != was done in yylex() */
-			res = (l != r);
-		}
-
-		$$ = (res) ? "1" : "0";
-
+	| expr COMPARE expr {
+		$$ = eval_compare($1, $2, $3) ? "1" : "0";
 		}
 	| LEFT_PARENT expr RIGHT_PARENT { $$ = $2; }
 	| LENGTH expr {
@@ -270,8 +155,8 @@ is_integer(const char *str)
 	return (endptr[0] == '\0');
 }
 
-static int64_t
-perform_arith_op(const char *left, const char *op, const char *right)
+static const char *
+eval_arith(const char *left, const char *op, const char *right)
 {
 	int64_t res, l, r;
 
@@ -380,7 +265,77 @@ perform_arith_op(const char *left, const
 		}
 		break;
 	}
-	return res;
+
+	char *val;
+	(void)asprintf(&val, "%lld", (long long int)res);
+	if (val == NULL)
+		err(1, NULL);
+	return val;
+}
+
+static int
+eval_compare(const char *left, const char *op, const char *right)
+{
+	int64_t l, r;
+
+	if (is_integer(left) && is_integer(right)) {
+		l = strtoll(left, NULL, 10);
+		r = strtoll(right, NULL, 10);
+	} else {
+		l = strcoll(left, right);
+		r = 0;
+	}
+
+	switch (op[0]) {
+	case '=':
+		return l == r;
+	case '>':
+		if (op[1] == '=')
+			return l >= r;
+		else
+			return l > r;
+	case '<':
+		if (op[1] == '=')
+			return l <= r;
+		else
+			return l < r;
+	default:
+		return l != r;
+	}
+}
+
+static const char *
+eval_match(const char *str, const char *re)
+{
+	regex_t rp;
+	regmatch_t rm[2];
+	int eval;
+
+	if ((eval = regcomp(&rp, re, REG_BASIC)) != 0) {
+		char errbuf[256];
+		(void)regerror(eval, &rp, errbuf, sizeof(errbuf));
+		yyerror("%s", errbuf);
+	}
+
+	if (regexec(&rp, str, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
+		char *val;
+		if (rm[1].rm_so >= 0) {
+			(void)asprintf(&val, "%.*s",
+				(int)(rm[1].rm_eo - rm[1].rm_so),
+				str + rm[1].rm_so);
+		} else {
+			(void)asprintf(&val, "%d",
+				(int)(rm[0].rm_eo - rm[0].rm_so));
+		}
+		if (val == NULL)
+			err(1, NULL);
+		return val;
+	}
+
+	if (rp.re_nsub == 0)
+		return "0";
+	else
+		return "";
 }
 
 static const char *x = "|&=<>+-*/%:()";

Reply via email to