diff --git a/check.t b/check.t index 25a3739..c4612d5 100644 --- a/check.t +++ b/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 # diff --git a/expr.c b/expr.c index cc9dfd5..829d424 100644 --- a/expr.c +++ b/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 * diff --git a/mksh.1 b/mksh.1 index f413708..02d9ae6 100644 --- a/mksh.1 +++ b/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): diff --git a/sh.h b/sh.h index c7f3ba2..2268ec7 100644 --- a/sh.h +++ b/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 */