awk: fix 'delete array[var--]' decrementing var twice

function                                             old     new   delta
evaluate                                            3395    3390      -5

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-01-07 01:19:08 +01:00
parent 7367a949a6
commit 6f4a785bd1
2 changed files with 50 additions and 23 deletions

View File

@ -2514,6 +2514,32 @@ static var *evaluate(node *op, var *res)
op1 = op->l.n;
debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
/* "delete" is special:
* "delete array[var--]" must evaluate index expr only once,
* must not evaluate it in "execute inevitable things" part.
*/
if (XC(opinfo & OPCLSMASK) == XC(OC_DELETE)) {
uint32_t info = op1->info & OPCLSMASK;
var *v;
debug_printf_eval("DELETE\n");
if (info == OC_VAR) {
v = op1->l.v;
} else if (info == OC_FNARG) {
v = &fnargs[op1->l.aidx];
} else {
syntax_error(EMSG_NOT_ARRAY);
}
if (op1->r.n) { /* array ref? */
const char *s;
s = getvar_s(evaluate(op1->r.n, v1));
hash_remove(iamarray(v), s);
} else {
clear_array(iamarray(v));
}
goto next;
}
/* execute inevitable things */
if (opinfo & OF_RES1)
L.v = evaluate(op1, v1);
@ -2621,28 +2647,7 @@ static var *evaluate(node *op, var *res)
break;
}
case XC( OC_DELETE ): {
uint32_t info = op1->info & OPCLSMASK;
var *v;
if (info == OC_VAR) {
v = op1->l.v;
} else if (info == OC_FNARG) {
v = &fnargs[op1->l.aidx];
} else {
syntax_error(EMSG_NOT_ARRAY);
}
if (op1->r.n) {
const char *s;
clrvar(L.v);
s = getvar_s(evaluate(op1->r.n, v1));
hash_remove(iamarray(v), s);
} else {
clear_array(iamarray(v));
}
break;
}
/* case XC( OC_DELETE ): - moved to happen before arg evaluation */
case XC( OC_NEWSOURCE ):
g_progname = op->l.new_progname;
@ -2666,12 +2671,14 @@ static var *evaluate(node *op, var *res)
/* -- recursive node type -- */
case XC( OC_VAR ):
debug_printf_eval("VAR\n");
L.v = op->l.v;
if (L.v == intvar[NF])
split_f0();
goto v_cont;
case XC( OC_FNARG ):
debug_printf_eval("FNARG[%d]\n", op->l.aidx);
L.v = &fnargs[op->l.aidx];
v_cont:
res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
@ -3035,7 +3042,8 @@ static var *evaluate(node *op, var *res)
default:
syntax_error(EMSG_POSSIBLE_ERROR);
}
} /* switch */
next:
if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
op = op->a.n;
if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS)

View File

@ -261,6 +261,25 @@ end d
" \
"" ""
prg='
BEGIN{
cnt = 0
a[cnt] = "zeroth"
a[++cnt] = "first"
delete a[cnt--]
print cnt
print "[0]:" a[0]
print "[1]:" a[1]
}'
testing "awk 'delete a[v--]' evaluates v-- once" \
"awk '$prg'" \
"\
0
[0]:zeroth
[1]:
" \
"" ""
testing "awk handles empty ()" \
"awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""