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 <jdole...@netbsd.org> and J.T. Conklin <j...@netbsd.org>. + * by Jaromir Dolecek <jdole...@netbsd.org>, J.T. Conklin <j...@netbsd.org> + * and Roland Illig <ril...@netbsd.org>. * * 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); }