bc: more fixes for unusual input bases
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 29 Dec 2018 01:40:03 +0000 (02:40 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 29 Dec 2018 02:08:12 +0000 (03:08 +0100)
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 <vda.linux@googlemail.com>
miscutils/bc.c
testsuite/bc_numbers2.bc [new file with mode: 0644]
testsuite/bc_numbers2_results.txt [new file with mode: 0644]

index 07327af6fc79fd4f471a2b3f5f2cade44d3fbc4b..cc15a8dd23bb993f248ecfd1c96115157010ca91 100644 (file)
@@ -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
+                               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;
-                               n->len = 1;
                                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 (file)
index 0000000..208fe0d
--- /dev/null
@@ -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 (file)
index 0000000..e3400bd
--- /dev/null
@@ -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