From d5b0fa6abf725cc9281f3b11fc2a4c0f12df0793 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 29 Dec 2018 02:40:03 +0100 Subject: [PATCH] bc: more fixes for unusual input bases function old new delta zxc_program_num 990 1020 +30 zxc_lex_number 172 202 +30 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 60/0) Total: 60 bytes Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 21 ++++++++----- testsuite/bc_numbers2.bc | 18 +++++++++++ testsuite/bc_numbers2_results.txt | 50 +++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 testsuite/bc_numbers2.bc create mode 100644 testsuite/bc_numbers2_results.txt diff --git a/miscutils/bc.c b/miscutils/bc.c index 07327af6f..cc15a8dd2 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -2591,7 +2591,7 @@ static void bc_num_parseDecimal(BcNum *n, const char *val) if (len == 0) return; - bc_num_expand(n, len); + bc_num_expand(n, len + 1); // +1 for e.g. "A" converting into 10 ptr = strchr(val, '.'); @@ -2603,11 +2603,15 @@ static void bc_num_parseDecimal(BcNum *n, const char *val) 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; + unsigned c = val[0] - '0'; n->len = 1; + if (c > 9) { // A-Z => 10-36 + n->len = 2; + c -= ('A' - '9' - 1); + n->num[1] = c/10; + c = c%10; + } + n->num[0] = c; break; } i = len - 1; @@ -2817,17 +2821,20 @@ static BC_STATUS zxc_lex_number(char last) { BcParse *p = &G.prs; bool pt; + char last_valid_ch; 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. +// bc: "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." +// dc only allows A-F, the rules about single-char and multi-char are the same. + last_valid_ch = (IS_BC ? 'Z' : 'F'); pt = (last == '.'); p->lex = XC_LEX_NUMBER; for (;;) { @@ -2843,7 +2850,7 @@ 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 > 'Z')) { + if (!isdigit(c) && (c < 'A' || c > last_valid_ch)) { if (c != '.') break; // if '.' was already seen, stop on second one: if (pt) break; diff --git a/testsuite/bc_numbers2.bc b/testsuite/bc_numbers2.bc new file mode 100644 index 000000000..208fe0d4d --- /dev/null +++ b/testsuite/bc_numbers2.bc @@ -0,0 +1,18 @@ +define f() { + "ibase:";ibase + a=A;a + a=F;a + a=G;a + a=Z;a + a=0A;a + a=0F;a + a=0G;a + a=0Z;a +} +f() +ibase=9;f() +ibase=A;f() +ibase=F;f() +ibase=G;f() +#ibase=Z;f() +halt diff --git a/testsuite/bc_numbers2_results.txt b/testsuite/bc_numbers2_results.txt new file mode 100644 index 000000000..e3400bd92 --- /dev/null +++ b/testsuite/bc_numbers2_results.txt @@ -0,0 +1,50 @@ +ibase:10 +10 +15 +16 +35 +10 +15 +16 +35 +0 +ibase:9 +10 +15 +16 +35 +10 +15 +16 +35 +0 +ibase:10 +10 +15 +16 +35 +10 +15 +16 +35 +0 +ibase:15 +10 +15 +16 +35 +10 +15 +16 +35 +0 +ibase:16 +10 +15 +16 +35 +10 +15 +16 +35 +0