bc: fix handling of "digits" above 9
function old new delta zxc_lex_next 1573 1608 +35 xc_parse_pushIndex 58 56 -2 xc_program_index 71 63 -8 zxc_program_num 1022 990 -32 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 35/-42) Total: -7 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
@ -2555,13 +2555,16 @@ static void xc_read_line(BcVec *vec, FILE *fp)
|
||||
// Parsing routines
|
||||
//
|
||||
|
||||
static bool xc_num_strValid(const char *val, size_t base)
|
||||
// "Input numbers may contain the characters 0-9 and A-Z.
|
||||
// (Note: They must be capitals. Lower case letters are variable names.)
|
||||
// Single digit numbers always have the value of the digit regardless of
|
||||
// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
|
||||
// all input digits greater or equal to ibase to the value of ibase-1.
|
||||
// This makes the number ZZZ always be the largest 3 digit number of the
|
||||
// input base."
|
||||
static bool xc_num_strValid(const char *val)
|
||||
{
|
||||
BcDig b;
|
||||
bool radix;
|
||||
|
||||
b = (BcDig)(base <= 10 ? base + '0' : base - 10 + 'A');
|
||||
radix = false;
|
||||
bool radix = false;
|
||||
for (;;) {
|
||||
BcDig c = *val++;
|
||||
if (c == '\0')
|
||||
@ -2571,7 +2574,7 @@ static bool xc_num_strValid(const char *val, size_t base)
|
||||
radix = true;
|
||||
continue;
|
||||
}
|
||||
if (c < '0' || c >= b || (c > '9' && c < 'A'))
|
||||
if ((c < '0' || c > '9') && (c < 'A' || c > 'Z'))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -2599,10 +2602,21 @@ static void bc_num_parseDecimal(BcNum *n, const char *val)
|
||||
for (i = 0; val[i]; ++i) {
|
||||
if (val[i] != '0' && val[i] != '.') {
|
||||
// Not entirely zero value - convert it, and exit
|
||||
if (len == 1) {
|
||||
char c = val[0] - '0';
|
||||
if (c > 9) // A-Z => 10-36
|
||||
c -= ('A' - '9' - 1);
|
||||
n->num[0] = c;
|
||||
n->len = 1;
|
||||
break;
|
||||
}
|
||||
i = len - 1;
|
||||
for (;;) {
|
||||
n->num[n->len] = val[i] - '0';
|
||||
++n->len;
|
||||
char c = val[i] - '0';
|
||||
if (c > 9) // A-Z => 9
|
||||
c = 9;
|
||||
n->num[n->len] = c;
|
||||
n->len++;
|
||||
skip_dot:
|
||||
if (i == 0) break;
|
||||
if (val[--i] == '.') goto skip_dot;
|
||||
@ -2692,7 +2706,7 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
|
||||
|
||||
static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
|
||||
{
|
||||
if (!xc_num_strValid(val, base_t))
|
||||
if (!xc_num_strValid(val))
|
||||
RETURN_STATUS(bc_error("bad number string"));
|
||||
|
||||
bc_num_zero(n);
|
||||
@ -2807,6 +2821,13 @@ static BC_STATUS zxc_lex_number(char last)
|
||||
bc_vec_pop_all(&p->lex_strnumbuf);
|
||||
bc_vec_pushByte(&p->lex_strnumbuf, last);
|
||||
|
||||
// "Input numbers may contain the characters 0-9 and A-Z.
|
||||
// (Note: They must be capitals. Lower case letters are variable names.)
|
||||
// Single digit numbers always have the value of the digit regardless of
|
||||
// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
|
||||
// all input digits greater or equal to ibase to the value of ibase-1.
|
||||
// This makes the number ZZZ always be the largest 3 digit number of the
|
||||
// input base."
|
||||
pt = (last == '.');
|
||||
p->lex = XC_LEX_NUMBER;
|
||||
for (;;) {
|
||||
@ -2822,13 +2843,13 @@ static BC_STATUS zxc_lex_number(char last)
|
||||
c = peek_inbuf(); // force next line to be read
|
||||
goto check_c;
|
||||
}
|
||||
if (!isdigit(c) && (c < 'A' || c > 'F')) {
|
||||
if (!isdigit(c) && (c < 'A' || c > 'Z')) {
|
||||
if (c != '.') break;
|
||||
// if '.' was already seen, stop on second one:
|
||||
if (pt) break;
|
||||
pt = true;
|
||||
}
|
||||
// c is one of "0-9A-F."
|
||||
// c is one of "0-9A-Z."
|
||||
last = c;
|
||||
bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
|
||||
p->lex_inbuf++;
|
||||
@ -3167,6 +3188,26 @@ static BC_STATUS zbc_lex_token(void)
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
s = zxc_lex_number(c);
|
||||
break;
|
||||
case ';':
|
||||
@ -3450,13 +3491,14 @@ static void xc_parse_pushIndex(size_t idx)
|
||||
|
||||
mask = ((size_t)0xff) << (sizeof(idx) * 8 - 8);
|
||||
amt = sizeof(idx);
|
||||
do {
|
||||
for (;;) {
|
||||
if (idx & mask) break;
|
||||
mask >>= 8;
|
||||
amt--;
|
||||
} while (amt != 0);
|
||||
}
|
||||
// amt is at least 1 here - "one byte of length data follows"
|
||||
|
||||
xc_parse_push(SMALL_INDEX_LIMIT + amt);
|
||||
xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt);
|
||||
|
||||
while (idx != 0) {
|
||||
push_idx:
|
||||
@ -5260,13 +5302,15 @@ static size_t xc_program_index(char *code, size_t *bgn)
|
||||
*bgn += 1;
|
||||
return amt;
|
||||
}
|
||||
amt -= SMALL_INDEX_LIMIT;
|
||||
amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here
|
||||
*bgn += amt + 1;
|
||||
|
||||
amt *= 8;
|
||||
res = 0;
|
||||
for (i = 0; i < amt; i += 8)
|
||||
i = 0;
|
||||
do {
|
||||
res |= (size_t)(*bytes++) << i;
|
||||
i += 8;
|
||||
} while (--amt != 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user