From e79133b55e5185e61376edb84cc1ca5004331614 Mon Sep 17 00:00:00 2001 From: kre Date: Mon, 24 Jul 2017 13:21:14 +0000 Subject: [PATCH] Add support for ++ and -- (pre & post) and ',' to arithmetic. --- bin/sh/arith_token.c | 21 ++++++++++++----- bin/sh/arith_tokens.h | 5 ++++- bin/sh/arithmetic.c | 52 +++++++++++++++++++++++++++++++++++++------ bin/sh/sh.1 | 27 +++++++++++++++------- 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/bin/sh/arith_token.c b/bin/sh/arith_token.c index bc553675723e..03e4db37413b 100644 --- a/bin/sh/arith_token.c +++ b/bin/sh/arith_token.c @@ -1,4 +1,4 @@ -/* $NetBSD: arith_token.c,v 1.5 2017/06/07 05:08:32 kre Exp $ */ +/* $NetBSD: arith_token.c,v 1.6 2017/07/24 13:21:14 kre Exp $ */ /*- * Copyright (c) 2002 @@ -39,7 +39,7 @@ #include #ifndef lint -__RCSID("$NetBSD: arith_token.c,v 1.5 2017/06/07 05:08:32 kre Exp $"); +__RCSID("$NetBSD: arith_token.c,v 1.6 2017/07/24 13:21:14 kre Exp $"); #endif /* not lint */ #include @@ -212,13 +212,19 @@ arith_token(void) goto checkeq; case '+': - if (buf[1] == '+') - error("arithmetic: ++ operator unsupported"); + if (buf[1] == '+') { + buf++; + token = ARITH_INCR; + break; + } token = ARITH_ADD; goto checkeq; case '-': - if (buf[1] == '-') - error("arithmetic: -- operator unsupported"); + if (buf[1] == '-') { + buf++; + token = ARITH_DECR; + break; + } token = ARITH_SUB; goto checkeq; case '~': @@ -234,6 +240,9 @@ arith_token(void) case ':': token = ARITH_COLON; break; + case ',': + token = ARITH_COMMA; + break; } break; } diff --git a/bin/sh/arith_tokens.h b/bin/sh/arith_tokens.h index f8a7f77c6951..f655aa9daf37 100644 --- a/bin/sh/arith_tokens.h +++ b/bin/sh/arith_tokens.h @@ -1,4 +1,4 @@ -/* $NetBSD: arith_tokens.h,v 1.2 2017/06/07 05:08:32 kre Exp $ */ +/* $NetBSD: arith_tokens.h,v 1.3 2017/07/24 13:21:14 kre Exp $ */ /*- * Copyright (c) 1993 @@ -98,6 +98,9 @@ #define ARITH_BNOT 36 #define ARITH_QMARK 37 #define ARITH_COLON 38 +#define ARITH_INCR 39 +#define ARITH_DECR 40 +#define ARITH_COMMA 41 /* * Globals shared between arith parser, and lexer diff --git a/bin/sh/arithmetic.c b/bin/sh/arithmetic.c index 3a5430fa7902..1ad856c7c266 100644 --- a/bin/sh/arithmetic.c +++ b/bin/sh/arithmetic.c @@ -1,4 +1,4 @@ -/* $NetBSD: arithmetic.c,v 1.3 2017/06/07 05:08:32 kre Exp $ */ +/* $NetBSD: arithmetic.c,v 1.4 2017/07/24 13:21:14 kre Exp $ */ /*- * Copyright (c) 1993 @@ -39,7 +39,7 @@ #include #ifndef lint -__RCSID("$NetBSD: arithmetic.c,v 1.3 2017/06/07 05:08:32 kre Exp $"); +__RCSID("$NetBSD: arithmetic.c,v 1.4 2017/07/24 13:21:14 kre Exp $"); #endif /* not lint */ #include @@ -192,19 +192,21 @@ do_binop(int op, intmax_t a, intmax_t b) } } -static intmax_t assignment(int var, int noeval); +static intmax_t assignment(int, int); +static intmax_t comma_list(int, int); static intmax_t primary(int token, union a_token_val *val, int op, int noeval) { intmax_t result; + char sresult[DIGITS(result) + 1]; VTRACE(DBG_ARITH, ("Arith primary: token %d op %d%s\n", token, op, noeval ? " noeval" : "")); switch (token) { case ARITH_LPAREN: - result = assignment(op, noeval); + result = comma_list(op, noeval); if (last_token != ARITH_RPAREN) arith_err("expecting ')'"); last_token = arith_token(); @@ -213,8 +215,18 @@ primary(int token, union a_token_val *val, int op, int noeval) last_token = op; return val->val; case ARITH_VAR: - last_token = op; - return noeval ? val->val : arith_lookupvarint(val->name); + result = noeval ? val->val : arith_lookupvarint(val->name); + if (op == ARITH_INCR || op == ARITH_DECR) { + last_token = arith_token(); + if (noeval) + return val->val; + + snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, + result + (op == ARITH_INCR ? 1 : -1)); + setvar(val->name, sresult, 0); + } else + last_token = op; + return result; case ARITH_ADD: *val = a_t_val; return primary(op, val, arith_token(), noeval); @@ -227,6 +239,18 @@ primary(int token, union a_token_val *val, int op, int noeval) case ARITH_BNOT: *val = a_t_val; return ~primary(op, val, arith_token(), noeval); + case ARITH_INCR: + case ARITH_DECR: + if (op != ARITH_VAR) + arith_err("incr/decr require var name"); + last_token = arith_token(); + if (noeval) + return val->val; + result = arith_lookupvarint(a_t_val.name); + snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, + result += (token == ARITH_INCR ? 1 : -1)); + setvar(a_t_val.name, sresult, 0); + return result; default: arith_err("expecting primary"); } @@ -374,6 +398,20 @@ assignment(int var, int noeval) return result; } +static intmax_t +comma_list(int token, int noeval) +{ + intmax_t result = assignment(token, noeval); + + while (last_token == ARITH_COMMA) { + VTRACE(DBG_ARITH, ("Arith: comma discarding %jd%s\n", result, + noeval ? " noeval" : "")); + result = assignment(arith_token(), noeval); + } + + return result; +} + intmax_t arith(const char *s, int lno) { @@ -405,7 +443,7 @@ arith(const char *s, int lno) arith_buf = arith_startbuf = s; - result = assignment(arith_token(), 0); + result = comma_list(arith_token(), 0); if (last_token) arith_err("expecting end of expression"); diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index d7aefe75b1f3..0dde89635c33 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: sh.1,v 1.160 2017/07/24 12:36:02 kre Exp $ +.\" $NetBSD: sh.1,v 1.161 2017/07/24 13:21:14 kre Exp $ .\" Copyright (c) 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -1528,13 +1528,24 @@ string, which might result in syntax errors. Referencing the value of a variable which is not numeric is an error. .Pp All of the C expression operators applicable to integers are supported, -and operate as they would in a C expression, except the unary -.Dq ++ -and -.Dq -- -operators (in both prefix and postfix forms) and the -.Dq \&, -(comma) operator, which are currently not supported. +and operate as they would in a C expression. +Use white space, or parentheses, to disambiguate confusing syntax, +otherwise, as in C, the longest sequence of consecutive characters +which make a valid token (operator, variable name, or number) is taken +to be that token, even if the token designated cannot be used +and a different interpretation could produce a successful parse. +This means, as an example, that +.Dq a+++++b +is parsed as the gibberish sequence +.Dq "a ++ ++ + b" , +rather than as the valid alternative +.Dq "a ++ + ++ b" . +Similarly, separate the +.Sq \&, +operator from numbers with white space to avoid the possibility +of confusion with the decimal indicator in some locales (though +fractional, or floating-point, numbers are not supported in this +implementation.) .Pp It should not be necessary to state that the C operators which operate on, or produce, pointer types, are not supported.