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 = "|&=<>+-*/%:()";