bc: support ibase up to 36 (GNU compat)
[oweals/busybox.git] / miscutils / bc.c
index 2569967d61bf99debc1e4efeeea6fe75474a7e49..798bc0a3e072aa82e48d5019f1bfb249bb6107d2 100644 (file)
@@ -4,9 +4,20 @@
  * Adapted from https://github.com/gavinhoward/bc
  * Original code copyright (c) 2018 Gavin D. Howard and contributors.
  */
+//TODO: GNU extensions:
+// support "define void f()..."
+// support "define f(*param[])" - "pass array by reference" syntax
+
+#define DEBUG_LEXER   0
+#define DEBUG_COMPILE 0
+#define DEBUG_EXEC    0
+// This can be left enabled for production as well:
+#define SANITY_CHECKS 1
+
 //config:config BC
-//config:      bool "bc (45 kb; 49 kb when combined with dc)"
+//config:      bool "bc (45 kb)"
 //config:      default y
+//config:      select FEATURE_DC_BIG
 //config:      help
 //config:      bc is a command-line, arbitrary-precision calculator with a
 //config:      Turing-complete language. See the GNU bc manual
 //config:           easier.
 //config:        5) "read()" accepts expressions, not only numeric literals.
 //config:
-//config:      Options:
-//config:        -i  --interactive  force interactive mode
-//config:        -q  --quiet        don't print version and copyright
-//config:        -s  --standard     error if any non-POSIX extensions are used
-//config:        -w  --warn         warn if any non-POSIX extensions are used
-//config:        -l  --mathlib      use predefined math routines:
-//config:              s(expr) sine in radians
-//config:              c(expr) cosine in radians
-//config:              a(expr) arctangent, returning radians
-//config:              l(expr) natural log
-//config:              e(expr) raises e to the power of expr
-//config:              j(n, x) Bessel function of integer order n of x
-//config:
 //config:config DC
-//config:      bool "dc (38 kb; 49 kb when combined with bc)"
+//config:      bool "dc (36 kb)"
 //config:      default y
 //config:      help
 //config:      dc is a reverse-polish notation command-line calculator which
 //config:           whitespace where a register should be, it skips the whitespace.
 //config:           If the character following is not a lowercase letter, an error
 //config:           is issued. Otherwise, the register name is parsed by the
-//config:           following regex:
-//config:              [a-z][a-z0-9_]*
+//config:           following regex: [a-z][a-z0-9_]*
 //config:           This generally means that register names will be surrounded by
 //config:           whitespace. Examples:
 //config:              l idx s temp L index S temp2 < do_thing
 //config:           Also note that, like the FreeBSD dc, extended registers are not
 //config:           allowed unless the "-x" option is given.
 //config:
-//config:config FEATURE_DC_SMALL
-//config:      bool "Minimal dc implementation (4.2 kb), not using bc code base"
-//config:      depends on DC && !BC
-//config:      default n
+//config:if BC || DC  # for menuconfig indenting
+//config:
+//config:config FEATURE_DC_BIG
+//config:      bool "Use bc code base for dc (larger, more features)"
+//config:      default y
 //config:
 //config:config FEATURE_DC_LIBM
 //config:      bool "Enable power and exp functions (requires libm)"
 //config:      default y
-//config:      depends on FEATURE_DC_SMALL
+//config:      depends on DC && !BC && !FEATURE_DC_BIG
 //config:      help
 //config:      Enable power and exp functions.
 //config:      NOTE: This will require libm to be present for linking.
 //config:
-//config:config FEATURE_BC_SIGNALS
+//config:config FEATURE_BC_INTERACTIVE
 //config:      bool "Interactive mode (+4kb)"
 //config:      default y
-//config:      depends on (BC || DC) && !FEATURE_DC_SMALL
+//config:      depends on BC || (DC && FEATURE_DC_BIG)
 //config:      help
 //config:      Enable interactive mode: when started on a tty,
 //config:      ^C interrupts execution and returns to command line,
@@ -99,9 +97,9 @@
 //config:config FEATURE_BC_LONG_OPTIONS
 //config:      bool "Enable bc/dc long options"
 //config:      default y
-//config:      depends on (BC || DC) && !FEATURE_DC_SMALL
-//config:      help
-//config:      Enable long options for bc and dc.
+//config:      depends on BC || (DC && FEATURE_DC_BIG)
+//config:
+//config:endif
 
 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
 //usage:       "obase = A\n"
 //usage:
 //usage:#define dc_trivial_usage
-//usage:       IF_NOT_FEATURE_DC_SMALL("[-x] ")"[-eSCRIPT]... [-fFILE]... [FILE]..."
+//usage:       IF_FEATURE_DC_BIG("[-x] ")"[-eSCRIPT]... [-fFILE]... [FILE]..."
 //usage:
 //usage:#define dc_full_usage "\n"
 //usage:     "\nTiny RPN calculator. Operations:"
-//usage:     "\n+, -, *, /, %, ~, ^," IF_NOT_FEATURE_DC_SMALL(" |,")
+//usage:     "\n+, -, *, /, %, ~, ^," IF_FEATURE_DC_BIG(" |,")
 //usage:     "\np - print top of the stack without popping"
 //usage:     "\nf - print entire stack"
 //usage:     "\nk - pop the value and set the precision"
 #include "libbb.h"
 #include "common_bufsiz.h"
 
-#if ENABLE_FEATURE_DC_SMALL
+#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG
 # include "dc.c"
 #else
 
-#define DEBUG_LEXER   0
-#define DEBUG_COMPILE 0
-#define DEBUG_EXEC    0
-// This can be left enabled for production as well:
-#define SANITY_CHECKS 1
-
 #if DEBUG_LEXER
 static uint8_t lex_indent;
 #define dbg_lex(...) \
@@ -215,8 +207,8 @@ typedef enum BcStatus {
        BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr_empty_ok() uses this
 } BcStatus;
 
-#define BC_VEC_INVALID_IDX ((size_t) -1)
-#define BC_VEC_START_CAP (1 << 5)
+#define BC_VEC_INVALID_IDX  ((size_t) -1)
+#define BC_VEC_START_CAP    (1 << 5)
 
 typedef void (*BcVecFree)(void *) FAST_FUNC;
 
@@ -238,12 +230,12 @@ typedef struct BcNum {
        bool neg;
 } BcNum;
 
-#define BC_NUM_MAX_IBASE        ((unsigned long) 16)
+#define BC_NUM_MAX_IBASE        36
 // larger value might speed up BIGNUM calculations a bit:
-#define BC_NUM_DEF_SIZE         (16)
-#define BC_NUM_PRINT_WIDTH      (69)
+#define BC_NUM_DEF_SIZE         16
+#define BC_NUM_PRINT_WIDTH      69
 
-#define BC_NUM_KARATSUBA_LEN    (32)
+#define BC_NUM_KARATSUBA_LEN    32
 
 typedef enum BcInst {
 #if ENABLE_BC
@@ -436,7 +428,7 @@ typedef enum BcLexType {
        BC_LEX_LPAREN, // () are 0x28 and 0x29
        BC_LEX_RPAREN, // must be LPAREN+1: code uses (c - '(' + BC_LEX_LPAREN)
 
-       BC_LEX_LBRACKET, // [] are 0x5B and 5D
+       BC_LEX_LBRACKET, // [] are 0x5B and 0x5D
        BC_LEX_COMMA,
        BC_LEX_RBRACKET, // must be LBRACKET+2: code uses (c - '[' + BC_LEX_LBRACKET)
 
@@ -453,10 +445,10 @@ typedef enum BcLexType {
        BC_LEX_KEY_FOR,
        BC_LEX_KEY_HALT,
        // code uses "type - BC_LEX_KEY_IBASE + XC_INST_IBASE" construct,
-       BC_LEX_KEY_IBASE,       // relative order should match for: XC_INST_IBASE
-       BC_LEX_KEY_OBASE,       // relative order should match for: XC_INST_OBASE
+       BC_LEX_KEY_IBASE,    // relative order should match for: XC_INST_IBASE
+       BC_LEX_KEY_OBASE,    // relative order should match for: XC_INST_OBASE
        BC_LEX_KEY_IF,
-       IF_BC(BC_LEX_KEY_LAST,) // relative order should match for: BC_INST_LAST
+       BC_LEX_KEY_LAST,     // relative order should match for: BC_INST_LAST
        BC_LEX_KEY_LENGTH,
        BC_LEX_KEY_LIMITS,
        BC_LEX_KEY_PRINT,
@@ -610,7 +602,7 @@ static ALWAYS_INLINE long lex_allowed_in_bc_expr(unsigned i)
 
 // This is an array of data for operators that correspond to
 // [XC_LEX_1st_op...] token types.
-static const uint8_t bc_parse_ops[] = {
+static const uint8_t bc_ops_prec_and_assoc[] ALIGN1 = {
 #define OP(p,l) ((int)(l) * 0x10 + (p))
        OP(1, false), // neg
        OP(6, true ), OP( 6, true  ), OP( 6, true  ), OP( 6, true  ), OP( 6, true  ), OP( 6, true ), // == <= >= != < >
@@ -624,60 +616,60 @@ static const uint8_t bc_parse_ops[] = {
        OP(0, false), OP( 0, false ), // inc dec
 #undef OP
 };
-#define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
-#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
+#define bc_operation_PREC(i) (bc_ops_prec_and_assoc[i] & 0x0f)
+#define bc_operation_LEFT(i) (bc_ops_prec_and_assoc[i] & 0x10)
 #endif // ENABLE_BC
 
 #if ENABLE_DC
 static const //BcLexType - should be this type
 uint8_t
-dc_char_to_LEX[] = {
-       /* %&'( */
+dc_char_to_LEX[] ALIGN1 = {
+       // %&'(
        XC_LEX_OP_MODULUS, XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_LPAREN,
-       /* )*+, */
+       // )*+,
        XC_LEX_INVALID, XC_LEX_OP_MULTIPLY, XC_LEX_OP_PLUS, XC_LEX_INVALID,
-       /* -./ */
+       // -./
        XC_LEX_OP_MINUS, XC_LEX_INVALID, XC_LEX_OP_DIVIDE,
-       /* 0123456789 */
+       // 0123456789
        XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
        XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
        XC_LEX_INVALID, XC_LEX_INVALID,
-       /* :;<=>?@ */
+       // :;<=>?@
        DC_LEX_COLON, DC_LEX_SCOLON, XC_LEX_OP_REL_GT, XC_LEX_OP_REL_EQ,
        XC_LEX_OP_REL_LT, DC_LEX_READ, XC_LEX_INVALID,
-       /* ABCDEFGH */
+       // ABCDEFGH
        XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
        XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_EQ_NO_REG, XC_LEX_INVALID,
-       /* IJKLMNOP */
+       // IJKLMNOP
        DC_LEX_IBASE, XC_LEX_INVALID, DC_LEX_SCALE, DC_LEX_LOAD_POP,
        XC_LEX_INVALID, DC_LEX_OP_BOOL_NOT, DC_LEX_OBASE, DC_LEX_PRINT_STREAM,
-       /* QRSTUVWXY */
+       // QRSTUVWXY
        DC_LEX_NQUIT, DC_LEX_POP, DC_LEX_STORE_PUSH, XC_LEX_INVALID, XC_LEX_INVALID,
        XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_SCALE_FACTOR, XC_LEX_INVALID,
-       /* Z[\] */
+       // Z[\]
        DC_LEX_LENGTH, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
-       /* ^_` */
+       // ^_`
        XC_LEX_OP_POWER, XC_LEX_NEG, XC_LEX_INVALID,
-       /* abcdefgh */
+       // abcdefgh
        DC_LEX_ASCIIFY, XC_LEX_INVALID, DC_LEX_CLEAR_STACK, DC_LEX_DUPLICATE,
        DC_LEX_ELSE, DC_LEX_PRINT_STACK, XC_LEX_INVALID, XC_LEX_INVALID,
-       /* ijklmnop */
+       // ijklmnop
        DC_LEX_STORE_IBASE, XC_LEX_INVALID, DC_LEX_STORE_SCALE, DC_LEX_LOAD,
        XC_LEX_INVALID, DC_LEX_PRINT_POP, DC_LEX_STORE_OBASE, DC_LEX_PRINT,
-       /* qrstuvwx */
+       // qrstuvwx
        DC_LEX_QUIT, DC_LEX_SWAP, DC_LEX_OP_ASSIGN, XC_LEX_INVALID,
        XC_LEX_INVALID, DC_LEX_SQRT, XC_LEX_INVALID, DC_LEX_EXECUTE,
-       /* yz */
+       // yz
        XC_LEX_INVALID, DC_LEX_STACK_LEVEL,
-       /* {|}~ */
+       // {|}~
        DC_LEX_LBRACE, DC_LEX_OP_MODEXP, XC_LEX_INVALID, DC_LEX_OP_DIVMOD,
 };
 static const //BcInst - should be this type. Using signed narrow type since DC_INST_INVALID is -1
 int8_t
-dc_LEX_to_INST[] = { // starts at XC_LEX_OP_POWER       // corresponding XC/DC_LEX_xyz:
-       XC_INST_POWER,       XC_INST_MULTIPLY,          // OP_POWER     OP_MULTIPLY
-       XC_INST_DIVIDE,      XC_INST_MODULUS,           // OP_DIVIDE    OP_MODULUS
-       XC_INST_PLUS,        XC_INST_MINUS,             // OP_PLUS      OP_MINUS
+dc_LEX_to_INST[] ALIGN1 = { //starts at XC_LEX_OP_POWER // corresponding XC/DC_LEX_xyz:
+       XC_INST_POWER,       XC_INST_MULTIPLY,          // XC_LEX_OP_POWER    XC_LEX_OP_MULTIPLY
+       XC_INST_DIVIDE,      XC_INST_MODULUS,           // XC_LEX_OP_DIVIDE   XC_LEX_OP_MODULUS
+       XC_INST_PLUS,        XC_INST_MINUS,             // XC_LEX_OP_PLUS     XC_LEX_OP_MINUS
        XC_INST_BOOL_NOT,                               // DC_LEX_OP_BOOL_NOT
        DC_INST_INVALID,                                // DC_LEX_OP_ASSIGN
        XC_INST_REL_GT,                                 // DC_LEX_LPAREN
@@ -692,18 +684,18 @@ dc_LEX_to_INST[] = { // starts at XC_LEX_OP_POWER       // corresponding XC/DC_L
        XC_INST_SQRT,                                   // DC_LEX_SQRT
        XC_INST_REL_GE,                                 // DC_LEX_LBRACE
        XC_INST_REL_EQ,                                 // DC_LEX_EQ_NO_REG
-       DC_INST_MODEXP,      DC_INST_DIVMOD,            // OP_MODEXP    OP_DIVMOD
-       DC_INST_INVALID,     DC_INST_INVALID,           // COLON        ELSE
-       DC_INST_EXECUTE,                                // EXECUTE
-       DC_INST_PRINT_STACK, DC_INST_CLEAR_STACK,       // PRINT_STACK  CLEAR_STACK
-       DC_INST_STACK_LEN,   DC_INST_DUPLICATE,         // STACK_LEVEL  DUPLICATE
-       DC_INST_SWAP,        XC_INST_POP,               // SWAP         POP
-       DC_INST_ASCIIFY,     DC_INST_PRINT_STREAM,      // ASCIIFY      PRINT_STREAM
-       DC_INST_INVALID,     DC_INST_INVALID,           // STORE_IBASE  STORE_OBASE
-       DC_INST_INVALID,     DC_INST_INVALID,           // STORE_SCALE  LOAD
-       DC_INST_INVALID,     DC_INST_INVALID,           // LOAD_POP     STORE_PUSH
-       XC_INST_PRINT,       DC_INST_NQUIT,             // PRINT_POP    NQUIT
-       XC_INST_SCALE_FUNC,                             // SCALE_FACTOR
+       DC_INST_MODEXP,      DC_INST_DIVMOD,            // DC_LEX_OP_MODEXP   DC_LEX_OP_DIVMOD
+       DC_INST_INVALID,     DC_INST_INVALID,           // DC_LEX_COLON       DC_LEX_ELSE
+       DC_INST_EXECUTE,                                // DC_LEX_EXECUTE
+       DC_INST_PRINT_STACK, DC_INST_CLEAR_STACK,       // DC_LEX_PRINT_STACK DC_LEX_CLEAR_STACK
+       DC_INST_STACK_LEN,   DC_INST_DUPLICATE,         // DC_LEX_STACK_LEVEL DC_LEX_DUPLICATE
+       DC_INST_SWAP,        XC_INST_POP,               // DC_LEX_SWAP        DC_LEX_POP
+       DC_INST_ASCIIFY,     DC_INST_PRINT_STREAM,      // DC_LEX_ASCIIFY     DC_LEX_PRINT_STREAM
+       DC_INST_INVALID,     DC_INST_INVALID,           // DC_LEX_STORE_IBASE DC_LEX_STORE_OBASE
+       DC_INST_INVALID,     DC_INST_INVALID,           // DC_LEX_STORE_SCALE DC_LEX_LOAD
+       DC_INST_INVALID,     DC_INST_INVALID,           // DC_LEX_LOAD_POP    DC_LEX_STORE_PUSH
+       XC_INST_PRINT,       DC_INST_NQUIT,             // DC_LEX_PRINT_POP   DC_LEX_NQUIT
+       XC_INST_SCALE_FUNC,                             // DC_LEX_SCALE_FACTOR
        // DC_INST_INVALID in this table either means that corresponding LEX
        // is not possible for dc, or that it does not compile one-to-one
        // to a single INST.
@@ -765,7 +757,7 @@ struct globals {
 
        BcVec input_buffer;
 
-       IF_FEATURE_BC_SIGNALS(smallint ttyin;)
+       IF_FEATURE_BC_INTERACTIVE(smallint ttyin;)
        IF_FEATURE_CLEAN_UP(smallint exiting;)
 
        BcProgram prog;
@@ -788,7 +780,7 @@ struct globals {
 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
 #define G_warn  (ENABLE_BC && (option_mask32 & BC_FLAG_W))
 #define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
 # define G_interrupt bb_got_signal
 # define G_ttyin     G.ttyin
 #else
@@ -810,26 +802,19 @@ struct globals {
 # define BC_PARSE_NOCALL        (1 << 3)
 #endif
 
-#define BC_PROG_MAIN (0)
-#define BC_PROG_READ (1)
+#define BC_PROG_MAIN      0
+#define BC_PROG_READ      1
 #if ENABLE_DC
-#define BC_PROG_REQ_FUNCS (2)
+#define BC_PROG_REQ_FUNCS 2
 #endif
 
-#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
-#define BC_PROG_NUM(r, n) \
-       ((r)->t != XC_RESULT_ARRAY && (r)->t != XC_RESULT_STR && !BC_PROG_STR(n))
-
 #define BC_FLAG_W (1 << 0)
 #define BC_FLAG_V (1 << 1)
 #define BC_FLAG_S (1 << 2)
 #define BC_FLAG_Q (1 << 3)
 #define BC_FLAG_L (1 << 4)
-#define BC_FLAG_I (1 << 5)
-#define DC_FLAG_X (1 << 6)
-
-#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
-#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define BC_FLAG_I ((1 << 5) * ENABLE_DC)
+#define DC_FLAG_X ((1 << 6) * ENABLE_DC)
 
 #define BC_MAX_OBASE    ((unsigned) 999)
 #define BC_MAX_DIM      ((unsigned) INT_MAX)
@@ -876,7 +861,7 @@ struct globals {
 // To make code more readable, each such function has a "z"
 // ("always returning zero") prefix, i.e. zbc_foo or zdc_foo.
 //
-#if ENABLE_FEATURE_BC_SIGNALS || ENABLE_FEATURE_CLEAN_UP
+#if ENABLE_FEATURE_BC_INTERACTIVE || ENABLE_FEATURE_CLEAN_UP
 # define ERRORS_ARE_FATAL 0
 # define ERRORFUNC        /*nothing*/
 # define IF_ERROR_RETURN_POSSIBLE(a)  a
@@ -896,6 +881,9 @@ struct globals {
 // Utility routines
 //
 
+#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
+
 static void fflush_and_check(void)
 {
        fflush_all();
@@ -906,14 +894,11 @@ static void fflush_and_check(void)
 #if ENABLE_FEATURE_CLEAN_UP
 #define QUIT_OR_RETURN_TO_MAIN \
 do { \
-       IF_FEATURE_BC_SIGNALS(G_ttyin = 0;) /* do not loop in main loop anymore */ \
+       IF_FEATURE_BC_INTERACTIVE(G_ttyin = 0;) /* do not loop in main loop anymore */ \
        G_exiting = 1; \
        return BC_STATUS_FAILURE; \
 } while (0)
 #else
-#define QUIT_OR_RETURN_TO_MAIN quit()
-#endif
-
 static void quit(void) NORETURN;
 static void quit(void)
 {
@@ -923,6 +908,8 @@ static void quit(void)
        dbg_exec("quit(): exiting with exitcode SUCCESS");
        exit(0);
 }
+#define QUIT_OR_RETURN_TO_MAIN quit()
+#endif
 
 static void bc_verror_msg(const char *fmt, va_list p)
 {
@@ -1165,23 +1152,23 @@ static FAST_FUNC void bc_vec_free(void *vec)
        free(v->v);
 }
 
-static BcFunc* bc_program_func(size_t idx)
+static BcFunc* xc_program_func(size_t idx)
 {
        return bc_vec_item(&G.prog.fns, idx);
 }
 // BC_PROG_MAIN is zeroth element, so:
-#define bc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
+#define xc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
 
 #if ENABLE_BC
 static BcFunc* bc_program_current_func(void)
 {
        BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
-       BcFunc *func = bc_program_func(ip->func);
+       BcFunc *func = xc_program_func(ip->func);
        return func;
 }
 #endif
 
-static char** bc_program_str(size_t idx)
+static char** xc_program_str(size_t idx)
 {
 #if ENABLE_BC
        if (IS_BC) {
@@ -1192,7 +1179,7 @@ static char** bc_program_str(size_t idx)
        IF_DC(return bc_vec_item(&G.prog.strs, idx);)
 }
 
-static char** bc_program_const(size_t idx)
+static char** xc_program_const(size_t idx)
 {
 #if ENABLE_BC
        if (IS_BC) {
@@ -1637,7 +1624,7 @@ static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scal
        RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
 }
 
-static const BcNumBinaryOp zbc_program_ops[] = {
+static const BcNumBinaryOp zxc_program_ops[] = {
        zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
 };
 #define zbc_num_add(...) (zbc_num_add(__VA_ARGS__) COMMA_SUCCESS)
@@ -1835,7 +1822,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
                        c->num[i + j] += (BcDig) carry;
                        len = BC_MAX(len, i + j + !!carry);
 
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
                        // a=2^1000000
                        // a*a <- without check below, this will not be interruptible
                        if (G_interrupt) return BC_STATUS_FAILURE;
@@ -2002,7 +1989,7 @@ static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size
                for (q = 0; n[len] != 0 || bc_num_compare(n, b->num, len) >= 0; ++q)
                        bc_num_subArrays(n, b->num, len);
                c->num[i] = q;
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
                // a=2^100000
                // scale=40000
                // 1/a <- without check below, this will not be interruptible
@@ -2170,6 +2157,7 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
 {
        BcStatus s;
        BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
+       BcDig half_digs[1];
        size_t pow, len, digs, digs1, resrdx, req, times = 0;
        ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
 
@@ -2194,10 +2182,11 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
 
        bc_num_init(&num1, len);
        bc_num_init(&num2, len);
-       bc_num_init_DEF_SIZE(&half);
 
+       half.cap = ARRAY_SIZE(half_digs);
+       half.num = half_digs;
        bc_num_one(&half);
-       half.num[0] = 5;
+       half_digs[0] = 5;
        half.rdx = 1;
 
        bc_num_init(&f, len);
@@ -2260,7 +2249,6 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
  err:
        bc_num_free(&fprime);
        bc_num_free(&f);
-       bc_num_free(&half);
        bc_num_free(&num2);
        bc_num_free(&num1);
        RETURN_STATUS(s);
@@ -2298,7 +2286,7 @@ static BC_STATUS zdc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
 {
        BcStatus s;
        BcNum base, exp, two, temp;
-       BcDig two_digs[2];
+       BcDig two_digs[1];
 
        if (c->len == 0)
                RETURN_STATUS(bc_error("divide by zero"));
@@ -2481,13 +2469,13 @@ static int bad_input_byte(char c)
        return 0;
 }
 
-static void bc_read_line(BcVec *vec, FILE *fp)
+static void xc_read_line(BcVec *vec, FILE *fp)
 {
  again:
        bc_vec_pop_all(vec);
        fflush_and_check();
 
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
        if (G_interrupt) { // ^C was pressed
  intr:
                if (fp != stdin) {
@@ -2534,7 +2522,7 @@ static void bc_read_line(BcVec *vec, FILE *fp)
                bool bad_chars = 0;
 
                do {
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
                        if (G_interrupt) {
                                // ^C was pressed: ignore entire line, get another one
                                bc_vec_pop_all(vec);
@@ -2568,13 +2556,16 @@ static void bc_read_line(BcVec *vec, FILE *fp)
 // Parsing routines
 //
 
-static bool bc_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')
@@ -2584,7 +2575,7 @@ static bool bc_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;
@@ -2601,7 +2592,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, '.');
 
@@ -2612,10 +2603,25 @@ 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) {
+                               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;
                        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;
@@ -2631,32 +2637,33 @@ static void bc_num_parseDecimal(BcNum *n, const char *val)
 static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
 {
        BcStatus s;
-       BcNum temp, mult, result;
+       BcNum mult, result;
+       BcNum temp;
        BcNum base;
+       BcDig temp_digs[ULONG_NUM_BUFSIZE];
        BcDig base_digs[ULONG_NUM_BUFSIZE];
        BcDig c = '\0';
-       unsigned long v;
-       size_t i, digits;
-
-       for (i = 0; ; ++i) {
-               if (val[i] == '\0')
-                       return;
-               if (val[i] != '.' && val[i] != '0')
-                       break;
-       }
+       size_t digits;
 
-       bc_num_init_DEF_SIZE(&temp);
        bc_num_init_DEF_SIZE(&mult);
+
+       temp.cap = ARRAY_SIZE(temp_digs);
+       temp.num = temp_digs;
+
        base.cap = ARRAY_SIZE(base_digs);
        base.num = base_digs;
        bc_num_ulong2num(&base, base_t);
+       base_t--;
 
        for (;;) {
+               unsigned v;
+
                c = *val++;
                if (c == '\0') goto int_err;
                if (c == '.') break;
 
-               v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
+               v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
+               if (v > base_t) v = base_t;
 
                s = zbc_num_mul(n, &base, &mult, 0);
                if (s) goto int_err;
@@ -2671,11 +2678,14 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
 
        digits = 0;
        for (;;) {
+               unsigned v;
+
                c = *val++;
                if (c == '\0') break;
                digits++;
 
-               v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
+               v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
+               if (v > base_t) v = base_t;
 
                s = zbc_num_mul(&result, &base, &result, 0);
                if (s) goto err;
@@ -2700,39 +2710,34 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
        bc_num_free(&result);
  int_err:
        bc_num_free(&mult);
-       bc_num_free(&temp);
 }
 
-static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t)
+static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
 {
-       if (!bc_num_strValid(val, base_t))
+       size_t i;
+
+       if (!xc_num_strValid(val))
                RETURN_STATUS(bc_error("bad number string"));
 
        bc_num_zero(n);
-       while (*val == '0') val++;
+       while (*val == '0')
+               val++;
+       for (i = 0; ; ++i) {
+               if (val[i] == '\0')
+                       RETURN_STATUS(BC_STATUS_SUCCESS);
+               if (val[i] != '.' && val[i] != '0')
+                       break;
+       }
 
-       if (base_t == 10)
+       if (base_t == 10 || val[1] == '\0')
+               // Decimal, or single-digit number
                bc_num_parseDecimal(n, val);
        else
                bc_num_parseBase(n, val, base_t);
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
-#define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
-
-static bool bc_lex_more_input(void)
-{
-       BcParse *p = &G.prs;
-
-       bc_vec_pop_all(&G.input_buffer);
-
-       bc_read_line(&G.input_buffer, G.prs.lex_input_fp);
-
-       p->lex_inbuf = G.input_buffer.v;
-//     bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v);
-
-       return G.input_buffer.len > 1;
-}
+#define zxc_num_parse(...) (zxc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
 
 // p->lex_inbuf points to the current string to be parsed.
 // if p->lex_inbuf points to '\0', it's either EOF or it points after
@@ -2767,10 +2772,13 @@ static bool bc_lex_more_input(void)
 // end"         - ...prints "str#\<newline>end"
 static char peek_inbuf(void)
 {
-       if (*G.prs.lex_inbuf == '\0') {
-               if (G.prs.lex_input_fp)
-                       if (!bc_lex_more_input())
-                               G.prs.lex_input_fp = NULL;
+       if (*G.prs.lex_inbuf == '\0'
+        && G.prs.lex_input_fp
+       ) {
+               xc_read_line(&G.input_buffer, G.prs.lex_input_fp);
+               G.prs.lex_inbuf = G.input_buffer.v;
+               if (G.input_buffer.len <= 1) // on EOF, len is 1 (NUL byte)
+                       G.prs.lex_input_fp = NULL;
        }
        return *G.prs.lex_inbuf;
 }
@@ -2781,7 +2789,7 @@ static char eat_inbuf(void)
        return c;
 }
 
-static void bc_lex_lineComment(void)
+static void xc_lex_lineComment(void)
 {
        BcParse *p = &G.prs;
        char c;
@@ -2789,13 +2797,13 @@ static void bc_lex_lineComment(void)
        // Try: echo -n '#foo' | bc
        p->lex = XC_LEX_WHITESPACE;
 
-       // We depend here on input being done in whole lines:
+       // Not peek_inbuf(): we depend on input being done in whole lines:
        // '\0' which isn't the EOF can only be seen after '\n'.
        while ((c = *p->lex_inbuf) != '\n' && c != '\0')
                p->lex_inbuf++;
 }
 
-static void bc_lex_whitespace(void)
+static void xc_lex_whitespace(void)
 {
        BcParse *p = &G.prs;
 
@@ -2812,14 +2820,24 @@ static void bc_lex_whitespace(void)
        }
 }
 
-static BC_STATUS zbc_lex_number(char last)
+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);
 
+// 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 (;;) {
@@ -2835,13 +2853,13 @@ static BC_STATUS zbc_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 > last_valid_ch)) {
                        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++;
@@ -2853,9 +2871,9 @@ static BC_STATUS zbc_lex_number(char last)
        G.err_line = G.prs.lex_line;
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
-#define zbc_lex_number(...) (zbc_lex_number(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_lex_number(...) (zxc_lex_number(__VA_ARGS__) COMMA_SUCCESS)
 
-static void bc_lex_name(void)
+static void xc_lex_name(void)
 {
        BcParse *p = &G.prs;
        size_t i;
@@ -2893,7 +2911,7 @@ IF_DC(static BC_STATUS zdc_lex_token(void);)
 #define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
 #define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_lex_next(void)
+static BC_STATUS zxc_lex_next(void)
 {
        BcParse *p = &G.prs;
        BcStatus s;
@@ -2928,13 +2946,13 @@ static BC_STATUS zbc_lex_next(void)
 
        RETURN_STATUS(s);
 }
-#define zbc_lex_next(...) (zbc_lex_next(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_lex_next(...) (zxc_lex_next(__VA_ARGS__) COMMA_SUCCESS)
 
 #if ENABLE_BC
 static BC_STATUS zbc_lex_skip_if_at_NLINE(void)
 {
        if (G.prs.lex == XC_LEX_NLINE)
-               RETURN_STATUS(zbc_lex_next());
+               RETURN_STATUS(zxc_lex_next());
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
 #define zbc_lex_skip_if_at_NLINE(...) (zbc_lex_skip_if_at_NLINE(__VA_ARGS__) COMMA_SUCCESS)
@@ -2942,24 +2960,14 @@ static BC_STATUS zbc_lex_skip_if_at_NLINE(void)
 static BC_STATUS zbc_lex_next_and_skip_NLINE(void)
 {
        BcStatus s;
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        // if(cond)<newline>stmt is accepted too (but not 2+ newlines)
        s = zbc_lex_skip_if_at_NLINE();
        RETURN_STATUS(s);
 }
 #define zbc_lex_next_and_skip_NLINE(...) (zbc_lex_next_and_skip_NLINE(__VA_ARGS__) COMMA_SUCCESS)
-#endif
-
-static BC_STATUS zbc_lex_text_init(const char *text)
-{
-       G.prs.lex_inbuf = text;
-       G.prs.lex = G.prs.lex_last = XC_LEX_INVALID;
-       RETURN_STATUS(zbc_lex_next());
-}
-#define zbc_lex_text_init(...) (zbc_lex_text_init(__VA_ARGS__) COMMA_SUCCESS)
 
-#if ENABLE_BC
 static BC_STATUS zbc_lex_identifier(void)
 {
        BcParse *p = &G.prs;
@@ -2991,7 +2999,7 @@ static BC_STATUS zbc_lex_identifier(void)
                RETURN_STATUS(BC_STATUS_SUCCESS);
        }
 
-       bc_lex_name();
+       xc_lex_name();
        s = BC_STATUS_SUCCESS;
 
        if (p->lex_strnumbuf.len > 2) {
@@ -3016,7 +3024,7 @@ static BC_STATUS zbc_lex_string(void)
        for (;;) {
                char c = peek_inbuf(); // strings can cross lines
                if (c == '\0') {
-                       RETURN_STATUS(bc_error("unterminated string1"));
+                       RETURN_STATUS(bc_error("unterminated string"));
                }
                if (c == '"')
                        break;
@@ -3060,7 +3068,7 @@ static BC_STATUS zbc_lex_comment(void)
  check_star:
                if (c == '*') {
                        p->lex_inbuf++;
-                       c = peek_inbuf();
+                       c = *p->lex_inbuf; // no need to peek_inbuf()
                        if (c == '/')
                                break;
                        goto check_star;
@@ -3101,7 +3109,7 @@ static BC_STATUS zbc_lex_token(void)
        case '\f':
        case '\r':
        case ' ':
-               bc_lex_whitespace();
+               xc_lex_whitespace();
                break;
        case '!':
                parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
@@ -3116,7 +3124,7 @@ static BC_STATUS zbc_lex_token(void)
        case '#':
                s = zbc_POSIX_does_not_allow("'#' script comments");
                if (s) RETURN_STATUS(s);
-               bc_lex_lineComment();
+               xc_lex_lineComment();
                break;
        case '%':
                parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MODULUS, XC_LEX_OP_MODULUS);
@@ -3161,7 +3169,7 @@ static BC_STATUS zbc_lex_token(void)
                break;
        case '.':
                if (isdigit(*p->lex_inbuf))
-                       s = zbc_lex_number(c);
+                       s = zxc_lex_number(c);
                else {
                        p->lex = BC_LEX_KEY_LAST;
                        s = zbc_POSIX_does_not_allow("'.' as 'last'");
@@ -3190,7 +3198,27 @@ static BC_STATUS zbc_lex_token(void)
        case 'D':
        case 'E':
        case 'F':
-               s = zbc_lex_number(c);
+       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 ';':
                p->lex = BC_LEX_SCOLON;
@@ -3278,9 +3306,9 @@ static BC_STATUS zdc_lex_register(void)
 {
        BcParse *p = &G.prs;
        if (G_exreg && isspace(*p->lex_inbuf)) {
-               bc_lex_whitespace(); // eats whitespace (but not newline)
-               p->lex_inbuf++; // bc_lex_name() expects this
-               bc_lex_name();
+               xc_lex_whitespace(); // eats whitespace (but not newline)
+               p->lex_inbuf++; // xc_lex_name() expects this
+               xc_lex_name();
        } else {
                bc_vec_pop_all(&p->lex_strnumbuf);
                bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf++);
@@ -3326,16 +3354,16 @@ static BC_STATUS zdc_lex_string(void)
 #undef zdc_lex_token
 static BC_STATUS zdc_lex_token(void)
 {
-       BcParse *p = &G.prs;
        static const //BcLexType - should be this type, but narrower type saves size:
        uint8_t
-       dc_lex_regs[] = {
+       dc_lex_regs[] ALIGN1 = {
                XC_LEX_OP_REL_EQ, XC_LEX_OP_REL_LE, XC_LEX_OP_REL_GE, XC_LEX_OP_REL_NE,
                XC_LEX_OP_REL_LT, XC_LEX_OP_REL_GT, DC_LEX_SCOLON, DC_LEX_COLON,
                DC_LEX_ELSE, DC_LEX_LOAD, DC_LEX_LOAD_POP, DC_LEX_OP_ASSIGN,
                DC_LEX_STORE_PUSH,
        };
 
+       BcParse *p = &G.prs;
        BcStatus s;
        char c, c2;
        size_t i;
@@ -3375,7 +3403,7 @@ static BC_STATUS zdc_lex_token(void)
        case '\f':
        case '\r':
        case ' ':
-               bc_lex_whitespace();
+               xc_lex_whitespace();
                break;
        case '!':
                c2 = *p->lex_inbuf;
@@ -3390,11 +3418,11 @@ static BC_STATUS zdc_lex_token(void)
                p->lex_inbuf++;
                break;
        case '#':
-               bc_lex_lineComment();
+               xc_lex_lineComment();
                break;
        case '.':
                if (isdigit(*p->lex_inbuf))
-                       s = zbc_lex_number(c);
+                       s = zxc_lex_number(c);
                else
                        s = bc_error_bad_character(c);
                break;
@@ -3414,7 +3442,7 @@ static BC_STATUS zdc_lex_token(void)
        case 'D':
        case 'E':
        case 'F':
-               s = zbc_lex_number(c);
+               s = zxc_lex_number(c);
                break;
        case '[':
                s = zdc_lex_string();
@@ -3430,38 +3458,61 @@ static BC_STATUS zdc_lex_token(void)
 #define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
 #endif // ENABLE_DC
 
-static void bc_parse_push(char i)
+static void xc_parse_push(char i)
 {
        BcVec *code = &G.prs.func->code;
        dbg_compile("%s:%d pushing bytecode %zd:%d", __func__, __LINE__, code->len, i);
        bc_vec_pushByte(code, i);
 }
 
-static void bc_parse_pushName(char *name)
+static void xc_parse_pushName(char *name)
 {
+#if 1
+       BcVec *code = &G.prs.func->code;
+       size_t pos = code->len;
+       size_t len = strlen(name) + 1;
+
+       bc_vec_expand(code, pos + len);
+       strcpy(code->v + pos, name);
+       code->len = pos + len;
+#else
+       // Smaller code, but way slow:
        do {
-               bc_parse_push(*name);
+               xc_parse_push(*name);
        } while (*name++);
+#endif
 }
 
-static void bc_parse_pushIndex(size_t idx)
+// Indexes < 0xfc are encoded verbatim, else first byte is
+// 0xfc, 0xfd, 0xfe or 0xff, encoding "1..4 bytes",
+// followed by that many bytes, lsb first.
+// (The above describes 32-bit case).
+#define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t))
+
+static void xc_parse_pushIndex(size_t idx)
 {
        size_t mask;
        unsigned amt;
 
        dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx);
+       if (idx < SMALL_INDEX_LIMIT) {
+               goto push_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"
 
-       bc_parse_push(amt);
+       xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt);
 
        while (idx != 0) {
-               bc_parse_push((unsigned char)idx);
+ push_idx:
+               xc_parse_push((unsigned char)idx);
                idx >>= 8;
        }
 }
@@ -3469,14 +3520,14 @@ static void bc_parse_pushIndex(size_t idx)
 #if ENABLE_BC
 static void bc_parse_pushJUMP(size_t idx)
 {
-       bc_parse_push(BC_INST_JUMP);
-       bc_parse_pushIndex(idx);
+       xc_parse_push(BC_INST_JUMP);
+       xc_parse_pushIndex(idx);
 }
 
 static void bc_parse_pushJUMP_ZERO(size_t idx)
 {
-       bc_parse_push(BC_INST_JUMP_ZERO);
-       bc_parse_pushIndex(idx);
+       xc_parse_push(BC_INST_JUMP_ZERO);
+       xc_parse_pushIndex(idx);
 }
 
 static BC_STATUS zbc_parse_pushSTR(void)
@@ -3484,16 +3535,16 @@ static BC_STATUS zbc_parse_pushSTR(void)
        BcParse *p = &G.prs;
        char *str = xstrdup(p->lex_strnumbuf.v);
 
-       bc_parse_push(XC_INST_STR);
-       bc_parse_pushIndex(p->func->strs.len);
+       xc_parse_push(XC_INST_STR);
+       xc_parse_pushIndex(p->func->strs.len);
        bc_vec_push(&p->func->strs, &str);
 
-       RETURN_STATUS(zbc_lex_next());
+       RETURN_STATUS(zxc_lex_next());
 }
 #define zbc_parse_pushSTR(...) (zbc_parse_pushSTR(__VA_ARGS__) COMMA_SUCCESS)
 #endif
 
-static void bc_parse_pushNUM(void)
+static void xc_parse_pushNUM(void)
 {
        BcParse *p = &G.prs;
        char *num = xstrdup(p->lex_strnumbuf.v);
@@ -3504,22 +3555,22 @@ static void bc_parse_pushNUM(void)
 #else // DC
        size_t idx = bc_vec_push(&G.prog.consts, &num);
 #endif
-       bc_parse_push(XC_INST_NUM);
-       bc_parse_pushIndex(idx);
+       xc_parse_push(XC_INST_NUM);
+       xc_parse_pushIndex(idx);
 }
 
-static BC_STATUS zbc_parse_text_init(const char *text)
+static BC_STATUS zxc_parse_text_init(const char *text)
 {
-       BcParse *p = &G.prs;
-       p->func = bc_program_func(p->fidx);
-
-       RETURN_STATUS(zbc_lex_text_init(text));
+       G.prs.func = xc_program_func(G.prs.fidx);
+       G.prs.lex_inbuf = text;
+       G.prs.lex = G.prs.lex_last = XC_LEX_INVALID;
+       RETURN_STATUS(zxc_lex_next());
 }
-#define zbc_parse_text_init(...) (zbc_parse_text_init(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_parse_text_init(...) (zxc_parse_text_init(__VA_ARGS__) COMMA_SUCCESS)
 
 // Called when parsing or execution detects a failure,
 // resets execution structures.
-static void bc_program_reset(void)
+static void xc_program_reset(void)
 {
        BcFunc *f;
        BcInstPtr *ip;
@@ -3527,14 +3578,14 @@ static void bc_program_reset(void)
        bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
        bc_vec_pop_all(&G.prog.results);
 
-       f = bc_program_func_BC_PROG_MAIN();
+       f = xc_program_func_BC_PROG_MAIN();
        ip = bc_vec_top(&G.prog.exestack);
        ip->inst_idx = f->code.len;
 }
 
 // Called when parsing code detects a failure,
 // resets parsing structures.
-static void bc_parse_reset(void)
+static void xc_parse_reset(void)
 {
        BcParse *p = &G.prs;
        if (p->fidx != BC_PROG_MAIN) {
@@ -3542,7 +3593,7 @@ static void bc_parse_reset(void)
                bc_func_init(p->func);
 
                p->fidx = BC_PROG_MAIN;
-               p->func = bc_program_func_BC_PROG_MAIN();
+               p->func = xc_program_func_BC_PROG_MAIN();
        }
 
        p->lex_inbuf += strlen(p->lex_inbuf);
@@ -3552,10 +3603,10 @@ static void bc_parse_reset(void)
        IF_BC(bc_vec_pop_all(&p->conds);)
        IF_BC(bc_vec_pop_all(&p->ops);)
 
-       bc_program_reset();
+       xc_program_reset();
 }
 
-static void bc_parse_free(void)
+static void xc_parse_free(void)
 {
        IF_BC(bc_vec_free(&G.prs.exits);)
        IF_BC(bc_vec_free(&G.prs.conds);)
@@ -3563,7 +3614,7 @@ static void bc_parse_free(void)
        bc_vec_free(&G.prs.lex_strnumbuf);
 }
 
-static void bc_parse_create(size_t fidx)
+static void xc_parse_create(size_t fidx)
 {
        BcParse *p = &G.prs;
        memset(p, 0, sizeof(BcParse));
@@ -3574,10 +3625,10 @@ static void bc_parse_create(size_t fidx)
        IF_BC(bc_vec_init(&p->ops, sizeof(BcLexType), NULL);)
 
        p->fidx = fidx;
-       p->func = bc_program_func(fidx);
+       p->func = xc_program_func(fidx);
 }
 
-static void bc_program_add_fn(void)
+static void xc_program_add_fn(void)
 {
        //size_t idx;
        BcFunc f;
@@ -3608,11 +3659,11 @@ static size_t bc_program_addFunc(char *name)
        if (!inserted) {
                // There is already a function with this name.
                // It'll be redefined now, clear old definition.
-               BcFunc *func = bc_program_func(entry_ptr->idx);
+               BcFunc *func = xc_program_func(entry_ptr->idx);
                bc_func_free(func);
                bc_func_init(func);
        } else {
-               bc_program_add_fn();
+               xc_program_add_fn();
        }
 
        return idx;
@@ -3663,17 +3714,17 @@ static BC_STATUS zbc_parse_stmt_allow_NLINE_before(const char *after_X)
 static void bc_parse_operator(BcLexType type, size_t start, size_t *nexprs)
 {
        BcParse *p = &G.prs;
-       char l, r = bc_parse_op_PREC(type - XC_LEX_1st_op);
-       bool left = bc_parse_op_LEFT(type - XC_LEX_1st_op);
+       char l, r = bc_operation_PREC(type - XC_LEX_1st_op);
+       bool left = bc_operation_LEFT(type - XC_LEX_1st_op);
 
        while (p->ops.len > start) {
                BcLexType t = BC_PARSE_TOP_OP(p);
                if (t == BC_LEX_LPAREN) break;
 
-               l = bc_parse_op_PREC(t - XC_LEX_1st_op);
+               l = bc_operation_PREC(t - XC_LEX_1st_op);
                if (l >= r && (l != r || !left)) break;
 
-               bc_parse_push(BC_TOKEN_2_INST(t));
+               xc_parse_push(BC_TOKEN_2_INST(t));
                bc_vec_pop(&p->ops);
                *nexprs -= (t != BC_LEX_OP_BOOL_NOT && t != XC_LEX_NEG);
        }
@@ -3691,7 +3742,7 @@ static BC_STATUS zbc_parse_rightParen(size_t ops_bgn, size_t *nexs)
        top = BC_PARSE_TOP_OP(p);
 
        while (top != BC_LEX_LPAREN) {
-               bc_parse_push(BC_TOKEN_2_INST(top));
+               xc_parse_push(BC_TOKEN_2_INST(top));
 
                bc_vec_pop(&p->ops);
                *nexs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
@@ -3716,7 +3767,7 @@ static BC_STATUS zbc_parse_params(uint8_t flags)
        dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
        flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        nparams = 0;
@@ -3730,13 +3781,13 @@ static BC_STATUS zbc_parse_params(uint8_t flags)
                                        break;
                                RETURN_STATUS(bc_error_bad_token());
                        }
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) RETURN_STATUS(s);
                }
        }
 
-       bc_parse_push(BC_INST_CALL);
-       bc_parse_pushIndex(nparams);
+       xc_parse_push(BC_INST_CALL);
+       xc_parse_pushIndex(nparams);
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
@@ -3770,9 +3821,9 @@ static BC_STATUS zbc_parse_call(char *name, uint8_t flags)
                free(name);
 
        entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
-       bc_parse_pushIndex(entry_ptr->idx);
+       xc_parse_pushIndex(entry_ptr->idx);
 
-       RETURN_STATUS(zbc_lex_next());
+       RETURN_STATUS(zxc_lex_next());
  err:
        free(name);
        RETURN_STATUS(s);
@@ -3786,11 +3837,11 @@ static BC_STATUS zbc_parse_name(BcInst *type, uint8_t flags)
        char *name;
 
        name = xstrdup(p->lex_strnumbuf.v);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) goto err;
 
        if (p->lex == BC_LEX_LBRACKET) {
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) goto err;
 
                if (p->lex == BC_LEX_RBRACKET) {
@@ -3805,10 +3856,10 @@ static BC_STATUS zbc_parse_name(BcInst *type, uint8_t flags)
                        s = zbc_parse_expr(flags);
                        if (s) goto err;
                }
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) goto err;
-               bc_parse_push(*type);
-               bc_parse_pushName(name);
+               xc_parse_push(*type);
+               xc_parse_pushName(name);
                free(name);
        } else if (p->lex == BC_LEX_LPAREN) {
                if (flags & BC_PARSE_NOCALL) {
@@ -3819,8 +3870,8 @@ static BC_STATUS zbc_parse_name(BcInst *type, uint8_t flags)
                s = zbc_parse_call(name, flags);
        } else {
                *type = XC_INST_VAR;
-               bc_parse_push(XC_INST_VAR);
-               bc_parse_pushName(name);
+               xc_parse_push(XC_INST_VAR);
+               xc_parse_pushName(name);
                free(name);
        }
 
@@ -3836,15 +3887,15 @@ static BC_STATUS zbc_parse_read(void)
        BcParse *p = &G.prs;
        BcStatus s;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
 
-       bc_parse_push(XC_INST_READ);
+       xc_parse_push(XC_INST_READ);
 
        RETURN_STATUS(s);
 }
@@ -3855,13 +3906,13 @@ static BC_STATUS zbc_parse_builtin(BcLexType type, uint8_t flags, BcInst *prev)
        BcParse *p = &G.prs;
        BcStatus s;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
 
        flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        s = zbc_parse_expr(flags);
@@ -3870,7 +3921,7 @@ static BC_STATUS zbc_parse_builtin(BcLexType type, uint8_t flags, BcInst *prev)
        if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
 
        *prev = (type == BC_LEX_KEY_LENGTH) ? XC_INST_LENGTH : XC_INST_SQRT;
-       bc_parse_push(*prev);
+       xc_parse_push(*prev);
 
        RETURN_STATUS(s);
 }
@@ -3881,28 +3932,28 @@ static BC_STATUS zbc_parse_scale(BcInst *type, uint8_t flags)
        BcParse *p = &G.prs;
        BcStatus s;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        if (p->lex != BC_LEX_LPAREN) {
                *type = XC_INST_SCALE;
-               bc_parse_push(XC_INST_SCALE);
+               xc_parse_push(XC_INST_SCALE);
                RETURN_STATUS(BC_STATUS_SUCCESS);
        }
 
        *type = XC_INST_SCALE_FUNC;
        flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        s = zbc_parse_expr(flags);
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_RPAREN)
                RETURN_STATUS(bc_error_bad_token());
-       bc_parse_push(XC_INST_SCALE_FUNC);
+       xc_parse_push(XC_INST_SCALE_FUNC);
 
-       RETURN_STATUS(zbc_lex_next());
+       RETURN_STATUS(zxc_lex_next());
 }
 #define zbc_parse_scale(...) (zbc_parse_scale(__VA_ARGS__) COMMA_SUCCESS)
 
@@ -3920,13 +3971,13 @@ static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr,
         || etype == XC_INST_IBASE || etype == XC_INST_OBASE
        ) {
                *prev = inst = BC_INST_INC_POST + (p->lex != BC_LEX_OP_INC);
-               bc_parse_push(inst);
-               s = zbc_lex_next();
+               xc_parse_push(inst);
+               s = zxc_lex_next();
        } else {
                *prev = inst = BC_INST_INC_PRE + (p->lex != BC_LEX_OP_INC);
                *paren_expr = true;
 
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) RETURN_STATUS(s);
                type = p->lex;
 
@@ -3941,23 +3992,23 @@ static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr,
                case BC_LEX_KEY_IBASE:
                case BC_LEX_KEY_LAST:
                case BC_LEX_KEY_OBASE:
-                       bc_parse_push(type - BC_LEX_KEY_IBASE + XC_INST_IBASE);
-                       s = zbc_lex_next();
+                       xc_parse_push(type - BC_LEX_KEY_IBASE + XC_INST_IBASE);
+                       s = zxc_lex_next();
                        break;
                case BC_LEX_KEY_SCALE:
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) RETURN_STATUS(s);
                        if (p->lex == BC_LEX_LPAREN)
                                s = bc_error_bad_token();
                        else
-                               bc_parse_push(XC_INST_SCALE);
+                               xc_parse_push(XC_INST_SCALE);
                        break;
                default:
                        s = bc_error_bad_token();
                        break;
                }
 
-               if (!s) bc_parse_push(inst);
+               if (!s) xc_parse_push(inst);
        }
 
        RETURN_STATUS(s);
@@ -3990,7 +4041,7 @@ static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn,
        BcLexType type;
        BcInst etype = *prev;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        type = BC_PARSE_LEAF(etype, rparen) ? XC_LEX_OP_MINUS : XC_LEX_NEG;
@@ -4014,7 +4065,7 @@ static BC_STATUS zbc_parse_print(void)
        BcLexType type;
 
        for (;;) {
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) RETURN_STATUS(s);
                type = p->lex;
                if (type == XC_LEX_STR) {
@@ -4023,7 +4074,7 @@ static BC_STATUS zbc_parse_print(void)
                        s = zbc_parse_expr(0);
                }
                if (s) RETURN_STATUS(s);
-               bc_parse_push(XC_INST_PRINT_POP);
+               xc_parse_push(XC_INST_PRINT_POP);
                if (p->lex != BC_LEX_COMMA)
                        break;
        }
@@ -4039,18 +4090,18 @@ static BC_STATUS zbc_parse_return(void)
        BcLexType t;
 
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        t = p->lex;
        if (t == XC_LEX_NLINE || t == BC_LEX_SCOLON)
-               bc_parse_push(BC_INST_RET0);
+               xc_parse_push(BC_INST_RET0);
        else {
                bool paren = (t == BC_LEX_LPAREN);
                s = bc_parse_expr_empty_ok(0);
                if (s == BC_STATUS_PARSE_EMPTY_EXP) {
-                       bc_parse_push(BC_INST_RET0);
-                       s = zbc_lex_next();
+                       xc_parse_push(BC_INST_RET0);
+                       s = zxc_lex_next();
                }
                if (s) RETURN_STATUS(s);
 
@@ -4059,7 +4110,7 @@ static BC_STATUS zbc_parse_return(void)
                        if (s) RETURN_STATUS(s);
                }
 
-               bc_parse_push(XC_INST_RET);
+               xc_parse_push(XC_INST_RET);
        }
 
        dbg_lex_done("%s:%d done", __func__, __LINE__);
@@ -4081,11 +4132,11 @@ static BC_STATUS zbc_parse_if(void)
        size_t ip_idx;
 
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        s = zbc_parse_expr(BC_PARSE_REL);
        if (s) RETURN_STATUS(s);
@@ -4133,10 +4184,10 @@ static BC_STATUS zbc_parse_while(void)
        size_t cond_idx;
        size_t ip_idx;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
@@ -4175,15 +4226,15 @@ static BC_STATUS zbc_parse_for(void)
        size_t cond_idx, exit_idx, body_idx, update_idx;
 
        dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        if (p->lex != BC_LEX_SCOLON) {
                s = zbc_parse_expr(0);
-               bc_parse_push(XC_INST_POP);
+               xc_parse_push(XC_INST_POP);
                if (s) RETURN_STATUS(s);
        } else {
                s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("init");
@@ -4191,7 +4242,7 @@ static BC_STATUS zbc_parse_for(void)
        }
 
        if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
@@ -4202,18 +4253,18 @@ static BC_STATUS zbc_parse_for(void)
        if (p->lex != BC_LEX_SCOLON)
                s = zbc_parse_expr(BC_PARSE_REL);
        else {
-               // Set this for the next call to bc_parse_pushNUM().
+               // Set this for the next call to xc_parse_pushNUM().
                // This is safe to set because the current token is a semicolon,
                // which has no string requirement.
                bc_vec_string(&p->lex_strnumbuf, 1, "1");
-               bc_parse_pushNUM();
+               xc_parse_pushNUM();
                s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
        }
        if (s) RETURN_STATUS(s);
 
        if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        bc_parse_pushJUMP_ZERO(exit_idx);
@@ -4226,7 +4277,7 @@ static BC_STATUS zbc_parse_for(void)
                s = zbc_parse_expr(0);
                if (s) RETURN_STATUS(s);
                if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
-               bc_parse_push(XC_INST_POP);
+               xc_parse_push(XC_INST_POP);
        } else {
                s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("update");
                if (s) RETURN_STATUS(s);
@@ -4268,7 +4319,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcLexType type)
        }
        bc_parse_pushJUMP(i);
 
-       RETURN_STATUS(zbc_lex_next());
+       RETURN_STATUS(zxc_lex_next());
 }
 #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS)
 
@@ -4301,20 +4352,20 @@ static BC_STATUS zbc_parse_funcdef(void)
        char *name;
 
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != XC_LEX_NAME)
                RETURN_STATUS(bc_error("bad function definition"));
 
        name = xstrdup(p->lex_strnumbuf.v);
        p->fidx = bc_program_addFunc(name);
-       p->func = bc_program_func(p->fidx);
+       p->func = xc_program_func(p->fidx);
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != BC_LEX_LPAREN)
                RETURN_STATUS(bc_error("bad function definition"));
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        while (p->lex != BC_LEX_RPAREN) {
@@ -4324,13 +4375,13 @@ static BC_STATUS zbc_parse_funcdef(void)
                ++p->func->nparams;
 
                name = xstrdup(p->lex_strnumbuf.v);
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) goto err;
 
                var = p->lex != BC_LEX_LBRACKET;
 
                if (!var) {
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) goto err;
 
                        if (p->lex != BC_LEX_RBRACKET) {
@@ -4338,13 +4389,13 @@ static BC_STATUS zbc_parse_funcdef(void)
                                goto err;
                        }
 
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) goto err;
                }
 
                comma = p->lex == BC_LEX_COMMA;
                if (comma) {
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) goto err;
                }
 
@@ -4354,7 +4405,7 @@ static BC_STATUS zbc_parse_funcdef(void)
 
        if (comma) RETURN_STATUS(bc_error("bad function definition"));
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        if (p->lex != BC_LEX_LBRACE) {
@@ -4374,11 +4425,11 @@ static BC_STATUS zbc_parse_funcdef(void)
        p->in_funcdef--;
        if (s) RETURN_STATUS(s);
 
-       bc_parse_push(BC_INST_RET0);
+       xc_parse_push(BC_INST_RET0);
 
        // Subsequent code generation is into main program
        p->fidx = BC_PROG_MAIN;
-       p->func = bc_program_func_BC_PROG_MAIN();
+       p->func = xc_program_func_BC_PROG_MAIN();
 
        dbg_lex_done("%s:%d done", __func__, __LINE__);
        RETURN_STATUS(s);
@@ -4396,7 +4447,7 @@ static BC_STATUS zbc_parse_auto(void)
        char *name;
 
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        for (;;) {
@@ -4406,19 +4457,19 @@ static BC_STATUS zbc_parse_auto(void)
                        RETURN_STATUS(bc_error("bad 'auto' syntax"));
 
                name = xstrdup(p->lex_strnumbuf.v);
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) goto err;
 
                var = (p->lex != BC_LEX_LBRACKET);
                if (!var) {
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) goto err;
 
                        if (p->lex != BC_LEX_RBRACKET) {
                                s = bc_error("bad 'auto' syntax");
                                goto err;
                        }
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) goto err;
                }
 
@@ -4433,7 +4484,7 @@ static BC_STATUS zbc_parse_auto(void)
                }
                if (p->lex != BC_LEX_COMMA)
                        RETURN_STATUS(bc_error("bad 'auto' syntax"));
-               s = zbc_lex_next(); // skip comma
+               s = zxc_lex_next(); // skip comma
                if (s) RETURN_STATUS(s);
        }
 
@@ -4456,17 +4507,17 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
 
        if (p->lex == XC_LEX_NLINE) {
                dbg_lex_done("%s:%d done (seen XC_LEX_NLINE)", __func__, __LINE__);
-               RETURN_STATUS(zbc_lex_next());
+               RETURN_STATUS(zxc_lex_next());
        }
        if (p->lex == BC_LEX_SCOLON) {
                dbg_lex_done("%s:%d done (seen BC_LEX_SCOLON)", __func__, __LINE__);
-               RETURN_STATUS(zbc_lex_next());
+               RETURN_STATUS(zxc_lex_next());
        }
 
        if (p->lex == BC_LEX_LBRACE) {
                dbg_lex("%s:%d BC_LEX_LBRACE: (auto_allowed:%d)", __func__, __LINE__, auto_allowed);
                do {
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) RETURN_STATUS(s);
                } while (p->lex == XC_LEX_NLINE);
                if (auto_allowed && p->lex == BC_LEX_KEY_AUTO) {
@@ -4479,7 +4530,7 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
                        s = zbc_parse_stmt();
                        if (s) RETURN_STATUS(s);
                }
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                dbg_lex_done("%s:%d done (seen BC_LEX_RBRACE)", __func__, __LINE__);
                RETURN_STATUS(s);
        }
@@ -4504,7 +4555,7 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
                break;
        case XC_LEX_STR:
                s = zbc_parse_pushSTR();
-               bc_parse_push(XC_INST_PRINT_STR);
+               xc_parse_push(XC_INST_PRINT_STR);
                break;
        case BC_LEX_KEY_BREAK:
        case BC_LEX_KEY_CONTINUE:
@@ -4514,8 +4565,8 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
                s = zbc_parse_for();
                break;
        case BC_LEX_KEY_HALT:
-               bc_parse_push(BC_INST_HALT);
-               s = zbc_lex_next();
+               xc_parse_push(BC_INST_HALT);
+               s = zxc_lex_next();
                break;
        case BC_LEX_KEY_IF:
                s = zbc_parse_if();
@@ -4533,7 +4584,7 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
                        "MAX Exponent    = "BC_MAX_EXP_STR   "\n"
                        "Number of vars  = "BC_MAX_VARS_STR  "\n"
                );
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                break;
        case BC_LEX_KEY_PRINT:
                s = zbc_parse_print();
@@ -4664,7 +4715,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
                        nrelops += (t >= XC_LEX_OP_REL_EQ && t <= XC_LEX_OP_REL_GT);
                        prev = BC_TOKEN_2_INST(t);
                        bc_parse_operator(t, ops_bgn, &nexprs);
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        rprn = false;
                        //get_token = false; - already is
                        bin_last = (t != BC_LEX_OP_BOOL_NOT);
@@ -4710,7 +4761,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
                        dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
                        if (BC_PARSE_LEAF(prev, rprn))
                                return bc_error_bad_expression();
-                       bc_parse_pushNUM();
+                       xc_parse_pushNUM();
                        prev = XC_INST_NUM;
                        get_token = true;
                        paren_expr = true;
@@ -4724,7 +4775,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
                        if (BC_PARSE_LEAF(prev, rprn))
                                return bc_error_bad_expression();
                        prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE);
-                       bc_parse_push((char) prev);
+                       xc_parse_push((char) prev);
                        get_token = true;
                        paren_expr = true;
                        rprn = bin_last = false;
@@ -4770,7 +4821,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
                if (s || G_interrupt) // error, or ^C: stop parsing
                        return BC_STATUS_FAILURE;
                if (get_token) {
-                       s = zbc_lex_next();
+                       s = zxc_lex_next();
                        if (s) return s;
                }
        }
@@ -4783,7 +4834,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
                if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
                        return bc_error_bad_expression();
 
-               bc_parse_push(BC_TOKEN_2_INST(top));
+               xc_parse_push(BC_TOKEN_2_INST(top));
 
                nexprs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
                bc_vec_pop(&p->ops);
@@ -4804,8 +4855,8 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags)
 
        if (flags & BC_PARSE_PRINT) {
                if (paren_first || !assign)
-                       bc_parse_push(XC_INST_PRINT);
-               bc_parse_push(XC_INST_POP);
+                       xc_parse_push(XC_INST_PRINT);
+               xc_parse_push(XC_INST_POP);
        }
 
        dbg_lex_done("%s:%d done", __func__, __LINE__);
@@ -4821,11 +4872,11 @@ static BC_STATUS zdc_parse_register(void)
        BcParse *p = &G.prs;
        BcStatus s;
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
        if (p->lex != XC_LEX_NAME) RETURN_STATUS(bc_error_bad_token());
 
-       bc_parse_pushName(p->lex_strnumbuf.v);
+       xc_parse_pushName(p->lex_strnumbuf.v);
 
        RETURN_STATUS(s);
 }
@@ -4840,13 +4891,13 @@ static void dc_parse_string(void)
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
 
        str = xstrdup(p->lex_strnumbuf.v);
-       bc_parse_push(XC_INST_STR);
-       bc_parse_pushIndex(len);
+       xc_parse_push(XC_INST_STR);
+       xc_parse_pushIndex(len);
        bc_vec_push(&G.prog.strs, &str);
 
        // Explanation needed here
-       bc_program_add_fn();
-       p->func = bc_program_func(p->fidx);
+       xc_program_add_fn();
+       p->func = xc_program_func(p->fidx);
 
        dbg_lex_done("%s:%d done", __func__, __LINE__);
 }
@@ -4855,16 +4906,16 @@ static BC_STATUS zdc_parse_mem(uint8_t inst, bool name, bool store)
 {
        BcStatus s;
 
-       bc_parse_push(inst);
+       xc_parse_push(inst);
        if (name) {
                s = zdc_parse_register();
                if (s) RETURN_STATUS(s);
        }
 
        if (store) {
-               bc_parse_push(DC_INST_SWAP);
-               bc_parse_push(XC_INST_ASSIGN);
-               bc_parse_push(XC_INST_POP);
+               xc_parse_push(DC_INST_SWAP);
+               xc_parse_push(XC_INST_ASSIGN);
+               xc_parse_push(XC_INST_POP);
        }
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
@@ -4876,13 +4927,13 @@ static BC_STATUS zdc_parse_cond(uint8_t inst)
        BcParse *p = &G.prs;
        BcStatus s;
 
-       bc_parse_push(inst);
-       bc_parse_push(DC_INST_EXEC_COND);
+       xc_parse_push(inst);
+       xc_parse_push(DC_INST_EXEC_COND);
 
        s = zdc_parse_register();
        if (s) RETURN_STATUS(s);
 
-       s = zbc_lex_next();
+       s = zxc_lex_next();
        if (s) RETURN_STATUS(s);
 
        // Note that 'else' part can not be on the next line:
@@ -4891,9 +4942,9 @@ static BC_STATUS zdc_parse_cond(uint8_t inst)
        if (p->lex == DC_LEX_ELSE) {
                s = zdc_parse_register();
                if (s) RETURN_STATUS(s);
-               s = zbc_lex_next();
+               s = zxc_lex_next();
        } else {
-               bc_parse_push('\0');
+               xc_parse_push('\0');
        }
 
        RETURN_STATUS(s);
@@ -4931,20 +4982,20 @@ static BC_STATUS zdc_parse_token(BcLexType t)
                break;
        case XC_LEX_NEG:
                dbg_lex("%s:%d LEX_NEG", __func__, __LINE__);
-               s = zbc_lex_next();
+               s = zxc_lex_next();
                if (s) RETURN_STATUS(s);
                if (G.prs.lex != XC_LEX_NUMBER)
                        RETURN_STATUS(bc_error_bad_token());
-               bc_parse_pushNUM();
-               bc_parse_push(XC_INST_NEG);
+               xc_parse_pushNUM();
+               xc_parse_push(XC_INST_NEG);
                break;
        case XC_LEX_NUMBER:
                dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
-               bc_parse_pushNUM();
+               xc_parse_pushNUM();
                break;
        case DC_LEX_READ:
                dbg_lex("%s:%d LEX_KEY_READ", __func__, __LINE__);
-               bc_parse_push(XC_INST_READ);
+               xc_parse_push(XC_INST_READ);
                break;
        case DC_LEX_OP_ASSIGN:
        case DC_LEX_STORE_PUSH:
@@ -4971,7 +5022,7 @@ static BC_STATUS zdc_parse_token(BcLexType t)
                RETURN_STATUS(bc_error_bad_token());
        }
 
-       if (!s && get_token) s = zbc_lex_next();
+       if (!s && get_token) s = zxc_lex_next();
 
        dbg_lex_done("%s:%d done", __func__, __LINE__);
        RETURN_STATUS(s);
@@ -4987,8 +5038,8 @@ static BC_STATUS zdc_parse_expr(void)
        if (i >= 0) {
                BcInst inst = dc_LEX_to_INST[i];
                if (inst != DC_INST_INVALID) {
-                       bc_parse_push(inst);
-                       RETURN_STATUS(zbc_lex_next());
+                       xc_parse_push(inst);
+                       RETURN_STATUS(zxc_lex_next());
                }
        }
        RETURN_STATUS(zdc_parse_token(p->lex));
@@ -5015,10 +5066,14 @@ static BC_STATUS zdc_parse_exprs_until_eof(void)
 // Execution engine
 //
 
+#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
+#define BC_PROG_NUM(r, n) \
+       ((r)->t != XC_RESULT_ARRAY && (r)->t != XC_RESULT_STR && !BC_PROG_STR(n))
+
 #define STACK_HAS_MORE_THAN(s, n)          ((s)->len > ((size_t)(n)))
 #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n)))
 
-static BcVec* bc_program_search(char *id, bool var)
+static BcVec* xc_program_search(char *id, bool var)
 {
        BcId e, *ptr;
        BcVec *v, *map;
@@ -5044,7 +5099,7 @@ static BcVec* bc_program_search(char *id, bool var)
 }
 
 // 'num' need not be initialized on entry
-static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
+static BC_STATUS zxc_program_num(BcResult *r, BcNum **num)
 {
        switch (r->t) {
        case XC_RESULT_STR:
@@ -5057,17 +5112,14 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
        case XC_RESULT_CONSTANT: {
                BcStatus s;
                char *str;
-               unsigned base_t;
                size_t len;
 
-               str = *bc_program_const(r->d.id.idx);
+               str = *xc_program_const(r->d.id.idx);
                len = strlen(str);
 
                bc_num_init(&r->d.n, len);
 
-               hex = hex && len == 1;
-               base_t = hex ? 16 : G.prog.ib_t;
-               s = zbc_num_parse(&r->d.n, str, base_t);
+               s = zxc_num_parse(&r->d.n, str, G.prog.ib_t);
                if (s) {
                        bc_num_free(&r->d.n);
                        RETURN_STATUS(s);
@@ -5080,15 +5132,19 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
        case XC_RESULT_ARRAY:
        case XC_RESULT_ARRAY_ELEM: {
                BcVec *v;
-
-               v = bc_program_search(r->d.id.name, r->t == XC_RESULT_VAR);
-
+               void *p;
+               v = xc_program_search(r->d.id.name, r->t == XC_RESULT_VAR);
+// dc variables are all stacks, so here we have this:
+               p = bc_vec_top(v);
+// TODO: eliminate these stacks for bc-only config?
                if (r->t == XC_RESULT_ARRAY_ELEM) {
-                       v = bc_vec_top(v);
-                       if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
+                       v = p;
+                       if (v->len <= r->d.id.idx)
+                               bc_array_expand(v, r->d.id.idx + 1);
                        *num = bc_vec_item(v, r->d.id.idx);
-               } else
-                       *num = bc_vec_top(v);
+               } else {
+                       *num = p;
+               }
                break;
        }
 #if ENABLE_BC
@@ -5108,13 +5164,12 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
-#define zbc_program_num(...) (zbc_program_num(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_num(...) (zxc_program_num(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_binOpPrep(BcResult **l, BcNum **ln,
+static BC_STATUS zxc_program_binOpPrep(BcResult **l, BcNum **ln,
                                      BcResult **r, BcNum **rn, bool assign)
 {
        BcStatus s;
-       bool hex;
        BcResultType lt, rt;
 
        if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
@@ -5123,19 +5178,18 @@ static BC_STATUS zbc_program_binOpPrep(BcResult **l, BcNum **ln,
        *r = bc_vec_item_rev(&G.prog.results, 0);
        *l = bc_vec_item_rev(&G.prog.results, 1);
 
-       lt = (*l)->t;
-       rt = (*r)->t;
-       hex = assign && (lt == XC_RESULT_IBASE || lt == XC_RESULT_OBASE);
-
-       s = zbc_program_num(*l, ln, false);
+       s = zxc_program_num(*l, ln);
        if (s) RETURN_STATUS(s);
-       s = zbc_program_num(*r, rn, hex);
+       s = zxc_program_num(*r, rn);
        if (s) RETURN_STATUS(s);
 
+       lt = (*l)->t;
+       rt = (*r)->t;
+
        // We run this again under these conditions in case any vector has been
        // reallocated out from under the BcNums or arrays we had.
        if (lt == rt && (lt == XC_RESULT_VAR || lt == XC_RESULT_ARRAY_ELEM)) {
-               s = zbc_program_num(*l, ln, false);
+               s = zxc_program_num(*l, ln);
                if (s) RETURN_STATUS(s);
        }
 
@@ -5146,9 +5200,9 @@ static BC_STATUS zbc_program_binOpPrep(BcResult **l, BcNum **ln,
 
        RETURN_STATUS(s);
 }
-#define zbc_program_binOpPrep(...) (zbc_program_binOpPrep(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_binOpPrep(...) (zxc_program_binOpPrep(__VA_ARGS__) COMMA_SUCCESS)
 
-static void bc_program_binOpRetire(BcResult *r)
+static void xc_program_binOpRetire(BcResult *r)
 {
        r->t = XC_RESULT_TEMP;
        bc_vec_pop(&G.prog.results);
@@ -5156,7 +5210,7 @@ static void bc_program_binOpRetire(BcResult *r)
 }
 
 // Note: *r and *n need not be initialized by caller
-static BC_STATUS zbc_program_prep(BcResult **r, BcNum **n)
+static BC_STATUS zxc_program_prep(BcResult **r, BcNum **n)
 {
        BcStatus s;
 
@@ -5164,7 +5218,7 @@ static BC_STATUS zbc_program_prep(BcResult **r, BcNum **n)
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
        *r = bc_vec_top(&G.prog.results);
 
-       s = zbc_program_num(*r, n, false);
+       s = zxc_program_num(*r, n);
        if (s) RETURN_STATUS(s);
 
        if (!BC_PROG_NUM((*r), (*n)))
@@ -5172,37 +5226,37 @@ static BC_STATUS zbc_program_prep(BcResult **r, BcNum **n)
 
        RETURN_STATUS(s);
 }
-#define zbc_program_prep(...) (zbc_program_prep(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_prep(...) (zxc_program_prep(__VA_ARGS__) COMMA_SUCCESS)
 
-static void bc_program_retire(BcResult *r, BcResultType t)
+static void xc_program_retire(BcResult *r, BcResultType t)
 {
        r->t = t;
        bc_result_pop_and_push(r);
 }
 
-static BC_STATUS zbc_program_op(char inst)
+static BC_STATUS zxc_program_op(char inst)
 {
        BcStatus s;
        BcResult *opd1, *opd2, res;
        BcNum *n1, *n2;
 
-       s = zbc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
+       s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
        if (s) RETURN_STATUS(s);
        bc_num_init_DEF_SIZE(&res.d.n);
 
        s = BC_STATUS_SUCCESS;
-       IF_ERROR_RETURN_POSSIBLE(s =) zbc_program_ops[inst - XC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
+       IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - XC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
        if (s) goto err;
-       bc_program_binOpRetire(&res);
+       xc_program_binOpRetire(&res);
 
        RETURN_STATUS(s);
  err:
        bc_num_free(&res.d.n);
        RETURN_STATUS(s);
 }
-#define zbc_program_op(...) (zbc_program_op(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_op(...) (zxc_program_op(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_read(void)
+static BC_STATUS zxc_program_read(void)
 {
        BcStatus s;
        BcParse sv_parse;
@@ -5211,16 +5265,16 @@ static BC_STATUS zbc_program_read(void)
        BcFunc *f;
 
        bc_char_vec_init(&buf);
-       bc_read_line(&buf, stdin);
+       xc_read_line(&buf, stdin);
 
-       f = bc_program_func(BC_PROG_READ);
+       f = xc_program_func(BC_PROG_READ);
        bc_vec_pop_all(&f->code);
 
        sv_parse = G.prs; // struct copy
-       bc_parse_create(BC_PROG_READ);
+       xc_parse_create(BC_PROG_READ);
        //G.err_line = G.prs.lex_line = 1; - not needed, error line info is not printed for read()
 
-       s = zbc_parse_text_init(buf.v);
+       s = zxc_parse_text_init(buf.v);
        if (s) goto exec_err;
        if (IS_BC) {
                IF_BC(s = zbc_parse_expr(0));
@@ -5228,28 +5282,26 @@ static BC_STATUS zbc_program_read(void)
                IF_DC(s = zdc_parse_exprs_until_eof());
        }
        if (s) goto exec_err;
-
        if (G.prs.lex != XC_LEX_NLINE && G.prs.lex != XC_LEX_EOF) {
                s = bc_error("bad read() expression");
                goto exec_err;
        }
+       xc_parse_push(XC_INST_RET);
 
        ip.func = BC_PROG_READ;
        ip.inst_idx = 0;
        IF_BC(ip.results_len_before_call = G.prog.results.len;)
-
-       bc_parse_push(XC_INST_RET);
        bc_vec_push(&G.prog.exestack, &ip);
 
  exec_err:
-       bc_parse_free();
+       xc_parse_free();
        G.prs = sv_parse; // struct copy
        bc_vec_free(&buf);
        RETURN_STATUS(s);
 }
-#define zbc_program_read(...) (zbc_program_read(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS)
 
-static size_t bc_program_index(char *code, size_t *bgn)
+static size_t xc_program_index(char *code, size_t *bgn)
 {
        unsigned char *bytes = (void*)(code + *bgn);
        unsigned amt;
@@ -5257,17 +5309,24 @@ static size_t bc_program_index(char *code, size_t *bgn)
        size_t res;
 
        amt = *bytes++;
+       if (amt < SMALL_INDEX_LIMIT) {
+               *bgn += 1;
+               return amt;
+       }
+       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;
 }
 
-static char *bc_program_name(char *code, size_t *bgn)
+static char *xc_program_name(char *code, size_t *bgn)
 {
        code += *bgn;
        *bgn += strlen(code) + 1;
@@ -5275,7 +5334,7 @@ static char *bc_program_name(char *code, size_t *bgn)
        return xstrdup(code);
 }
 
-static void bc_program_printString(const char *str)
+static void xc_program_printString(const char *str)
 {
 #if ENABLE_DC
        if (!str[0]) {
@@ -5397,7 +5456,7 @@ static void bc_num_printDecimal(BcNum *n)
 
 typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
 
-static BC_STATUS zbc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print)
+static BC_STATUS zxc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print)
 {
        BcStatus s;
        BcVec stack;
@@ -5463,9 +5522,9 @@ static BC_STATUS zbc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNum
        bc_vec_free(&stack);
        RETURN_STATUS(s);
 }
-#define zbc_num_printNum(...) (zbc_num_printNum(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_num_printNum(...) (zxc_num_printNum(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_num_printBase(BcNum *n)
+static BC_STATUS zxc_num_printBase(BcNum *n)
 {
        BcStatus s;
        size_t width;
@@ -5479,7 +5538,7 @@ static BC_STATUS zbc_num_printBase(BcNum *n)
 
        n->neg = false;
 
-       if (G.prog.ob_t <= BC_NUM_MAX_IBASE) {
+       if (G.prog.ob_t <= 16) {
                width = 1;
                print = bc_num_printHex;
        } else {
@@ -5494,14 +5553,14 @@ static BC_STATUS zbc_num_printBase(BcNum *n)
                print = bc_num_printDigits;
        }
 
-       s = zbc_num_printNum(n, G.prog.ob_t, width, print);
+       s = zxc_num_printNum(n, G.prog.ob_t, width, print);
        n->neg = neg;
 
        RETURN_STATUS(s);
 }
-#define zbc_num_printBase(...) (zbc_num_printBase(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_num_printBase(...) (zxc_num_printBase(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_num_print(BcNum *n, bool newline)
+static BC_STATUS zxc_num_print(BcNum *n, bool newline)
 {
        BcStatus s = BC_STATUS_SUCCESS;
 
@@ -5513,7 +5572,7 @@ static BC_STATUS zbc_num_print(BcNum *n, bool newline)
        } else if (G.prog.ob_t == 10)
                bc_num_printDecimal(n);
        else
-               s = zbc_num_printBase(n);
+               s = zxc_num_printBase(n);
 
        if (newline) {
                bb_putchar('\n');
@@ -5522,9 +5581,9 @@ static BC_STATUS zbc_num_print(BcNum *n, bool newline)
 
        RETURN_STATUS(s);
 }
-#define zbc_num_print(...) (zbc_num_print(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_num_print(...) (zxc_num_print(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_print(char inst, size_t idx)
+static BC_STATUS zxc_program_print(char inst, size_t idx)
 {
        BcStatus s;
        BcResult *r;
@@ -5535,11 +5594,11 @@ static BC_STATUS zbc_program_print(char inst, size_t idx)
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
 
        r = bc_vec_item_rev(&G.prog.results, idx);
-       s = zbc_program_num(r, &num, false);
+       s = zxc_program_num(r, &num);
        if (s) RETURN_STATUS(s);
 
        if (BC_PROG_NUM(r, num)) {
-               s = zbc_num_print(num, !pop);
+               s = zxc_num_print(num, !pop);
 #if ENABLE_BC
                if (!s && IS_BC) bc_num_copy(&G.prog.last, num);
 #endif
@@ -5547,7 +5606,7 @@ static BC_STATUS zbc_program_print(char inst, size_t idx)
                char *str;
 
                idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
-               str = *bc_program_str(idx);
+               str = *xc_program_str(idx);
 
                if (inst == XC_INST_PRINT_STR) {
                        for (;;) {
@@ -5558,7 +5617,7 @@ static BC_STATUS zbc_program_print(char inst, size_t idx)
                                if (c == '\n') G.prog.nchars = 0;
                        }
                } else {
-                       bc_program_printString(str);
+                       xc_program_printString(str);
                        if (inst == XC_INST_PRINT) bb_putchar('\n');
                }
        }
@@ -5567,35 +5626,35 @@ static BC_STATUS zbc_program_print(char inst, size_t idx)
 
        RETURN_STATUS(s);
 }
-#define zbc_program_print(...) (zbc_program_print(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_print(...) (zxc_program_print(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_negate(void)
+static BC_STATUS zxc_program_negate(void)
 {
        BcStatus s;
        BcResult res, *ptr;
        BcNum *num;
 
-       s = zbc_program_prep(&ptr, &num);
+       s = zxc_program_prep(&ptr, &num);
        if (s) RETURN_STATUS(s);
 
        bc_num_init(&res.d.n, num->len);
        bc_num_copy(&res.d.n, num);
        if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
 
-       bc_program_retire(&res, XC_RESULT_TEMP);
+       xc_program_retire(&res, XC_RESULT_TEMP);
 
        RETURN_STATUS(s);
 }
-#define zbc_program_negate(...) (zbc_program_negate(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_negate(...) (zxc_program_negate(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_logical(char inst)
+static BC_STATUS zxc_program_logical(char inst)
 {
        BcStatus s;
        BcResult *opd1, *opd2, res;
        BcNum *n1, *n2;
        ssize_t cond;
 
-       s = zbc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
+       s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
        if (s) RETURN_STATUS(s);
 
        bc_num_init_DEF_SIZE(&res.d.n);
@@ -5631,11 +5690,11 @@ static BC_STATUS zbc_program_logical(char inst)
        if (cond) bc_num_one(&res.d.n);
        //else bc_num_zero(&res.d.n); - already is
 
-       bc_program_binOpRetire(&res);
+       xc_program_binOpRetire(&res);
 
        RETURN_STATUS(s);
 }
-#define zbc_program_logical(...) (zbc_program_logical(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_logical(...) (zxc_program_logical(__VA_ARGS__) COMMA_SUCCESS)
 
 #if ENABLE_DC
 static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push)
@@ -5662,7 +5721,7 @@ static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push)
 #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS)
 #endif // ENABLE_DC
 
-static BC_STATUS zbc_program_copyToVar(char *name, bool var)
+static BC_STATUS zxc_program_copyToVar(char *name, bool var)
 {
        BcStatus s;
        BcResult *ptr, r;
@@ -5675,7 +5734,7 @@ static BC_STATUS zbc_program_copyToVar(char *name, bool var)
        ptr = bc_vec_top(&G.prog.results);
        if ((ptr->t == XC_RESULT_ARRAY) != !var)
                RETURN_STATUS(bc_error_variable_is_wrong_type());
-       v = bc_program_search(name, var);
+       v = xc_program_search(name, var);
 
 #if ENABLE_DC
        if (ptr->t == XC_RESULT_STR && !var)
@@ -5684,11 +5743,11 @@ static BC_STATUS zbc_program_copyToVar(char *name, bool var)
                RETURN_STATUS(zdc_program_assignStr(ptr, v, true));
 #endif
 
-       s = zbc_program_num(ptr, &n, false);
+       s = zxc_program_num(ptr, &n);
        if (s) RETURN_STATUS(s);
 
        // Do this once more to make sure that pointers were not invalidated.
-       v = bc_program_search(name, var);
+       v = xc_program_search(name, var);
 
        if (var) {
                bc_num_init_DEF_SIZE(&r.d.n);
@@ -5703,9 +5762,9 @@ static BC_STATUS zbc_program_copyToVar(char *name, bool var)
 
        RETURN_STATUS(s);
 }
-#define zbc_program_copyToVar(...) (zbc_program_copyToVar(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_copyToVar(...) (zxc_program_copyToVar(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_program_assign(char inst)
+static BC_STATUS zxc_program_assign(char inst)
 {
        BcStatus s;
        BcResult *left, *right, res;
@@ -5713,7 +5772,7 @@ static BC_STATUS zbc_program_assign(char inst)
        bool assign = (inst == XC_INST_ASSIGN);
        bool ib, sc;
 
-       s = zbc_program_binOpPrep(&left, &l, &right, &r, assign);
+       s = zxc_program_binOpPrep(&left, &l, &right, &r, assign);
        if (s) RETURN_STATUS(s);
 
        ib = left->t == XC_RESULT_IBASE;
@@ -5725,7 +5784,7 @@ static BC_STATUS zbc_program_assign(char inst)
 
                if (left->t != XC_RESULT_VAR)
                        RETURN_STATUS(bc_error_variable_is_wrong_type());
-               v = bc_program_search(left->d.id.name, true);
+               v = xc_program_search(left->d.id.name, true);
 
                RETURN_STATUS(zdc_program_assignStr(right, v, false));
        }
@@ -5745,7 +5804,7 @@ static BC_STATUS zbc_program_assign(char inst)
                bc_num_copy(l, r);
        else {
                s = BC_STATUS_SUCCESS;
-               IF_ERROR_RETURN_POSSIBLE(s =) zbc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
+               IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
        }
        if (s) RETURN_STATUS(s);
 #else
@@ -5784,29 +5843,29 @@ static BC_STATUS zbc_program_assign(char inst)
 
        bc_num_init(&res.d.n, l->len);
        bc_num_copy(&res.d.n, l);
-       bc_program_binOpRetire(&res);
+       xc_program_binOpRetire(&res);
 
        RETURN_STATUS(s);
 }
-#define zbc_program_assign(...) (zbc_program_assign(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_assign(...) (zxc_program_assign(__VA_ARGS__) COMMA_SUCCESS)
 
 #if !ENABLE_DC
-#define bc_program_pushVar(code, bgn, pop, copy) \
-       bc_program_pushVar(code, bgn)
+#define xc_program_pushVar(code, bgn, pop, copy) \
+       xc_program_pushVar(code, bgn)
 // for bc, 'pop' and 'copy' are always false
 #endif
-static BC_STATUS bc_program_pushVar(char *code, size_t *bgn,
+static BC_STATUS xc_program_pushVar(char *code, size_t *bgn,
                                    bool pop, bool copy)
 {
        BcResult r;
-       char *name = bc_program_name(code, bgn);
+       char *name = xc_program_name(code, bgn);
 
        r.t = XC_RESULT_VAR;
        r.d.id.name = name;
 
 #if ENABLE_DC
        if (pop || copy) {
-               BcVec *v = bc_program_search(name, true);
+               BcVec *v = xc_program_search(name, true);
                BcNum *num = bc_vec_top(v);
 
                free(name);
@@ -5831,7 +5890,7 @@ static BC_STATUS bc_program_pushVar(char *code, size_t *bgn,
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
-#define zbc_program_pushVar(...) (bc_program_pushVar(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_pushVar(...) (xc_program_pushVar(__VA_ARGS__) COMMA_SUCCESS)
 
 static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
 {
@@ -5839,7 +5898,7 @@ static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
        BcResult r;
        BcNum *num;
 
-       r.d.id.name = bc_program_name(code, bgn);
+       r.d.id.name = xc_program_name(code, bgn);
 
        if (inst == XC_INST_ARRAY) {
                r.t = XC_RESULT_ARRAY;
@@ -5848,7 +5907,7 @@ static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
                BcResult *operand;
                unsigned long temp;
 
-               s = zbc_program_prep(&operand, &num);
+               s = zxc_program_prep(&operand, &num);
                if (s) goto err;
                s = zbc_num_ulong(num, &temp);
                if (s) goto err;
@@ -5859,7 +5918,7 @@ static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
                }
 
                r.d.id.idx = (size_t) temp;
-               bc_program_retire(&r, XC_RESULT_ARRAY_ELEM);
+               xc_program_retire(&r, XC_RESULT_ARRAY_ELEM);
        }
  err:
        if (s) free(r.d.id.name);
@@ -5875,7 +5934,7 @@ static BC_STATUS zbc_program_incdec(char inst)
        BcNum *num;
        char inst2 = inst;
 
-       s = zbc_program_prep(&ptr, &num);
+       s = zxc_program_prep(&ptr, &num);
        if (s) RETURN_STATUS(s);
 
        if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
@@ -5890,7 +5949,7 @@ static BC_STATUS zbc_program_incdec(char inst)
                        : BC_INST_ASSIGN_MINUS;
 
        bc_vec_push(&G.prog.results, &res);
-       s = zbc_program_assign(inst);
+       s = zxc_program_assign(inst);
        if (s) RETURN_STATUS(s);
 
        if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
@@ -5909,10 +5968,10 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx)
        BcId *a;
        BcResult *arg;
 
-       nparams = bc_program_index(code, idx);
+       nparams = xc_program_index(code, idx);
        ip.inst_idx = 0;
-       ip.func = bc_program_index(code, idx);
-       func = bc_program_func(ip.func);
+       ip.func = xc_program_index(code, idx);
+       func = xc_program_func(ip.func);
 
        if (func->code.len == 0) {
                RETURN_STATUS(bc_error("undefined function"));
@@ -5931,7 +5990,7 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx)
                if ((!a->idx) != (arg->t == XC_RESULT_ARRAY) || arg->t == XC_RESULT_STR)
                        RETURN_STATUS(bc_error_variable_is_wrong_type());
 
-               s = zbc_program_copyToVar(a->name, a->idx);
+               s = zxc_program_copyToVar(a->name, a->idx);
                if (s) RETURN_STATUS(s);
        }
 
@@ -5939,7 +5998,7 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx)
        for (; i < func->autos.len; i++, a++) {
                BcVec *v;
 
-               v = bc_program_search(a->name, a->idx);
+               v = xc_program_search(a->name, a->idx);
                if (a->idx) {
                        BcNum n2;
                        bc_num_init_DEF_SIZE(&n2);
@@ -5968,7 +6027,7 @@ static BC_STATUS zbc_program_return(char inst)
        if (!STACK_HAS_EQUAL_OR_MORE_THAN(&G.prog.results, ip->results_len_before_call + (inst == XC_INST_RET)))
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
 
-       f = bc_program_func(ip->func);
+       f = xc_program_func(ip->func);
        res.t = XC_RESULT_TEMP;
 
        if (inst == XC_INST_RET) {
@@ -5976,7 +6035,7 @@ static BC_STATUS zbc_program_return(char inst)
                BcNum *num;
                BcResult *operand = bc_vec_top(&G.prog.results);
 
-               s = zbc_program_num(operand, &num, false);
+               s = zxc_program_num(operand, &num);
                if (s) RETURN_STATUS(s);
                bc_num_init(&res.d.n, num->len);
                bc_num_copy(&res.d.n, num);
@@ -5989,7 +6048,7 @@ static BC_STATUS zbc_program_return(char inst)
        a = (void*)f->autos.v;
        for (i = 0; i < f->autos.len; i++, a++) {
                BcVec *v;
-               v = bc_program_search(a->name, a->idx);
+               v = xc_program_search(a->name, a->idx);
                bc_vec_pop(v);
        }
 
@@ -6002,12 +6061,12 @@ static BC_STATUS zbc_program_return(char inst)
 #define zbc_program_return(...) (zbc_program_return(__VA_ARGS__) COMMA_SUCCESS)
 #endif // ENABLE_BC
 
-static unsigned long bc_program_scale(BcNum *n)
+static unsigned long xc_program_scale(BcNum *n)
 {
        return (unsigned long) n->rdx;
 }
 
-static unsigned long bc_program_len(BcNum *n)
+static unsigned long xc_program_len(BcNum *n)
 {
        size_t len = n->len;
 
@@ -6020,7 +6079,7 @@ static unsigned long bc_program_len(BcNum *n)
        return len;
 }
 
-static BC_STATUS zbc_program_builtin(char inst)
+static BC_STATUS zxc_program_builtin(char inst)
 {
        BcStatus s;
        BcResult *opnd;
@@ -6032,7 +6091,7 @@ static BC_STATUS zbc_program_builtin(char inst)
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
        opnd = bc_vec_top(&G.prog.results);
 
-       s = zbc_program_num(opnd, &num, false);
+       s = zxc_program_num(opnd, &num);
        if (s) RETURN_STATUS(s);
 
 #if ENABLE_DC
@@ -6054,19 +6113,19 @@ static BC_STATUS zbc_program_builtin(char inst)
                char **str;
                size_t idx = opnd->t == XC_RESULT_STR ? opnd->d.id.idx : num->rdx;
 
-               str = bc_program_str(idx);
+               str = xc_program_str(idx);
                bc_num_ulong2num(&res.d.n, strlen(*str));
        }
 #endif
        else {
-               bc_num_ulong2num(&res.d.n, len ? bc_program_len(num) : bc_program_scale(num));
+               bc_num_ulong2num(&res.d.n, len ? xc_program_len(num) : xc_program_scale(num));
        }
 
-       bc_program_retire(&res, XC_RESULT_TEMP);
+       xc_program_retire(&res, XC_RESULT_TEMP);
 
        RETURN_STATUS(s);
 }
-#define zbc_program_builtin(...) (zbc_program_builtin(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_builtin(...) (zxc_program_builtin(__VA_ARGS__) COMMA_SUCCESS)
 
 #if ENABLE_DC
 static BC_STATUS zdc_program_divmod(void)
@@ -6075,7 +6134,7 @@ static BC_STATUS zdc_program_divmod(void)
        BcResult *opd1, *opd2, res, res2;
        BcNum *n1, *n2;
 
-       s = zbc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
+       s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
        if (s) RETURN_STATUS(s);
 
        bc_num_init_DEF_SIZE(&res.d.n);
@@ -6084,7 +6143,7 @@ static BC_STATUS zdc_program_divmod(void)
        s = zbc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
        if (s) goto err;
 
-       bc_program_binOpRetire(&res2);
+       xc_program_binOpRetire(&res2);
        res.t = XC_RESULT_TEMP;
        bc_vec_push(&G.prog.results, &res);
 
@@ -6104,11 +6163,11 @@ static BC_STATUS zdc_program_modexp(void)
 
        if (!STACK_HAS_MORE_THAN(&G.prog.results, 2))
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
-       s = zbc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
+       s = zxc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
        if (s) RETURN_STATUS(s);
 
        r1 = bc_vec_item_rev(&G.prog.results, 2);
-       s = zbc_program_num(r1, &n1, false);
+       s = zxc_program_num(r1, &n1);
        if (s) RETURN_STATUS(s);
        if (!BC_PROG_NUM(r1, n1))
                RETURN_STATUS(bc_error_variable_is_wrong_type());
@@ -6116,11 +6175,11 @@ static BC_STATUS zdc_program_modexp(void)
        // Make sure that the values have their pointers updated, if necessary.
        if (r1->t == XC_RESULT_VAR || r1->t == XC_RESULT_ARRAY_ELEM) {
                if (r1->t == r2->t) {
-                       s = zbc_program_num(r2, &n2, false);
+                       s = zxc_program_num(r2, &n2);
                        if (s) RETURN_STATUS(s);
                }
                if (r1->t == r3->t) {
-                       s = zbc_program_num(r3, &n3, false);
+                       s = zxc_program_num(r3, &n3);
                        if (s) RETURN_STATUS(s);
                }
        }
@@ -6130,7 +6189,7 @@ static BC_STATUS zdc_program_modexp(void)
        if (s) goto err;
 
        bc_vec_pop(&G.prog.results);
-       bc_program_binOpRetire(&res);
+       xc_program_binOpRetire(&res);
 
        RETURN_STATUS(s);
  err:
@@ -6163,9 +6222,9 @@ static BC_STATUS zdc_program_asciify(void)
 
        if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
-       r = bc_vec_top(&G.prog.results);
 
-       s = zbc_program_num(r, &num, false);
+       r = bc_vec_top(&G.prog.results);
+       s = zxc_program_num(r, &num);
        if (s) RETURN_STATUS(s);
 
        if (BC_PROG_NUM(r, num)) {
@@ -6180,8 +6239,8 @@ static BC_STATUS zdc_program_asciify(void)
                strmb.cap = ARRAY_SIZE(strmb_digs);
                strmb.num = strmb_digs;
                bc_num_ulong2num(&strmb, 0x100);
-               s = zbc_num_mod(&n, &strmb, &n, 0);
 
+               s = zbc_num_mod(&n, &strmb, &n, 0);
                if (s) goto num_err;
                s = zbc_num_ulong(&n, &val);
                if (s) goto num_err;
@@ -6192,7 +6251,7 @@ static BC_STATUS zdc_program_asciify(void)
        } else {
                char *sp;
                idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
-               sp = *bc_program_str(idx);
+               sp = *xc_program_str(idx);
                c = sp[0];
        }
 
@@ -6229,15 +6288,15 @@ static BC_STATUS zdc_program_printStream(void)
                RETURN_STATUS(bc_error_stack_has_too_few_elements());
        r = bc_vec_top(&G.prog.results);
 
-       s = zbc_program_num(r, &n, false);
+       s = zxc_program_num(r, &n);
        if (s) RETURN_STATUS(s);
 
        if (BC_PROG_NUM(r, n)) {
-               s = zbc_num_printNum(n, 0x100, 1, dc_num_printChar);
+               s = zxc_num_printNum(n, 0x100, 1, dc_num_printChar);
        } else {
                char *str;
                idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : n->rdx;
-               str = *bc_program_str(idx);
+               str = *xc_program_str(idx);
                fputs(str, stdout);
        }
 
@@ -6252,7 +6311,7 @@ static BC_STATUS zdc_program_nquit(void)
        BcNum *num;
        unsigned long val;
 
-       s = zbc_program_prep(&opnd, &num);
+       s = zxc_program_prep(&opnd, &num);
        if (s) RETURN_STATUS(s);
        s = zbc_num_ulong(num, &val);
        if (s) RETURN_STATUS(s);
@@ -6288,13 +6347,13 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
                BcNum *n = n; // for compiler
                bool exec;
                char *name;
-               char *then_name = bc_program_name(code, bgn);
+               char *then_name = xc_program_name(code, bgn);
                char *else_name = NULL;
 
                if (code[*bgn] == '\0')
                        (*bgn) += 1;
                else
-                       else_name = bc_program_name(code, bgn);
+                       else_name = xc_program_name(code, bgn);
 
                exec = r->d.n.len != 0;
                name = then_name;
@@ -6305,7 +6364,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
 
                if (exec) {
                        BcVec *v;
-                       v = bc_program_search(name, true);
+                       v = xc_program_search(name, true);
                        n = bc_vec_top(v);
                }
 
@@ -6324,7 +6383,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
                        sidx = r->d.id.idx;
                } else if (r->t == XC_RESULT_VAR) {
                        BcNum *n;
-                       s = zbc_program_num(r, &n, false);
+                       s = zxc_program_num(r, &n);
                        if (s || !BC_PROG_STR(n)) goto exit;
                        sidx = n->rdx;
                } else
@@ -6333,24 +6392,24 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
 
        fidx = sidx + BC_PROG_REQ_FUNCS;
 
-       f = bc_program_func(fidx);
+       f = xc_program_func(fidx);
 
        if (f->code.len == 0) {
                BcParse sv_parse;
                char *str;
 
                sv_parse = G.prs; // struct copy
-               bc_parse_create(fidx);
-               str = *bc_program_str(sidx);
-               s = zbc_parse_text_init(str);
+               xc_parse_create(fidx);
+               str = *xc_program_str(sidx);
+               s = zxc_parse_text_init(str);
                if (s) goto err;
 
                s = zdc_parse_exprs_until_eof();
                if (s) goto err;
-               bc_parse_push(DC_INST_POP_EXEC);
+               xc_parse_push(DC_INST_POP_EXEC);
                if (G.prs.lex != XC_LEX_EOF)
                        s = bc_error_bad_expression();
-               bc_parse_free();
+               xc_parse_free();
                G.prs = sv_parse; // struct copy
                if (s) {
  err:
@@ -6373,7 +6432,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
 #define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS)
 #endif // ENABLE_DC
 
-static void bc_program_pushGlobal(char inst)
+static void xc_program_pushGlobal(char inst)
 {
        BcResult res;
        unsigned long val;
@@ -6391,11 +6450,11 @@ static void bc_program_pushGlobal(char inst)
        bc_vec_push(&G.prog.results, &res);
 }
 
-static BC_STATUS zbc_program_exec(void)
+static BC_STATUS zxc_program_exec(void)
 {
        BcResult r, *ptr;
        BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
-       BcFunc *func = bc_program_func(ip->func);
+       BcFunc *func = xc_program_func(ip->func);
        char *code = func->code.v;
 
        dbg_exec("func:%zd bytes:%zd ip:%zd results.len:%d",
@@ -6411,18 +6470,18 @@ static BC_STATUS zbc_program_exec(void)
                        BcNum *num;
                        bool zero;
                        dbg_exec("BC_INST_JUMP_ZERO:");
-                       s = zbc_program_prep(&ptr, &num);
+                       s = zxc_program_prep(&ptr, &num);
                        if (s) RETURN_STATUS(s);
                        zero = (bc_num_cmp(num, &G.prog.zero) == 0);
                        bc_vec_pop(&G.prog.results);
                        if (!zero) {
-                               bc_program_index(code, &ip->inst_idx);
+                               xc_program_index(code, &ip->inst_idx);
                                break;
                        }
                        // else: fall through
                }
                case BC_INST_JUMP: {
-                       size_t idx = bc_program_index(code, &ip->inst_idx);
+                       size_t idx = xc_program_index(code, &ip->inst_idx);
                        size_t *addr = bc_vec_item(&func->labels, idx);
                        dbg_exec("BC_INST_JUMP: to %ld", (long)*addr);
                        ip->inst_idx = *addr;
@@ -6458,15 +6517,15 @@ static BC_STATUS zbc_program_exec(void)
                case XC_INST_REL_LT:
                case XC_INST_REL_GT:
                        dbg_exec("BC_INST_BOOL:");
-                       s = zbc_program_logical(inst);
+                       s = zxc_program_logical(inst);
                        break;
                case XC_INST_READ:
                        dbg_exec("XC_INST_READ:");
-                       s = zbc_program_read();
+                       s = zxc_program_read();
                        goto read_updated_ip;
                case XC_INST_VAR:
                        dbg_exec("XC_INST_VAR:");
-                       s = zbc_program_pushVar(code, &ip->inst_idx, false, false);
+                       s = zxc_program_pushVar(code, &ip->inst_idx, false, false);
                        break;
                case XC_INST_ARRAY_ELEM:
                case XC_INST_ARRAY:
@@ -6484,18 +6543,18 @@ static BC_STATUS zbc_program_exec(void)
                case XC_INST_OBASE:
                case XC_INST_SCALE:
                        dbg_exec("XC_INST_internalvar(%d):", inst - XC_INST_IBASE);
-                       bc_program_pushGlobal(inst);
+                       xc_program_pushGlobal(inst);
                        break;
                case XC_INST_SCALE_FUNC:
                case XC_INST_LENGTH:
                case XC_INST_SQRT:
                        dbg_exec("BC_INST_builtin:");
-                       s = zbc_program_builtin(inst);
+                       s = zxc_program_builtin(inst);
                        break;
                case XC_INST_NUM:
                        dbg_exec("XC_INST_NUM:");
                        r.t = XC_RESULT_CONSTANT;
-                       r.d.id.idx = bc_program_index(code, &ip->inst_idx);
+                       r.d.id.idx = xc_program_index(code, &ip->inst_idx);
                        bc_vec_push(&G.prog.results, &r);
                        break;
                case XC_INST_POP:
@@ -6509,12 +6568,12 @@ static BC_STATUS zbc_program_exec(void)
                case XC_INST_PRINT_POP:
                case XC_INST_PRINT_STR:
                        dbg_exec("XC_INST_PRINTxyz:");
-                       s = zbc_program_print(inst, 0);
+                       s = zxc_program_print(inst, 0);
                        break;
                case XC_INST_STR:
                        dbg_exec("XC_INST_STR:");
                        r.t = XC_RESULT_STR;
-                       r.d.id.idx = bc_program_index(code, &ip->inst_idx);
+                       r.d.id.idx = xc_program_index(code, &ip->inst_idx);
                        bc_vec_push(&G.prog.results, &r);
                        break;
                case XC_INST_POWER:
@@ -6524,23 +6583,23 @@ static BC_STATUS zbc_program_exec(void)
                case XC_INST_PLUS:
                case XC_INST_MINUS:
                        dbg_exec("BC_INST_binaryop:");
-                       s = zbc_program_op(inst);
+                       s = zxc_program_op(inst);
                        break;
                case XC_INST_BOOL_NOT: {
                        BcNum *num;
                        dbg_exec("XC_INST_BOOL_NOT:");
-                       s = zbc_program_prep(&ptr, &num);
+                       s = zxc_program_prep(&ptr, &num);
                        if (s) RETURN_STATUS(s);
                        bc_num_init_DEF_SIZE(&r.d.n);
                        if (bc_num_cmp(num, &G.prog.zero) == 0)
                                bc_num_one(&r.d.n);
                        //else bc_num_zero(&r.d.n); - already is
-                       bc_program_retire(&r, XC_RESULT_TEMP);
+                       xc_program_retire(&r, XC_RESULT_TEMP);
                        break;
                }
                case XC_INST_NEG:
                        dbg_exec("XC_INST_NEG:");
-                       s = zbc_program_negate();
+                       s = zxc_program_negate();
                        break;
 #if ENABLE_BC
                case BC_INST_ASSIGN_POWER:
@@ -6552,7 +6611,7 @@ static BC_STATUS zbc_program_exec(void)
 #endif
                case XC_INST_ASSIGN:
                        dbg_exec("BC_INST_ASSIGNxyz:");
-                       s = zbc_program_assign(inst);
+                       s = zxc_program_assign(inst);
                        break;
 #if ENABLE_DC
                case DC_INST_POP_EXEC:
@@ -6576,7 +6635,7 @@ static BC_STATUS zbc_program_exec(void)
                        size_t idx;
                        dbg_exec("DC_INST_PRINT_STACK:");
                        for (idx = 0; idx < G.prog.results.len; ++idx) {
-                               s = zbc_program_print(XC_INST_PRINT, idx);
+                               s = zxc_program_print(XC_INST_PRINT, idx);
                                if (s) break;
                        }
                        break;
@@ -6620,12 +6679,12 @@ static BC_STATUS zbc_program_exec(void)
                case DC_INST_LOAD:
                case DC_INST_PUSH_VAR: {
                        bool copy = inst == DC_INST_LOAD;
-                       s = zbc_program_pushVar(code, &ip->inst_idx, true, copy);
+                       s = zxc_program_pushVar(code, &ip->inst_idx, true, copy);
                        break;
                }
                case DC_INST_PUSH_TO_VAR: {
-                       char *name = bc_program_name(code, &ip->inst_idx);
-                       s = zbc_program_copyToVar(name, true);
+                       char *name = xc_program_name(code, &ip->inst_idx);
+                       s = zxc_program_copyToVar(name, true);
                        free(name);
                        break;
                }
@@ -6643,13 +6702,13 @@ static BC_STATUS zbc_program_exec(void)
  read_updated_ip:
                        // Instruction stack has changed, read new pointers
                        ip = bc_vec_top(&G.prog.exestack);
-                       func = bc_program_func(ip->func);
+                       func = xc_program_func(ip->func);
                        code = func->code.v;
                        dbg_exec("func:%zd bytes:%zd ip:%zd", ip->func, func->code.len, ip->inst_idx);
                }
 
                if (s || G_interrupt) {
-                       bc_program_reset();
+                       xc_program_reset();
                        RETURN_STATUS(s);
                }
 
@@ -6658,9 +6717,9 @@ static BC_STATUS zbc_program_exec(void)
 
        RETURN_STATUS(BC_STATUS_SUCCESS);
 }
-#define zbc_program_exec(...) (zbc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
 
-static unsigned bc_vm_envLen(const char *var)
+static unsigned xc_vm_envLen(const char *var)
 {
        char *lenv;
        unsigned len;
@@ -6676,12 +6735,12 @@ static unsigned bc_vm_envLen(const char *var)
        return len;
 }
 
-static BC_STATUS zbc_vm_process(const char *text)
+static BC_STATUS zxc_vm_process(const char *text)
 {
        BcStatus s;
 
        dbg_lex_enter("%s:%d entered", __func__, __LINE__);
-       s = zbc_parse_text_init(text); // does the first zbc_lex_next()
+       s = zxc_parse_text_init(text); // does the first zxc_lex_next()
        if (s) RETURN_STATUS(s);
 
  IF_BC(check_eof:)
@@ -6695,7 +6754,7 @@ static BC_STATUS zbc_vm_process(const char *text)
                        if (G.prs.lex == BC_LEX_SCOLON
                         || G.prs.lex == XC_LEX_NLINE
                        ) {
-                               s = zbc_lex_next();
+                               s = zxc_lex_next();
                                if (s) goto err;
                                goto check_eof;
                        }
@@ -6719,14 +6778,14 @@ static BC_STATUS zbc_vm_process(const char *text)
                                goto err;
                        }
                        // The above logic is fragile. Check these examples:
-                       // - interative read() still works
+                       // - interactive read() still works
 #endif
                } else {
 #if ENABLE_DC
                        // Most of dc parsing assumes all whitespace,
                        // including '\n', is eaten.
                        while (G.prs.lex == XC_LEX_NLINE) {
-                               s = zbc_lex_next();
+                               s = zxc_lex_next();
                                if (s) goto err;
                                if (G.prs.lex == XC_LEX_EOF)
                                        goto done;
@@ -6736,14 +6795,14 @@ static BC_STATUS zbc_vm_process(const char *text)
                }
                if (s || G_interrupt) {
  err:
-                       bc_parse_reset(); // includes bc_program_reset()
+                       xc_parse_reset(); // includes xc_program_reset()
                        RETURN_STATUS(BC_STATUS_FAILURE);
                }
 
                dbg_lex("%s:%d executing...", __func__, __LINE__);
-               s = zbc_program_exec();
+               s = zxc_program_exec();
                if (s) {
-                       bc_program_reset();
+                       xc_program_reset();
                        break;
                }
 
@@ -6754,7 +6813,7 @@ static BC_STATUS zbc_vm_process(const char *text)
                if (ip->func != BC_PROG_MAIN)
                        bb_error_msg_and_die("BUG:not MAIN");
 #endif
-               f = bc_program_func_BC_PROG_MAIN();
+               f = xc_program_func_BC_PROG_MAIN();
                // bc discards strings, constants and code after each
                // top-level statement in the "main program".
                // This prevents "yes 1 | bc" from growing its memory
@@ -6797,9 +6856,9 @@ static BC_STATUS zbc_vm_process(const char *text)
        dbg_lex_done("%s:%d done", __func__, __LINE__);
        RETURN_STATUS(s);
 }
-#define zbc_vm_process(...) (zbc_vm_process(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_vm_process(...) (zxc_vm_process(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_vm_execute_FILE(FILE *fp, const char *filename)
+static BC_STATUS zxc_vm_execute_FILE(FILE *fp, const char *filename)
 {
        // So far bc/dc have no way to include a file from another file,
        // therefore we know G.prs.lex_filename == NULL on entry
@@ -6811,7 +6870,7 @@ static BC_STATUS zbc_vm_execute_FILE(FILE *fp, const char *filename)
        G.err_line = G.prs.lex_line = 1;
 
        do {
-               s = zbc_vm_process("");
+               s = zxc_vm_process("");
                // We do not stop looping on errors here if reading stdin.
                // Example: start interactive bc and enter "return".
                // It should say "'return' not in a function"
@@ -6820,20 +6879,20 @@ static BC_STATUS zbc_vm_execute_FILE(FILE *fp, const char *filename)
        G.prs.lex_filename = NULL;
        RETURN_STATUS(s);
 }
-#define zbc_vm_execute_FILE(...) (zbc_vm_execute_FILE(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_vm_execute_FILE(...) (zxc_vm_execute_FILE(__VA_ARGS__) COMMA_SUCCESS)
 
-static BC_STATUS zbc_vm_file(const char *file)
+static BC_STATUS zxc_vm_file(const char *file)
 {
        BcStatus s;
        FILE *fp;
 
        fp = xfopen_for_read(file);
-       s = zbc_vm_execute_FILE(fp, file);
+       s = zxc_vm_execute_FILE(fp, file);
        fclose(fp);
 
        RETURN_STATUS(s);
 }
-#define zbc_vm_file(...) (zbc_vm_file(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_vm_file(...) (zxc_vm_file(__VA_ARGS__) COMMA_SUCCESS)
 
 #if ENABLE_BC
 static void bc_vm_info(void)
@@ -7079,7 +7138,7 @@ static const char bc_lib[] ALIGN1 = {
 };
 #endif // ENABLE_BC
 
-static BC_STATUS zbc_vm_exec(void)
+static BC_STATUS zxc_vm_exec(void)
 {
        char **fname;
        BcStatus s;
@@ -7090,7 +7149,7 @@ static BC_STATUS zbc_vm_exec(void)
                // We know that internal library is not buggy,
                // thus error checking is normally disabled.
 # define DEBUG_LIB 0
-               s = zbc_vm_process(bc_lib);
+               s = zxc_vm_process(bc_lib);
                if (DEBUG_LIB && s) RETURN_STATUS(s);
        }
 #endif
@@ -7098,7 +7157,7 @@ static BC_STATUS zbc_vm_exec(void)
        s = BC_STATUS_SUCCESS;
        fname = (void*)G.files.v;
        for (i = 0; i < G.files.len; i++) {
-               s = zbc_vm_file(*fname++);
+               s = zxc_vm_file(*fname++);
                if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin && s) {
                        // Debug config, non-interactive mode:
                        // return all the way back to main.
@@ -7109,14 +7168,14 @@ static BC_STATUS zbc_vm_exec(void)
        }
 
        if (IS_BC || (option_mask32 & BC_FLAG_I))
-               s = zbc_vm_execute_FILE(stdin, /*filename:*/ NULL);
+               s = zxc_vm_execute_FILE(stdin, /*filename:*/ NULL);
 
        RETURN_STATUS(s);
 }
-#define zbc_vm_exec(...) (zbc_vm_exec(__VA_ARGS__) COMMA_SUCCESS)
+#define zxc_vm_exec(...) (zxc_vm_exec(__VA_ARGS__) COMMA_SUCCESS)
 
 #if ENABLE_FEATURE_CLEAN_UP
-static void bc_program_free(void)
+static void xc_program_free(void)
 {
        bc_vec_free(&G.prog.fns);
        IF_BC(bc_vec_free(&G.prog.fn_map);)
@@ -7129,21 +7188,13 @@ static void bc_program_free(void)
        bc_vec_free(&G.prog.results);
        bc_vec_free(&G.prog.exestack);
        IF_BC(bc_num_free(&G.prog.last);)
-       IF_BC(bc_num_free(&G.prog.zero);)
+       //IF_BC(bc_num_free(&G.prog.zero);)
        IF_BC(bc_num_free(&G.prog.one);)
        bc_vec_free(&G.input_buffer);
 }
-
-static void bc_vm_free(void)
-{
-       bc_vec_free(&G.files);
-       bc_program_free();
-       bc_parse_free();
-       free(G.env_args);
-}
 #endif
 
-static void bc_program_init(void)
+static void xc_program_init(void)
 {
        BcInstPtr ip;
 
@@ -7157,7 +7208,7 @@ static void bc_program_init(void)
        IF_BC(bc_num_init_DEF_SIZE(&G.prog.last);)
        //IF_BC(bc_num_zero(&G.prog.last);) - already is
 
-       bc_num_init_DEF_SIZE(&G.prog.zero);
+       //bc_num_init_DEF_SIZE(&G.prog.zero); - not needed
        //bc_num_zero(&G.prog.zero); - already is
 
        IF_BC(bc_num_init_DEF_SIZE(&G.prog.one);)
@@ -7173,8 +7224,8 @@ static void bc_program_init(void)
                IF_BC(bc_program_addFunc(xstrdup("1"))); // func #1: for read()
        } else {
                // in dc, functions have no names
-               bc_program_add_fn();
-               bc_program_add_fn();
+               xc_program_add_fn();
+               xc_program_add_fn();
        }
 
        bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
@@ -7192,22 +7243,22 @@ static void bc_program_init(void)
        bc_char_vec_init(&G.input_buffer);
 }
 
-static int bc_vm_init(const char *env_len)
+static int xc_vm_init(const char *env_len)
 {
+       G.prog.len = xc_vm_envLen(env_len);
 #if ENABLE_FEATURE_EDITING
        G.line_input_state = new_line_input_t(DO_HISTORY);
 #endif
-       G.prog.len = bc_vm_envLen(env_len);
-
        bc_vec_init(&G.files, sizeof(char *), NULL);
+
+       xc_program_init();
        IF_BC(if (IS_BC) bc_vm_envArgs();)
-       bc_program_init();
-       bc_parse_create(BC_PROG_MAIN);
+       xc_parse_create(BC_PROG_MAIN);
 
 //TODO: in GNU bc, the check is (isatty(0) && isatty(1)),
 //-i option unconditionally enables this regardless of isatty():
        if (isatty(0)) {
-#if ENABLE_FEATURE_BC_SIGNALS
+#if ENABLE_FEATURE_BC_INTERACTIVE
                G_ttyin = 1;
                // With SA_RESTART, most system calls will restart
                // (IOW: they won't fail with EINTR).
@@ -7234,13 +7285,17 @@ static int bc_vm_init(const char *env_len)
        return 0; // "not a tty"
 }
 
-static BcStatus bc_vm_run(void)
+static BcStatus xc_vm_run(void)
 {
-       BcStatus st = zbc_vm_exec();
+       BcStatus st = zxc_vm_exec();
 #if ENABLE_FEATURE_CLEAN_UP
        if (G_exiting) // it was actually "halt" or "quit"
                st = EXIT_SUCCESS;
-       bc_vm_free();
+
+       bc_vec_free(&G.files);
+       xc_program_free();
+       xc_parse_free();
+       free(G.env_args);
 # if ENABLE_FEATURE_EDITING
        free_line_input_t(G.line_input_state);
 # endif
@@ -7258,14 +7313,14 @@ int bc_main(int argc UNUSED_PARAM, char **argv)
 
        INIT_G();
 
-       is_tty = bc_vm_init("BC_LINE_LENGTH");
+       is_tty = xc_vm_init("BC_LINE_LENGTH");
 
        bc_args(argv);
 
        if (is_tty && !(option_mask32 & BC_FLAG_Q))
                bc_vm_info();
 
-       return bc_vm_run();
+       return xc_vm_run();
 }
 #endif
 
@@ -7287,7 +7342,7 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
        //      |123\    |
        //      |456     |
        // Do the same, or it's a bug?
-       bc_vm_init("DC_LINE_LENGTH");
+       xc_vm_init("DC_LINE_LENGTH");
 
        // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
        noscript = BC_FLAG_I;
@@ -7298,12 +7353,12 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
                switch (n) {
                case 'e':
                        noscript = 0;
-                       n = zbc_vm_process(optarg);
+                       n = zxc_vm_process(optarg);
                        if (n) return n;
                        break;
                case 'f':
                        noscript = 0;
-                       n = zbc_vm_file(optarg);
+                       n = zxc_vm_file(optarg);
                        if (n) return n;
                        break;
                case 'x':
@@ -7322,8 +7377,9 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
 
        option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin
 
-       return bc_vm_run();
+       return xc_vm_run();
 }
 #endif
 
-#endif // not DC_SMALL
+#endif // DC_BIG
+