awk: improve nadling of negative numbers in bitwise ops;

fix handling of octal costants. add test for it

function                                             old     new   delta
getvar_i_int                                           -      93     +93
my_strtod                                              -      84     +84
qrealloc                                              33      36      +3
getvar_i                                              99      95      -4
next_token                                           979     919     -60
evaluate                                            6359    5627    -732
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/3 up/down: 180/-796)         Total: -616 bytes
This commit is contained in:
Denis Vlasenko 2008-09-02 09:00:23 +00:00
parent b424930e4e
commit a2e1eea189
2 changed files with 34 additions and 14 deletions

View File

@ -681,6 +681,18 @@ static ALWAYS_INLINE int isalnum_(int c)
return (isalnum(c) || c == '_'); return (isalnum(c) || c == '_');
} }
static double my_strtod(char **pp)
{
#if ENABLE_DESKTOP
if ((*pp)[0] == '0'
&& ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1]))
) {
return strtoull(*pp, pp, 0);
}
#endif
return strtod(*pp, pp);
}
/* -------- working with variables (set/get/copy/etc) -------- */ /* -------- working with variables (set/get/copy/etc) -------- */
static xhash *iamarray(var *v) static xhash *iamarray(var *v)
@ -790,7 +802,7 @@ static double getvar_i(var *v)
v->number = 0; v->number = 0;
s = v->string; s = v->string;
if (s && *s) { if (s && *s) {
v->number = strtod(s, &s); v->number = my_strtod(&s);
if (v->type & VF_USER) { if (v->type & VF_USER) {
skip_spaces(&s); skip_spaces(&s);
if (*s != '\0') if (*s != '\0')
@ -804,6 +816,18 @@ static double getvar_i(var *v)
return v->number; return v->number;
} }
/* Used for operands of bitwise ops */
static unsigned long getvar_i_int(var *v)
{
double d = getvar_i(v);
/* Casting doubles to longs is undefined for values outside
* of target type range. Try to widen it as much as possible */
if (d >= 0)
return (unsigned long)d;
return - (long) (unsigned long) (-d);
}
static var *copyvar(var *dest, const var *src) static var *copyvar(var *dest, const var *src)
{ {
if (dest != src) { if (dest != src) {
@ -973,12 +997,7 @@ static uint32_t next_token(uint32_t expected)
} else if (*p == '.' || isdigit(*p)) { } else if (*p == '.' || isdigit(*p)) {
/* it's a number */ /* it's a number */
#if ENABLE_DESKTOP t_double = my_strtod(&p);
if (p[0] == '0' && (p[1] | 0x20) == 'x')
t_double = strtoll(p, &p, 0);
else
#endif
t_double = strtod(p, &p);
if (*p == '.') if (*p == '.')
syntax_error(EMSG_UNEXP_TOKEN); syntax_error(EMSG_UNEXP_TOKEN);
tc = TC_NUMBER; tc = TC_NUMBER;
@ -2022,7 +2041,7 @@ static var *exec_builtin(node *op, var *res)
n = awk_split(as[0], spl, &s); n = awk_split(as[0], spl, &s);
s1 = s; s1 = s;
clear_array(iamarray(av[1])); clear_array(iamarray(av[1]));
for (i=1; i<=n; i++) for (i = 1; i <= n; i++)
setari_u(av[1], i, nextword(&s1)); setari_u(av[1], i, nextword(&s1));
free(s); free(s);
setvar_i(res, n); setvar_i(res, n);
@ -2042,27 +2061,27 @@ static var *exec_builtin(node *op, var *res)
/* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5: /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5:
* awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */ * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */
case B_an: case B_an:
setvar_i(res, (unsigned long)getvar_i(av[0]) & (unsigned long)getvar_i(av[1])); setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1]));
break; break;
case B_co: case B_co:
setvar_i(res, ~(unsigned long)getvar_i(av[0])); setvar_i(res, ~getvar_i_int(av[0]));
break; break;
case B_ls: case B_ls:
setvar_i(res, (unsigned long)getvar_i(av[0]) << (unsigned long)getvar_i(av[1])); setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1]));
break; break;
case B_or: case B_or:
setvar_i(res, (unsigned long)getvar_i(av[0]) | (unsigned long)getvar_i(av[1])); setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1]));
break; break;
case B_rs: case B_rs:
setvar_i(res, (unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])); setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1]));
break; break;
case B_xo: case B_xo:
setvar_i(res, (unsigned long)getvar_i(av[0]) ^ (unsigned long)getvar_i(av[1])); setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1]));
break; break;
case B_lo: case B_lo:

View File

@ -20,6 +20,7 @@ testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n"
testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n"
testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n"
testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n"
testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
tar xjf awk_t1.tar.bz2 tar xjf awk_t1.tar.bz2
testing "awk 'gcc build bug'" \ testing "awk 'gcc build bug'" \