Module Name: src
Committed By: rillig
Date: Sat Mar 15 10:00:56 UTC 2025
Modified Files:
src/bin/expr: expr.y
Log Message:
expr: clean up grammar and code
To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 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.48 src/bin/expr/expr.y:1.49
--- src/bin/expr/expr.y:1.48 Sat Mar 15 09:33:02 2025
+++ src/bin/expr/expr.y Sat Mar 15 10:00:56 2025
@@ -1,11 +1,12 @@
-/* $NetBSD: expr.y,v 1.48 2025/03/15 09:33:02 rillig Exp $ */
+/* $NetBSD: expr.y,v 1.49 2025/03/15 10:00:56 rillig Exp $ */
-/*_
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+/*-
+ * Copyright (c) 2000, 2025 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Jaromir Dolecek <[email protected]> and J.T. Conklin <[email protected]>.
+ * by Jaromir Dolecek <[email protected]>, J.T. Conklin <[email protected]>
+ * and Roland Illig <[email protected]>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,9 +32,7 @@
%{
#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: expr.y,v 1.48 2025/03/15 09:33:02 rillig Exp $");
-#endif /* not lint */
+__RCSID("$NetBSD: expr.y,v 1.49 2025/03/15 10:00:56 rillig Exp $");
#include <sys/types.h>
@@ -51,7 +50,7 @@ static const char * const *av;
static void yyerror(const char *, ...) __dead;
static int yylex(void);
-static int is_zero_or_null(const char *);
+static int is_empty_or_zero(const char *);
static int is_integer(const char *);
static const char *eval_arith(const char *, const char *, const char *);
static int eval_compare(const char *, const char *, const char *);
@@ -63,7 +62,7 @@ static const char *eval_match(const char
%token STRING
%left SPEC_OR
%left SPEC_AND
-%left COMPARE
+%left COMPARE
%left ADD_SUB_OPERATOR
%left MUL_DIV_MOD_OPERATOR
%left SPEC_REG
@@ -73,50 +72,48 @@ static const char *eval_match(const char
%%
exp: expr {
- (void) printf("%s\n", $1);
- return (is_zero_or_null($1));
- }
- ;
+ (void)printf("%s\n", $1);
+ return is_empty_or_zero($1);
+ }
+;
-expr: item { $$ = $1; }
- | expr SPEC_OR expr {
- if (!is_zero_or_null($1))
+expr: item
+| expr SPEC_OR expr {
+ if (!is_empty_or_zero($1))
$$ = $1;
else
$$ = $3;
- }
- | expr SPEC_AND expr {
- if (!is_zero_or_null($1) && !is_zero_or_null($3))
+ }
+| expr SPEC_AND expr {
+ if (!is_empty_or_zero($1) && !is_empty_or_zero($3))
$$ = $1;
else
$$ = "0";
- }
- | expr SPEC_REG expr {
+ }
+| expr SPEC_REG expr {
$$ = eval_match($1, $3);
- }
- | expr ADD_SUB_OPERATOR expr {
+ }
+| expr ADD_SUB_OPERATOR expr {
$$ = eval_arith($1, $2, $3);
- }
-
- | expr MUL_DIV_MOD_OPERATOR expr {
+ }
+| expr MUL_DIV_MOD_OPERATOR expr {
$$ = eval_arith($1, $2, $3);
- }
- | expr COMPARE expr {
+ }
+| expr COMPARE expr {
$$ = eval_compare($1, $2, $3) ? "1" : "0";
- }
- | LEFT_PARENT expr RIGHT_PARENT { $$ = $2; }
- | LENGTH expr {
- /*
- * Return length of 'expr' in bytes.
- */
+ }
+| LEFT_PARENT expr RIGHT_PARENT {
+ $$ = $2;
+ }
+| LENGTH expr {
char *ln;
asprintf(&ln, "%ld", (long) strlen($2));
if (ln == NULL)
err(1, NULL);
$$ = ln;
- }
- ;
+ }
+;
item: STRING
| ADD_SUB_OPERATOR
@@ -129,30 +126,36 @@ item: STRING
;
%%
-/*
- * Returns 1 if the string is empty or contains only numeric zero.
- */
static int
-is_zero_or_null(const char *str)
+is_empty_or_zero(const char *str)
{
char *endptr;
return str[0] == '\0'
- || ( strtoll(str, &endptr, 10) == 0LL
- && endptr[0] == '\0');
+ || (strtoll(str, &endptr, 10) == 0 && endptr[0] == '\0');
}
-/*
- * Returns 1 if the string is an integer.
- */
static int
is_integer(const char *str)
{
char *endptr;
- (void) strtoll(str, &endptr, 10);
+ (void)strtoll(str, &endptr, 10);
/* note we treat empty string as valid number */
- return (endptr[0] == '\0');
+ return endptr[0] == '\0';
+}
+
+static int64_t
+to_integer(const char *str)
+{
+ errno = 0;
+ int64_t num = strtoll(str, NULL, 10);
+ if (errno == ERANGE) {
+ yyerror("value '%s' is too %s is %lld", str,
+ num > 0 ? "big, maximum" : "small, minimum",
+ num > 0 ? LLONG_MAX : LLONG_MIN);
+ }
+ return num;
}
static const char *
@@ -162,107 +165,58 @@ eval_arith(const char *left, const char
res = 0;
- if (!is_integer(left)) {
+ if (!is_integer(left))
yyerror("non-integer argument '%s'", left);
- /* NOTREACHED */
- }
- if (!is_integer(right)) {
+ if (!is_integer(right))
yyerror("non-integer argument '%s'", right);
- /* NOTREACHED */
- }
- errno = 0;
- l = strtoll(left, NULL, 10);
- if (errno == ERANGE) {
- yyerror("value '%s' is %s is %lld", left,
- (l > 0) ? "too big, maximum" : "too small, minimum",
- (l > 0) ? LLONG_MAX : LLONG_MIN);
- /* NOTREACHED */
- }
+ l = to_integer(left);
+ r = to_integer(right);
- errno = 0;
- r = strtoll(right, NULL, 10);
- if (errno == ERANGE) {
- yyerror("value '%s' is %s is %lld", right,
- (l > 0) ? "too big, maximum" : "too small, minimum",
- (l > 0) ? LLONG_MAX : LLONG_MIN);
- /* NOTREACHED */
- }
-
- switch(op[0]) {
+ switch (op[0]) {
case '+':
- /*
- * Check for over-& underflow.
- */
- if ((l >= 0 && r <= INT64_MAX - l) ||
- (l <= 0 && r >= INT64_MIN - l)) {
- res = l + r;
- } else {
- yyerror("integer overflow or underflow occurred for "
- "operation '%s %s %s'", left, op, right);
- }
+ if ((r > 0 && l > INT64_MAX - r) ||
+ (r < 0 && l < INT64_MIN - r))
+ goto integer_overflow;
+ res = l + r;
break;
case '-':
- /*
- * Check for over-& underflow.
- */
if ((r > 0 && l < INT64_MIN + r) ||
- (r < 0 && l > INT64_MAX + r)) {
- yyerror("integer overflow or underflow occurred for "
- "operation '%s %s %s'", left, op, right);
- } else {
- res = l - r;
- }
+ (r < 0 && l > INT64_MAX + r))
+ goto integer_overflow;
+ res = l - r;
break;
case '/':
if (r == 0)
- yyerror("second argument to '%s' must not be zero", op);
+ goto invalid_zero;
if (l == INT64_MIN && r == -1)
- yyerror("integer overflow or underflow occurred for "
- "operation '%s %s %s'", left, op, right);
+ goto integer_overflow;
res = l / r;
-
break;
case '%':
if (r == 0)
- yyerror("second argument to '%s' must not be zero", op);
+ goto invalid_zero;
if (l == INT64_MIN && r == -1)
- yyerror("integer overflow or underflow occurred for "
- "operation '%s %s %s'", left, op, right);
+ goto integer_overflow;
res = l % r;
break;
case '*':
- /*
- * Check for over-& underflow.
- */
-
- /*
- * Simplify the conditions:
- * - remove the case of both negative arguments
- * unless the operation will cause an overflow
- */
if (l < 0 && r < 0 && l != INT64_MIN && r != INT64_MIN) {
l = -l;
r = -r;
}
- /* - remove the case of negative l and positive r */
if (l < 0 && r >= 0) {
- /* Use res as a temporary variable */
- res = l;
+ int64_t tmp = l;
l = r;
- r = res;
+ r = tmp;
}
if ((l < 0 && r < 0) ||
(r > 0 && l > INT64_MAX / r) ||
- (r <= 0 && l != 0 && r < INT64_MIN / l)) {
- yyerror("integer overflow or underflow occurred for "
- "operation '%s %s %s'", left, op, right);
- /* NOTREACHED */
- } else {
- res = l * r;
- }
+ (r <= 0 && l != 0 && r < INT64_MIN / l))
+ goto integer_overflow;
+ res = l * r;
break;
}
@@ -271,6 +225,13 @@ eval_arith(const char *left, const char
if (val == NULL)
err(1, NULL);
return val;
+
+integer_overflow:
+ yyerror("integer overflow or underflow occurred for "
+ "operation '%s %s %s'", left, op, right);
+
+invalid_zero:
+ yyerror("second argument to '%s' must not be zero", op);
}
static int
@@ -309,11 +270,11 @@ eval_match(const char *str, const char *
{
regex_t rp;
regmatch_t rm[2];
- int eval;
+ int rc;
- if ((eval = regcomp(&rp, re, REG_BASIC)) != 0) {
+ if ((rc = regcomp(&rp, re, REG_BASIC)) != 0) {
char errbuf[256];
- (void)regerror(eval, &rp, errbuf, sizeof(errbuf));
+ (void)regerror(rc, &rp, errbuf, sizeof(errbuf));
yyerror("%s", errbuf);
}