bc: convert all non-POSIX BC_STATUS_foo codes
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 4 Dec 2018 19:05:28 +0000 (20:05 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 14:43:35 +0000 (15:43 +0100)
function                                             old     new   delta
bc_program_asciify                                     -     469    +469
bc_parse_parse                                       432     495     +63
dc_parse_expr                                        727     775     +48
bc_vm_run                                           1955    1995     +40
bc_program_num                                      1115    1147     +32
bc_program_binOpPrep                                 296     324     +28
static.msg                                             -      24     +24
bc_parse_name                                        570     593     +23
bc_lex_token                                        1344    1367     +23
dc_lex_token                                         695     714     +19
bc_num_ulong                                          85     103     +18
bc_program_read                                      336     353     +17
dc_parse_parse                                        47      60     +13
bc_parse_stmt                                       2301    2313     +12
bc_parse_auto                                        291     302     +11
bc_program_prep                                       89      99     +10
bc_lex_next                                           71      81     +10
dc_parse_register                                     52      61      +9
bc_program_print                                     775     784      +9
bc_func_insert                                        89      98      +9
bc_program_assignStr                                 159     167      +8
bc_program_assign                                    476     484      +8
bc_parse_body                                        116     124      +8
bc_lex_name                                           83      91      +8
bc_program_pushVar                                   215     221      +6
bc_parse_text                                        141     147      +6
bc_num_shift                                          68      74      +6
bc_num_p                                             472     478      +6
bc_program_execStr                                   559     564      +5
bc_parse_else                                        139     143      +4
bc_lex_number                                        301     305      +4
bc_num_d                                             558     561      +3
bc_parse_endBody                                     422     424      +2
bc_num_r                                             231     230      -1
bc_program_copyToVar                                 343     340      -3
bc_program_call                                      372     367      -5
bc_parse_expr                                       2215    2210      -5
bc_program_modexp                                    763     756      -7
bc_err_msgs                                          164      60    -104
bc_program_pushArray                                 136       -    -136
bc_program_exec                                     4453    4153    -300
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 31/7 up/down: 961/-561)         Total: 400 bytes
   text    data     bss     dec     hex filename
 987766     485    7296  995547   f30db busybox_old
 988258     485    7296  996039   f32c7 busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/bc.c

index bd70670d5c724ded58947e5e996b9870f6593c15..7b20a94ccf818c9df3b10b0bbd35f8e1376c8058 100644 (file)
 #include "libbb.h"
 
 typedef enum BcStatus {
-       BC_STATUS_SUCCESS,
-       BC_STATUS_FAILURE,
+       BC_STATUS_SUCCESS = 0,
+       BC_STATUS_FAILURE = 1,
+       BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
 
 //     BC_STATUS_ALLOC_ERR,
 //     BC_STATUS_INPUT_EOF,
@@ -177,48 +178,47 @@ typedef enum BcStatus {
 //     BC_STATUS_PATH_IS_DIR,
 
 //     BC_STATUS_LEX_BAD_CHAR,
-       BC_STATUS_LEX_NO_STRING_END,
-       BC_STATUS_LEX_NO_COMMENT_END,
-       BC_STATUS_LEX_EOF,
+//     BC_STATUS_LEX_NO_STRING_END,
+//     BC_STATUS_LEX_NO_COMMENT_END,
+//     BC_STATUS_LEX_EOF,
 #if ENABLE_DC
-       BC_STATUS_LEX_EXTENDED_REG,
+//     BC_STATUS_LEX_EXTENDED_REG,
 #endif
-       BC_STATUS_PARSE_BAD_TOKEN,
-       BC_STATUS_PARSE_BAD_EXP,
-       BC_STATUS_PARSE_EMPTY_EXP,
-       BC_STATUS_PARSE_BAD_PRINT,
-       BC_STATUS_PARSE_BAD_FUNC,
-       BC_STATUS_PARSE_BAD_ASSIGN,
+//     BC_STATUS_PARSE_BAD_TOKEN,
+//     BC_STATUS_PARSE_BAD_EXP,
+//     BC_STATUS_PARSE_BAD_PRINT,
+//     BC_STATUS_PARSE_BAD_FUNC,
+//     BC_STATUS_PARSE_BAD_ASSIGN,
 //     BC_STATUS_PARSE_NO_AUTO,
-       BC_STATUS_PARSE_DUPLICATE_LOCAL,
-       BC_STATUS_PARSE_NO_BLOCK_END,
+//     BC_STATUS_PARSE_DUPLICATE_LOCAL,
+//     BC_STATUS_PARSE_NO_BLOCK_END,
 
-       BC_STATUS_MATH_NEGATIVE,
-       BC_STATUS_MATH_NON_INTEGER,
-       BC_STATUS_MATH_OVERFLOW,
-       BC_STATUS_MATH_DIVIDE_BY_ZERO,
-       BC_STATUS_MATH_BAD_STRING,
+//     BC_STATUS_MATH_NEGATIVE,
+//     BC_STATUS_MATH_NON_INTEGER,
+//     BC_STATUS_MATH_OVERFLOW,
+//     BC_STATUS_MATH_DIVIDE_BY_ZERO,
+//     BC_STATUS_MATH_BAD_STRING,
 
 //     BC_STATUS_EXEC_FILE_ERR,
 //     BC_STATUS_EXEC_MISMATCHED_PARAMS,
 //     BC_STATUS_EXEC_UNDEFINED_FUNC,
-       BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
-       BC_STATUS_EXEC_NUM_LEN,
-       BC_STATUS_EXEC_NAME_LEN,
-       BC_STATUS_EXEC_STRING_LEN,
-       BC_STATUS_EXEC_ARRAY_LEN,
-       BC_STATUS_EXEC_BAD_IBASE,
+//     BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
+//     BC_STATUS_EXEC_NUM_LEN,
+//     BC_STATUS_EXEC_NAME_LEN,
+//     BC_STATUS_EXEC_STRING_LEN,
+//     BC_STATUS_EXEC_ARRAY_LEN,
+//     BC_STATUS_EXEC_BAD_IBASE,
 //     BC_STATUS_EXEC_BAD_SCALE,
-       BC_STATUS_EXEC_BAD_READ_EXPR,
-       BC_STATUS_EXEC_REC_READ,
-       BC_STATUS_EXEC_BAD_TYPE,
+//     BC_STATUS_EXEC_BAD_READ_EXPR,
+//     BC_STATUS_EXEC_REC_READ,
+//     BC_STATUS_EXEC_BAD_TYPE,
 //     BC_STATUS_EXEC_BAD_OBASE,
 //     BC_STATUS_EXEC_SIGNAL,
-       BC_STATUS_EXEC_STACK,
+//     BC_STATUS_EXEC_STACK,
 
 //     BC_STATUS_VEC_OUT_OF_BOUNDS,
 //     BC_STATUS_VEC_ITEM_EXISTS,
-       BC_STATUS_BEFORE_POSIX = BC_STATUS_EXEC_STACK,
+       BC_STATUS_BEFORE_POSIX = BC_STATUS_PARSE_EMPTY_EXP,
 #if ENABLE_BC
        BC_STATUS_POSIX_NAME_LEN,
        BC_STATUS_POSIX_COMMENT,
@@ -242,51 +242,52 @@ typedef enum BcStatus {
 static const char *const bc_err_msgs[] = {
        NULL,
        NULL,
+       NULL,
+
 //     "memory allocation error",
 //     "I/O error",
 //     "file is not text:",
 //     "path is a directory:",
 
 //     "bad character",
-       "string end could not be found",
-       "comment end could not be found",
-       "end of file",
+//     "string end could not be found",
+//     "comment end could not be found",
+//     "end of file",
 #if ENABLE_DC
-       "extended register",
+//     "extended register",
 #endif
-       "bad token",
-       "bad expression",
-       "empty expression",
-       "bad print statement",
-       "bad function definition",
-       "bad assignment: left side must be scale, ibase, "
-               "obase, last, var, or array element",
+//     "bad token",
+//     "bad expression",
+//     "bad print statement",
+//     "bad function definition",
+//     "bad assignment: left side must be scale, ibase, "
+//             "obase, last, var, or array element",
 //     "no auto variable found",
-       "function parameter or auto var has the same name as another",
-       "block end could not be found",
+//     "function parameter or auto var has the same name as another",
+//     "block end could not be found",
 
-       "negative number",
-       "non integer number",
-       "overflow",
-       "divide by zero",
-       "bad number string",
+//     "negative number",
+//     "non integer number",
+//     "overflow",
+//     "divide by zero",
+//     "bad number string",
 
 //     "could not open file:",
 //     "mismatched parameters", // wrong number of them, to be exact
 //     "undefined function",
-       "file is not executable:",
-       "number too long: must be [1, BC_NUM_MAX]",
-       "name too long: must be [1, BC_NAME_MAX]",
-       "string too long: must be [1, BC_STRING_MAX]",
-       "array too long; must be [1, BC_DIM_MAX]",
-       "bad ibase; must be [2, 16]",
+//     "file is not executable:",
+//     "number too long: must be [1, BC_NUM_MAX]",
+//     "name too long: must be [1, BC_NAME_MAX]",
+//     "string too long: must be [1, BC_STRING_MAX]",
+//     "array too long; must be [1, BC_DIM_MAX]",
+//     "bad ibase; must be [2, 16]",
 //     "bad scale; must be [0, BC_SCALE_MAX]",
-       "bad read() expression",
-       "read() call inside of a read() call",
-       "variable is wrong type",
+//     "bad read() expression",
+//     "read() call inside of a read() call",
+//     "variable is wrong type",
 //     "bad obase; must be [2, BC_BASE_MAX]",
 //     "signal caught and not handled",
-       "stack has too few elements",
+//     "stack has too few elements",
 
 //     "index is out of bounds",
 //     "item already exists",
@@ -1577,7 +1578,8 @@ static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
 static BcStatus bc_num_shift(BcNum *n, size_t places)
 {
        if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
-       if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
+       if (places + n->len > BC_MAX_NUM)
+               return bc_error("number too long: must be [1, BC_NUM_MAX]");
 
        if (n->rdx >= places)
                n->rdx -= places;
@@ -1885,7 +1887,7 @@ static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
        bool zero = true;
 
        if (b->len == 0)
-               return BC_STATUS_MATH_DIVIDE_BY_ZERO;
+               return bc_error("divide by zero");
        else if (a->len == 0) {
                bc_num_setToZero(c, scale);
                return BC_STATUS_SUCCESS;
@@ -1948,7 +1950,8 @@ static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
        BcNum temp;
        bool neg;
 
-       if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
+       if (b->len == 0)
+               return bc_error("divide by zero");
 
        if (a->len == 0) {
                bc_num_setToZero(d, ts);
@@ -1997,7 +2000,7 @@ static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
        size_t i, powrdx, resrdx;
        bool neg, zero;
 
-       if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
+       if (b->rdx) return bc_error("non integer number");
 
        if (b->len == 0) {
                bc_num_one(c);
@@ -2435,7 +2438,8 @@ static void bc_num_copy(BcNum *d, BcNum *s)
 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
                              size_t base_t)
 {
-       if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
+       if (!bc_num_strValid(val, base_t))
+               return bc_error("bad number string");
 
        if (base_t == 10)
                bc_num_parseDecimal(n, val);
@@ -2474,7 +2478,7 @@ static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
        size_t i;
        unsigned long pow;
 
-       if (n->neg) return BC_STATUS_MATH_NEGATIVE;
+       if (n->neg) return bc_error("negative number");
 
        for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
 
@@ -2483,7 +2487,8 @@ static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
                *result += ((unsigned long) n->num[i]) * pow;
                pow *= 10;
 
-               if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
+               if (*result < prev || pow < powprev)
+                       return bc_error("overflow");
        }
 
        return BC_STATUS_SUCCESS;
@@ -2555,7 +2560,7 @@ static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
                return BC_STATUS_SUCCESS;
        }
        else if (a->neg)
-               return BC_STATUS_MATH_NEGATIVE;
+               return bc_error("negative number");
        else if (BC_NUM_ONE(a)) {
                bc_num_one(b);
                bc_num_extend(b, scale);
@@ -2674,9 +2679,12 @@ static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
        BcStatus s;
        BcNum base, exp, two, temp;
 
-       if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
-       if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
-       if (b->neg) return BC_STATUS_MATH_NEGATIVE;
+       if (c->len == 0)
+               return bc_error("divide by zero");
+       if (a->rdx || b->rdx || c->rdx)
+               return bc_error("non integer number");
+       if (b->neg)
+               return bc_error("negative number");
 
        bc_num_expand(d, c->len);
        bc_num_init(&base, c->len);
@@ -2735,8 +2743,8 @@ static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
        size_t i;
 
        for (i = 0; i < f->autos.len; ++i) {
-               if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
-                       return BC_STATUS_PARSE_DUPLICATE_LOCAL;
+               if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
+                       return bc_error("function parameter or auto var has the same name as another");
        }
 
        a.idx = var;
@@ -2918,7 +2926,8 @@ static BcStatus bc_lex_number(BcLex *l, char start)
        }
 
        len = i + 1 * !last_pt - bslashes * 2;
-       if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
+       if (len > BC_MAX_NUM)
+               return bc_error("number too long: must be [1, BC_NUM_MAX]");
 
        bc_vec_npop(&l->t.v, l->t.v.len);
        bc_vec_expand(&l->t.v, len + 1);
@@ -2955,7 +2964,8 @@ static BcStatus bc_lex_name(BcLex *l)
 
        while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
 
-       if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
+       if (i > BC_MAX_STRING)
+               return bc_error("name too long: must be [1, BC_NAME_MAX]");
        bc_vec_string(&l->t.v, i, buf);
 
        // Increment the index. We minus 1 because it has already been incremented.
@@ -2987,7 +2997,7 @@ static BcStatus bc_lex_next(BcLex *l)
        BcStatus s;
 
        l->t.last = l->t.t;
-       if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
+       if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
 
        l->line += l->newline;
        l->t.t = BC_LEX_EOF;
@@ -3060,11 +3070,12 @@ static BcStatus bc_lex_string(BcLex *l)
 
        if (c == '\0') {
                l->i = i;
-               return BC_STATUS_LEX_NO_STRING_END;
+               return bc_error("string end could not be found");
        }
 
        len = i - l->i;
-       if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
+       if (len > BC_MAX_STRING)
+               return bc_error("string too long: must be [1, BC_STRING_MAX]");
        bc_vec_string(&l->t.v, len, l->buf + l->i);
 
        l->i = i + 1;
@@ -3101,7 +3112,7 @@ static BcStatus bc_lex_comment(BcLex *l)
                }
                if (c == '\0') {
                        l->i = i;
-                       return BC_STATUS_LEX_NO_COMMENT_END;
+                       return bc_error("comment end could not be found");
                }
                nls += (c == '\n');
                i++;
@@ -3404,7 +3415,7 @@ static BcStatus dc_lex_register(BcLex *l)
                bc_lex_whitespace(l);
                ++l->i;
                if (!G_exreg)
-                       s = BC_STATUS_LEX_EXTENDED_REG;
+                       s = bc_error("extended register");
                else
                        s = bc_lex_name(l);
        }
@@ -3437,11 +3448,12 @@ static BcStatus dc_lex_string(BcLex *l)
 
        if (c == '\0') {
                l->i = i;
-               return BC_STATUS_LEX_NO_STRING_END;
+               return bc_error("string end could not be found");
        }
 
        bc_vec_pushByte(&l->t.v, '\0');
-       if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
+       if (i - l->i > BC_MAX_STRING)
+               return bc_error("string too long: must be [1, BC_STRING_MAX]");
 
        l->i = i;
        l->line += nls;
@@ -3606,11 +3618,12 @@ static BcStatus bc_parse_text(BcParse *p, const char *text)
 
        p->func = bc_vec_item(&G.prog.fns, p->fidx);
 
-       if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
+       if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
                p->l.t.t = BC_LEX_INVALID;
                s = p->parse(p);
                if (s) return s;
-               if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
+               if (!BC_PARSE_CAN_EXEC(p))
+                       return bc_error("file is not executable");
        }
 
        return bc_lex_text(&p->l, text);
@@ -3703,7 +3716,8 @@ static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
 {
        BcLexType top;
 
-       if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
+       if (p->ops.len <= ops_bgn)
+               return bc_error("bad expression");
        top = BC_PARSE_TOP_OP(p);
 
        while (top != BC_LEX_LPAREN) {
@@ -3713,7 +3727,8 @@ static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
                bc_vec_pop(&p->ops);
                *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
 
-               if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
+               if (p->ops.len <= ops_bgn)
+                       return bc_error("bad expression");
                top = BC_PARSE_TOP_OP(p);
        }
 
@@ -3744,7 +3759,7 @@ static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
                }
        }
 
-       if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (comma) return bc_error("bad token");
        bc_parse_push(p, BC_INST_CALL);
        bc_parse_pushIndex(p, nparams);
 
@@ -3763,7 +3778,7 @@ static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
        if (s) goto err;
 
        if (p->l.t.t != BC_LEX_RPAREN) {
-               s = BC_STATUS_PARSE_BAD_TOKEN;
+               s = bc_error("bad token");
                goto err;
        }
 
@@ -3805,7 +3820,7 @@ static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
                if (p->l.t.t == BC_LEX_RBRACKET) {
 
                        if (!(flags & BC_PARSE_ARRAY)) {
-                               s = BC_STATUS_PARSE_BAD_EXP;
+                               s = bc_error("bad expression");
                                goto err;
                        }
 
@@ -3828,7 +3843,7 @@ static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
        else if (p->l.t.t == BC_LEX_LPAREN) {
 
                if (flags & BC_PARSE_NOCALL) {
-                       s = BC_STATUS_PARSE_BAD_TOKEN;
+                       s = bc_error("bad token");
                        goto err;
                }
 
@@ -3854,11 +3869,11 @@ static BcStatus bc_parse_read(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
 
        bc_parse_push(p, BC_INST_READ);
 
@@ -3872,7 +3887,7 @@ static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
 
        flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
 
@@ -3882,7 +3897,7 @@ static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
        s = bc_parse_expr(p, flags, bc_parse_next_rel);
        if (s) return s;
 
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
 
        *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
        bc_parse_push(p, *prev);
@@ -3911,7 +3926,7 @@ static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
 
        s = bc_parse_expr(p, flags, bc_parse_next_rel);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
        bc_parse_push(p, BC_INST_SCALE_FUNC);
 
        return bc_lex_next(&p->l);
@@ -3968,7 +3983,7 @@ static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
                                s = bc_lex_next(&p->l);
                                if (s) return s;
                                if (p->l.t.t == BC_LEX_LPAREN)
-                                       s = BC_STATUS_PARSE_BAD_TOKEN;
+                                       s = bc_error("bad token");
                                else
                                        bc_parse_push(p, BC_INST_SCALE);
                                break;
@@ -3976,7 +3991,7 @@ static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
 
                        default:
                        {
-                               s = BC_STATUS_PARSE_BAD_TOKEN;
+                               s = bc_error("bad token");
                                break;
                        }
                }
@@ -4037,7 +4052,7 @@ static BcStatus bc_parse_print(BcParse *p)
        type = p->l.t.t;
 
        if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
-               return BC_STATUS_PARSE_BAD_PRINT;
+               return bc_error("bad print statement");
 
        while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
 
@@ -4057,7 +4072,7 @@ static BcStatus bc_parse_print(BcParse *p)
        }
 
        if (s) return s;
-       if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (comma) return bc_error("bad token");
 
        return bc_lex_next(&p->l);
 }
@@ -4068,7 +4083,7 @@ static BcStatus bc_parse_return(BcParse *p)
        BcLexType t;
        bool paren;
 
-       if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
 
        s = bc_lex_next(&p->l);
        if (s) return s;
@@ -4083,7 +4098,8 @@ static BcStatus bc_parse_return(BcParse *p)
                s = bc_parse_expr(p, 0, bc_parse_next_expr);
                if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
                        return s;
-               else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
+
+               if (s == BC_STATUS_PARSE_EMPTY_EXP) {
                        bc_parse_push(p, BC_INST_RET0);
                        s = bc_lex_next(&p->l);
                        if (s) return s;
@@ -4105,18 +4121,18 @@ static BcStatus bc_parse_endBody(BcParse *p, bool brace)
        BcStatus s = BC_STATUS_SUCCESS;
 
        if (p->flags.len <= 1 || (brace && p->nbraces == 0))
-               return BC_STATUS_PARSE_BAD_TOKEN;
+               return bc_error("bad token");
 
        if (brace) {
 
                if (p->l.t.t == BC_LEX_RBRACE) {
-                       if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
+                       if (!p->nbraces) return bc_error("bad token");
                        --p->nbraces;
                        s = bc_lex_next(&p->l);
                        if (s) return s;
                }
                else
-                       return BC_STATUS_PARSE_BAD_TOKEN;
+                       return bc_error("bad token");
        }
 
        if (BC_PARSE_IF(p)) {
@@ -4202,13 +4218,13 @@ static BcStatus bc_parse_if(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
 
        s = bc_lex_next(&p->l);
        if (s) return s;
        s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
 
        s = bc_lex_next(&p->l);
        if (s) return s;
@@ -4229,7 +4245,7 @@ static BcStatus bc_parse_else(BcParse *p)
 {
        BcInstPtr ip;
 
-       if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
 
        ip.idx = p->func->labels.len;
        ip.func = ip.len = 0;
@@ -4253,7 +4269,7 @@ static BcStatus bc_parse_while(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
@@ -4271,7 +4287,7 @@ static BcStatus bc_parse_while(BcParse *p)
 
        s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
@@ -4290,7 +4306,7 @@ static BcStatus bc_parse_for(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
@@ -4300,7 +4316,7 @@ static BcStatus bc_parse_for(BcParse *p)
                s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
 
        if (s) return s;
-       if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
@@ -4317,7 +4333,7 @@ static BcStatus bc_parse_for(BcParse *p)
                s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
 
        if (s) return s;
-       if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
 
        s = bc_lex_next(&p->l);
        if (s) return s;
@@ -4339,7 +4355,7 @@ static BcStatus bc_parse_for(BcParse *p)
 
        if (s) return s;
 
-       if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
        bc_parse_push(p, BC_INST_JUMP);
        bc_parse_pushIndex(p, cond_idx);
        bc_vec_push(&p->func->labels, &p->func->code.len);
@@ -4362,17 +4378,17 @@ static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
        size_t i;
        BcInstPtr *ip;
 
-       if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
 
        if (type == BC_LEX_KEY_BREAK) {
 
-               if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
+               if (p->exits.len == 0) return bc_error("bad token");
 
                i = p->exits.len - 1;
                ip = bc_vec_item(&p->exits, i);
 
                while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
-               if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
+               if (i >= p->exits.len && !ip->func) return bc_error("bad token");
 
                i = ip->idx;
        }
@@ -4386,7 +4402,7 @@ static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
        if (s) return s;
 
        if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
-               return BC_STATUS_PARSE_BAD_TOKEN;
+               return bc_error("bad token");
 
        return bc_lex_next(&p->l);
 }
@@ -4400,20 +4416,23 @@ static BcStatus bc_parse_func(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
+       if (p->l.t.t != BC_LEX_NAME)
+               return bc_error("bad function definition");
 
        name = xstrdup(p->l.t.v.v);
        bc_parse_addFunc(p, name, &p->fidx);
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
+       if (p->l.t.t != BC_LEX_LPAREN)
+               return bc_error("bad function definition");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
        while (p->l.t.t != BC_LEX_RPAREN) {
 
-               if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
+               if (p->l.t.t != BC_LEX_NAME)
+                       return bc_error("bad function definition");
 
                ++p->func->nparams;
 
@@ -4429,7 +4448,7 @@ static BcStatus bc_parse_func(BcParse *p)
                        if (s) goto err;
 
                        if (p->l.t.t != BC_LEX_RBRACKET) {
-                               s = BC_STATUS_PARSE_BAD_FUNC;
+                               s = bc_error("bad function definition");
                                goto err;
                        }
 
@@ -4447,7 +4466,7 @@ static BcStatus bc_parse_func(BcParse *p)
                if (s) goto err;
        }
 
-       if (comma) return BC_STATUS_PARSE_BAD_FUNC;
+       if (comma) return bc_error("bad function definition");
 
        flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
        bc_parse_startBody(p, flags);
@@ -4471,7 +4490,7 @@ static BcStatus bc_parse_auto(BcParse *p)
        bool comma, var, one;
        char *name;
 
-       if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (!p->auto_part) return bc_error("bad token");
        s = bc_lex_next(&p->l);
        if (s) return s;
 
@@ -4491,7 +4510,7 @@ static BcStatus bc_parse_auto(BcParse *p)
                        if (s) goto err;
 
                        if (p->l.t.t != BC_LEX_RBRACKET) {
-                               s = BC_STATUS_PARSE_BAD_FUNC;
+                               s = bc_error("bad function definition");
                                goto err;
                        }
 
@@ -4509,11 +4528,11 @@ static BcStatus bc_parse_auto(BcParse *p)
                if (s) goto err;
        }
 
-       if (comma) return BC_STATUS_PARSE_BAD_FUNC;
+       if (comma) return bc_error("bad function definition");
        if (!one) return bc_error("no auto variable found");
 
        if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
-               return BC_STATUS_PARSE_BAD_TOKEN;
+               return bc_error("bad token");
 
        return bc_lex_next(&p->l);
 
@@ -4531,7 +4550,7 @@ static BcStatus bc_parse_body(BcParse *p, bool brace)
 
        if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
 
-               if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
+               if (!brace) return bc_error("bad token");
                p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
 
                if (!p->auto_part) {
@@ -4568,7 +4587,7 @@ static BcStatus bc_parse_stmt(BcParse *p)
 
                case BC_LEX_LBRACE:
                {
-                       if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
+                       if (!BC_PARSE_BODY(p)) return bc_error("bad token");
 
                        ++p->nbraces;
                        s = bc_lex_next(&p->l);
@@ -4713,7 +4732,7 @@ static BcStatus bc_parse_stmt(BcParse *p)
 
                default:
                {
-                       s = BC_STATUS_PARSE_BAD_TOKEN;
+                       s = bc_error("bad token");
                        break;
                }
        }
@@ -4726,9 +4745,9 @@ static BcStatus bc_parse_parse(BcParse *p)
        BcStatus s;
 
        if (p->l.t.t == BC_LEX_EOF)
-               s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
+               s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
        else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
-               if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
+               if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
                s = bc_parse_func(p);
        }
        else
@@ -4787,7 +4806,11 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                                    prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
                                    prev != BC_INST_OBASE && prev != BC_INST_LAST)
                                {
-                                       s = BC_STATUS_PARSE_BAD_ASSIGN;
+                                       s = bc_error("bad assignment:"
+                                               " left side must be scale,"
+                                               " ibase, obase, last, var,"
+                                               " or array element"
+                                       );
                                        break;
                                }
                        }
@@ -4807,10 +4830,10 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                        case BC_LEX_OP_BOOL_OR:
                        case BC_LEX_OP_BOOL_AND:
                        {
-                               if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
-                                   (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
-                               {
-                                       return BC_STATUS_PARSE_BAD_EXP;
+                               if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
+                                || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
+                               {
+                                       return bc_error("bad expression");
                                }
 
                                nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
@@ -4824,8 +4847,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
 
                        case BC_LEX_LPAREN:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                ++nparens;
                                paren_expr = rprn = bin_last = false;
                                get_token = true;
@@ -4837,7 +4860,7 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                        case BC_LEX_RPAREN:
                        {
                                if (bin_last || prev == BC_INST_BOOL_NOT)
-                                       return BC_STATUS_PARSE_BAD_EXP;
+                                       return bc_error("bad expression");
 
                                if (nparens == 0) {
                                        s = BC_STATUS_SUCCESS;
@@ -4859,8 +4882,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
 
                        case BC_LEX_NAME:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                paren_expr = true;
                                rprn = get_token = bin_last = false;
                                s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
@@ -4871,8 +4894,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
 
                        case BC_LEX_NUMBER:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                bc_parse_number(p, &prev, &nexprs);
                                paren_expr = get_token = true;
                                rprn = bin_last = false;
@@ -4884,8 +4907,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                        case BC_LEX_KEY_LAST:
                        case BC_LEX_KEY_OBASE:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
                                bc_parse_push(p, (char) prev);
 
@@ -4899,8 +4922,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                        case BC_LEX_KEY_LENGTH:
                        case BC_LEX_KEY_SQRT:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                s = bc_parse_builtin(p, t, flags, &prev);
                                paren_expr = true;
                                rprn = get_token = bin_last = false;
@@ -4912,9 +4935,9 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                        case BC_LEX_KEY_READ:
                        {
                                if (BC_PARSE_LEAF(prev, rprn))
-                                       return BC_STATUS_PARSE_BAD_EXP;
+                                       return bc_error("bad expression");
                                else if (flags & BC_PARSE_NOREAD)
-                                       s = BC_STATUS_EXEC_REC_READ;
+                                       s = bc_error("read() call inside of a read() call");
                                else
                                        s = bc_parse_read(p);
 
@@ -4928,8 +4951,8 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
 
                        case BC_LEX_KEY_SCALE:
                        {
-                               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
-
+                               if (BC_PARSE_LEAF(prev, rprn))
+                                       return bc_error("bad expression");
                                s = bc_parse_scale(p, &prev, flags);
                                paren_expr = true;
                                rprn = get_token = bin_last = false;
@@ -4941,7 +4964,7 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
 
                        default:
                        {
-                               s = BC_STATUS_PARSE_BAD_TOKEN;
+                               s = bc_error("bad token");
                                break;
                        }
                }
@@ -4958,7 +4981,7 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
 
                if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
-                       return BC_STATUS_PARSE_BAD_EXP;
+                       return bc_error("bad expression");
 
                bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
 
@@ -4966,11 +4989,14 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
                bc_vec_pop(&p->ops);
        }
 
-       s = BC_STATUS_PARSE_BAD_EXP;
-       if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
+       if (prev == BC_INST_BOOL_NOT || nexprs != 1)
+               return bc_error("bad expression");
 
-       for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
-       if (s) return s;
+       for (i = 0; i < next.len; ++i)
+               if (t == next.tokens[i])
+                       goto ok;
+       return bc_error("bad expression");
+ ok:
 
        if (!(flags & BC_PARSE_REL) && nrelops) {
                s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
@@ -5008,7 +5034,7 @@ static BcStatus dc_parse_register(BcParse *p)
 
        s = bc_lex_next(&p->l);
        if (s) return s;
-       if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
+       if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
 
        name = xstrdup(p->l.t.v.v);
        bc_parse_pushName(p, name);
@@ -5115,7 +5141,8 @@ static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
                        if (t == BC_LEX_NEG) {
                                s = bc_lex_next(&p->l);
                                if (s) return s;
-                               if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
+                               if (p->l.t.t != BC_LEX_NUMBER)
+                                       return bc_error("bad token");
                        }
 
                        bc_parse_number(p, &prev, &p->nbraces);
@@ -5129,7 +5156,7 @@ static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
                case BC_LEX_KEY_READ:
                {
                        if (flags & BC_PARSE_NOREAD)
-                               s = BC_STATUS_EXEC_REC_READ;
+                               s = bc_error("read() call inside of a read() call");
                        else
                                bc_parse_push(p, BC_INST_READ);
                        get_token = true;
@@ -5164,7 +5191,7 @@ static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
 
                default:
                {
-                       s = BC_STATUS_PARSE_BAD_TOKEN;
+                       s = bc_error("bad token");
                        get_token = true;
                        break;
                }
@@ -5206,7 +5233,7 @@ static BcStatus dc_parse_parse(BcParse *p)
        BcStatus s;
 
        if (p->l.t.t == BC_LEX_EOF)
-               s = BC_STATUS_LEX_EOF;
+               s = bc_error("end of file");
        else
                s = dc_parse_expr(p, 0);
 
@@ -5349,7 +5376,8 @@ static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
        bool hex;
        BcResultType lt, rt;
 
-       if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 2))
+               return bc_error("stack has too few elements");
 
        *r = bc_vec_item_rev(&G.prog.results, 0);
        *l = bc_vec_item_rev(&G.prog.results, 1);
@@ -5371,8 +5399,9 @@ static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
        }
 
        if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
-               return BC_STATUS_EXEC_BAD_TYPE;
-       if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
+               return bc_error("variable is wrong type");
+       if (!assign && !BC_PROG_NUM((*r), (*ln)))
+               return bc_error("variable is wrong type");
 
        return s;
 }
@@ -5389,13 +5418,15 @@ static BcStatus bc_program_prep(BcResult **r, BcNum **n)
 {
        BcStatus s;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
        *r = bc_vec_top(&G.prog.results);
 
        s = bc_program_num(*r, n, false);
        if (s) return s;
 
-       if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
+       if (!BC_PROG_NUM((*r), (*n)))
+               return bc_error("variable is wrong type");
 
        return s;
 }
@@ -5439,7 +5470,8 @@ static BcStatus bc_program_read(void)
 
        for (i = 0; i < G.prog.stack.len; ++i) {
                BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
-               if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
+               if (ip_ptr->func == BC_PROG_READ)
+                       return bc_error("read() call inside of a read() call");
        }
 
        bc_vec_npop(&f->code, f->code.len);
@@ -5457,7 +5489,7 @@ static BcStatus bc_program_read(void)
        if (s) goto exec_err;
 
        if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
-               s = BC_STATUS_EXEC_BAD_READ_EXPR;
+               s = bc_error("bad read() expression");
                goto exec_err;
        }
 
@@ -5600,7 +5632,8 @@ static BcStatus bc_program_print(char inst, size_t idx)
        BcNum *num = NULL;
        bool pop = inst != BC_INST_PRINT;
 
-       if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, idx + 1))
+               return bc_error("stack has too few elements");
 
        r = bc_vec_item_rev(&G.prog.results, idx);
        s = bc_program_num(r, &num, false);
@@ -5731,7 +5764,8 @@ static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
        res.t = BC_RESULT_STR;
 
        if (!push) {
-               if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
+               if (!BC_PROG_STACK(&G.prog.results, 2))
+                       return bc_error("stack has too few elements");
                bc_vec_pop(v);
                bc_vec_pop(&G.prog.results);
        }
@@ -5752,14 +5786,17 @@ static BcStatus bc_program_copyToVar(char *name, bool var)
        BcVec *v;
        BcNum *n;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
 
        ptr = bc_vec_top(&G.prog.results);
-       if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
+       if ((ptr->t == BC_RESULT_ARRAY) != !var)
+               return bc_error("variable is wrong type");
        v = bc_program_search(name, var);
 
 #if ENABLE_DC
-       if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
+       if (ptr->t == BC_RESULT_STR && !var)
+               return bc_error("variable is wrong type");
        if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
 #endif
 
@@ -5804,7 +5841,8 @@ static BcStatus bc_program_assign(char inst)
 
                BcVec *v;
 
-               if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
+               if (left->t != BC_RESULT_VAR)
+                       return bc_error("variable is wrong type");
                v = bc_program_search(left->d.id.name, true);
 
                return bc_program_assignStr(right, v, false);
@@ -5812,11 +5850,15 @@ static BcStatus bc_program_assign(char inst)
 #endif
 
        if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
-               return BC_STATUS_PARSE_BAD_ASSIGN;
+               return bc_error("bad assignment:"
+                               " left side must be scale,"
+                               " ibase, obase, last, var,"
+                               " or array element"
+               );
 
 #if ENABLE_BC
        if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
-               return BC_STATUS_MATH_DIVIDE_BY_ZERO;
+               return bc_error("divide by zero");
 
        if (assign)
                bc_num_copy(l, r);
@@ -5829,25 +5871,35 @@ static BcStatus bc_program_assign(char inst)
 #endif
 
        if (ib || sc || left->t == BC_RESULT_OBASE) {
-
+               static const char *const msg[] = {
+                       "bad ibase; must be [2, 16]",           //BC_RESULT_IBASE
+                       "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
+                       "?1",                                   //BC_RESULT_LAST
+                       "?2",                                   //BC_RESULT_CONSTANT
+                       "?3",                                   //BC_RESULT_ONE
+                       "bad obase; must be [2, BC_BASE_MAX]",  //BC_RESULT_OBASE
+               };
                size_t *ptr;
 
                s = bc_num_ulong(l, &val);
-               if (s) return s;
-               s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
-
+               if (s)
+                       return s;
+               s = left->t - BC_RESULT_IBASE;
                if (sc) {
                        max = BC_MAX_SCALE;
                        ptr = &G.prog.scale;
                }
                else {
-                       if (val < BC_NUM_MIN_BASE) return s;
+                       if (val < BC_NUM_MIN_BASE)
+                               return bc_error(msg[s]);
                        max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
                        ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
                }
 
-               if (val > max) return s;
-               if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
+               if (val > max)
+                       return bc_error(msg[s]);
+               if (!sc)
+                       bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
 
                *ptr = (size_t) val;
                s = BC_STATUS_SUCCESS;
@@ -5884,7 +5936,7 @@ static BcStatus bc_program_pushVar(char *code, size_t *bgn,
 
                        if (!BC_PROG_STACK(v, 2 - copy)) {
                                free(name);
-                               return BC_STATUS_EXEC_STACK;
+                               return bc_error("stack has too few elements");
                        }
 
                        free(name);
@@ -5936,7 +5988,7 @@ static BcStatus bc_program_pushArray(char *code, size_t *bgn,
                if (s) goto err;
 
                if (temp > BC_MAX_DIM) {
-                       s = BC_STATUS_EXEC_ARRAY_LEN;
+                       s = bc_error("array too long; must be [1, BC_DIM_MAX]");
                        goto err;
                }
 
@@ -6010,7 +6062,7 @@ static BcStatus bc_program_call(char *code, size_t *idx)
                arg = bc_vec_top(&G.prog.results);
 
                if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
-                       return BC_STATUS_EXEC_BAD_TYPE;
+                       return bc_error("variable is wrong type");
 
                s = bc_program_copyToVar(a->name, a->idx);
                if (s) return s;
@@ -6046,7 +6098,7 @@ static BcStatus bc_program_return(char inst)
        BcInstPtr *ip = bc_vec_top(&G.prog.stack);
 
        if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
-               return BC_STATUS_EXEC_STACK;
+               return bc_error("stack has too few elements");
 
        f = bc_vec_item(&G.prog.fns, ip->func);
        res.t = BC_RESULT_TEMP;
@@ -6108,14 +6160,16 @@ static BcStatus bc_program_builtin(char inst)
        BcResult res;
        bool len = inst == BC_INST_LENGTH;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
        opnd = bc_vec_top(&G.prog.results);
 
        s = bc_program_num(opnd, &num, false);
        if (s) return s;
 
 #if ENABLE_DC
-       if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
+       if (!BC_PROG_NUM(opnd, num) && !len)
+               return bc_error("variable is wrong type");
 #endif
 
        bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
@@ -6180,14 +6234,16 @@ static BcStatus bc_program_modexp(void)
        BcResult *r1, *r2, *r3, res;
        BcNum *n1, *n2, *n3;
 
-       if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 3))
+               return bc_error("stack has too few elements");
        s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
        if (s) return s;
 
        r1 = bc_vec_item_rev(&G.prog.results, 2);
        s = bc_program_num(r1, &n1, false);
        if (s) return s;
-       if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
+       if (!BC_PROG_NUM(r1, n1))
+               return bc_error("variable is wrong type");
 
        // Make sure that the values have their pointers updated, if necessary.
        if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
@@ -6238,7 +6294,8 @@ static BcStatus bc_program_asciify(void)
        size_t len = G.prog.strs.len, idx;
        unsigned long val;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
        r = bc_vec_top(&G.prog.results);
 
        s = bc_program_num(r, &num, false);
@@ -6306,7 +6363,8 @@ static BcStatus bc_program_printStream(void)
        size_t idx;
        char *str;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
        r = bc_vec_top(&G.prog.results);
 
        s = bc_program_num(r, &n, false);
@@ -6338,7 +6396,7 @@ static BcStatus bc_program_nquit(void)
        bc_vec_pop(&G.prog.results);
 
        if (G.prog.stack.len < val)
-               return BC_STATUS_EXEC_STACK;
+               return bc_error("stack has too few elements");
        if (G.prog.stack.len == val)
                quit();
 
@@ -6360,7 +6418,8 @@ static BcStatus bc_program_execStr(char *code, size_t *bgn,
        BcNum *n;
        bool exec;
 
-       if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+       if (!BC_PROG_STACK(&G.prog.results, 1))
+               return bc_error("stack has too few elements");
 
        r = bc_vec_top(&G.prog.results);
 
@@ -6393,7 +6452,7 @@ static BcStatus bc_program_execStr(char *code, size_t *bgn,
 
                if (!exec) goto exit;
                if (!BC_PROG_STR(n)) {
-                       s = BC_STATUS_EXEC_BAD_TYPE;
+                       s = bc_error("variable is wrong type");
                        goto exit;
                }
 
@@ -6425,7 +6484,7 @@ static BcStatus bc_program_execStr(char *code, size_t *bgn,
                if (s) goto err;
 
                if (prs.l.t.t != BC_LEX_EOF) {
-                       s = BC_STATUS_PARSE_BAD_EXP;
+                       s = bc_error("bad expression");
                        goto err;
                }
 
@@ -6652,7 +6711,7 @@ static BcStatus bc_program_exec(void)
                        case BC_INST_POP:
                        {
                                if (!BC_PROG_STACK(&G.prog.results, 1))
-                                       s = BC_STATUS_EXEC_STACK;
+                                       s = bc_error("stack has too few elements");
                                else
                                        bc_vec_pop(&G.prog.results);
                                break;
@@ -6764,7 +6823,8 @@ static BcStatus bc_program_exec(void)
 
                        case BC_INST_DUPLICATE:
                        {
-                               if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
+                               if (!BC_PROG_STACK(&G.prog.results, 1))
+                                       return bc_error("stack has too few elements");
                                ptr = bc_vec_top(&G.prog.results);
                                bc_result_copy(&r, ptr);
                                bc_vec_push(&G.prog.results, &r);
@@ -6775,7 +6835,8 @@ static BcStatus bc_program_exec(void)
                        {
                                BcResult *ptr2;
 
-                               if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
+                               if (!BC_PROG_STACK(&G.prog.results, 2))
+                                       return bc_error("stack has too few elements");
 
                                ptr = bc_vec_item_rev(&G.prog.results, 0);
                                ptr2 = bc_vec_item_rev(&G.prog.results, 1);
@@ -6863,6 +6924,7 @@ static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
                fprintf(stderr, bc_err_line + 4 * !line, line);
        }
 
+///
        return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
 }
 
@@ -6983,7 +7045,8 @@ static BcStatus bc_vm_file(const char *file)
        main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
        ip = bc_vec_item(&G.prog.stack, 0);
 
-       if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
+       if (main_func->code.len < ip->idx)
+               s = bc_error("file '%s' is not executable", file);
 
 err:
        free(data);
@@ -7057,12 +7120,16 @@ static BcStatus bc_vm_stdin(void)
                bc_vec_npop(&buffer, buffer.len);
        }
 
-       if (str)
-               s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
+       if (str) {
+               bc_error("string end could not be found");
+               s = bc_vm_error(BC_STATUS_FAILURE, G.prs.l.f,
                                G.prs.l.line);
-       else if (comment)
-               s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
+       }
+       else if (comment) {
+               bc_error("comment end could not be found");
+               s = bc_vm_error(BC_STATUS_FAILURE, G.prs.l.f,
                                G.prs.l.line);
+       }
 
 err:
        bc_vec_free(&buf);