implement unsigned arithmetics as an mksh extension
This commit is contained in:
parent
06626b0de2
commit
858d8e8b5a
41
check.t
41
check.t
@ -1,4 +1,4 @@
|
||||
# $MirOS: src/bin/mksh/check.t,v 1.252 2008/12/13 17:02:11 tg Exp $
|
||||
# $MirOS: src/bin/mksh/check.t,v 1.253 2008/12/17 19:39:21 tg Exp $
|
||||
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
||||
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
||||
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
||||
@ -7,7 +7,7 @@
|
||||
# http://www.research.att.com/~gsf/public/ifs.sh
|
||||
|
||||
expected-stdout:
|
||||
@(#)MIRBSD KSH R36 2008/12/13
|
||||
@(#)MIRBSD KSH R36 2008/12/17
|
||||
description:
|
||||
Check version of shell.
|
||||
stdin:
|
||||
@ -240,6 +240,43 @@ expected-stdout:
|
||||
6
|
||||
6,5,3
|
||||
---
|
||||
name: arith-unsigned-1
|
||||
description:
|
||||
Check if unsigned arithmetics work
|
||||
stdin:
|
||||
# signed vs unsigned
|
||||
print x1 $((-1)) $((#-1))
|
||||
# calculating
|
||||
typeset -i vs
|
||||
typeset -Ui vu
|
||||
vs=4123456789; vu=4123456789
|
||||
print x2 $vs $vu
|
||||
(( vs %= 2147483647 ))
|
||||
(( vu %= 2147483647 ))
|
||||
print x3 $vs $vu
|
||||
vs=4123456789; vu=4123456789
|
||||
(( # vs %= 2147483647 ))
|
||||
(( # vu %= 2147483647 ))
|
||||
print x4 $vs $vu
|
||||
# make sure the calculation does not change unsigned flag
|
||||
vs=4123456789; vu=4123456789
|
||||
print x5 $vs $vu
|
||||
# short form
|
||||
print x6 $((# vs % 2147483647)) $((# vu % 2147483647))
|
||||
# array refs
|
||||
set -A va
|
||||
va[1975973142]=right
|
||||
va[4123456789]=wrong
|
||||
print x7 ${va[#4123456789%2147483647]}
|
||||
expected-stdout:
|
||||
x1 -1 4294967295
|
||||
x2 -171510507 4123456789
|
||||
x3 -171510507 4123456789
|
||||
x4 1975973142 1975973142
|
||||
x5 -171510507 4123456789
|
||||
x6 1975973142 1975973142
|
||||
x7 right
|
||||
---
|
||||
name: bksl-nl-ign-1
|
||||
description:
|
||||
Check that \newline is not collasped after #
|
||||
|
109
expr.c
109
expr.c
@ -2,7 +2,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.21 2008/12/13 17:02:13 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.22 2008/12/17 19:39:21 tg Exp $");
|
||||
|
||||
/* The order of these enums is constrained by the order of opinfo[] */
|
||||
enum token {
|
||||
@ -114,8 +114,26 @@ struct expr_state {
|
||||
struct tbl *evaling; /* variable that is being recursively
|
||||
* expanded (EXPRINEVAL flag set) */
|
||||
bool arith; /* evaluating an $(()) expression? */
|
||||
bool natural; /* unsigned arithmetic calculation */
|
||||
};
|
||||
|
||||
#define bivui(x, op, y) (es->natural ? \
|
||||
(long)((x)->val.u op (y)->val.u) : \
|
||||
(long)((x)->val.i op (y)->val.i) \
|
||||
)
|
||||
#define chvui(x, op) do { \
|
||||
if (es->natural) \
|
||||
(x)->val.u = op (x)->val.u; \
|
||||
else \
|
||||
(x)->val.i = op (x)->val.i; \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
#define stvui(x, n) do { \
|
||||
if (es->natural) \
|
||||
(x)->val.u = (n); \
|
||||
else \
|
||||
(x)->val.i = (n); \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
enum error_type {
|
||||
ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
|
||||
ET_LVALUE, ET_RDONLY, ET_STR
|
||||
@ -163,6 +181,7 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
|
||||
curstate.noassign = 0;
|
||||
curstate.arith = arith;
|
||||
curstate.evaling = NULL;
|
||||
curstate.natural = false;
|
||||
|
||||
newenv(E_ERRH);
|
||||
i = sigsetjmp(e->jbuf, 0);
|
||||
@ -190,6 +209,8 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
|
||||
if (es->tok != END)
|
||||
evalerr(es, ET_UNEXPECTED, NULL);
|
||||
|
||||
if (es->arith && es->natural)
|
||||
vp->flag |= INT_U;
|
||||
if (vp->flag & INTEGER)
|
||||
setint_v(vp, v, es->arith);
|
||||
else
|
||||
@ -272,11 +293,11 @@ evalexpr(Expr_state *es, int prec)
|
||||
exprtoken(es);
|
||||
vl = intvar(es, evalexpr(es, P_PRIMARY));
|
||||
if (op == O_BNOT)
|
||||
vl->val.i = ~vl->val.i;
|
||||
chvui(vl, ~);
|
||||
else if (op == O_LNOT)
|
||||
vl->val.i = !vl->val.i;
|
||||
chvui(vl, !);
|
||||
else if (op == O_MINUS)
|
||||
vl->val.i = -vl->val.i;
|
||||
chvui(vl, -);
|
||||
/* op == O_PLUS is a no-op */
|
||||
} else if (op == OPEN_PAREN) {
|
||||
exprtoken(es);
|
||||
@ -302,7 +323,7 @@ evalexpr(Expr_state *es, int prec)
|
||||
return (vl);
|
||||
}
|
||||
vl = evalexpr(es, prec - 1);
|
||||
for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
|
||||
for (op = es->tok; IS_BINOP(op) && opinfo[(int)op].prec == prec;
|
||||
op = es->tok) {
|
||||
exprtoken(es);
|
||||
vasn = vl;
|
||||
@ -320,70 +341,70 @@ evalexpr(Expr_state *es, int prec)
|
||||
else
|
||||
evalerr(es, ET_STR, "zero divisor");
|
||||
}
|
||||
switch ((int) op) {
|
||||
switch ((int)op) {
|
||||
case O_TIMES:
|
||||
case O_TIMESASN:
|
||||
res = vl->val.i * vr->val.i;
|
||||
res = bivui(vl, *, vr);
|
||||
break;
|
||||
case O_DIV:
|
||||
case O_DIVASN:
|
||||
res = vl->val.i / vr->val.i;
|
||||
res = bivui(vl, /, vr);
|
||||
break;
|
||||
case O_MOD:
|
||||
case O_MODASN:
|
||||
res = vl->val.i % vr->val.i;
|
||||
res = bivui(vl, %, vr);
|
||||
break;
|
||||
case O_PLUS:
|
||||
case O_PLUSASN:
|
||||
res = vl->val.i + vr->val.i;
|
||||
res = bivui(vl, +, vr);
|
||||
break;
|
||||
case O_MINUS:
|
||||
case O_MINUSASN:
|
||||
res = vl->val.i - vr->val.i;
|
||||
res = bivui(vl, -, vr);
|
||||
break;
|
||||
case O_LSHIFT:
|
||||
case O_LSHIFTASN:
|
||||
res = vl->val.i << vr->val.i;
|
||||
res = bivui(vl, <<, vr);
|
||||
break;
|
||||
case O_RSHIFT:
|
||||
case O_RSHIFTASN:
|
||||
res = vl->val.i >> vr->val.i;
|
||||
res = bivui(vl, >>, vr);
|
||||
break;
|
||||
case O_LT:
|
||||
res = vl->val.i < vr->val.i;
|
||||
res = bivui(vl, <, vr);
|
||||
break;
|
||||
case O_LE:
|
||||
res = vl->val.i <= vr->val.i;
|
||||
res = bivui(vl, <=, vr);
|
||||
break;
|
||||
case O_GT:
|
||||
res = vl->val.i > vr->val.i;
|
||||
res = bivui(vl, >, vr);
|
||||
break;
|
||||
case O_GE:
|
||||
res = vl->val.i >= vr->val.i;
|
||||
res = bivui(vl, >=, vr);
|
||||
break;
|
||||
case O_EQ:
|
||||
res = vl->val.i == vr->val.i;
|
||||
res = bivui(vl, ==, vr);
|
||||
break;
|
||||
case O_NE:
|
||||
res = vl->val.i != vr->val.i;
|
||||
res = bivui(vl, !=, vr);
|
||||
break;
|
||||
case O_BAND:
|
||||
case O_BANDASN:
|
||||
res = vl->val.i & vr->val.i;
|
||||
res = bivui(vl, &, vr);
|
||||
break;
|
||||
case O_BXOR:
|
||||
case O_BXORASN:
|
||||
res = vl->val.i ^ vr->val.i;
|
||||
res = bivui(vl, ^, vr);
|
||||
break;
|
||||
case O_BOR:
|
||||
case O_BORASN:
|
||||
res = vl->val.i | vr->val.i;
|
||||
res = bivui(vl, |, vr);
|
||||
break;
|
||||
case O_LAND:
|
||||
if (!vl->val.i)
|
||||
es->noassign++;
|
||||
vr = intvar(es, evalexpr(es, prec - 1));
|
||||
res = vl->val.i && vr->val.i;
|
||||
res = bivui(vl, &&, vr);
|
||||
if (!vl->val.i)
|
||||
es->noassign--;
|
||||
break;
|
||||
@ -391,13 +412,13 @@ evalexpr(Expr_state *es, int prec)
|
||||
if (vl->val.i)
|
||||
es->noassign++;
|
||||
vr = intvar(es, evalexpr(es, prec - 1));
|
||||
res = vl->val.i || vr->val.i;
|
||||
res = bivui(vl, ||, vr);
|
||||
if (vl->val.i)
|
||||
es->noassign--;
|
||||
break;
|
||||
case O_TERN:
|
||||
{
|
||||
int ev = vl->val.i != 0;
|
||||
bool ev = vl->val.i != 0;
|
||||
|
||||
if (!ev)
|
||||
es->noassign++;
|
||||
@ -423,14 +444,14 @@ evalexpr(Expr_state *es, int prec)
|
||||
break;
|
||||
}
|
||||
if (IS_ASSIGNOP(op)) {
|
||||
vr->val.i = res;
|
||||
stvui(vr, res);
|
||||
if (vasn->flag & INTEGER)
|
||||
setint_v(vasn, vr, es->arith);
|
||||
else
|
||||
setint(vasn, res);
|
||||
vl = vr;
|
||||
} else if (op != O_TERN)
|
||||
vl->val.i = res;
|
||||
stvui(vl, res);
|
||||
}
|
||||
return (vl);
|
||||
}
|
||||
@ -438,13 +459,20 @@ evalexpr(Expr_state *es, int prec)
|
||||
static void
|
||||
exprtoken(Expr_state *es)
|
||||
{
|
||||
const char *cp;
|
||||
const char *cp = es->tokp;
|
||||
int c;
|
||||
char *tvar;
|
||||
|
||||
/* skip white space */
|
||||
for (cp = es->tokp; (c = *cp), ksh_isspace(c); cp++)
|
||||
;
|
||||
skip_spaces:
|
||||
while ((c = *cp), ksh_isspace(c))
|
||||
++cp;
|
||||
if (es->tokp == es->expression && c == '#') {
|
||||
/* expression begins with # */
|
||||
es->natural = true; /* switch to unsigned */
|
||||
++cp;
|
||||
goto skip_spaces;
|
||||
}
|
||||
es->tokp = cp;
|
||||
|
||||
if (c == '\0')
|
||||
@ -499,7 +527,7 @@ exprtoken(Expr_state *es)
|
||||
for (i = 0; (n0 = opinfo[i].name[0]); i++)
|
||||
if (c == n0 &&
|
||||
strncmp(cp, opinfo[i].name, opinfo[i].len) == 0) {
|
||||
es->tok = (enum token) i;
|
||||
es->tok = (enum token)i;
|
||||
cp += opinfo[i].len;
|
||||
break;
|
||||
}
|
||||
@ -514,12 +542,23 @@ static struct tbl *
|
||||
do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
|
||||
{
|
||||
struct tbl *vl;
|
||||
int oval;
|
||||
long oval;
|
||||
|
||||
assign_check(es, op, vasn);
|
||||
|
||||
vl = intvar(es, vasn);
|
||||
oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
|
||||
oval = vl->val.i;
|
||||
if (op == O_PLUSPLUS) {
|
||||
if (es->natural)
|
||||
++vl->val.u;
|
||||
else
|
||||
++vl->val.i;
|
||||
} else {
|
||||
if (es->natural)
|
||||
--vl->val.u;
|
||||
else
|
||||
--vl->val.i;
|
||||
}
|
||||
if (vasn->flag & INTEGER)
|
||||
setint_v(vasn, vl, es->arith);
|
||||
else
|
||||
@ -534,9 +573,9 @@ static void
|
||||
assign_check(Expr_state *es, enum token op, struct tbl *vasn)
|
||||
{
|
||||
if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
|
||||
evalerr(es, ET_LVALUE, opinfo[(int) op].name);
|
||||
evalerr(es, ET_LVALUE, opinfo[(int)op].name);
|
||||
else if (vasn->flag & RDONLY)
|
||||
evalerr(es, ET_RDONLY, opinfo[(int) op].name);
|
||||
evalerr(es, ET_RDONLY, opinfo[(int)op].name);
|
||||
}
|
||||
|
||||
static struct tbl *
|
||||
|
9
mksh.1
9
mksh.1
@ -1,4 +1,4 @@
|
||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.147 2008/12/17 19:32:47 tg Exp $
|
||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.148 2008/12/17 19:39:22 tg Exp $
|
||||
.\" $OpenBSD: ksh.1,v 1.122 2008/05/17 23:31:52 sobrado Exp $
|
||||
.\"-
|
||||
.\" Try to make GNU groff and AT&T nroff more compatible
|
||||
@ -2096,6 +2096,13 @@ as numeric arguments to the
|
||||
.Ic test
|
||||
command, and as the value of an assignment to an integer parameter.
|
||||
.Pp
|
||||
Expressions are calculated using signed arithmetic and the
|
||||
.Vt long
|
||||
host type, unless they begin with a sole
|
||||
.Sq #
|
||||
character, in which case they use
|
||||
.Vt unsigned long .
|
||||
.Pp
|
||||
Expressions may contain alpha-numeric parameter identifiers, array references,
|
||||
and integer constants and may be combined with the following C operators
|
||||
(listed and grouped in increasing order of precedence):
|
||||
|
5
sh.h
5
sh.h
@ -103,9 +103,9 @@
|
||||
#define __SCCSID(x) __IDSTRING(sccsid,x)
|
||||
|
||||
#ifdef EXTERN
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.267 2008/12/13 18:32:27 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.268 2008/12/17 19:39:23 tg Exp $");
|
||||
#endif
|
||||
#define MKSH_VERSION "R36 2008/12/13"
|
||||
#define MKSH_VERSION "R36 2008/12/17"
|
||||
|
||||
#ifndef MKSH_INCLUDES_ONLY
|
||||
|
||||
@ -775,6 +775,7 @@ struct tbl { /* table item */
|
||||
union {
|
||||
char *s; /* string */
|
||||
long i; /* integer */
|
||||
unsigned long u; /* unsigned integer */
|
||||
int (*f)(const char **);/* int function */
|
||||
struct op *t; /* "function" tree */
|
||||
} val; /* value */
|
||||
|
Loading…
x
Reference in New Issue
Block a user