Add support for ++ and -- (pre & post) and ',' to arithmetic.

This commit is contained in:
kre 2017-07-24 13:21:14 +00:00
parent a304c3b3a5
commit e79133b55e
4 changed files with 83 additions and 22 deletions

View File

@ -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 * Copyright (c) 2002
@ -39,7 +39,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #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 */ #endif /* not lint */
#include <inttypes.h> #include <inttypes.h>
@ -212,13 +212,19 @@ arith_token(void)
goto checkeq; goto checkeq;
case '+': case '+':
if (buf[1] == '+') if (buf[1] == '+') {
error("arithmetic: ++ operator unsupported"); buf++;
token = ARITH_INCR;
break;
}
token = ARITH_ADD; token = ARITH_ADD;
goto checkeq; goto checkeq;
case '-': case '-':
if (buf[1] == '-') if (buf[1] == '-') {
error("arithmetic: -- operator unsupported"); buf++;
token = ARITH_DECR;
break;
}
token = ARITH_SUB; token = ARITH_SUB;
goto checkeq; goto checkeq;
case '~': case '~':
@ -234,6 +240,9 @@ arith_token(void)
case ':': case ':':
token = ARITH_COLON; token = ARITH_COLON;
break; break;
case ',':
token = ARITH_COMMA;
break;
} }
break; break;
} }

View File

@ -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 * Copyright (c) 1993
@ -98,6 +98,9 @@
#define ARITH_BNOT 36 #define ARITH_BNOT 36
#define ARITH_QMARK 37 #define ARITH_QMARK 37
#define ARITH_COLON 38 #define ARITH_COLON 38
#define ARITH_INCR 39
#define ARITH_DECR 40
#define ARITH_COMMA 41
/* /*
* Globals shared between arith parser, and lexer * Globals shared between arith parser, and lexer

View File

@ -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 * Copyright (c) 1993
@ -39,7 +39,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #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 */ #endif /* not lint */
#include <limits.h> #include <limits.h>
@ -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 static intmax_t
primary(int token, union a_token_val *val, int op, int noeval) primary(int token, union a_token_val *val, int op, int noeval)
{ {
intmax_t result; intmax_t result;
char sresult[DIGITS(result) + 1];
VTRACE(DBG_ARITH, ("Arith primary: token %d op %d%s\n", VTRACE(DBG_ARITH, ("Arith primary: token %d op %d%s\n",
token, op, noeval ? " noeval" : "")); token, op, noeval ? " noeval" : ""));
switch (token) { switch (token) {
case ARITH_LPAREN: case ARITH_LPAREN:
result = assignment(op, noeval); result = comma_list(op, noeval);
if (last_token != ARITH_RPAREN) if (last_token != ARITH_RPAREN)
arith_err("expecting ')'"); arith_err("expecting ')'");
last_token = arith_token(); last_token = arith_token();
@ -213,8 +215,18 @@ primary(int token, union a_token_val *val, int op, int noeval)
last_token = op; last_token = op;
return val->val; return val->val;
case ARITH_VAR: case ARITH_VAR:
last_token = op; result = noeval ? val->val : arith_lookupvarint(val->name);
return 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: case ARITH_ADD:
*val = a_t_val; *val = a_t_val;
return primary(op, val, arith_token(), noeval); 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: case ARITH_BNOT:
*val = a_t_val; *val = a_t_val;
return ~primary(op, val, arith_token(), noeval); 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: default:
arith_err("expecting primary"); arith_err("expecting primary");
} }
@ -374,6 +398,20 @@ assignment(int var, int noeval)
return result; 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 intmax_t
arith(const char *s, int lno) arith(const char *s, int lno)
{ {
@ -405,7 +443,7 @@ arith(const char *s, int lno)
arith_buf = arith_startbuf = s; arith_buf = arith_startbuf = s;
result = assignment(arith_token(), 0); result = comma_list(arith_token(), 0);
if (last_token) if (last_token)
arith_err("expecting end of expression"); arith_err("expecting end of expression");

View File

@ -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 .\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved. .\" 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. Referencing the value of a variable which is not numeric is an error.
.Pp .Pp
All of the C expression operators applicable to integers are supported, All of the C expression operators applicable to integers are supported,
and operate as they would in a C expression, except the unary and operate as they would in a C expression.
.Dq ++ Use white space, or parentheses, to disambiguate confusing syntax,
and otherwise, as in C, the longest sequence of consecutive characters
.Dq -- which make a valid token (operator, variable name, or number) is taken
operators (in both prefix and postfix forms) and the to be that token, even if the token designated cannot be used
.Dq \&, and a different interpretation could produce a successful parse.
(comma) operator, which are currently not supported. 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 .Pp
It should not be necessary to state that the C operators which It should not be necessary to state that the C operators which
operate on, or produce, pointer types, are not supported. operate on, or produce, pointer types, are not supported.