diff options
author | Gavin Howard <yzena.tech@gmail.com> | 2019-01-28 10:40:54 -0700 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2019-01-28 18:52:27 -0600 |
commit | a8ade49b0566cf0b55b404e0e3c175c9c17d7dc0 (patch) | |
tree | 0c34cab6c7ef81ad7f6d55097f5071fa35c94cd2 | |
parent | 0430bb09837ed5664ea781e54519f965c966992a (diff) | |
download | toybox-a8ade49b0566cf0b55b404e0e3c175c9c17d7dc0.tar.gz |
bc: Update to upstream version 1.1.0
-rw-r--r-- | toys/pending/bc.c | 4085 |
1 files changed, 2168 insertions, 1917 deletions
diff --git a/toys/pending/bc.c b/toys/pending/bc.c index ed091221..5a6485af 100644 --- a/toys/pending/bc.c +++ b/toys/pending/bc.c @@ -36,95 +36,100 @@ config BC #include "toys.h" GLOBALS( - long tty; - long ttyin; - - unsigned long sig; - unsigned long sigc; - unsigned long signe; - long sig_other; + // This actually needs to be a BcVm*, but the toybox build + // system complains if I make it so. Instead, we'll just cast. + char *vm; ) -typedef enum BcStatus { +#define BC_VM ((BcVm*) TT.vm) - BC_STATUS_SUCCESS, - - BC_STATUS_ALLOC_ERR, - BC_STATUS_IO_ERR, - BC_STATUS_BIN_FILE, - 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_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_NO_AUTO, - 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_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_BAD_SCALE, - 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_VEC_OUT_OF_BOUNDS, - BC_STATUS_VEC_ITEM_EXISTS, - - BC_STATUS_POSIX_NAME_LEN, - BC_STATUS_POSIX_COMMENT, - BC_STATUS_POSIX_BAD_KW, - BC_STATUS_POSIX_DOT, - BC_STATUS_POSIX_RET, - BC_STATUS_POSIX_BOOL, - BC_STATUS_POSIX_REL_POS, - BC_STATUS_POSIX_MULTIREL, - BC_STATUS_POSIX_FOR1, - BC_STATUS_POSIX_FOR2, - BC_STATUS_POSIX_FOR3, - BC_STATUS_POSIX_BRACE, +typedef enum BcStatus { + BC_STATUS_SUCCESS = 0, + BC_STATUS_ERROR, + BC_STATUS_EOF, + BC_STATUS_EMPTY_EXPR, + BC_STATUS_SIGNAL, BC_STATUS_QUIT, - BC_STATUS_LIMITS, } BcStatus; +typedef enum BcError { + + BC_ERROR_VM_ALLOC_ERR, + BC_ERROR_VM_IO_ERR, + BC_ERROR_VM_BIN_FILE, + BC_ERROR_VM_PATH_DIR, + + BC_ERROR_PARSE_EOF, + BC_ERROR_PARSE_CHAR, + BC_ERROR_PARSE_STRING, + BC_ERROR_PARSE_COMMENT, + BC_ERROR_PARSE_TOKEN, + BC_ERROR_EXEC_NUM_LEN, + BC_ERROR_EXEC_NAME_LEN, + BC_ERROR_EXEC_STRING_LEN, + BC_ERROR_PARSE_EXPR, + BC_ERROR_PARSE_EMPTY_EXPR, + BC_ERROR_PARSE_PRINT, + BC_ERROR_PARSE_FUNC, + BC_ERROR_PARSE_ASSIGN, + BC_ERROR_PARSE_NO_AUTO, + BC_ERROR_PARSE_DUP_LOCAL, + BC_ERROR_PARSE_BLOCK, + BC_ERROR_PARSE_RET_VOID, + + BC_ERROR_MATH_NEGATIVE, + BC_ERROR_MATH_NON_INTEGER, + BC_ERROR_MATH_OVERFLOW, + BC_ERROR_MATH_DIVIDE_BY_ZERO, + + BC_ERROR_EXEC_FILE_ERR, + BC_ERROR_EXEC_ARRAY_LEN, + BC_ERROR_EXEC_IBASE, + BC_ERROR_EXEC_OBASE, + BC_ERROR_EXEC_SCALE, + BC_ERROR_EXEC_READ_EXPR, + BC_ERROR_EXEC_REC_READ, + BC_ERROR_EXEC_TYPE, + BC_ERROR_EXEC_PARAMS, + BC_ERROR_EXEC_UNDEF_FUNC, + BC_ERROR_EXEC_VOID_VAL, + + BC_ERROR_POSIX_START, + + BC_ERROR_POSIX_NAME_LEN = BC_ERROR_POSIX_START, + BC_ERROR_POSIX_COMMENT, + BC_ERROR_POSIX_KW, + BC_ERROR_POSIX_DOT, + BC_ERROR_POSIX_RET, + BC_ERROR_POSIX_BOOL, + BC_ERROR_POSIX_REL_POS, + BC_ERROR_POSIX_MULTIREL, + BC_ERROR_POSIX_FOR1, + BC_ERROR_POSIX_FOR2, + BC_ERROR_POSIX_FOR3, + BC_ERROR_POSIX_BRACE, + BC_ERROR_POSIX_REF, + +} BcError; + #define BC_ERR_IDX_VM (0) -#define BC_ERR_IDX_LEX (1) -#define BC_ERR_IDX_PARSE (2) -#define BC_ERR_IDX_MATH (3) -#define BC_ERR_IDX_EXEC (4) -#define BC_ERR_IDX_VEC (5) -#define BC_ERR_IDX_POSIX (6) +#define BC_ERR_IDX_PARSE (1) +#define BC_ERR_IDX_MATH (2) +#define BC_ERR_IDX_EXEC (3) +#define BC_ERR_IDX_POSIX (4) + +#define BC_UNUSED(e) ((void) (e)) #define BC_VEC_START_CAP (1<<5) +typedef unsigned char uchar; + typedef void (*BcVecFree)(void*); -typedef int (*BcVecCmp)(void*, void*); + +// Forward declaration. +struct BcId; typedef struct BcVec { char *v; @@ -139,7 +144,7 @@ typedef struct BcVec { #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free)) -#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~')) +#define BC_READ_BIN_CHAR(c) (((c) < ' ' && !isspace((c))) || ((uchar) c) > '~') typedef signed char BcDig; @@ -152,30 +157,43 @@ typedef struct BcNum { } BcNum; #define BC_NUM_MIN_BASE ((unsigned long) 2) -#define BC_NUM_MAX_IBASE ((unsigned long) 16) +#define BC_NUM_MAX_POSIX_IBASE ((unsigned long) 16) +#define BC_NUM_MAX_IBASE ((unsigned long) 36) +// This is the max base allowed by bc_num_parseChar(). +#define BC_NUM_MAX_LBASE ('Z' + 10 + 1) #define BC_NUM_DEF_SIZE (16) #define BC_NUM_PRINT_WIDTH (69) #define BC_NUM_KARATSUBA_LEN (32) +// A crude, but always big enough, calculation of +// the size required for ibase and obase BcNum's. +#define BC_NUM_LONG_LOG10 ((CHAR_BIT * sizeof(unsigned long) + 1) / 2 + 1) + #define BC_NUM_NEG(n, neg) ((((ssize_t) (n)) ^ -((ssize_t) (neg))) + (neg)) + #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1) #define BC_NUM_INT(n) ((n)->len - (n)->rdx) -#define BC_NUM_AREQ(a, b) \ - (maxof((a)->rdx, (b)->rdx) + maxof(BC_NUM_INT(a), BC_NUM_INT(b)) + 1) -#define BC_NUM_MREQ(a, b, scale) \ - (BC_NUM_INT(a) + BC_NUM_INT(b) + maxof((scale), (a)->rdx + (b)->rdx) + 1) +#define BC_NUM_CMP_ZERO(a) (BC_NUM_NEG((a)->len != 0, (a)->neg)) +#define BC_NUM_PREQ(a, b) ((a)->len + (b)->len + 1) +#define BC_NUM_SHREQ(a) ((a)->len) + +#define BC_NUM_NUM_LETTER(c) ((c) - 'A' + 10) typedef BcStatus (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t); -typedef void (*BcNumDigitOp)(size_t, size_t, int, size_t*, size_t); +typedef size_t (*BcNumBinaryOpReq)(BcNum*, BcNum*, size_t); +typedef void (*BcNumDigitOp)(size_t, size_t, int); void bc_num_init(BcNum *n, size_t req); +void bc_num_setup(BcNum *n, BcDig *num, size_t cap); void bc_num_expand(BcNum *n, size_t req); void bc_num_copy(BcNum *d, BcNum *s); +void bc_num_createCopy(BcNum *d, BcNum *s); +void bc_num_createFromUlong(BcNum *n, unsigned long val); void bc_num_free(void *num); BcStatus bc_num_ulong(BcNum *n, unsigned long *result); -BcStatus bc_num_ulong2num(BcNum *n, unsigned long val); +void bc_num_ulong2num(BcNum *n, unsigned long val); BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale); BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale); @@ -186,14 +204,20 @@ BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale); BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale); BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale); +size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale); + +size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale); +size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale); + typedef enum BcInst { + BC_INST_INC_POST = 0, + BC_INST_DEC_POST, BC_INST_INC_PRE, BC_INST_DEC_PRE, - BC_INST_INC_POST, - BC_INST_DEC_POST, BC_INST_NEG, + BC_INST_BOOL_NOT, BC_INST_POWER, BC_INST_MULTIPLY, @@ -209,7 +233,6 @@ typedef enum BcInst { BC_INST_REL_LT, BC_INST_REL_GT, - BC_INST_BOOL_NOT, BC_INST_BOOL_OR, BC_INST_BOOL_AND, @@ -226,14 +249,15 @@ typedef enum BcInst { BC_INST_ARRAY_ELEM, BC_INST_ARRAY, - BC_INST_SCALE_FUNC, + BC_INST_LAST, BC_INST_IBASE, + BC_INST_OBASE, BC_INST_SCALE, - BC_INST_LAST, BC_INST_LENGTH, - BC_INST_READ, - BC_INST_OBASE, + BC_INST_SCALE_FUNC, BC_INST_SQRT, + BC_INST_ABS, + BC_INST_READ, BC_INST_PRINT, BC_INST_PRINT_POP, @@ -247,6 +271,7 @@ typedef enum BcInst { BC_INST_RET, BC_INST_RET0, + BC_INST_RET_VOID, BC_INST_HALT, @@ -261,31 +286,37 @@ typedef struct BcId { } BcId; typedef struct BcFunc { + BcVec code; BcVec labels; - size_t nparams; BcVec autos; + size_t nparams; + + BcVec strs; + BcVec consts; + + char *name; + int voidfn; + } BcFunc; typedef enum BcResultType { - BC_RESULT_TEMP, - BC_RESULT_VAR, BC_RESULT_ARRAY_ELEM, BC_RESULT_ARRAY, BC_RESULT_STR, - BC_RESULT_IBASE, - BC_RESULT_SCALE, - BC_RESULT_LAST, - - // These are between to calculate ibase, obase, and last from instructions. BC_RESULT_CONSTANT, - BC_RESULT_ONE, + BC_RESULT_TEMP, + BC_RESULT_VOID, + BC_RESULT_ONE, + BC_RESULT_LAST, + BC_RESULT_IBASE, BC_RESULT_OBASE, + BC_RESULT_SCALE, } BcResultType; @@ -306,8 +337,19 @@ typedef struct BcInstPtr { size_t len; } BcInstPtr; +typedef enum BcType { + BC_TYPE_VAR, + BC_TYPE_ARRAY, +} BcType; + void bc_array_expand(BcVec *a, size_t len); -int bc_id_cmp(void *e1, void *e2); +int bc_id_cmp(BcId *e1, BcId *e2); + +#define bc_lex_err(l, e) (bc_vm_error((e), (l)->line)) +#define bc_lex_verr(l, e, ...) (bc_vm_error((e), (l)->line, __VA_ARGS__)) + +#define BC_LEX_NUM_CHAR(c, l, pt) \ + (isdigit(c) || ((c) >= 'A' && (c) <= (l)) || ((c) == '.' && !(pt))) // BC_LEX_NEG is not used in lexing; it is only for parsing. typedef enum BcLexType { @@ -319,6 +361,7 @@ typedef enum BcLexType { BC_LEX_OP_DEC, BC_LEX_NEG, + BC_LEX_OP_BOOL_NOT, BC_LEX_OP_POWER, BC_LEX_OP_MULTIPLY, @@ -334,7 +377,6 @@ typedef enum BcLexType { BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, - BC_LEX_OP_BOOL_NOT, BC_LEX_OP_BOOL_OR, BC_LEX_OP_BOOL_AND, @@ -368,22 +410,23 @@ typedef enum BcLexType { BC_LEX_KEY_BREAK, BC_LEX_KEY_CONTINUE, BC_LEX_KEY_DEFINE, - BC_LEX_KEY_ELSE, BC_LEX_KEY_FOR, - BC_LEX_KEY_HALT, - BC_LEX_KEY_IBASE, BC_LEX_KEY_IF, - BC_LEX_KEY_LAST, - BC_LEX_KEY_LENGTH, BC_LEX_KEY_LIMITS, + BC_LEX_KEY_RETURN, + BC_LEX_KEY_WHILE, + BC_LEX_KEY_HALT, + BC_LEX_KEY_LAST, + BC_LEX_KEY_IBASE, BC_LEX_KEY_OBASE, + BC_LEX_KEY_SCALE, + BC_LEX_KEY_LENGTH, BC_LEX_KEY_PRINT, + BC_LEX_KEY_SQRT, + BC_LEX_KEY_ABS, BC_LEX_KEY_QUIT, BC_LEX_KEY_READ, - BC_LEX_KEY_RETURN, - BC_LEX_KEY_SCALE, - BC_LEX_KEY_SQRT, - BC_LEX_KEY_WHILE, + BC_LEX_KEY_ELSE, } BcLexType; @@ -392,23 +435,15 @@ typedef struct BcLex { char *buf; size_t i; size_t line; - char *f; size_t len; - int newline; - struct { - BcLexType t; - BcLexType last; - BcVec v; - } t; + BcLexType t; + BcLexType last; + BcVec str; } BcLex; -#define BC_PARSE_STREND ((char) UCHAR_MAX) - -#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i))) -#define bc_parse_updateFunc(p, f) \ - ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f)))) +#define BC_PARSE_STREND ((uchar) UCHAR_MAX) #define BC_PARSE_REL (1<<0) #define BC_PARSE_PRINT (1<<1) @@ -416,63 +451,21 @@ typedef struct BcLex { #define BC_PARSE_NOREAD (1<<3) #define BC_PARSE_ARRAY (1<<4) -#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t*) bc_vec_top(&(parse)->flags)) -#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse))) - -#define BC_PARSE_FLAG_FUNC_INNER (1<<0) -#define BC_PARSE_FUNC_INNER(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER) - -#define BC_PARSE_FLAG_FUNC (1<<1) -#define BC_PARSE_FUNC(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC) - -#define BC_PARSE_FLAG_BODY (1<<2) -#define BC_PARSE_BODY(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY) - -#define BC_PARSE_FLAG_LOOP (1<<3) -#define BC_PARSE_LOOP(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP) - -#define BC_PARSE_FLAG_LOOP_INNER (1<<4) -#define BC_PARSE_LOOP_INNER(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER) - -#define BC_PARSE_FLAG_IF (1<<5) -#define BC_PARSE_IF(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF) - -#define BC_PARSE_FLAG_ELSE (1<<6) -#define BC_PARSE_ELSE(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE) - -#define BC_PARSE_FLAG_IF_END (1<<7) -#define BC_PARSE_IF_END(parse) \ - (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END) - -#define BC_PARSE_CAN_EXEC(parse) \ - (!(BC_PARSE_TOP_FLAG(parse) & (BC_PARSE_FLAG_FUNC_INNER | \ - BC_PARSE_FLAG_FUNC | \ - BC_PARSE_FLAG_BODY | \ - BC_PARSE_FLAG_LOOP | \ - BC_PARSE_FLAG_LOOP_INNER | \ - BC_PARSE_FLAG_IF | \ - BC_PARSE_FLAG_ELSE | \ - BC_PARSE_FLAG_IF_END))) +#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uchar) (i))) +#define bc_parse_number(p)(bc_parse_addId((p), BC_INST_NUM)) +#define bc_parse_string(p)(bc_parse_addId((p), BC_INST_STR)) -typedef struct BcOp { - char prec; - int left; -} BcOp; +#define bc_parse_err(p, e) (bc_vm_error((e), (p)->l.line)) +#define bc_parse_verr(p, e, ...) (bc_vm_error((e), (p)->l.line, __VA_ARGS__)) typedef struct BcParseNext { - uint32_t len; - BcLexType tokens[4]; + uchar len; + uchar tokens[4]; } BcParseNext; #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ } -#define BC_PARSE_NEXT(a, ...) { .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) } +#define BC_PARSE_NEXT(a, ...) \ + { .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) } struct BcProgram; @@ -481,47 +474,112 @@ typedef struct BcParse { BcLex l; BcVec flags; - BcVec exits; BcVec conds; - BcVec ops; struct BcProgram *prog; BcFunc *func; size_t fidx; - size_t nbraces; int auto_part; } BcParse; typedef struct BcLexKeyword { + uchar data; char name[9]; - char len; - int posix; } BcLexKeyword; -#define BC_LEX_KW_ENTRY(a, b, c) { .name = a, .len = (b), .posix = (c) } +#define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1)) + +#define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1))) +#define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1)))) + +#define BC_LEX_KW_ENTRY(a, b, c) \ + { .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c),.name = a } + +#define bc_lex_posixErr(l, e) (bc_vm_posixError((e), (l)->line)) +#define bc_lex_vposixErr(l, e, ...) \ + (bc_vm_posixError((e), (l)->line, __VA_ARGS__)) BcStatus bc_lex_token(BcLex *l); +#define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags)) +#define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p))) + +#define BC_PARSE_FLAG_BRACE (1<<0) +#define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE) + +#define BC_PARSE_FLAG_FUNC_INNER (1<<1) +#define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER) + +#define BC_PARSE_FLAG_FUNC (1<<2) +#define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC) + +#define BC_PARSE_FLAG_BODY (1<<3) +#define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY) + +#define BC_PARSE_FLAG_LOOP (1<<4) +#define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP) + +#define BC_PARSE_FLAG_LOOP_INNER (1<<5) +#define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER) + +#define BC_PARSE_FLAG_IF (1<<6) +#define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF) + +#define BC_PARSE_FLAG_ELSE (1<<7) +#define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE) + +#define BC_PARSE_FLAG_IF_END (1<<8) +#define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END) + +#define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0) + +#define BC_PARSE_DELIMITER(t) \ + ((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF) + +#define BC_PARSE_BLOCK_STMT(f) \ + ((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER)) + +#define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l))) + +#define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)] +#define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1)) +#define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1))) + +#define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \ + (((e1) << 7) | ((e2) << 6) | ((e3) << 5) | ((e4) << 4) | \ + ((e5) << 3) | ((e6) << 2) | ((e7) << 1) | ((e8) << 0)) + +#define BC_PARSE_EXPR(i) \ + (bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07)))) + #define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops))) -#define BC_PARSE_LEAF(p, rparen) \ - (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \ - (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST) +#define BC_PARSE_LEAF(prev, bin_last, rparen) \ + (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev))) +#define BC_PARSE_INST_VAR(t) \ + ((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY) + +#define BC_PARSE_PREV_PREFIX(p) \ + ((p) >= BC_INST_INC_PRE && (p) <= BC_INST_BOOL_NOT) +#define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG) // We can calculate the conversion between tokens and exprs by subtracting the -// position of the first operator in the lex enum and adding the position of the -// first in the expr enum. Note: This only works for binary operators. -#define BC_PARSE_TOKEN_INST(t) ((char) ((t) - BC_LEX_NEG + BC_INST_NEG)) +// position of the first operator in the lex enum and adding the position of +// the first in the expr enum. Note: This only works for binary operators. +#define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG)) + +#define bc_parse_posixErr(p, e) (bc_vm_posixError((e), (p)->l.line)) BcStatus bc_parse_parse(BcParse *p); -BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); +BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next); + +#define BC_PROG_ONE_CAP (1) typedef struct BcProgram { - size_t len; size_t scale; BcNum ib; @@ -529,8 +587,6 @@ typedef struct BcProgram { BcNum ob; size_t ob_t; - BcNum hexb; - BcVec results; BcVec stack; @@ -543,20 +599,16 @@ typedef struct BcProgram { BcVec arrs; BcVec arr_map; - BcVec strs; - BcVec consts; - - char *file; - - BcNum last; - BcNum zero; BcNum one; + BcNum last; - size_t nchars; + BcDig ib_num[BC_NUM_LONG_LOG10]; + BcDig ob_num[BC_NUM_LONG_LOG10]; + BcDig one_num[BC_PROG_ONE_CAP]; } BcProgram; -#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n)) +#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) (n))) #define BC_PROG_MAIN (0) #define BC_PROG_READ (1) @@ -565,37 +617,67 @@ typedef struct BcProgram { #define BC_PROG_NUM(r, n) \ ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n)) -typedef unsigned long (*BcProgramBuiltIn)(BcNum*); +typedef void (*BcProgramUnary)(BcResult*, BcNum*); -void bc_program_addFunc(BcProgram *p, char *name, size_t *idx); +void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name); +size_t bc_program_insertFunc(BcProgram *p, char *name); BcStatus bc_program_reset(BcProgram *p, BcStatus s); BcStatus bc_program_exec(BcProgram *p); -#define BC_MAX_OBASE ((unsigned long) 999) +unsigned long bc_program_scale(BcNum *n); +unsigned long bc_program_len(BcNum *n); + +void bc_program_negate(BcResult *r, BcNum *n); +void bc_program_not(BcResult *r, BcNum *n); + +#define BC_FLAG_TTYIN (1<<7) +#define BC_TTYIN (toys.optflags & BC_FLAG_TTYIN) + +#define BC_S (toys.optflags & FLAG_s) +#define BC_W (toys.optflags & FLAG_w) +#define BC_L (toys.optflags & FLAG_l) +#define BC_I (toys.optflags & FLAG_i) + +#define BC_MAX_OBASE ((unsigned long) INT_MAX) #define BC_MAX_DIM ((unsigned long) INT_MAX) #define BC_MAX_SCALE ((unsigned long) UINT_MAX) #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1) #define BC_MAX_NAME BC_MAX_STRING #define BC_MAX_NUM BC_MAX_STRING -#define BC_MAX_EXP ((unsigned long) LONG_MAX) +#define BC_MAX_EXP ((unsigned long) ULONG_MAX) #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1) +#define BC_SIGNAL (BC_VM->sig) +#define BC_SIGINT (BC_VM->sig == SIGINT) + +#ifdef SIGQUIT +#define BC_SIGTERM (BC_VM->sig == SIGTERM || BC_VM->sig == SIGQUIT) +#else // SIGQUIT +#define BC_SIGTERM (BC_VM->sig == SIGTERM) +#endif // SIGQUIT + +#define bc_vm_err(e) (bc_vm_error((e), 0)) +#define bc_vm_verr(e, ...) (bc_vm_error((e), 0, __VA_ARGS__)) + typedef struct BcVm { BcParse prs; BcProgram prog; -} BcVm; + size_t nchars; -BcStatus bc_vm_posixError(BcStatus s, char *file, size_t line, char *msg); + char *file; + + uchar sig; -void bc_vm_exit(BcStatus s); -void bc_vm_printf(FILE *f, char *fmt, ...); -void bc_vm_puts(char *str, FILE *f); -void bc_vm_putchar(int c); -void bc_vm_fflush(FILE *f); + uint16_t line_len; + uchar max_ibase; -// clang-format off +} BcVm; + +BcStatus bc_vm_posixError(BcError e, size_t line, ...); + +BcStatus bc_vm_error(BcError e, size_t line, ...); char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n"; @@ -604,53 +686,50 @@ char bc_copyright[] = "Report bugs at: https://github.com/gavinhoward/bc\n\n" "This is free software with ABSOLUTELY NO WARRANTY.\n"; -char bc_err_fmt[] = "\n%s error: %s\n"; -char bc_warn_fmt[] = "\n%s warning: %s\n"; -char bc_err_line[] = ":%zu\n\n"; +char *bc_err_fmt = "\n%s error: "; +char *bc_warn_fmt = "\n%s warning: "; +char *bc_err_line = ":%zu"; char *bc_errs[] = { "VM", - "Lex", "Parse", "Math", "Runtime", - "Vector", "POSIX", }; -uint8_t bc_err_ids[] = { - BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, - BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, +char bc_err_ids[] = { + BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, + BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, + BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, + BC_ERR_IDX_PARSE, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, - BC_ERR_IDX_MATH, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, - BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, - BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, - BC_ERR_IDX_EXEC, - BC_ERR_IDX_VEC, BC_ERR_IDX_VEC, + BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, - BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, + BC_ERR_IDX_POSIX, }; char *bc_err_msgs[] = { - NULL, "memory allocation error", "I/O error", - "file is not text:", - "path is a directory:", + "file is not ASCII: %s", + "path is a directory: %s", - "bad character", + "end of file", + "bad character (%c)", "string end could not be found", "comment end could not be found", - "end of file", - "bad token", + "name too long: must be [1, %lu]", + "string too long: must be [1, %lu]", + "array too long; must be [1, %lu]", "bad expression", "empty expression", "bad print statement", @@ -658,99 +737,100 @@ char *bc_err_msgs[] = { "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", + "function parameter or auto \"%s\" already exists", "block end could not be found", + "cannot return a value from void function: %s()", "negative number", "non integer number", - "overflow", + "overflow; %s", "divide by zero", - "bad number string", - - "could not open file:", - "mismatched parameters", - "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]", - "bad scale; must be [0, BC_SCALE_MAX]", + + "could not open file: %s", + "number too long: must be [1, %lu]", + "bad ibase; must be [%lu, %lu]", + "bad obase; must be [%lu, %lu]", + "bad scale; must be [%lu, %lu]", "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", + "mismatched parameters; need %zu, have %zu", + "undefined function: %s()", + "cannot use a void value in an expression", - "index is out of bounds", - "item already exists", - - "POSIX only allows one character names; the following is bad:", + "POSIX does not allow names longer than 1 character, like \"%s\"", "POSIX does not allow '#' script comments", - "POSIX does not allow the following keyword:", + "POSIX does not allow \"%s\" as a keyword", "POSIX does not allow a period ('.') as a shortcut for the last result", "POSIX requires parentheses around return expressions", - "POSIX does not allow intean operators; the following is bad:", + "POSIX does not allow the \"%s\" operators", "POSIX does not allow comparison operators outside if or loops", - "POSIX requires exactly one comparison operator per condition", + "POSIX requires zero or one comparison operator per condition", "POSIX does not allow an empty init expression in a for loop", "POSIX does not allow an empty condition expression in a for loop", "POSIX does not allow an empty update expression in a for loop", "POSIX requires the left brace be on the same line as the function header", + "POSIX does not allow array references as function parameters", }; char bc_func_main[] = "(main)"; char bc_func_read[] = "(read)"; -BcLexKeyword bc_lex_kws[20] = { +BcLexKeyword bc_lex_kws[] = { BC_LEX_KW_ENTRY("auto", 4, 1), BC_LEX_KW_ENTRY("break", 5, 1), BC_LEX_KW_ENTRY("continue", 8, 0), BC_LEX_KW_ENTRY("define", 6, 1), - BC_LEX_KW_ENTRY("else", 4, 0), BC_LEX_KW_ENTRY("for", 3, 1), - BC_LEX_KW_ENTRY("halt", 4, 0), - BC_LEX_KW_ENTRY("ibase", 5, 1), BC_LEX_KW_ENTRY("if", 2, 1), - BC_LEX_KW_ENTRY("last", 4, 0), - BC_LEX_KW_ENTRY("length", 6, 1), BC_LEX_KW_ENTRY("limits", 6, 0), + BC_LEX_KW_ENTRY("return", 6, 1), + BC_LEX_KW_ENTRY("while", 5, 1), + BC_LEX_KW_ENTRY("halt", 4, 0), + BC_LEX_KW_ENTRY("last", 4, 0), + BC_LEX_KW_ENTRY("ibase", 5, 1), BC_LEX_KW_ENTRY("obase", 5, 1), + BC_LEX_KW_ENTRY("scale", 5, 1), + BC_LEX_KW_ENTRY("length", 6, 1), BC_LEX_KW_ENTRY("print", 5, 0), + BC_LEX_KW_ENTRY("sqrt", 4, 1), + BC_LEX_KW_ENTRY("abs", 3, 0), BC_LEX_KW_ENTRY("quit", 4, 1), BC_LEX_KW_ENTRY("read", 4, 0), - BC_LEX_KW_ENTRY("return", 6, 1), - BC_LEX_KW_ENTRY("scale", 5, 1), - BC_LEX_KW_ENTRY("sqrt", 4, 1), - BC_LEX_KW_ENTRY("while", 5, 1), + BC_LEX_KW_ENTRY("else", 4, 0), }; +size_t bc_lex_kws_len = sizeof(bc_lex_kws) / sizeof(BcLexKeyword); + +char *bc_parse_const1 = "1"; + // This is an array that corresponds to token types. An entry is // 1 if the token is valid in an expression, 0 otherwise. -int bc_parse_exprs[] = { - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, - 1, 0, +uint8_t bc_parse_exprs[] = { + BC_PARSE_EXPR_ENTRY(0, 0, 1, 1, 1, 1, 1, 1), + BC_PARSE_EXPR_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + BC_PARSE_EXPR_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + BC_PARSE_EXPR_ENTRY(1, 1, 1, 0, 0, 1, 1, 0), + BC_PARSE_EXPR_ENTRY(0, 0, 0, 0, 0, 0, 1, 1), + BC_PARSE_EXPR_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + BC_PARSE_EXPR_ENTRY(0, 0, 1, 1, 1, 1, 1, 0), + BC_PARSE_EXPR_ENTRY(1, 1, 0, 1, 0, 0, 0, 0) }; // This is an array of data for operators that correspond to token types. -BcOp bc_parse_ops[] = { - { 0, 0 }, { 0, 0 }, - { 1, 0 }, - { 2, 0 }, - { 3, 1 }, { 3, 1 }, { 3, 1 }, - { 4, 1 }, { 4, 1 }, - { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, - { 1, 0 }, - { 7, 1 }, { 7, 1 }, - { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, - { 5, 0 }, { 5, 0 }, +uchar bc_parse_ops[] = { + BC_PARSE_OP(0, 0), BC_PARSE_OP(0, 0), + BC_PARSE_OP(1, 0), BC_PARSE_OP(1, 0), + BC_PARSE_OP(4, 0), + BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1), + BC_PARSE_OP(6, 1), BC_PARSE_OP(6, 1), + BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), + BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), + BC_PARSE_OP(11, 1), BC_PARSE_OP(10, 1), + BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), + BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), + BC_PARSE_OP(8, 0), }; // These identify what tokens can come after expressions in certain cases. @@ -772,96 +852,98 @@ BcNumBinaryOp bc_program_ops[] = { bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub, }; +BcNumBinaryOpReq bc_program_opReqs[] = { + bc_num_powReq, bc_num_mulReq, bc_num_mulReq, bc_num_mulReq, + bc_num_addReq, bc_num_addReq, +}; + +BcProgramUnary bc_program_unarys[] = { + bc_program_negate, bc_program_not, +}; + char bc_program_stdin_name[] = "<stdin>"; char bc_program_ready_msg[] = "ready for more input\n"; +char bc_program_esc_chars[] = "ab\\efnqrt"; +char bc_program_esc_seqs[] = "\a\b\\\\\f\n\"\r\t"; -// clang-format on char *bc_lib_name = "gen/lib.bc"; char bc_lib[] = { 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123, - 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102, - 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102, - 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115, - 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99, - 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40, - 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108, - 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10, - 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33, - 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9, - 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40, - 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10, - 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114, - 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10, - 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115, - 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9, - 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40, - 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10, - 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101, - 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40, - 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120, - 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112, - 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61, - 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9, - 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42, - 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61, - 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101, - 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40, - 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105, - 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99, - 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40, - 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120, - 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47, - 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41, - 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10, - 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105, - 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9, - 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101, - 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47, - 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105, - 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105, - 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10, - 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43, - 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114, - 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97, - 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44, - 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101, - 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10, - 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102, - 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46, - 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56, - 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55, - 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10, - 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60, - 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53, - 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48, - 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54, - 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101, - 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9, - 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119, - 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40, - 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120, - 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116, - 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105, - 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97, - 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110, - 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117, - 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97, - 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115, - 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9, - 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125, - 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41, - 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94, - 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47, - 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40, - 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33, - 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105, - 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98, - 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116, - 117,114,110,40,97,42,114,47,49,41,10,125,10,0 + 10,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,44, + 118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120, + 60,48,41,123,10,110,61,49,10,120,61,45,120,10,125,10,115,61,115,99,97,108,101, + 10,114,61,54,43,115,43,46,52,52,42,120,10,115,99,97,108,101,61,115,99,97,108, + 101,40,120,41,43,49,10,119,104,105,108,101,40,120,62,49,41,123,10,100,43,61, + 49,10,120,47,61,50,10,115,99,97,108,101,43,61,49,10,125,10,115,99,97,108,101, + 61,114,10,114,61,120,43,49,10,112,61,120,10,102,61,118,61,49,10,102,111,114, + 40,105,61,50,59,118,59,43,43,105,41,123,10,112,42,61,120,10,102,42,61,105,10, + 118,61,112,47,102,10,114,43,61,118,10,125,10,119,104,105,108,101,40,100,45, + 45,41,114,42,61,114,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98, + 10,105,102,40,110,41,114,101,116,117,114,110,40,49,47,114,41,10,114,101,116, + 117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,108,40,120, + 41,123,10,97,117,116,111,32,98,44,115,44,114,44,112,44,97,44,113,44,105,44, + 118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120, + 60,61,48,41,123,10,114,61,40,49,45,49,48,94,115,99,97,108,101,41,47,49,10,105, + 98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125,10,115,61,115, + 99,97,108,101,10,115,99,97,108,101,43,61,54,10,112,61,50,10,119,104,105,108, + 101,40,120,62,61,50,41,123,10,112,42,61,50,10,120,61,115,113,114,116,40,120, + 41,10,125,10,119,104,105,108,101,40,120,60,61,46,53,41,123,10,112,42,61,50, + 10,120,61,115,113,114,116,40,120,41,10,125,10,114,61,97,61,40,120,45,49,41, + 47,40,120,43,49,41,10,113,61,97,42,97,10,118,61,49,10,102,111,114,40,105,61, + 51,59,118,59,105,43,61,50,41,123,10,97,42,61,113,10,118,61,97,47,105,10,114, + 43,61,118,10,125,10,114,42,61,112,10,115,99,97,108,101,61,115,10,105,98,97, + 115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101, + 102,105,110,101,32,115,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114, + 44,97,44,113,44,105,10,105,102,40,120,60,48,41,114,101,116,117,114,110,40,45, + 115,40,45,120,41,41,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10, + 115,61,115,99,97,108,101,10,115,99,97,108,101,61,49,46,49,42,115,43,50,10,97, + 61,97,40,49,41,10,115,99,97,108,101,61,48,10,113,61,40,120,47,97,43,50,41,47, + 52,10,120,45,61,52,42,113,42,97,10,105,102,40,113,37,50,41,120,61,45,120,10, + 115,99,97,108,101,61,115,43,50,10,114,61,97,61,120,10,113,61,45,120,42,120, + 10,102,111,114,40,105,61,51,59,97,59,105,43,61,50,41,123,10,97,42,61,113,47, + 40,105,42,40,105,45,49,41,41,10,114,43,61,97,10,125,10,115,99,97,108,101,61, + 115,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10, + 125,10,100,101,102,105,110,101,32,99,40,120,41,123,10,97,117,116,111,32,98, + 44,115,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,115,61,115, + 99,97,108,101,10,115,99,97,108,101,42,61,49,46,50,10,120,61,115,40,50,42,97, + 40,49,41,43,120,41,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10, + 114,101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32, + 97,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109, + 44,116,44,102,44,105,44,117,10,98,61,105,98,97,115,101,10,105,98,97,115,101, + 61,65,10,110,61,49,10,105,102,40,120,60,48,41,123,10,110,61,45,49,10,120,61, + 45,120,10,125,10,105,102,40,115,99,97,108,101,60,54,53,41,123,10,105,102,40, + 120,61,61,49,41,123,10,114,61,46,55,56,53,51,57,56,49,54,51,51,57,55,52,52, + 56,51,48,57,54,49,53,54,54,48,56,52,53,56,49,57,56,55,53,55,50,49,48,52,57, + 50,57,50,51,52,57,56,52,51,55,55,54,52,53,53,50,52,51,55,51,54,49,52,56,48, + 47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125, + 10,105,102,40,120,61,61,46,50,41,123,10,114,61,46,49,57,55,51,57,53,53,53,57, + 56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,50, + 57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,56, + 56,57,52,48,50,47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110, + 40,114,41,10,125,10,125,10,115,61,115,99,97,108,101,10,105,102,40,120,62,46, + 50,41,123,10,115,99,97,108,101,43,61,53,10,97,61,97,40,46,50,41,10,125,10,115, + 99,97,108,101,61,115,43,51,10,119,104,105,108,101,40,120,62,46,50,41,123,10, + 109,43,61,49,10,120,61,40,120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,125, + 10,114,61,117,61,120,10,102,61,45,120,42,120,10,116,61,49,10,102,111,114,40, + 105,61,51,59,116,59,105,43,61,50,41,123,10,117,42,61,102,10,116,61,117,47,105, + 10,114,43,61,116,10,125,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61, + 98,10,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,41,10,125,10, + 100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,97,117,116,111,32,98, + 44,115,44,111,44,97,44,105,44,118,44,102,10,98,61,105,98,97,115,101,10,105, + 98,97,115,101,61,65,10,115,61,115,99,97,108,101,10,115,99,97,108,101,61,48, + 10,110,47,61,49,10,105,102,40,110,60,48,41,123,10,110,61,45,110,10,111,61,110, + 37,50,10,125,10,97,61,49,10,102,111,114,40,105,61,50,59,105,60,61,110,59,43, + 43,105,41,97,42,61,105,10,115,99,97,108,101,61,49,46,53,42,115,10,97,61,40, + 120,94,110,41,47,50,94,110,47,97,10,114,61,118,61,49,10,102,61,45,120,42,120, + 47,52,10,115,99,97,108,101,43,61,108,101,110,103,116,104,40,97,41,45,115,99, + 97,108,101,40,97,41,10,102,111,114,40,105,61,49,59,118,59,43,43,105,41,123, + 10,118,61,118,42,102,47,105,47,40,110,43,105,41,10,114,43,61,118,10,125,10, + 115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10,105,102,40,111,41,97, + 61,45,97,10,114,101,116,117,114,110,40,97,42,114,47,49,41,10,125,10,0 }; -void bc_vec_grow(BcVec *v, size_t n) { +static void bc_vec_grow(BcVec *v, size_t n) { size_t cap = v->cap * 2; while (cap < v->len + n) cap *= 2; v->v = xrealloc(v->v, v->size * cap); @@ -891,17 +973,35 @@ void bc_vec_npop(BcVec *v, size_t n) { } } +void bc_vec_npush(BcVec *v, size_t n, void *data) { + if (v->len + n > v->cap) bc_vec_grow(v, n); + memcpy(v->v + (v->size * v->len), data, v->size * n); + v->len += n; +} + void bc_vec_push(BcVec *v, void *data) { - if (v->len + 1 > v->cap) bc_vec_grow(v, 1); - memmove(v->v + (v->size * v->len), data, v->size); - v->len += 1; + bc_vec_npush(v, 1, data); } -void bc_vec_pushByte(BcVec *v, char data) { +void bc_vec_pushByte(BcVec *v, uchar data) { bc_vec_push(v, &data); } -void bc_vec_pushAt(BcVec *v, void *data, size_t idx) { +void bc_vec_pushIndex(BcVec *v, size_t idx) { + + uchar amt, nums[sizeof(size_t)]; + + for (amt = 0; idx; ++amt) { + nums[amt] = (uchar) idx; + idx &= ((size_t) ~(UCHAR_MAX)); + idx >>= sizeof(uchar) * CHAR_BIT; + } + + bc_vec_push(v, &amt); + bc_vec_npush(v, amt, nums); +} + +static void bc_vec_pushAt(BcVec *v, void *data, size_t idx) { if (idx == v->len) bc_vec_push(v, data); else { @@ -931,7 +1031,7 @@ void bc_vec_concat(BcVec *v, char *str) { size_t len; - if (v->len == 0) bc_vec_pushByte(v, '\0'); + if (!v->len) bc_vec_pushByte(v, '\0'); len = v->len + strlen(str); @@ -941,6 +1041,11 @@ void bc_vec_concat(BcVec *v, char *str) { v->len = len; } +void bc_vec_empty(BcVec *v) { + bc_vec_npop(v, v->len); + bc_vec_pushByte(v, '\0'); +} + void* bc_vec_item(BcVec *v, size_t idx) { return v->v + v->size * idx; } @@ -955,7 +1060,7 @@ void bc_vec_free(void *vec) { free(v->v); } -size_t bc_map_find(BcVec *v, void *ptr) { +static size_t bc_map_find(BcVec *v, BcId *ptr) { size_t low = 0, high = v->len; @@ -965,7 +1070,7 @@ size_t bc_map_find(BcVec *v, void *ptr) { BcId *id = bc_vec_item(v, mid); int result = bc_id_cmp(ptr, id); - if (result == 0) return mid; + if (!result) return mid; else if (result < 0) high = mid; else low = mid + 1; } @@ -973,38 +1078,47 @@ size_t bc_map_find(BcVec *v, void *ptr) { return low; } -BcStatus bc_map_insert(BcVec *v, void *ptr, size_t *i) { - - BcStatus s = BC_STATUS_SUCCESS; +int bc_map_insert(BcVec *v, BcId *ptr, size_t *i) { *i = bc_map_find(v, ptr); if (*i == v->len) bc_vec_push(v, ptr); - else if (!bc_id_cmp(ptr, bc_vec_item(v, *i))) s = BC_STATUS_VEC_ITEM_EXISTS; + else if (!bc_id_cmp(ptr, bc_vec_item(v, *i))) return 0; else bc_vec_pushAt(v, ptr, *i); - return s; + return 1; } -size_t bc_map_index(BcVec* v, void *ptr) { +size_t bc_map_index(BcVec *v, BcId *ptr) { size_t i = bc_map_find(v, ptr); - if (i >= v->len) return ((size_t) -1); - return bc_id_cmp(ptr, bc_vec_item(v, i)) ? ((size_t) -1) : i; + if (i >= v->len) return SIZE_MAX; + return bc_id_cmp(ptr, bc_vec_item(v, i)) ? SIZE_MAX : i; } -BcStatus bc_read_line(BcVec *vec, char* prompt) { +static int bc_read_binary(char *buf, size_t size) { - int i; - signed char c = 0; + size_t i; - if (TT.ttyin && !(toys.optflags & FLAG_s)) { - bc_vm_puts(prompt, stderr); - bc_vm_fflush(stderr); + for (i = 0; i < size; ++i) { + if (BC_READ_BIN_CHAR(buf[i])) return 1; } + return 0; +} + +BcStatus bc_read_chars(BcVec *vec, char *prompt) { + + int i; + signed char c = 0; + bc_vec_npop(vec, vec->len); - while (c != '\n') { + if (BC_TTYIN && !BC_S) { + fputs(prompt, stderr); + fflush(stderr); + } + + while (!BC_SIGNAL && c != '\n') { i = fgetc(stdin); @@ -1012,45 +1126,63 @@ BcStatus bc_read_line(BcVec *vec, char* prompt) { if (errno == EINTR) { - TT.sigc = TT.sig; - TT.signe = 0; + if (BC_SIGTERM) return BC_STATUS_SIGNAL; + + BC_VM->sig = 0; - if (TT.ttyin) { - bc_vm_puts(bc_program_ready_msg, stderr); - if (!(toys.optflags & FLAG_s)) bc_vm_puts(prompt, stderr); - bc_vm_fflush(stderr); + if (BC_TTYIN) { + fputs(bc_program_ready_msg, stderr); + if (!BC_S) fputs(prompt, stderr); + fflush(stderr); } + else return BC_STATUS_SIGNAL; continue; } - return BC_STATUS_IO_ERR; + bc_vec_pushByte(vec, '\0'); + return BC_STATUS_EOF; } c = (signed char) i; - if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE; bc_vec_push(vec, &c); } bc_vec_pushByte(vec, '\0'); + return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS; +} + +BcStatus bc_read_line(BcVec *vec, char *prompt) { + + BcStatus s; + + // We are about to output to stderr, so flush stdout to + // make sure that we don't get the outputs mixed up. + fflush(stdout); + + s = bc_read_chars(vec, prompt); + if (s && s != BC_STATUS_EOF) return s; + if (bc_read_binary(vec->v, vec->len - 1)) + return bc_vm_verr(BC_ERROR_VM_BIN_FILE, bc_program_stdin_name); + return BC_STATUS_SUCCESS; } BcStatus bc_read_file(char *path, char **buf) { - BcStatus s = BC_STATUS_IO_ERR; + BcError e = BC_ERROR_VM_IO_ERR; FILE *f; size_t size, read; long res; struct stat pstat; f = fopen(path, "r"); - if (!f) bc_vm_exit(BC_STATUS_EXEC_FILE_ERR); + if (!f) return bc_vm_verr(BC_ERROR_EXEC_FILE_ERR, path); if (fstat(fileno(f), &pstat) == -1) goto malloc_err; if (S_ISDIR(pstat.st_mode)) { - s = BC_STATUS_PATH_IS_DIR; + e = BC_ERROR_VM_PATH_DIR; goto malloc_err; } @@ -1066,10 +1198,10 @@ BcStatus bc_read_file(char *path, char **buf) { if (read != size) goto read_err; (*buf)[size] = '\0'; - s = BC_STATUS_BIN_FILE; - for (read = 0; read < size; ++read) { - if (BC_READ_BIN_CHAR((*buf)[read])) goto read_err; + if (bc_read_binary(*buf, size)) { + e = BC_ERROR_VM_BIN_FILE; + goto read_err; } fclose(f); @@ -1080,16 +1212,16 @@ read_err: free(*buf); malloc_err: fclose(f); - return s; + return bc_vm_verr(e, path); } -void bc_num_setToZero(BcNum *n, size_t scale) { +static void bc_num_setToZero(BcNum *n, size_t scale) { n->len = 0; n->neg = 0; n->rdx = scale; } -void bc_num_zero(BcNum *n) { +static void bc_num_zero(BcNum *n) { bc_num_setToZero(n, 0); } @@ -1106,21 +1238,29 @@ void bc_num_ten(BcNum *n) { n->num[1] = 1; } -BcStatus bc_num_subArrays(BcDig *a, BcDig *b, size_t len) { +static size_t bc_num_log10(size_t i) { + size_t len; + for (len = 1; i; i /= 10, ++len); + return len; +} + +static BcStatus bc_num_subArrays(BcDig *a, BcDig *b, size_t len) +{ size_t i, j; - for (i = 0; !TT.signe && i < len; ++i) { - for (a[i] -= b[i], j = 0; !TT.signe && a[i + j] < 0;) { + for (i = 0; !BC_SIGNAL && i < len; ++i) { + for (a[i] -= b[i], j = 0; !BC_SIGNAL && a[i + j] < 0;) { a[i + j++] += 10; a[i + j] -= 1; } } - return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; + return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS; } -ssize_t bc_num_compare(BcDig *a, BcDig *b, size_t len) { +static ssize_t bc_num_compare(BcDig *a, BcDig *b, size_t len) +{ size_t i; int c = 0; - for (i = len - 1; !TT.signe && i < len && !(c = a[i] - b[i]); --i); + for (i = len - 1; !BC_SIGNAL && i < len && !(c = a[i] - b[i]); --i); return BC_NUM_NEG(i + 1, c < 0); } @@ -1132,8 +1272,8 @@ ssize_t bc_num_cmp(BcNum *a, BcNum *b) { ssize_t cmp; if (a == b) return 0; - if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg); - if (b->len == 0) return BC_NUM_NEG(1, a->neg); + if (!a->len) return BC_NUM_NEG(b->len != 0, !b->neg); + if (!b->len) return BC_NUM_CMP_ZERO(a); if (a->neg) { if (b->neg) neg = 1; else return -1; @@ -1163,58 +1303,59 @@ ssize_t bc_num_cmp(BcNum *a, BcNum *b) { cmp = bc_num_compare(max_num, min_num, b_int + min); if (cmp) return BC_NUM_NEG(cmp, (!a_max) != neg); - for (max_num -= diff, i = diff - 1; !TT.signe && i < diff; --i) { + for (max_num -= diff, i = diff - 1; !BC_SIGNAL && i < diff; --i) { if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg); } return 0; } +static void bc_num_clean(BcNum *n) { + while (n->len && !n->num[n->len - 1]) --n->len; + if (!n->len) n->neg = 0; + else if (n->len < n->rdx) n->len = n->rdx; +} + void bc_num_truncate(BcNum *n, size_t places) { - if (places == 0) return; + if (!places) return; n->rdx -= places; if (n->len) { n->len -= places; memmove(n->num, n->num + places, n->len * sizeof(BcDig)); + bc_num_clean(n); } } -void bc_num_extend(BcNum *n, size_t places) { +static void bc_num_extend(BcNum *n, size_t places) { size_t len = n->len + places; - if (places) { + if (!places) return; - if (n->cap < len) bc_num_expand(n, len); + if (n->cap < len) bc_num_expand(n, len); - memmove(n->num + places, n->num, sizeof(BcDig) * n->len); - memset(n->num, 0, sizeof(BcDig) * places); + memmove(n->num + places, n->num, sizeof(BcDig) * n->len); + memset(n->num, 0, sizeof(BcDig) * places); - n->len += places; - n->rdx += places; - } -} + if (n->len) n->len += places; -void bc_num_clean(BcNum *n) { - while (n->len > 0 && n->num[n->len - 1] == 0) --n->len; - if (n->len == 0) n->neg = 0; - else if (n->len < n->rdx) n->len = n->rdx; + n->rdx += places; } -void bc_num_retireMul(BcNum *n, size_t scale, int neg1, int neg2) { +static void bc_num_retireMul(BcNum *n, size_t scale, int neg1, int neg2) { if (n->rdx < scale) bc_num_extend(n, scale - n->rdx); else bc_num_truncate(n, n->rdx - scale); bc_num_clean(n); - if (n->len) n->neg = !neg1 != !neg2; + if (n->len) n->neg = (!neg1 != !neg2); } -void bc_num_split(BcNum *n, size_t idx, BcNum *a, BcNum *b) -{ +static void bc_num_split(BcNum *n, size_t idx, BcNum *a, BcNum *b) { + if (idx < n->len) { b->len = n->len - idx; @@ -1223,20 +1364,19 @@ void bc_num_split(BcNum *n, size_t idx, BcNum *a, BcNum *b) memcpy(b->num, n->num + idx, b->len * sizeof(BcDig)); memcpy(a->num, n->num, idx * sizeof(BcDig)); + + bc_num_clean(b); } - else { - bc_num_zero(b); - bc_num_copy(a, n); - } + else bc_num_copy(a, n); bc_num_clean(a); - bc_num_clean(b); } -BcStatus bc_num_shift(BcNum *n, size_t places) { +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) return BC_STATUS_SUCCESS; + if (places + n->len > BC_MAX_NUM) + return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "shifted left too far"); if (n->rdx >= places) n->rdx -= places; else { @@ -1249,7 +1389,7 @@ BcStatus bc_num_shift(BcNum *n, size_t places) { return BC_STATUS_SUCCESS; } -BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) { +static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) { BcNum one; BcDig num[2]; @@ -1261,21 +1401,28 @@ BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) { return bc_num_div(&one, a, b, scale); } -BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) { +static unsigned int bc_num_addDigit(BcDig *num, unsigned int d, unsigned int c) +{ + d += c; + *num = (BcDig) (d % 10); + return d / 10; +} + +static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) { BcDig *ptr, *ptr_a, *ptr_b, *ptr_c; size_t i, max, min_rdx, min_int, diff, a_int, b_int; - int carry, in; + unsigned int carry; // Because this function doesn't need to use scale (per the bc spec), // I am hijacking it to say whether it's doing an add or a subtract. - if (a->len == 0) { + if (!a->len) { bc_num_copy(c, b); if (sub && c->len) c->neg = !c->neg; return BC_STATUS_SUCCESS; } - else if (b->len == 0) { + if (!b->len) { bc_num_copy(c, a); return BC_STATUS_SUCCESS; } @@ -1283,7 +1430,6 @@ BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) { c->neg = a->neg; c->rdx = maxof(a->rdx, b->rdx); min_rdx = minof(a->rdx, b->rdx); - c->len = 0; if (a->rdx > b->rdx) { diff = a->rdx - b->rdx; @@ -1298,8 +1444,9 @@ BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) { ptr_b = b->num + diff; } - for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i]; + for (ptr_c = c->num, i = 0; i < diff; ++i) ptr_c[i] = ptr[i]; + c->len = diff; ptr_c += diff; a_int = BC_NUM_INT(a); b_int = BC_NUM_INT(b); @@ -1315,24 +1462,22 @@ BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) { ptr = ptr_b; } - for (carry = 0, i = 0; !TT.signe && i < min_rdx + min_int; ++i, ++c->len) { - in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry; - carry = in / 10; - ptr_c[i] = (BcDig) (in % 10); + for (carry = 0, i = 0; !BC_SIGNAL && i < min_rdx + min_int; ++i) { + unsigned int in = (unsigned int) (ptr_a[i] + ptr_b[i]); + carry = bc_num_addDigit(ptr_c + i, in, carry); } - for (; !TT.signe && i < max + min_rdx; ++i, ++c->len) { - in = ((int) ptr[i]) + carry; - carry = in / 10; - ptr_c[i] = (BcDig) (in % 10); - } + for (; !BC_SIGNAL && i < max + min_rdx; ++i) + carry = bc_num_addDigit(ptr_c + i, (unsigned int) ptr[i], carry); + + c->len += i; if (carry) c->num[c->len++] = (BcDig) carry; - return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; + return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS; } -BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { +static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { BcStatus s; ssize_t cmp; @@ -1343,12 +1488,12 @@ BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { // Because this function doesn't need to use scale (per the bc spec), // I am hijacking it to say whether it's doing an add or a subtract. - if (a->len == 0) { + if (!a->len) { bc_num_copy(c, b); if (sub && c->len) c->neg = !c->neg; return BC_STATUS_SUCCESS; } - else if (b->len == 0) { + if (!b->len) { bc_num_copy(c, a); return BC_STATUS_SUCCESS; } @@ -1362,11 +1507,12 @@ BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { a->neg = aneg; b->neg = bneg; - if (cmp == 0) { + if (!cmp) { bc_num_setToZero(c, maxof(a->rdx, b->rdx)); return BC_STATUS_SUCCESS; } - else if (cmp > 0) { + + if (cmp > 0) { neg = a->neg; minuend = a; subtrahend = b; @@ -1394,20 +1540,20 @@ BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { return s; } -BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *c) { +static BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *c) { BcStatus s; - int carry; - size_t i, j, len, max = maxof(a->len, b->len), max2 = (max + 1) / 2; + size_t max = maxof(a->len, b->len), max2 = (max + 1) / 2; BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp; int aone = BC_NUM_ONE(a); - if (TT.signe) return BC_STATUS_EXEC_SIGNAL; - if (a->len == 0 || b->len == 0) { + // This is here because the function is recursive. + if (BC_SIGNAL) return BC_STATUS_SIGNAL; + if (!a->len || !b->len) { bc_num_zero(c); return BC_STATUS_SUCCESS; } - else if (aone || BC_NUM_ONE(b)) { + if (aone || BC_NUM_ONE(b)) { bc_num_copy(c, aone ? b : a); return BC_STATUS_SUCCESS; } @@ -1415,28 +1561,35 @@ BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *c) { if (a->len + b->len < BC_NUM_KARATSUBA_LEN || a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN) { + size_t i, j, len; + unsigned int carry; + BcDig *ptr_c; + bc_num_expand(c, a->len + b->len + 1); - memset(c->num, 0, sizeof(BcDig) * c->cap); - c->len = carry = len = 0; + ptr_c = c->num; + memset(ptr_c, 0, sizeof(BcDig) * c->cap); + c->len = len = 0; - for (i = 0; !TT.signe && i < b->len; ++i) { + for (i = 0; !BC_SIGNAL && i < b->len; ++i) { - for (j = 0; !TT.signe && j < a->len; ++j) { - int in = (int) c->num[i + j]; - in += ((int) a->num[j]) * ((int) b->num[i]) + carry; - carry = in / 10; - c->num[i + j] = (BcDig) (in % 10); - } + BcDig *ptr = ptr_c + i; - c->num[i + j] += (BcDig) carry; - len = maxof(len, i + j + !!carry); carry = 0; + + for (j = 0; !BC_SIGNAL && j < a->len; ++j) { + unsigned int in = (uchar) ptr[j]; + in += ((unsigned int) a->num[j]) * ((unsigned int) b->num[i]); + carry = bc_num_addDigit(ptr + j, in, carry); + } + + ptr[j] += (BcDig) carry; + len = maxof(len, i + j + (carry != 0)); } c->len = len; - return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; + return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS; } bc_num_init(&l1, max); @@ -1492,7 +1645,7 @@ err: return s; } -BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcStatus s; BcNum cpa, cpb; @@ -1503,11 +1656,9 @@ BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) { scale = minof(a->rdx + b->rdx, scale); maxrdx = maxof(maxrdx, scale); - bc_num_init(&cpa, a->len); - bc_num_init(&cpb, b->len); + bc_num_createCopy(&cpa, a); + bc_num_createCopy(&cpb, b); - bc_num_copy(&cpa, a); - bc_num_copy(&cpb, b); cpa.neg = cpb.neg = 0; s = bc_num_shift(&cpa, maxrdx); @@ -1534,7 +1685,7 @@ err: return s; } -BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcStatus s = BC_STATUS_SUCCESS; BcDig *n, *p, q; @@ -1542,18 +1693,18 @@ BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcNum cp; int zero = 1; - if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO; - else if (a->len == 0) { + if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO); + if (!a->len) { bc_num_setToZero(c, scale); return BC_STATUS_SUCCESS; } - else if (BC_NUM_ONE(b)) { + if (BC_NUM_ONE(b)) { bc_num_copy(c, a); bc_num_retireMul(c, scale, a->neg, b->neg); return BC_STATUS_SUCCESS; } - bc_num_init(&cp, BC_NUM_MREQ(a, b, scale)); + bc_num_init(&cp, bc_num_mulReq(a, b, scale)); bc_num_copy(&cp, a); len = b->len; @@ -1579,15 +1730,14 @@ BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { bc_num_expand(c, cp.len); - bc_num_zero(c); memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig)); c->rdx = cp.rdx; c->len = cp.len; p = b->num; - for (i = end - 1; !TT.signe && !s && i < end; --i) { + for (i = end - 1; !BC_SIGNAL && !s && i < end; --i) { n = cp.num + i; - for (q = 0; (!s && n[len]) || bc_num_compare(n, p, len) >= 0; ++q) + for (q = 0; !s && (n[len] || bc_num_compare(n, p, len) >= 0); ++q) s = bc_num_subArrays(n, p, len); c->num[i] = q; } @@ -1598,16 +1748,16 @@ BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { return s; } -BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale, +static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale, size_t ts) { BcStatus s; BcNum temp; int neg; - if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO; - - if (a->len == 0) { + if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO); + if (!a->len) { + bc_num_setToZero(c, ts); bc_num_setToZero(d, ts); return BC_STATUS_SUCCESS; } @@ -1633,11 +1783,11 @@ err: return s; } -BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcStatus s; BcNum c1; - size_t ts = maxof(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts); + size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts); bc_num_init(&c1, len); s = bc_num_r(a, b, &c1, c, scale, ts); @@ -1646,25 +1796,25 @@ BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *c, size_t scale) { return s; } -BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcStatus s = BC_STATUS_SUCCESS; BcNum copy; - unsigned long pow; + unsigned long pow = 0; size_t i, powrdx, resrdx; int neg, zero; - if (b->rdx) return BC_STATUS_MATH_NON_INTEGER; + if (b->rdx) return bc_vm_err(BC_ERROR_MATH_NON_INTEGER); - if (b->len == 0) { + if (!b->len) { bc_num_one(c); return BC_STATUS_SUCCESS; } - else if (a->len == 0) { + if (!a->len) { bc_num_setToZero(c, scale); return BC_STATUS_SUCCESS; } - else if (BC_NUM_ONE(b)) { + if (BC_NUM_ONE(b)) { if (!b->neg) bc_num_copy(c, a); else s = bc_num_inv(a, c, scale); return s; @@ -1672,31 +1822,29 @@ BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { neg = b->neg; b->neg = 0; - s = bc_num_ulong(b, &pow); + b->neg = neg; if (s) return s; - bc_num_init(©, a->len); - bc_num_copy(©, a); + bc_num_createCopy(©, a); if (!neg) scale = minof(a->rdx * pow, maxof(scale, a->rdx)); - b->neg = neg; - - for (powrdx = a->rdx; !TT.signe && !(pow & 1); pow >>= 1) { + for (powrdx = a->rdx; !BC_SIGNAL && !(pow & 1); pow >>= 1) { powrdx <<= 1; s = bc_num_mul(©, ©, ©, powrdx); if (s) goto err; } - if (TT.signe) { - s = BC_STATUS_EXEC_SIGNAL; + if (BC_SIGNAL) { + s = BC_STATUS_SIGNAL; goto err; } bc_num_copy(c, ©); + resrdx = powrdx; - for (resrdx = powrdx, pow >>= 1; !TT.signe && pow; pow >>= 1) { + while (!BC_SIGNAL && (pow >>= 1)) { powrdx <<= 1; s = bc_num_mul(©, ©, ©, powrdx); @@ -1714,8 +1862,8 @@ BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { if (s) goto err; } - if (TT.signe) { - s = BC_STATUS_EXEC_SIGNAL; + if (BC_SIGNAL) { + s = BC_STATUS_SIGNAL; goto err; } @@ -1730,8 +1878,8 @@ err: return s; } -BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, - BcNumBinaryOp op, size_t req) +static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, + BcNumBinaryOp op, size_t req) { BcStatus s; BcNum num2, *ptr_a, *ptr_b; @@ -1763,37 +1911,18 @@ BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, return s; } -int bc_num_strValid(char *val, size_t base) { - - BcDig b; - int small, radix = 0; - size_t i, len = strlen(val); - - if (!len) return 1; - - small = base <= 10; - b = (BcDig) (small ? base + '0' : base - 10 + 'A'); - - for (i = 0; i < len; ++i) { - - BcDig c = val[i]; +static unsigned long bc_num_parseChar(char c, size_t base_t) { - if (c == '.') { - - if (radix) return 0; - - radix = 1; - continue; - } - - if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b))) - return 0; + if (isupper(c)) { + c = BC_NUM_NUM_LETTER(c); + c = ((size_t) c) >= base_t ? (char) base_t - 1 : c; } + else c -= '0'; - return 1; + return (unsigned long) (uchar) c; } -void bc_num_parseDecimal(BcNum *n, char *val) { +static void bc_num_parseDecimal(BcNum *n, char *val) { size_t len, i; char *ptr; @@ -1803,10 +1932,9 @@ void bc_num_parseDecimal(BcNum *n, char *val) { val += i; len = strlen(val); - bc_num_zero(n); if (len) { - for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.'; + for (i = 0; zero && i < len; ++i) zero = (val[i] == '0') || val[i] == '.'; bc_num_expand(n, len); } @@ -1816,63 +1944,58 @@ void bc_num_parseDecimal(BcNum *n, char *val) { n->rdx = (size_t) ((ptr != NULL) * ((val + len) - (ptr + 1))); if (!zero) { - for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.')) - n->num[n->len] = val[i] - '0'; + for (i = len - 1; i < len; ++n->len, --i) { + + char c = val[i]; + + if (c == '.') n->len -= 1; + else { + if (isupper(c)) c = '9'; + n->num[n->len] = c - '0'; + } + } } } -void bc_num_parseBase(BcNum *n, char *val, BcNum *base) { - - BcStatus s; +static BcStatus bc_num_parseBase(BcNum *n, char *val, + BcNum *base, size_t base_t) +{ + BcStatus s = BC_STATUS_SUCCESS; BcNum temp, mult, result; - BcDig c = '\0'; + BcDig c = 0; int zero = 1; unsigned long v; size_t i, digits, len = strlen(val); - bc_num_zero(n); - for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0'); - if (zero) return; - - bc_num_init(&temp, BC_NUM_DEF_SIZE); - bc_num_init(&mult, BC_NUM_DEF_SIZE); + if (zero) return BC_STATUS_SUCCESS; - for (i = 0; i < len; ++i) { + bc_num_init(&temp, BC_NUM_LONG_LOG10); + bc_num_init(&mult, BC_NUM_LONG_LOG10); - c = val[i]; - if (c == '.') break; + for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) { - v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); + v = bc_num_parseChar(c, base_t); s = bc_num_mul(n, base, &mult, 0); if (s) goto int_err; - s = bc_num_ulong2num(&temp, v); - if (s) goto int_err; + bc_num_ulong2num(&temp, v); s = bc_num_add(&mult, &temp, n, 0); if (s) goto int_err; } - if (i == len) { - c = val[i]; - if (c == 0) goto int_err; - } + if (i == len && !(c = val[i])) goto int_err; bc_num_init(&result, base->len); - bc_num_zero(&result); bc_num_one(&mult); - for (i += 1, digits = 0; i < len; ++i, ++digits) { + for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) { - c = val[i]; - if (c == 0) break; - - v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); + v = bc_num_parseChar(c, base_t); s = bc_num_mul(&result, base, &result, 0); if (s) goto err; - s = bc_num_ulong2num(&temp, v); - if (s) goto err; + bc_num_ulong2num(&temp, v); s = bc_num_add(&result, &temp, &result, 0); if (s) goto err; s = bc_num_mul(&mult, base, &mult, 0); @@ -1894,64 +2017,63 @@ err: int_err: bc_num_free(&mult); bc_num_free(&temp); + return s; } -void bc_num_printNewline(size_t *nchars, size_t line_len) { - if (*nchars == line_len - 1) { - bc_vm_putchar('\\'); - bc_vm_putchar('\n'); - *nchars = 0; +static void bc_num_printNewline() { + if (BC_VM->nchars >= (size_t) (BC_VM->line_len - 1)) { + putchar('\\'); + putchar('\n'); + BC_VM->nchars = 0; } } -void bc_num_printDigits(size_t num, size_t width, int radix, - size_t *nchars, size_t line_len) -{ - size_t exp, pow, div; +static void bc_num_printDigits(size_t n, size_t len, int rdx) { - bc_num_printNewline(nchars, line_len); - bc_vm_putchar(radix ? '.' : ' '); - ++(*nchars); + size_t exp, pow; - bc_num_printNewline(nchars, line_len); - for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10); + bc_num_printNewline(); + putchar(rdx ? '.' : ' '); + ++BC_VM->nchars; - for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) { - bc_num_printNewline(nchars, line_len); - div = num / pow; - num -= div * pow; - bc_vm_putchar(((char) div) + '0'); + bc_num_printNewline(); + for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= 10); + + for (exp = 0; exp < len; pow /= 10, ++BC_VM->nchars, ++exp) { + size_t dig; + bc_num_printNewline(); + dig = n / pow; + n -= dig * pow; + putchar(((uchar) dig) + '0'); } } -void bc_num_printHex(size_t num, size_t width, int radix, - size_t *nchars, size_t line_len) -{ +static void bc_num_printHex(size_t n, size_t len, int rdx) { - if (radix) { - bc_num_printNewline(nchars, line_len); - bc_vm_putchar('.'); - *nchars += 1; + if (rdx) { + bc_num_printNewline(); + putchar('.'); + BC_VM->nchars += 1; } - bc_num_printNewline(nchars, line_len); - bc_vm_putchar(bc_num_hex_digits[num]); - *nchars = *nchars + width; + bc_num_printNewline(); + putchar(bc_num_hex_digits[n]); + BC_VM->nchars += len; } -void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len) { +static void bc_num_printDecimal(BcNum *n) { size_t i, rdx = n->rdx - 1; - if (n->neg) bc_vm_putchar('-'); - (*nchars) += n->neg; + if (n->neg) putchar('-'); + BC_VM->nchars += n->neg; for (i = n->len - 1; i < n->len; --i) - bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len); + bc_num_printHex((size_t) n->num[i], 1, i == rdx); } -BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, size_t *nchars, - size_t len, BcNumDigitOp print) +static BcStatus bc_num_printNum(BcNum *n, BcNum *base, + size_t len, BcNumDigitOp print) { BcStatus s; BcVec stack; @@ -1960,18 +2082,17 @@ BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, size_t *nchars, size_t i; int radix; - if (n->len == 0) { - print(0, width, 0, nchars, len); + if (!n->len) { + print(0, len, 0); return BC_STATUS_SUCCESS; } - bc_vec_init(&stack, sizeof(long), NULL); - bc_num_init(&intp, n->len); + bc_vec_init(&stack, sizeof(unsigned long), NULL); bc_num_init(&fracp, n->rdx); - bc_num_init(&digit, width); + bc_num_init(&digit, len); bc_num_init(&frac_len, BC_NUM_INT(n)); - bc_num_copy(&intp, n); bc_num_one(&frac_len); + bc_num_createCopy(&intp, n); bc_num_truncate(&intp, intp.rdx); s = bc_num_sub(n, &intp, &fracp, 0); @@ -1987,7 +2108,7 @@ BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, size_t *nchars, for (i = 0; i < stack.len; ++i) { ptr = bc_vec_item_rev(&stack, i); - print(*ptr, width, 0, nchars, len); + print(*ptr, len, 0); } if (!n->rdx) goto err; @@ -1997,11 +2118,10 @@ BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, size_t *nchars, if (s) goto err; s = bc_num_ulong(&fracp, &dig); if (s) goto err; - s = bc_num_ulong2num(&intp, dig); - if (s) goto err; + bc_num_ulong2num(&intp, dig); s = bc_num_sub(&fracp, &intp, &fracp, 0); if (s) goto err; - print(dig, width, radix, nchars, len); + print(dig, len, radix); s = bc_num_mul(&frac_len, base, &frac_len, 0); if (s) goto err; } @@ -2015,39 +2135,43 @@ err: return s; } -BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t, - size_t *nchars, size_t line_len) -{ +static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t) { + BcStatus s; - size_t width, i; + size_t width; BcNumDigitOp print; int neg = n->neg; - if (neg) bc_vm_putchar('-'); - (*nchars) += neg; + if (neg) putchar('-'); + BC_VM->nchars += neg; n->neg = 0; - if (base_t <= BC_NUM_MAX_IBASE) { + if (base_t <= BC_NUM_MAX_POSIX_IBASE) { width = 1; print = bc_num_printHex; } else { - for (i = base_t - 1, width = 0; i; i /= 10, ++width); + width = bc_num_log10(base_t - 1) - 1; print = bc_num_printDigits; } - s = bc_num_printNum(n, base, width, nchars, line_len, print); + s = bc_num_printNum(n, base, width, print); n->neg = neg; return s; } +void bc_num_setup(BcNum *n, BcDig *num, size_t cap) { + n->num = num; + n->cap = cap; + n->rdx = n->len = 0; + n->neg = 0; +} + void bc_num_init(BcNum *n, size_t req) { req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; - memset(n, 0, sizeof(BcNum)); - n->num = xmalloc(req); - n->cap = req; + bc_num_setup(n, xmalloc(req), req); } void bc_num_expand(BcNum *n, size_t req) { @@ -2063,43 +2187,50 @@ void bc_num_free(void *num) { } void bc_num_copy(BcNum *d, BcNum *s) { + if (d == s) return; + bc_num_expand(d, s->len); + d->len = s->len; + d->neg = s->neg; + d->rdx = s->rdx; + memcpy(d->num, s->num, sizeof(BcDig) * d->len); +} - if (d != s) { - bc_num_expand(d, s->cap); - d->len = s->len; - d->neg = s->neg; - d->rdx = s->rdx; - memcpy(d->num, s->num, sizeof(BcDig) * d->len); - } +void bc_num_createCopy(BcNum *d, BcNum *s) { + bc_num_init(d, s->len); + bc_num_copy(d, s); } -BcStatus bc_num_parse(BcNum *n, char *val, BcNum *base, size_t base_t) { +void bc_num_createFromUlong(BcNum *n, unsigned long val) { + bc_num_init(n, BC_NUM_LONG_LOG10); + bc_num_ulong2num(n, val); +} - if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING; +BcStatus bc_num_parse(BcNum *n, char *val, + BcNum *base, size_t base_t, int letter) +{ + BcStatus s = BC_STATUS_SUCCESS; - if (base_t == 10) bc_num_parseDecimal(n, val); - else bc_num_parseBase(n, val, base); + if (letter) bc_num_ulong2num(n, bc_num_parseChar(val[0], BC_NUM_MAX_LBASE)); + else if (base_t == 10) bc_num_parseDecimal(n, val); + else s = bc_num_parseBase(n, val, base, base_t); - return BC_STATUS_SUCCESS; + return s; } -BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, int newline, - size_t *nchars, size_t line_len) +BcStatus bc_num_print(BcNum *n, BcNum *base, + size_t base_t, int newline) { BcStatus s = BC_STATUS_SUCCESS; - bc_num_printNewline(nchars, line_len); + bc_num_printNewline(); - if (n->len == 0) { - bc_vm_putchar('0'); - ++(*nchars); - } - else if (base_t == 10) bc_num_printDecimal(n, nchars, line_len); - else s = bc_num_printBase(n, base, base_t, nchars, line_len); + if (!n->len) bc_num_printHex(0, 1, 0); + else if (base_t == 10) bc_num_printDecimal(n); + else s = bc_num_printBase(n, base, base_t); - if (newline) { - bc_vm_putchar('\n'); - *nchars = 0; + if (!s && newline) { + putchar('\n'); + BC_VM->nchars = 0; } return s; @@ -2108,24 +2239,29 @@ BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, int newline, BcStatus bc_num_ulong(BcNum *n, unsigned long *result) { size_t i; - unsigned long pow; + unsigned long pow, r; + + *result = 0; - if (n->neg) return BC_STATUS_MATH_NEGATIVE; + if (n->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE); - for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) { + for (r = 0, pow = 1, i = n->rdx; i < n->len; ++i) { - unsigned long prev = *result, powprev = pow; + unsigned long prev = r, powprev = pow; - *result += ((unsigned long) n->num[i]) * pow; + r += ((unsigned long) n->num[i]) * pow; pow *= 10; - if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW; + if (r < prev || pow < powprev) + return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "number cannot fit"); } + *result = r; + return BC_STATUS_SUCCESS; } -BcStatus bc_num_ulong2num(BcNum *n, unsigned long val) { +void bc_num_ulong2num(BcNum *n, unsigned long val) { size_t len; BcDig *ptr; @@ -2133,62 +2269,71 @@ BcStatus bc_num_ulong2num(BcNum *n, unsigned long val) { bc_num_zero(n); - if (val == 0) return BC_STATUS_SUCCESS; + if (!val) return; - for (len = 1, i = ULONG_MAX; i; i /= 10, ++len) + len = bc_num_log10(ULONG_MAX); bc_num_expand(n, len); for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10; +} - return BC_STATUS_SUCCESS; +size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale) { + BC_UNUSED(scale); + return maxof(a->rdx, b->rdx) + maxof(BC_NUM_INT(a), BC_NUM_INT(b)) + 1; +} + +size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale) { + return BC_NUM_INT(a) + BC_NUM_INT(b) + maxof(scale, a->rdx + b->rdx) + 1; +} + +size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale) { + BC_UNUSED(scale); + return BC_NUM_PREQ(a, b); } BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s; - (void) scale; - return bc_num_binary(a, b, c, 0, op, BC_NUM_AREQ(a, b)); + BC_UNUSED(scale); + return bc_num_binary(a, b, c, 0, op, bc_num_addReq(a, b, scale)); } BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) { BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a; - (void) scale; - return bc_num_binary(a, b, c, 1, op, BC_NUM_AREQ(a, b)); + BC_UNUSED(scale); + return bc_num_binary(a, b, c, 1, op, bc_num_addReq(a, b, scale)); } BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) { - size_t req = BC_NUM_MREQ(a, b, scale); - return bc_num_binary(a, b, c, scale, bc_num_m, req); + return bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale)); } BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) { - size_t req = BC_NUM_MREQ(a, b, scale); - return bc_num_binary(a, b, c, scale, bc_num_d, req); + return bc_num_binary(a, b, c, scale, bc_num_d, bc_num_mulReq(a, b, scale)); } BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) { - size_t req = BC_NUM_MREQ(a, b, scale); - return bc_num_binary(a, b, c, scale, bc_num_rem, req); + return bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_mulReq(a, b, scale)); } BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) { - return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1); + return bc_num_binary(a, b, c, scale, bc_num_p, BC_NUM_PREQ(a, b)); } BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) { - BcStatus s; + BcStatus s = BC_STATUS_SUCCESS; BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; - size_t pow, len, digs, digs1, resrdx, req, times = 0; + size_t pow, len, digs, digs1, resrdx, times = 0; ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX; + BcDig half_digs[2]; - req = maxof(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1; - bc_num_expand(b, req); + bc_num_init(b, maxof(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1); - if (a->len == 0) { + if (!a->len) { bc_num_setToZero(b, scale); return BC_STATUS_SUCCESS; } - else if (a->neg) return BC_STATUS_MATH_NEGATIVE; - else if (BC_NUM_ONE(a)) { + if (a->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE); + if (BC_NUM_ONE(a)) { bc_num_one(b); bc_num_extend(b, scale); return BC_STATUS_SUCCESS; @@ -2199,7 +2344,7 @@ BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) { bc_num_init(&num1, len); bc_num_init(&num2, len); - bc_num_init(&half, BC_NUM_DEF_SIZE); + bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig)); bc_num_one(&half); half.num[0] = 5; @@ -2231,7 +2376,7 @@ BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) { resrdx = scale + 2; len = BC_NUM_INT(x0) + resrdx - 1; - while (!TT.signe && (cmp || digs < len)) { + while (!BC_SIGNAL && (cmp || digs < len)) { s = bc_num_div(a, x0, &f, resrdx); if (s) goto err; @@ -2257,8 +2402,8 @@ BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) { x1 = temp; } - if (TT.signe) { - s = BC_STATUS_EXEC_SIGNAL; + if (BC_SIGNAL) { + s = BC_STATUS_SIGNAL; goto err; } @@ -2269,7 +2414,6 @@ BcStatus bc_num_sqrt(BcNum *a, BcNum *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 s; @@ -2280,7 +2424,7 @@ BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { BcStatus s; BcNum num2, *ptr_a; int init = 0; - size_t ts = maxof(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts); + size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts); if (c == a) { memcpy(&num2, c, sizeof(BcNum)); @@ -2300,25 +2444,30 @@ BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) { return s; } -int bc_id_cmp(void *e1, void *e2) { - return strcmp(((BcId*) e1)->name, ((BcId*) e2)->name); +int bc_id_cmp(BcId *e1, BcId *e2) { + return strcmp(e1->name, e2->name); } void bc_id_free(void *id) { free(((BcId*) id)->name); } -BcStatus bc_func_insert(BcFunc *f, char *name, int var) { +void bc_string_free(void *string) { + free(*((char**) string)); +} + +BcStatus bc_func_insert(BcFunc *f, char *name, BcType type, size_t line) { BcId a; 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; + BcId *id = bc_vec_item(&f->autos, i); + if (!strcmp(name, id->name) && type == (BcType) id->idx) + return bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name); } - a.idx = var; + a.idx = type; a.name = name; bc_vec_push(&f->autos, &a); @@ -2326,16 +2475,32 @@ BcStatus bc_func_insert(BcFunc *f, char *name, int var) { return BC_STATUS_SUCCESS; } -void bc_func_init(BcFunc *f) { - bc_vec_init(&f->code, sizeof(char), NULL); +void bc_func_init(BcFunc *f, char *name) { + bc_vec_init(&f->code, sizeof(uchar), NULL); + bc_vec_init(&f->strs, sizeof(char*), bc_string_free); + bc_vec_init(&f->consts, sizeof(char*), bc_string_free); bc_vec_init(&f->autos, sizeof(BcId), bc_id_free); bc_vec_init(&f->labels, sizeof(size_t), NULL); f->nparams = 0; + f->voidfn = 0; + f->name = name; +} + +void bc_func_reset(BcFunc *f) { + bc_vec_npop(&f->code, f->code.len); + bc_vec_npop(&f->strs, f->strs.len); + bc_vec_npop(&f->consts, f->consts.len); + bc_vec_npop(&f->autos, f->autos.len); + bc_vec_npop(&f->labels, f->labels.len); + f->nparams = 0; + f->voidfn = 0; } void bc_func_free(void *func) { BcFunc *f = (BcFunc*) func; bc_vec_free(&f->code); + bc_vec_free(&f->strs); + bc_vec_free(&f->consts); bc_vec_free(&f->autos); bc_vec_free(&f->labels); } @@ -2356,33 +2521,28 @@ void bc_array_copy(BcVec *d, BcVec *s) { for (i = 0; i < s->len; ++i) { BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i); - bc_num_init(dnum, snum->len); - bc_num_copy(dnum, snum); + bc_num_createCopy(dnum, snum); } } void bc_array_expand(BcVec *a, size_t len) { - BcResultData data; - if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) { + BcNum n; while (len > a->len) { - bc_num_init(&data.n, BC_NUM_DEF_SIZE); - bc_vec_push(a, &data.n); + bc_num_init(&n, BC_NUM_DEF_SIZE); + bc_vec_push(a, &n); } } else { + BcVec v; while (len > a->len) { - bc_array_init(&data.v, 1); - bc_vec_push(a, &data.v); + bc_array_init(&v, 1); + bc_vec_push(a, &v); } } } -void bc_string_free(void *string) { - free(*((char**) string)); -} - void bc_result_free(void *result) { BcResult *r = (BcResult*) result; @@ -2406,7 +2566,11 @@ void bc_result_free(void *result) { break; } - default: + case BC_RESULT_STR: + case BC_RESULT_CONSTANT: + case BC_RESULT_VOID: + case BC_RESULT_ONE: + case BC_RESULT_LAST: { // Do nothing. break; @@ -2414,66 +2578,92 @@ void bc_result_free(void *result) { } } +BcStatus bc_lex_invalidChar(BcLex *l, char c) { + l->t = BC_LEX_INVALID; + return bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c); +} + void bc_lex_lineComment(BcLex *l) { - l->t.t = BC_LEX_WHITESPACE; - while (l->i < l->len && l->buf[l->i++] != '\n'); - --l->i; + l->t = BC_LEX_WHITESPACE; + while (l->i < l->len && l->buf[l->i] != '\n') ++l->i; +} + +BcStatus bc_lex_comment(BcLex *l) { + + size_t i, nlines = 0; + char *buf = l->buf; + int end = 0; + char c; + + l->t = BC_LEX_WHITESPACE; + + for (i = ++l->i; !end; i += !end) { + + for (; (c = buf[i]) && c != '*'; ++i) nlines += (c == '\n'); + + if (!c || buf[i + 1] == '\0') { + l->i = i; + return bc_lex_err(l, BC_ERROR_PARSE_COMMENT); + } + + end = buf[i + 1] == '/'; + } + + l->i = i + 2; + l->line += nlines; + + return BC_STATUS_SUCCESS; } void bc_lex_whitespace(BcLex *l) { char c; - l->t.t = BC_LEX_WHITESPACE; + l->t = BC_LEX_WHITESPACE; for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]); } BcStatus bc_lex_number(BcLex *l, char start) { char *buf = l->buf + l->i; - size_t len, hits = 0, bslashes = 0, i = 0, j; - char c = buf[i]; - int last_pt, pt = start == '.'; + size_t i; + char last_valid, c; + int last_pt, pt = (start == '.'); - last_pt = pt; - l->t.t = BC_LEX_NUMBER; + l->t = BC_LEX_NUMBER; + last_valid = 'Z'; - while (c && (isdigit(c) || (c >= 'A' && c <= 'F') || - (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n'))) - { - if (c != '\\') { - last_pt = c == '.'; - pt = pt || last_pt; - } - else { - ++i; - bslashes += 1; - } + bc_vec_npop(&l->str, l->str.len); + bc_vec_push(&l->str, &start); - c = buf[++i]; - } + for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, last_valid, pt) || + (c == '\\' && buf[i + 1] == '\n')); ++i) + { + if (c == '\\') { - len = i + 1 * !last_pt - bslashes * 2; - if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN; + if (buf[i + 1] == '\n') { - bc_vec_npop(&l->t.v, l->t.v.len); - bc_vec_expand(&l->t.v, len + 1); - bc_vec_push(&l->t.v, &start); + i += 2; - for (buf -= 1, j = 1; j < len + hits * 2; ++j) { + // Make sure to eat whitespace at the beginning of the line. + while(isspace(buf[i]) && buf[i] != '\n') ++i; - c = buf[j]; + c = buf[i]; - // If we have hit a backslash, skip it. We don't have - // to check for a newline because it's guaranteed. - if (hits < bslashes && c == '\\') { - ++hits; - ++j; - continue; + if (!BC_LEX_NUM_CHAR(c, last_valid, pt)) break; + } + else break; } - bc_vec_push(&l->t.v, &c); + last_pt = (c == '.'); + if (pt && last_pt) break; + pt = pt || last_pt; + + bc_vec_push(&l->str, &c); } - bc_vec_pushByte(&l->t.v, '\0'); + if (l->str.len - pt > BC_MAX_NUM) + return bc_lex_verr(l, BC_ERROR_EXEC_NUM_LEN, BC_MAX_NUM); + + bc_vec_pushByte(&l->str, '\0'); l->i += i; return BC_STATUS_SUCCESS; @@ -2485,12 +2675,14 @@ BcStatus bc_lex_name(BcLex *l) { char *buf = l->buf + l->i - 1; char c = buf[i]; - l->t.t = BC_LEX_NAME; + l->t = BC_LEX_NAME; while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i]; - if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN; - bc_vec_string(&l->t.v, i, buf); + if (i > BC_MAX_NAME) + return bc_lex_verr(l, BC_ERROR_EXEC_NAME_LEN, BC_MAX_NAME); + + bc_vec_string(&l->str, i, buf); // Increment the index. We minus 1 because it has already been incremented. l->i += i - 1; @@ -2499,38 +2691,36 @@ BcStatus bc_lex_name(BcLex *l) { } void bc_lex_init(BcLex *l) { - - bc_vec_init(&l->t.v, sizeof(char), NULL); + bc_vec_init(&l->str, sizeof(char), NULL); } void bc_lex_free(BcLex *l) { - bc_vec_free(&l->t.v); + bc_vec_free(&l->str); } void bc_lex_file(BcLex *l, char *file) { l->line = 1; - l->newline = 0; - l->f = file; + BC_VM->file = file; } 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; + l->last = l->t; + l->line += (l->i != 0 && l->buf[l->i - 1] == '\n'); - l->line += l->newline; - l->t.t = BC_LEX_EOF; + if (l->last == BC_LEX_EOF) return bc_lex_err(l, BC_ERROR_PARSE_EOF); - l->newline = (l->i == l->len); - if (l->newline) return BC_STATUS_SUCCESS; + l->t = BC_LEX_EOF; + + if (l->i == l->len) return BC_STATUS_SUCCESS; // Loop until failure or we don't have whitespace. This // is so the parser doesn't get inundated with whitespace. do { s = bc_lex_token(l); - } while (!s && l->t.t == BC_LEX_WHITESPACE); + } while (!s && l->t == BC_LEX_WHITESPACE); return s; } @@ -2539,27 +2729,27 @@ BcStatus bc_lex_text(BcLex *l, char *text) { l->buf = text; l->i = 0; l->len = strlen(text); - l->t.t = l->t.last = BC_LEX_INVALID; + l->t = l->last = BC_LEX_INVALID; return bc_lex_next(l); } -BcStatus bc_lex_identifier(BcLex *l) { +static BcStatus bc_lex_identifier(BcLex *l) { BcStatus s; size_t i; char *buf = l->buf + l->i - 1; - for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) { - - unsigned long len = (unsigned long) bc_lex_kws[i].len; + for (i = 0; i < bc_lex_kws_len; ++i) { - if (strncmp(buf, bc_lex_kws[i].name, len) == 0) { + BcLexKeyword *kw = bc_lex_kws + i; + size_t len = BC_LEX_KW_LEN(kw); - l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i; + if (!strncmp(buf, kw->name, len) && !isalnum(buf[len]) && buf[len] != '_') + { + l->t = BC_LEX_KEY_AUTO + (BcLexType) i; - if (!bc_lex_kws[i].posix) { - s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, - l->line, bc_lex_kws[i].name); + if (!BC_LEX_KW_POSIX(kw)) { + s = bc_lex_vposixErr(l, BC_ERROR_POSIX_KW, kw->name); if (s) return s; } @@ -2572,69 +2762,45 @@ BcStatus bc_lex_identifier(BcLex *l) { s = bc_lex_name(l); if (s) return s; - if (l->t.v.len - 1 > 1) - s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf); + if (l->str.len - 1 > 1) s = bc_lex_vposixErr(l, BC_ERROR_POSIX_NAME_LEN, buf); return s; } -BcStatus bc_lex_string(BcLex *l) { +static BcStatus bc_lex_string(BcLex *l) { - size_t len, nls = 0, i = l->i; + size_t len, nlines = 0, i = l->i; + char *buf = l->buf; char c; - l->t.t = BC_LEX_STR; + l->t = BC_LEX_STR; - for (c = l->buf[i]; c && c != '"'; c = l->buf[++i]) nls += (c == '\n'); + for (; (c = buf[i]) && c != '"'; ++i) nlines += c == '\n'; if (c == '\0') { l->i = i; - return BC_STATUS_LEX_NO_STRING_END; + return bc_lex_err(l, BC_ERROR_PARSE_STRING); } len = i - l->i; - if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN; - bc_vec_string(&l->t.v, len, l->buf + l->i); + + if (len > BC_MAX_STRING) + return bc_lex_verr(l, BC_ERROR_EXEC_STRING_LEN, BC_MAX_STRING); + + bc_vec_string(&l->str, len, l->buf + l->i); l->i = i + 1; - l->line += nls; + l->line += nlines; return BC_STATUS_SUCCESS; } -void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) { +static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) { if (l->buf[l->i] == '=') { ++l->i; - l->t.t = with; + l->t = with; } - else l->t.t = without; -} - -BcStatus bc_lex_comment(BcLex *l) { - - size_t i, nls = 0; - char *buf = l->buf; - int end = 0; - char c; - - l->t.t = BC_LEX_WHITESPACE; - - for (i = ++l->i; !end; i += !end) { - - for (c = buf[i]; c != '*' && c; c = buf[++i]) nls += (c == '\n'); - - if (c == 0 || buf[i + 1] == '\0') { - l->i = i; - return BC_STATUS_LEX_NO_COMMENT_END; - } - - end = buf[i + 1] == '/'; - } - - l->i = i + 2; - l->line += nls; - - return BC_STATUS_SUCCESS; + else l->t = without; } BcStatus bc_lex_token(BcLex *l) { @@ -2648,8 +2814,7 @@ BcStatus bc_lex_token(BcLex *l) { case '\0': case '\n': { - l->newline = 1; - l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE; + l->t = !c ? BC_LEX_EOF : BC_LEX_NLINE; break; } @@ -2667,8 +2832,8 @@ BcStatus bc_lex_token(BcLex *l) { { bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT); - if (l->t.t == BC_LEX_OP_BOOL_NOT) { - s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!"); + if (l->t == BC_LEX_OP_BOOL_NOT) { + s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "!"); if (s) return s; } @@ -2683,7 +2848,7 @@ BcStatus bc_lex_token(BcLex *l) { case '#': { - s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL); + s = bc_lex_posixErr(l, BC_ERROR_POSIX_COMMENT); if (s) return s; bc_lex_lineComment(l); @@ -2702,24 +2867,20 @@ BcStatus bc_lex_token(BcLex *l) { c2 = l->buf[l->i]; if (c2 == '&') { - s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&"); + s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "&&"); if (s) return s; ++l->i; - l->t.t = BC_LEX_OP_BOOL_AND; - } - else { - l->t.t = BC_LEX_INVALID; - s = BC_STATUS_LEX_BAD_CHAR; + l->t = BC_LEX_OP_BOOL_AND; } + else s = bc_lex_invalidChar(l, c); break; } - case '(': case ')': { - l->t.t = (BcLexType) (c - '(' + BC_LEX_LPAREN); + l->t = (BcLexType) (c - '(' + BC_LEX_LPAREN); break; } @@ -2734,7 +2895,7 @@ BcStatus bc_lex_token(BcLex *l) { c2 = l->buf[l->i]; if (c2 == '+') { ++l->i; - l->t.t = BC_LEX_OP_INC; + l->t = BC_LEX_OP_INC; } else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS); break; @@ -2742,7 +2903,7 @@ BcStatus bc_lex_token(BcLex *l) { case ',': { - l->t.t = BC_LEX_COMMA; + l->t = BC_LEX_COMMA; break; } @@ -2751,7 +2912,7 @@ BcStatus bc_lex_token(BcLex *l) { c2 = l->buf[l->i]; if (c2 == '-') { ++l->i; - l->t.t = BC_LEX_OP_DEC; + l->t = BC_LEX_OP_DEC; } else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS); break; @@ -2759,10 +2920,11 @@ BcStatus bc_lex_token(BcLex *l) { case '.': { - if (isdigit(l->buf[l->i])) s = bc_lex_number(l, c); + c2 = l->buf[l->i]; + if (BC_LEX_NUM_CHAR(c2, 'Z', 1)) s = bc_lex_number(l, c); else { - l->t.t = BC_LEX_KEY_LAST; - s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL); + l->t = BC_LEX_KEY_LAST; + s = bc_lex_posixErr(l, BC_ERROR_POSIX_DOT); } break; } @@ -2791,6 +2953,30 @@ BcStatus bc_lex_token(BcLex *l) { case 'D': case 'E': case 'F': + // Apparently, GNU bc (and maybe others) allows any uppercase letter as a + // number. When single digits, they act like the ones above. When multi- + // digit, any letter above the input base is automatically set to the + // biggest allowable digit in the input base. + 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 = bc_lex_number(l, c); break; @@ -2798,7 +2984,7 @@ BcStatus bc_lex_token(BcLex *l) { case ';': { - l->t.t = BC_LEX_SCOLON; + l->t = BC_LEX_SCOLON; break; } @@ -2823,17 +3009,17 @@ BcStatus bc_lex_token(BcLex *l) { case '[': case ']': { - l->t.t = (BcLexType) (c - '[' + BC_LEX_LBRACKET); + l->t = (BcLexType) (c - '[' + BC_LEX_LBRACKET); break; } case '\\': { if (l->buf[l->i] == '\n') { - l->t.t = BC_LEX_WHITESPACE; + l->t = BC_LEX_WHITESPACE; ++l->i; } - else s = BC_STATUS_LEX_BAD_CHAR; + else s = bc_lex_invalidChar(l, c); break; } @@ -2877,7 +3063,7 @@ BcStatus bc_lex_token(BcLex *l) { case '{': case '}': { - l->t.t = (BcLexType) (c - '{' + BC_LEX_LBRACE); + l->t = (BcLexType) (c - '{' + BC_LEX_LBRACE); break; } @@ -2887,24 +3073,20 @@ BcStatus bc_lex_token(BcLex *l) { if (c2 == '|') { - s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||"); + s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "||"); if (s) return s; ++l->i; - l->t.t = BC_LEX_OP_BOOL_OR; - } - else { - l->t.t = BC_LEX_INVALID; - s = BC_STATUS_LEX_BAD_CHAR; + l->t = BC_LEX_OP_BOOL_OR; } + else s = bc_lex_invalidChar(l, c); break; } default: { - l->t.t = BC_LEX_INVALID; - s = BC_STATUS_LEX_BAD_CHAR; + s = bc_lex_invalidChar(l, c); break; } } @@ -2912,79 +3094,49 @@ BcStatus bc_lex_token(BcLex *l) { return s; } -void bc_parse_addFunc(BcParse *p, char *name, size_t *idx) { - bc_program_addFunc(p->prog, name, idx); - p->func = bc_vec_item(&p->prog->fns, p->fidx); +void bc_parse_updateFunc(BcParse *p, size_t fidx) { + p->fidx = fidx; + p->func = bc_vec_item(&p->prog->fns, fidx); } void bc_parse_pushName(BcParse *p, char *name) { - - size_t i = 0, len = strlen(name); - - for (; i < len; ++i) bc_parse_push(p, name[i]); + bc_vec_npush(&p->func->code, strlen(name), name); bc_parse_push(p, BC_PARSE_STREND); - - free(name); } void bc_parse_pushIndex(BcParse *p, size_t idx) { - - unsigned char amt, i, nums[sizeof(size_t)]; - - for (amt = 0; idx; ++amt) { - nums[amt] = (char) idx; - idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT; - } - - bc_parse_push(p, amt); - for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]); + bc_vec_pushIndex(&p->func->code, idx); } -void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs) { +void bc_parse_addId(BcParse *p, uchar inst) { - char *num = xstrdup(p->l.t.v.v); - size_t idx = p->prog->consts.len; + BcFunc *f = p->func; + BcVec *v = inst == BC_INST_NUM ? &f->consts : &f->strs; + size_t idx = v->len; + char *str = xstrdup(p->l.str.v); - bc_vec_push(&p->prog->consts, &num); - - bc_parse_push(p, BC_INST_NUM); + bc_vec_push(v, &str); + bc_parse_updateFunc(p, p->fidx); + bc_parse_push(p, inst); bc_parse_pushIndex(p, idx); - - ++(*nexs); - (*prev) = BC_INST_NUM; } BcStatus bc_parse_text(BcParse *p, char *text) { - - BcStatus s; - + // Make sure the pointer isn't invalidated. p->func = bc_vec_item(&p->prog->fns, p->fidx); - - if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) { - p->l.t.t = BC_LEX_INVALID; - s = bc_parse_parse(p); - if (s) return s; - if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE; - } - return bc_lex_text(&p->l, text); } BcStatus bc_parse_reset(BcParse *p, BcStatus s) { if (p->fidx != BC_PROG_MAIN) { - - p->func->nparams = 0; - bc_vec_npop(&p->func->code, p->func->code.len); - bc_vec_npop(&p->func->autos, p->func->autos.len); - bc_vec_npop(&p->func->labels, p->func->labels.len); - + bc_func_reset(p->func); bc_parse_updateFunc(p, BC_PROG_MAIN); } p->l.i = p->l.len; - p->l.t.t = BC_LEX_EOF; - p->auto_part = (p->nbraces = 0); + p->l.t = BC_LEX_EOF; + p->auto_part = 0; bc_vec_npop(&p->flags, p->flags.len - 1); bc_vec_npop(&p->exits, p->exits.len); @@ -3002,68 +3154,145 @@ void bc_parse_free(BcParse *p) { bc_lex_free(&p->l); } -void bc_parse_init(BcParse *p, BcProgram *prog, size_t func) { - - memset(p, 0, sizeof(BcParse)); - - bc_lex_init(&p->l); - bc_vec_init(&p->flags, sizeof(uint8_t), NULL); +void bc_parse_init(BcParse *p, BcProgram *prog, size_t func) +{ + uint16_t flag = 0; + bc_vec_init(&p->flags, sizeof(uint16_t), NULL); + bc_vec_push(&p->flags, &flag); bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL); bc_vec_init(&p->conds, sizeof(size_t), NULL); - bc_vec_pushByte(&p->flags, 0); bc_vec_init(&p->ops, sizeof(BcLexType), NULL); + bc_lex_init(&p->l); + p->prog = prog; - p->auto_part = (p->nbraces = 0); + p->auto_part = 0; bc_parse_updateFunc(p, func); } -BcStatus bc_parse_else(BcParse *p); -BcStatus bc_parse_stmt(BcParse *p); +static BcStatus bc_parse_else(BcParse *p); +static BcStatus bc_parse_stmt(BcParse *p); +static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next); + +static int bc_parse_inst_isLeaf(BcInst t) { + return (t >= BC_INST_NUM && t <= BC_INST_ABS) || + t == BC_INST_INC_POST || t == BC_INST_DEC_POST; +} + +static int bc_parse_isDelimiter(BcParse *p) { + + BcLexType t = p->l.t; + int good = 0; + + if (BC_PARSE_DELIMITER(t)) return 1; + + if (t == BC_LEX_KEY_ELSE) { + + size_t i; + uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE; + + for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) { + fptr = bc_vec_item_rev(&p->flags, i); + flags = *fptr; + if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE) + return 0; + } + + good = ((flags & BC_PARSE_FLAG_IF) != 0); + } + else if (t == BC_LEX_RBRACE) { + + size_t i; + + for (i = 0; !good && i < p->flags.len; ++i) { + uint16_t *fptr = bc_vec_item_rev(&p->flags, i); + good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0); + } + } + + return good; +} + +static void bc_parse_setLabel(BcParse *p) { + + BcFunc *func = p->func; + BcInstPtr *ip = bc_vec_top(&p->exits); + size_t *label; + + label = bc_vec_item(&func->labels, ip->idx); + *label = func->code.len; + + bc_vec_pop(&p->exits); +} + +static void bc_parse_createLabel(BcParse *p, size_t idx) { + bc_vec_push(&p->func->labels, &idx); +} + +static void bc_parse_createCondLabel(BcParse *p, size_t idx) { + bc_parse_createLabel(p, p->func->code.len); + bc_vec_push(&p->conds, &idx); +} + +static void bc_parse_createExitLabel(BcParse *p, size_t idx, int loop) { + + BcInstPtr ip; + + ip.func = loop; + ip.idx = idx; + ip.len = 0; + + bc_vec_push(&p->exits, &ip); + bc_parse_createLabel(p, SIZE_MAX); +} + +static size_t bc_parse_addFunc(BcParse *p, char *name) { + + size_t idx = bc_program_insertFunc(p->prog, name); + + // Make sure that this pointer was not invalidated. + p->func = bc_vec_item(&p->prog->fns, p->fidx); + + return idx; +} -BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start, - size_t *nexprs, int next) +static void bc_parse_operator(BcParse *p, BcLexType type, + size_t start, size_t *nexprs) { - BcStatus s = BC_STATUS_SUCCESS; BcLexType t; - char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec; - int left = bc_parse_ops[type - BC_LEX_OP_INC].left; + uchar l, r = BC_PARSE_OP_PREC(type); + uchar left = BC_PARSE_OP_LEFT(type); while (p->ops.len > start) { t = BC_PARSE_TOP_OP(p); if (t == BC_LEX_LPAREN) break; - l = bc_parse_ops[t - BC_LEX_OP_INC].prec; + l = BC_PARSE_OP_PREC(t); if (l >= r && (l != r || !left)) break; bc_parse_push(p, BC_PARSE_TOKEN_INST(t)); bc_vec_pop(&p->ops); - *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG; + *nexprs -= !BC_PARSE_OP_PREFIX(t); } bc_vec_push(&p->ops, &type); - if (next) s = bc_lex_next(&p->l); - - return s; } -BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs) { +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; - top = BC_PARSE_TOP_OP(p); + if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - while (top != BC_LEX_LPAREN) { + while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) { bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); bc_vec_pop(&p->ops); - *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG; + *nexs -= !BC_PARSE_OP_PREFIX(top); - if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP; - top = BC_PARSE_TOP_OP(p); + if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR); } bc_vec_pop(&p->ops); @@ -3071,7 +3300,7 @@ BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs) { return bc_lex_next(&p->l); } -BcStatus bc_parse_params(BcParse *p, uint8_t flags) { +static BcStatus bc_parse_params(BcParse *p, uint8_t flags) { BcStatus s; int comma = 0; @@ -3080,54 +3309,52 @@ BcStatus bc_parse_params(BcParse *p, uint8_t flags) { s = bc_lex_next(&p->l); if (s) return s; - for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) { + for (nparams = 0; p->l.t != BC_LEX_RPAREN; ++nparams) { flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY; - s = bc_parse_expr(p, flags, bc_parse_next_param); + s = bc_parse_expr_status(p, flags, bc_parse_next_param); if (s) return s; - comma = p->l.t.t == BC_LEX_COMMA; + comma = p->l.t == BC_LEX_COMMA; if (comma) { s = bc_lex_next(&p->l); if (s) return s; } } - if (comma) return BC_STATUS_PARSE_BAD_TOKEN; + if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); bc_parse_push(p, BC_INST_CALL); bc_parse_pushIndex(p, nparams); return BC_STATUS_SUCCESS; } -BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) { +static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) { BcStatus s; - BcId entry, *entry_ptr; + BcId id, *id_ptr; size_t idx; - entry.name = name; + id.name = name; s = bc_parse_params(p, flags); if (s) goto err; - if (p->l.t.t != BC_LEX_RPAREN) { - s = BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t != BC_LEX_RPAREN) { + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); goto err; } - idx = bc_map_index(&p->prog->fn_map, &entry); + idx = bc_map_index(&p->prog->fn_map, &id); - if (idx == ((size_t) -1)) { - name = xstrdup(entry.name); - bc_parse_addFunc(p, name, &idx); - idx = bc_map_index(&p->prog->fn_map, &entry); - free(entry.name); + if (idx == SIZE_MAX) { + bc_parse_addFunc(p, name); + idx = bc_map_index(&p->prog->fn_map, &id); } else free(name); - entry_ptr = bc_vec_item(&p->prog->fn_map, idx); - bc_parse_pushIndex(p, entry_ptr->idx); + id_ptr = bc_vec_item(&p->prog->fn_map, idx); + bc_parse_pushIndex(p, id_ptr->idx); return bc_lex_next(&p->l); @@ -3136,24 +3363,24 @@ err: return s; } -BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) { +static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) { BcStatus s; char *name; - name = xstrdup(p->l.t.v.v); + name = xstrdup(p->l.str.v); s = bc_lex_next(&p->l); if (s) goto err; - if (p->l.t.t == BC_LEX_LBRACKET) { + if (p->l.t == BC_LEX_LBRACKET) { s = bc_lex_next(&p->l); if (s) goto err; - if (p->l.t.t == BC_LEX_RBRACKET) { + if (p->l.t == BC_LEX_RBRACKET) { if (!(flags & BC_PARSE_ARRAY)) { - s = BC_STATUS_PARSE_BAD_EXP; + s = bc_parse_err(p, BC_ERROR_PARSE_EXPR); goto err; } @@ -3164,88 +3391,95 @@ BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) { *type = BC_INST_ARRAY_ELEM; flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL); - s = bc_parse_expr(p, flags, bc_parse_next_elem); + s = bc_parse_expr_status(p, flags, bc_parse_next_elem); if (s) goto err; + + if (p->l.t != BC_LEX_RBRACKET) { + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + goto err; + } } s = bc_lex_next(&p->l); if (s) goto err; + bc_parse_push(p, *type); bc_parse_pushName(p, name); } - else if (p->l.t.t == BC_LEX_LPAREN) { + else if (p->l.t == BC_LEX_LPAREN) { if (flags & BC_PARSE_NOCALL) { - s = BC_STATUS_PARSE_BAD_TOKEN; + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); goto err; } *type = BC_INST_CALL; - s = bc_parse_call(p, name, flags); + + // Return early because bc_parse_call() frees the name. + return bc_parse_call(p, name, flags); } else { *type = BC_INST_VAR; - bc_parse_push(p, BC_INST_VAR); + bc_parse_push(p, BC_INST_VAR); bc_parse_pushName(p, name); } - return s; - err: free(name); return s; } -BcStatus bc_parse_read(BcParse *p) { +static BcStatus bc_parse_read(BcParse *p) { BcStatus s; 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 != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_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 != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); bc_parse_push(p, BC_INST_READ); return bc_lex_next(&p->l); } -BcStatus bc_parse_builtin(BcParse *p, BcLexType type, - uint8_t flags, BcInst *prev) +static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, + uint8_t flags, BcInst *prev) { BcStatus s; s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN; - - flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY; + if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; - s = bc_parse_expr(p, flags, bc_parse_next_rel); + flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)); + if (type == BC_LEX_KEY_LENGTH) flags |= BC_PARSE_ARRAY; + + s = bc_parse_expr_status(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 != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); - *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT; + *prev = type - BC_LEX_KEY_LENGTH + BC_INST_LENGTH; bc_parse_push(p, *prev); return bc_lex_next(&p->l); } -BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) { +static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) { BcStatus s; s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_LPAREN) { + if (p->l.t != BC_LEX_LPAREN) { *type = BC_INST_SCALE; bc_parse_push(p, BC_INST_SCALE); return BC_STATUS_SUCCESS; @@ -3257,75 +3491,57 @@ BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) { s = bc_lex_next(&p->l); if (s) return s; - s = bc_parse_expr(p, flags, bc_parse_next_rel); + s = bc_parse_expr_status(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 != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + bc_parse_push(p, BC_INST_SCALE_FUNC); return bc_lex_next(&p->l); } -BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, int *paren_expr, - size_t *nexprs, uint8_t flags) +static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, + size_t *nexs, uint8_t flags) { BcStatus s; BcLexType type; - char inst; + uchar inst; BcInst etype = *prev; + BcLexType last = p->l.last; - if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM || - etype == BC_INST_SCALE || etype == BC_INST_LAST || - etype == BC_INST_IBASE || etype == BC_INST_OBASE) - { - *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC); + if (last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC || last == BC_LEX_RPAREN) + return s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN); + + if (BC_PARSE_INST_VAR(etype)) { + *prev = inst = BC_INST_INC_POST + (p->l.t != BC_LEX_OP_INC); bc_parse_push(p, inst); s = bc_lex_next(&p->l); } else { - *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC); - *paren_expr = 1; + *prev = inst = BC_INST_INC_PRE + (p->l.t != BC_LEX_OP_INC); s = bc_lex_next(&p->l); if (s) return s; - type = p->l.t.t; + type = p->l.t; // Because we parse the next part of the expression // right here, we need to increment this. - *nexprs = *nexprs + 1; - - switch (type) { + *nexs = *nexs + 1; - case BC_LEX_NAME: - { - s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL); - break; - } - - case BC_LEX_KEY_IBASE: - case BC_LEX_KEY_LAST: - case BC_LEX_KEY_OBASE: - { - bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE); - s = bc_lex_next(&p->l); - break; - } - - case BC_LEX_KEY_SCALE: - { - s = bc_lex_next(&p->l); - if (s) return s; - if (p->l.t.t == BC_LEX_LPAREN) s = BC_STATUS_PARSE_BAD_TOKEN; - else bc_parse_push(p, BC_INST_SCALE); - break; - } - - default: - { - s = BC_STATUS_PARSE_BAD_TOKEN; - break; - } + if (type == BC_LEX_NAME) + s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL); + else if (type >= BC_LEX_KEY_LAST && type <= BC_LEX_KEY_OBASE) { + bc_parse_push(p, type - BC_LEX_KEY_LAST + BC_INST_LAST); + s = bc_lex_next(&p->l); + } + else if (type == BC_LEX_KEY_SCALE) { + s = bc_lex_next(&p->l); + if (s) return s; + if (p->l.t == BC_LEX_LPAREN) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + else bc_parse_push(p, BC_INST_SCALE); } + else s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); if (!s) bc_parse_push(p, inst); } @@ -3333,106 +3549,106 @@ BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, int *paren_expr, return s; } -BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn, - int rparen, size_t *nexprs) +static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn, + int rparen, int bin_last, size_t *nexprs) { BcStatus s; BcLexType type; - BcInst etype = *prev; s = bc_lex_next(&p->l); if (s) return s; - type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST || - (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ? - BC_LEX_OP_MINUS : BC_LEX_NEG; + type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG; *prev = BC_PARSE_TOKEN_INST(type); // We can just push onto the op stack because this is the largest // precedence operator that gets pushed. Inc/dec does not. if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type); - else s = bc_parse_operator(p, type, ops_bgn, nexprs, 0); + else bc_parse_operator(p, type, ops_bgn, nexprs); return s; } -BcStatus bc_parse_string(BcParse *p, char inst) { - - char *str = xstrdup(p->l.t.v.v); - - bc_parse_push(p, BC_INST_STR); - bc_parse_pushIndex(p, p->prog->strs.len); - bc_vec_push(&p->prog->strs, &str); +static BcStatus bc_parse_str(BcParse *p, char inst) { + bc_parse_string(p); bc_parse_push(p, inst); - return bc_lex_next(&p->l); } -BcStatus bc_parse_print(BcParse *p) { +static BcStatus bc_parse_print(BcParse *p) { BcStatus s; - BcLexType type; + BcLexType t; int comma = 0; s = bc_lex_next(&p->l); if (s) return s; - type = p->l.t.t; + t = p->l.t; - if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE) - return BC_STATUS_PARSE_BAD_PRINT; + if (bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_PRINT); - while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) { - - if (type == BC_LEX_STR) s = bc_parse_string(p, BC_INST_PRINT_POP); + do { + if (t == BC_LEX_STR) s = bc_parse_str(p, BC_INST_PRINT_POP); else { - s = bc_parse_expr(p, 0, bc_parse_next_print); - if (s) return s; - bc_parse_push(p, BC_INST_PRINT_POP); + s = bc_parse_expr_status(p, 0, bc_parse_next_print); + if (!s) bc_parse_push(p, BC_INST_PRINT_POP); } if (s) return s; - comma = p->l.t.t == BC_LEX_COMMA; + comma = (p->l.t == BC_LEX_COMMA); + if (comma) s = bc_lex_next(&p->l); - type = p->l.t.t; - } + else { + if (!bc_parse_isDelimiter(p)) + return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + else break; + } + + t = p->l.t; + } while (!s); if (s) return s; - if (comma) return BC_STATUS_PARSE_BAD_TOKEN; + if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); - return bc_lex_next(&p->l); + return s; } -BcStatus bc_parse_return(BcParse *p) { +static BcStatus bc_parse_return(BcParse *p) { BcStatus s; BcLexType t; int paren; + uchar inst = BC_INST_RET0; + + if (!BC_PARSE_FUNC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); - if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->func->voidfn) inst = BC_INST_RET_VOID; s = bc_lex_next(&p->l); if (s) return s; - t = p->l.t.t; + t = p->l.t; paren = t == BC_LEX_LPAREN; - if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON) bc_parse_push(p, BC_INST_RET0); + if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst); else { - 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) { - bc_parse_push(p, BC_INST_RET0); + s = bc_parse_expr_err(p, 0, bc_parse_next_expr); + if (s && s != BC_STATUS_EMPTY_EXPR) return s; + else if (s == BC_STATUS_EMPTY_EXPR) { + bc_parse_push(p, inst); s = bc_lex_next(&p->l); if (s) return s; } - if (!paren || p->l.t.last != BC_LEX_RPAREN) { - s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL); + if (!paren || p->l.last != BC_LEX_RPAREN) { + s = bc_parse_posixErr(p, BC_ERROR_POSIX_RET); if (s) return s; } + else if (p->func->voidfn) + return bc_parse_verr(p, BC_ERROR_PARSE_RET_VOID, p->func->name); bc_parse_push(p, BC_INST_RET); } @@ -3440,203 +3656,188 @@ BcStatus bc_parse_return(BcParse *p) { return s; } -BcStatus bc_parse_endBody(BcParse *p, int brace) { +static BcStatus bc_parse_endBody(BcParse *p, int brace) { BcStatus s = BC_STATUS_SUCCESS; + int has_brace, new_else = 0; - if (p->flags.len <= 1 || (brace && p->nbraces == 0)) - return BC_STATUS_PARSE_BAD_TOKEN; + if (p->flags.len <= 1) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); if (brace) { - - if (p->l.t.t == BC_LEX_RBRACE) { - if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN; - --p->nbraces; + if (p->l.t == BC_LEX_RBRACE) { s = bc_lex_next(&p->l); if (s) return s; + if (!bc_parse_isDelimiter(p)) + return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); } - else return BC_STATUS_PARSE_BAD_TOKEN; + else return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); } - if (BC_PARSE_IF(p)) { + has_brace = (BC_PARSE_BRACE(p) != 0); - uint8_t *flag_ptr; + do { + size_t len = p->flags.len; + int loop; - while (p->l.t.t == BC_LEX_NLINE) { - s = bc_lex_next(&p->l); - if (s) return s; - } + if (has_brace && !brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); - bc_vec_pop(&p->flags); + loop = BC_PARSE_LOOP_INNER(p) != 0; - flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); - *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END); + if (loop || BC_PARSE_ELSE(p)) { - if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p); - } - else if (BC_PARSE_ELSE(p)) { + if (loop) { - BcInstPtr *ip; - size_t *label; + size_t *label = bc_vec_top(&p->conds); - bc_vec_pop(&p->flags); + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, *label); - ip = bc_vec_top(&p->exits); - label = bc_vec_item(&p->func->labels, ip->idx); - *label = p->func->code.len; + bc_vec_pop(&p->conds); + } - bc_vec_pop(&p->exits); - } - else if (BC_PARSE_FUNC_INNER(p)) { - bc_parse_push(p, BC_INST_RET0); - bc_parse_updateFunc(p, BC_PROG_MAIN); - bc_vec_pop(&p->flags); - } - else { + bc_parse_setLabel(p); + bc_vec_pop(&p->flags); + } + else if (BC_PARSE_FUNC_INNER(p)) { + BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0); + bc_parse_push(p, inst); + bc_parse_updateFunc(p, BC_PROG_MAIN); + bc_vec_pop(&p->flags); + } + else if (BC_PARSE_BRACE(p) && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags); - BcInstPtr *ip = bc_vec_top(&p->exits); - size_t *label = bc_vec_top(&p->conds); + // This needs to be last to parse nested if's properly. + if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) { - bc_parse_push(p, BC_INST_JUMP); - bc_parse_pushIndex(p, *label); + while (p->l.t == BC_LEX_NLINE) { + s = bc_lex_next(&p->l); + if (s) return s; + } - label = bc_vec_item(&p->func->labels, ip->idx); - *label = p->func->code.len; + bc_vec_pop(&p->flags); + *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END; - bc_vec_pop(&p->flags); - bc_vec_pop(&p->exits); - bc_vec_pop(&p->conds); - } + new_else = (p->l.t == BC_LEX_KEY_ELSE); + if (new_else) s = bc_parse_else(p); + } + + if (brace && has_brace) brace = 0; + + } while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) && + !(has_brace = (BC_PARSE_BRACE(p) != 0))); + + if (!s && p->flags.len == 1 && brace) + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); return s; } -void bc_parse_startBody(BcParse *p, uint8_t flags) { - uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); - flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP)); +static void bc_parse_startBody(BcParse *p, uint16_t flags) { + flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP)); flags |= BC_PARSE_FLAG_BODY; bc_vec_push(&p->flags, &flags); } -void bc_parse_noElse(BcParse *p) { - - BcInstPtr *ip; - size_t *label; - uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); - +static void bc_parse_noElse(BcParse *p) { + uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END)); - - ip = bc_vec_top(&p->exits); - label = bc_vec_item(&p->func->labels, ip->idx); - *label = p->func->code.len; - - bc_vec_pop(&p->exits); + bc_parse_setLabel(p); } -BcStatus bc_parse_if(BcParse *p) { +static BcStatus bc_parse_if(BcParse *p) { BcStatus s; - BcInstPtr ip; + size_t idx; 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 != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; - s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); + s = bc_parse_expr_status(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 != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; bc_parse_push(p, BC_INST_JUMP_ZERO); - ip.idx = p->func->labels.len; - ip.func = ip.len = 0; + idx = p->func->labels.len; - bc_parse_pushIndex(p, ip.idx); - bc_vec_push(&p->exits, &ip); - bc_vec_push(&p->func->labels, &ip.idx); + bc_parse_pushIndex(p, idx); + bc_parse_createExitLabel(p, idx, 0); bc_parse_startBody(p, BC_PARSE_FLAG_IF); return BC_STATUS_SUCCESS; } -BcStatus bc_parse_else(BcParse *p) { - - BcInstPtr ip; +static BcStatus bc_parse_else(BcParse *p) { - if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN; + size_t idx = p->func->labels.len; - ip.idx = p->func->labels.len; - ip.func = ip.len = 0; + if (!BC_PARSE_IF_END(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); bc_parse_push(p, BC_INST_JUMP); - bc_parse_pushIndex(p, ip.idx); + bc_parse_pushIndex(p, idx); bc_parse_noElse(p); - bc_vec_push(&p->exits, &ip); - bc_vec_push(&p->func->labels, &ip.idx); + bc_parse_createExitLabel(p, idx, 0); bc_parse_startBody(p, BC_PARSE_FLAG_ELSE); return bc_lex_next(&p->l); } -BcStatus bc_parse_while(BcParse *p) { +static BcStatus bc_parse_while(BcParse *p) { BcStatus s; - BcInstPtr ip; + size_t idx; 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 != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; - ip.idx = p->func->labels.len; + bc_parse_createCondLabel(p, p->func->labels.len); - bc_vec_push(&p->func->labels, &p->func->code.len); - bc_vec_push(&p->conds, &ip.idx); + idx = p->func->labels.len; - ip.idx = p->func->labels.len; - ip.func = 1; - ip.len = 0; - - bc_vec_push(&p->exits, &ip); - bc_vec_push(&p->func->labels, &ip.idx); + bc_parse_createExitLabel(p, idx, 1); - s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); + s = bc_parse_expr_status(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 != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; bc_parse_push(p, BC_INST_JUMP_ZERO); - bc_parse_pushIndex(p, ip.idx); + bc_parse_pushIndex(p, idx); bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); return BC_STATUS_SUCCESS; } -BcStatus bc_parse_for(BcParse *p) { +static BcStatus bc_parse_for(BcParse *p) { BcStatus s; - BcInstPtr ip; size_t cond_idx, exit_idx, body_idx, update_idx; 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 != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_SCOLON) s = bc_parse_expr(p, 0, bc_parse_next_for); - else s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL); + if (p->l.t != BC_LEX_SCOLON) { + s = bc_parse_expr_status(p, 0, bc_parse_next_for); + if (!s) bc_parse_push(p, BC_INST_POP); + } + else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR1); if (s) return s; - if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; @@ -3645,14 +3846,23 @@ BcStatus bc_parse_for(BcParse *p) { body_idx = update_idx + 1; exit_idx = body_idx + 1; - bc_vec_push(&p->func->labels, &p->func->code.len); + bc_parse_createLabel(p, p->func->code.len); + + if (p->l.t != BC_LEX_SCOLON) + s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_for); + else { + + // Set this for the next call to bc_parse_number. + // This is safe to set because the current token + // is a semicolon, which has no string requirement. + bc_vec_string(&p->l.str, strlen(bc_parse_const1), bc_parse_const1); + bc_parse_number(p); - if (p->l.t.t != BC_LEX_SCOLON) - s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for); - else s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL); + s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR2); + } if (s) return s; - if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; @@ -3662,50 +3872,45 @@ BcStatus bc_parse_for(BcParse *p) { bc_parse_push(p, BC_INST_JUMP); bc_parse_pushIndex(p, body_idx); - ip.idx = p->func->labels.len; + bc_parse_createCondLabel(p, update_idx); - bc_vec_push(&p->conds, &update_idx); - bc_vec_push(&p->func->labels, &p->func->code.len); - - if (p->l.t.t != BC_LEX_RPAREN) s = bc_parse_expr(p, 0, bc_parse_next_rel); - else s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL); + if (p->l.t != BC_LEX_RPAREN) { + s = bc_parse_expr_status(p, 0, bc_parse_next_rel); + if (!s) bc_parse_push(p, BC_INST_POP); + } + else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR3); if (s) return s; - if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); bc_parse_push(p, BC_INST_JUMP); bc_parse_pushIndex(p, cond_idx); - bc_vec_push(&p->func->labels, &p->func->code.len); + bc_parse_createLabel(p, p->func->code.len); - ip.idx = exit_idx; - ip.func = 1; - ip.len = 0; - - bc_vec_push(&p->exits, &ip); - bc_vec_push(&p->func->labels, &ip.idx); - bc_lex_next(&p->l); - bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); + bc_parse_createExitLabel(p, exit_idx, 1); + s = bc_lex_next(&p->l); + if (!s) bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); - return BC_STATUS_SUCCESS; + return s; } -BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) { +static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) { - BcStatus s; size_t i; BcInstPtr *ip; - if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN; + if (!BC_PARSE_LOOP(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); if (type == BC_LEX_KEY_BREAK) { - if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN; + if (!p->exits.len) return bc_parse_err(p, BC_ERROR_PARSE_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_parse_err(p, BC_ERROR_PARSE_TOKEN); i = ip->idx; } @@ -3714,54 +3919,66 @@ BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) { bc_parse_push(p, BC_INST_JUMP); bc_parse_pushIndex(p, i); - s = bc_lex_next(&p->l); - 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_lex_next(&p->l); } -BcStatus bc_parse_func(BcParse *p) { +static BcStatus bc_parse_func(BcParse *p) { BcStatus s; - int var, comma = 0; - uint8_t flags; + int comma = 0, voidfn; + uint16_t flags; char *name; + size_t idx; s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC; - name = xstrdup(p->l.t.v.v); - bc_parse_addFunc(p, name, &p->fidx); + if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC); + + voidfn = (!BC_S && !BC_W && p->l.t == BC_LEX_NAME && + !strcmp(p->l.str.v, "void")); s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC; + + voidfn = (voidfn && p->l.t == BC_LEX_NAME); + + if (voidfn) { + s = bc_lex_next(&p->l); + if (s) return s; + } + + if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_FUNC); + + name = xstrdup(p->l.str.v); + idx = bc_program_insertFunc(p->prog, name); + bc_parse_updateFunc(p, idx); + p->func->voidfn = voidfn; + s = bc_lex_next(&p->l); if (s) return s; - while (p->l.t.t != BC_LEX_RPAREN) { + while (p->l.t != BC_LEX_RPAREN) { - if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC; + BcType t = BC_TYPE_VAR; + + if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC); ++p->func->nparams; - name = xstrdup(p->l.t.v.v); + name = xstrdup(p->l.str.v); s = bc_lex_next(&p->l); if (s) goto err; - var = p->l.t.t != BC_LEX_LBRACKET; + if (p->l.t == BC_LEX_LBRACKET) { - if (!var) { + if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY; s = bc_lex_next(&p->l); if (s) goto err; - if (p->l.t.t != BC_LEX_RBRACKET) { - s = BC_STATUS_PARSE_BAD_FUNC; + if (p->l.t != BC_LEX_RBRACKET) { + s = bc_parse_err(p, BC_ERROR_PARSE_FUNC); goto err; } @@ -3769,17 +3986,17 @@ BcStatus bc_parse_func(BcParse *p) { if (s) goto err; } - comma = p->l.t.t == BC_LEX_COMMA; + comma = p->l.t == BC_LEX_COMMA; if (comma) { s = bc_lex_next(&p->l); if (s) goto err; } - s = bc_func_insert(p->func, name, var); + s = bc_func_insert(p->func, name, t, p->l.line); if (s) goto err; } - if (comma) return BC_STATUS_PARSE_BAD_FUNC; + if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC); flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY; bc_parse_startBody(p, flags); @@ -3787,8 +4004,7 @@ BcStatus bc_parse_func(BcParse *p) { s = bc_lex_next(&p->l); if (s) return s; - if (p->l.t.t != BC_LEX_LBRACE) - s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL); + if (p->l.t != BC_LEX_LBRACE) s = bc_parse_posixErr(p, BC_ERROR_POSIX_BRACE); return s; @@ -3797,138 +4013,139 @@ err: return s; } -BcStatus bc_parse_auto(BcParse *p) { +static BcStatus bc_parse_auto(BcParse *p) { BcStatus s; - int comma, var, one; + int comma, one; char *name; - if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN; + if (!p->auto_part) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_lex_next(&p->l); if (s) return s; p->auto_part = comma = 0; - one = p->l.t.t == BC_LEX_NAME; + one = p->l.t == BC_LEX_NAME; + + while (p->l.t == BC_LEX_NAME) { - while (p->l.t.t == BC_LEX_NAME) { + BcType t; - name = xstrdup(p->l.t.v.v); + name = xstrdup(p->l.str.v); s = bc_lex_next(&p->l); if (s) goto err; - var = p->l.t.t != BC_LEX_LBRACKET; - if (!var) { + if (p->l.t == BC_LEX_LBRACKET) { + + t = BC_TYPE_ARRAY; s = bc_lex_next(&p->l); if (s) goto err; - if (p->l.t.t != BC_LEX_RBRACKET) { - s = BC_STATUS_PARSE_BAD_FUNC; + if (p->l.t != BC_LEX_RBRACKET) { + s = bc_parse_err(p, BC_ERROR_PARSE_FUNC); goto err; } s = bc_lex_next(&p->l); if (s) goto err; } + else t = BC_TYPE_VAR; - comma = p->l.t.t == BC_LEX_COMMA; + comma = p->l.t == BC_LEX_COMMA; if (comma) { s = bc_lex_next(&p->l); if (s) goto err; } - s = bc_func_insert(p->func, name, var); + s = bc_func_insert(p->func, name, t, p->l.line); if (s) goto err; } - if (comma) return BC_STATUS_PARSE_BAD_FUNC; - if (!one) return BC_STATUS_PARSE_NO_AUTO; - - if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON) - return BC_STATUS_PARSE_BAD_TOKEN; + if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC); + if (!one) return bc_parse_err(p, BC_ERROR_PARSE_NO_AUTO); + if (!bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); - return bc_lex_next(&p->l); + return s; err: free(name); return s; } -BcStatus bc_parse_body(BcParse *p, int brace) { +static BcStatus bc_parse_body(BcParse *p, int brace) { BcStatus s = BC_STATUS_SUCCESS; - uint8_t *flag_ptr = bc_vec_top(&p->flags); + uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); *flag_ptr &= ~(BC_PARSE_FLAG_BODY); if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) { - if (!brace) return BC_STATUS_PARSE_BAD_TOKEN; - p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO; + if (!brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + + p->auto_part = p->l.t != BC_LEX_KEY_AUTO; if (!p->auto_part) { + + // Make sure this is 1 to not get a parse error. + p->auto_part = 1; + s = bc_parse_auto(p); if (s) return s; } - if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l); + if (p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l); } else { s = bc_parse_stmt(p); - if (!s && !brace) s = bc_parse_endBody(p, 0); + if (!s && !brace && !BC_PARSE_BODY(p)) s = bc_parse_endBody(p, 0); } return s; } -BcStatus bc_parse_stmt(BcParse *p) { +static BcStatus bc_parse_stmt(BcParse *p) { BcStatus s = BC_STATUS_SUCCESS; + size_t len; + uint16_t flags; + BcLexType type = p->l.t; - switch (p->l.t.t) { - - case BC_LEX_NLINE: - { - return bc_lex_next(&p->l); - } - - case BC_LEX_KEY_ELSE: - { - p->auto_part = 0; - break; - } - - case BC_LEX_LBRACE: - { - if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN; + if (type == BC_LEX_NLINE) return bc_lex_next(&p->l); + if (type == BC_LEX_KEY_AUTO) return bc_parse_auto(p); - ++p->nbraces; - s = bc_lex_next(&p->l); - if (s) return s; + p->auto_part = 0; - return bc_parse_body(p, 1); - } + if (type != BC_LEX_KEY_ELSE) { - case BC_LEX_KEY_AUTO: - { - return bc_parse_auto(p); + if (BC_PARSE_IF_END(p)) { + bc_parse_noElse(p); + if (p->flags.len > 1 && !BC_PARSE_BRACE(p)) + s = bc_parse_endBody(p, 0); + return s; } + else if (type == BC_LEX_LBRACE) { - default: - { - p->auto_part = 0; - - if (BC_PARSE_IF_END(p)) { - bc_parse_noElse(p); - return BC_STATUS_SUCCESS; + if (!BC_PARSE_BODY(p)) { + bc_parse_startBody(p, BC_PARSE_FLAG_BRACE); + s = bc_lex_next(&p->l); + } + else { + *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE; + s = bc_lex_next(&p->l); + if (!s) s = bc_parse_body(p, 1); } - else if (BC_PARSE_BODY(p)) return bc_parse_body(p, 0); - break; + return s; } + else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p)) + return bc_parse_body(p, 0); } - switch (p->l.t.t) { + len = p->flags.len; + flags = BC_PARSE_TOP_FLAG(p); + + switch (type) { case BC_LEX_OP_INC: case BC_LEX_OP_DEC: @@ -3944,8 +4161,9 @@ BcStatus bc_parse_stmt(BcParse *p) { case BC_LEX_KEY_READ: case BC_LEX_KEY_SCALE: case BC_LEX_KEY_SQRT: + case BC_LEX_KEY_ABS: { - s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr); + s = bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr); break; } @@ -3957,7 +4175,7 @@ BcStatus bc_parse_stmt(BcParse *p) { case BC_LEX_SCOLON: { - while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l); + // Do nothing. break; } @@ -3969,14 +4187,14 @@ BcStatus bc_parse_stmt(BcParse *p) { case BC_LEX_STR: { - s = bc_parse_string(p, BC_INST_PRINT_STR); + s = bc_parse_str(p, BC_INST_PRINT_STR); break; } case BC_LEX_KEY_BREAK: case BC_LEX_KEY_CONTINUE: { - s = bc_parse_loopExit(p, p->l.t.t); + s = bc_parse_loopExit(p, p->l.t); break; } @@ -4001,9 +4219,17 @@ BcStatus bc_parse_stmt(BcParse *p) { case BC_LEX_KEY_LIMITS: { + printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE); + printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM); + printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE); + printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING); + printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME); + printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM); + printf("MAX Exponent = %lu\n", BC_MAX_EXP); + printf("Number of vars = %lu\n", BC_MAX_VARS); + s = bc_lex_next(&p->l); - if (s) return s; - s = BC_STATUS_LIMITS; + break; } @@ -4035,11 +4261,18 @@ BcStatus bc_parse_stmt(BcParse *p) { default: { - s = BC_STATUS_PARSE_BAD_TOKEN; + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); break; } } + if (!s && len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) { + if (!bc_parse_isDelimiter(p)) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); + } + + // Make sure semicolons are eaten. + while (!s && p->l.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l); + return s; } @@ -4047,51 +4280,56 @@ 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; - else if (p->l.t.t == BC_LEX_KEY_DEFINE) { - if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t == BC_LEX_EOF) s = bc_parse_err(p, BC_ERROR_PARSE_EOF); + else if (p->l.t == BC_LEX_KEY_DEFINE) { + if (BC_PARSE_NO_EXEC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN); s = bc_parse_func(p); } else s = bc_parse_stmt(p); - if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || TT.signe) - s = bc_parse_reset(p, s); + if ((s && s != BC_STATUS_QUIT) || BC_SIGNAL) s = bc_parse_reset(p, s); return s; } -BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) { +static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next) { BcStatus s = BC_STATUS_SUCCESS; BcInst prev = BC_INST_PRINT; - BcLexType top, t = p->l.t.t; + BcLexType top, t = p->l.t; size_t nexprs = 0, ops_bgn = p->ops.len; uint32_t i, nparens, nrelops; - int paren_first, paren_expr, rprn, done, get_token, assign, bin_last; + int pfirst, rprn, done, get_token, assign, bin_last, incdec; - paren_first = p->l.t.t == BC_LEX_LPAREN; + pfirst = p->l.t == BC_LEX_LPAREN; nparens = nrelops = 0; - paren_expr = rprn = done = get_token = assign = 0; + rprn = done = get_token = assign = incdec = 0; bin_last = 1; - for (; !TT.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) - { + // We want to eat newlines if newlines are not a valid ending token. + // This is for spacing in things like for loop headers. + while (!s && (t = p->l.t) == BC_LEX_NLINE) s = bc_lex_next(&p->l); + + for (; !BC_SIGNAL && !s && !done && BC_PARSE_EXPR(t); t = p->l.t) { + switch (t) { case BC_LEX_OP_INC: case BC_LEX_OP_DEC: { - s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags); + if (incdec) return bc_parse_err(p, BC_ERROR_PARSE_ASSIGN); + s = bc_parse_incdec(p, &prev, &nexprs, flags); rprn = get_token = bin_last = 0; + incdec = 1; break; } case BC_LEX_OP_MINUS: { - s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs); + s = bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs); rprn = get_token = 0; - bin_last = prev == BC_INST_MINUS; + bin_last = (prev == BC_INST_MINUS); + if (bin_last) incdec = 0; break; } @@ -4103,11 +4341,8 @@ BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) { case BC_LEX_OP_ASSIGN_MINUS: case BC_LEX_OP_ASSIGN: { - if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM && - prev != BC_INST_SCALE && prev != BC_INST_IBASE && - prev != BC_INST_OBASE && prev != BC_INST_LAST) - { - s = BC_STATUS_PARSE_BAD_ASSIGN; + if (!BC_PARSE_INST_VAR(prev)) { + s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN); break; } } @@ -4127,27 +4362,30 @@ 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 (BC_PARSE_OP_PREFIX(t)) { + if (!bin_last && !BC_PARSE_OP_PREFIX(p->l.last)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); } + else if (BC_PARSE_PREV_PREFIX(prev) || bin_last) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT; + nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT); prev = BC_PARSE_TOKEN_INST(t); - s = bc_parse_operator(p, t, ops_bgn, &nexprs, 1); - rprn = get_token = 0; - bin_last = t != BC_LEX_OP_BOOL_NOT; + bc_parse_operator(p, t, ops_bgn, &nexprs); + rprn = incdec = 0; + get_token = 1; + bin_last = !BC_PARSE_OP_PREFIX(t); break; } case BC_LEX_LPAREN: { - if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + if (BC_PARSE_LEAF(prev, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); ++nparens; - paren_expr = rprn = bin_last = 0; + rprn = incdec = 0; get_token = 1; bc_vec_push(&p->ops, &t); @@ -4156,20 +4394,23 @@ 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; + // This needs to be a status. The error + // is handled in bc_parse_expr_status(). + if (p->l.last == BC_LEX_LPAREN) return BC_STATUS_EMPTY_EXPR; + + if (bin_last || BC_PARSE_PREV_PREFIX(prev)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - if (nparens == 0) { + if (!nparens) { s = BC_STATUS_SUCCESS; done = 1; get_token = 0; break; } - else if (!paren_expr) return BC_STATUS_PARSE_EMPTY_EXP; --nparens; - paren_expr = rprn = 1; - get_token = bin_last = 0; + rprn = 1; + get_token = bin_last = incdec = 0; s = bc_parse_rightParen(p, ops_bgn, &nexprs); @@ -4178,11 +4419,12 @@ 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, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - paren_expr = 1; - rprn = get_token = bin_last = 0; + get_token = bin_last = 0; s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL); + rprn = (prev == BC_INST_CALL); ++nexprs; break; @@ -4190,10 +4432,13 @@ 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, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - bc_parse_number(p, &prev, &nexprs); - paren_expr = get_token = 1; + bc_parse_number(p); + nexprs += 1; + prev = BC_INST_NUM; + get_token = 1; rprn = bin_last = 0; break; @@ -4203,12 +4448,13 @@ 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, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE); - bc_parse_push(p, (char) prev); + prev = (uchar) (t - BC_LEX_KEY_LAST + BC_INST_LAST); + bc_parse_push(p, (uchar) prev); - paren_expr = get_token = 1; + get_token = 1; rprn = bin_last = 0; ++nexprs; @@ -4217,12 +4463,13 @@ BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) { case BC_LEX_KEY_LENGTH: case BC_LEX_KEY_SQRT: + case BC_LEX_KEY_ABS: { - if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + if (BC_PARSE_LEAF(prev, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); s = bc_parse_builtin(p, t, flags, &prev); - paren_expr = 1; - rprn = get_token = bin_last = 0; + rprn = get_token = bin_last = incdec = 0; ++nexprs; break; @@ -4230,12 +4477,13 @@ 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; - else if (flags & BC_PARSE_NOREAD) s = BC_STATUS_EXEC_REC_READ; + if (BC_PARSE_LEAF(prev, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); + else if (flags & BC_PARSE_NOREAD) + s = bc_parse_err(p, BC_ERROR_EXEC_REC_READ); else s = bc_parse_read(p); - paren_expr = 1; - rprn = get_token = bin_last = 0; + rprn = get_token = bin_last = incdec = 0; ++nexprs; prev = BC_INST_READ; @@ -4244,20 +4492,19 @@ 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, bin_last, rprn)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); s = bc_parse_scale(p, &prev, flags); - paren_expr = 1; rprn = get_token = bin_last = 0; ++nexprs; - prev = BC_INST_SCALE; break; } default: { - s = BC_STATUS_PARSE_BAD_TOKEN; + s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN); break; } } @@ -4266,7 +4513,7 @@ BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) { } if (s) return s; - if (TT.signe) return BC_STATUS_EXEC_SIGNAL; + if (BC_SIGNAL) return BC_STATUS_SIGNAL; while (p->ops.len > ops_bgn) { @@ -4274,53 +4521,127 @@ 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_parse_err(p, BC_ERROR_PARSE_EXPR); bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); - nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG; + nexprs -= !BC_PARSE_OP_PREFIX(top); bc_vec_pop(&p->ops); } - s = BC_STATUS_PARSE_BAD_EXP; - if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s; + if (nexprs != 1) return bc_parse_err(p, BC_ERROR_PARSE_EXPR); - for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i]; - if (s) return s; + for (i = 0; i < next.len && t != next.tokens[i]; ++i); + if (i == next.len && !bc_parse_isDelimiter(p)) + return bc_parse_err(p, BC_ERROR_PARSE_EXPR); if (!(flags & BC_PARSE_REL) && nrelops) { - s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL); + s = bc_parse_posixErr(p, BC_ERROR_POSIX_REL_POS); if (s) return s; } else if ((flags & BC_PARSE_REL) && nrelops > 1) { - s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL); + s = bc_parse_posixErr(p, BC_ERROR_POSIX_MULTIREL); if (s) return s; } if (flags & BC_PARSE_PRINT) { - if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT); + if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT); bc_parse_push(p, BC_INST_POP); } + // We want to eat newlines if newlines are not a valid ending token. + // This is for spacing in things like for loop headers. + for (incdec = 1, i = 0; i < next.len && incdec; ++i) + incdec = (next.tokens[i] != BC_LEX_NLINE); + if (incdec) { + while (!s && p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l); + } + return s; } -void bc_program_search(BcProgram *p, char *id, BcVec **ret, int var) { +BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) { + + BcStatus s = bc_parse_expr_err(p, flags, next); + + if (s == BC_STATUS_EMPTY_EXPR) s = bc_parse_err(p, BC_ERROR_PARSE_EMPTY_EXPR); + + return s; +} + +BcStatus bc_parse_expr(BcParse *p, uint8_t flags) { + return bc_parse_expr_status(p, flags, bc_parse_next_read); +} + +static BcStatus bc_program_type_num(BcResult *r, BcNum *n) { + if (!BC_PROG_NUM(r, n)) return bc_vm_err(BC_ERROR_EXEC_TYPE); + return BC_STATUS_SUCCESS; +} + +static BcStatus bc_program_type_match(BcResult *r, BcType t) { + if ((r->t != BC_RESULT_ARRAY) != (!t)) return bc_vm_err(BC_ERROR_EXEC_TYPE); + return BC_STATUS_SUCCESS; +} + +static char *bc_program_str(BcProgram *p, size_t idx, int str) { + + BcFunc *f; + BcVec *v; + size_t i; + + BcInstPtr *ip = bc_vec_item_rev(&p->stack, 0); + i = ip->func; + + f = bc_vec_item(&p->fns, i); + v = str ? &f->strs : &f->consts; + + return *((char**) bc_vec_item(v, idx)); +} + +static size_t bc_program_index(char *code, size_t *bgn) { + + uchar amt = (uchar) code[(*bgn)++], i = 0; + size_t res = 0; + + for (; i < amt; ++i, ++(*bgn)) { + size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX); + res |= (temp << (i * CHAR_BIT)); + } + + return res; +} + +static char *bc_program_name(char *code, size_t *bgn) { + + size_t i; + uchar c; + char *s; + char *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND); + + s = xmalloc(((unsigned long) ptr) - ((unsigned long) str) + 1); + + for (i = 0; (c = (uchar) code[(*bgn)++]) && c != BC_PARSE_STREND; ++i) + s[i] = (char) c; + + s[i] = '\0'; + + return s; +} + +static BcVec* bc_program_search(BcProgram *p, char *id, BcType type) { - BcStatus s; BcId e, *ptr; BcVec *v, *map; size_t i; BcResultData data; - int new; + int new, var = (type == BC_TYPE_VAR); v = var ? &p->vars : &p->arrs; map = var ? &p->var_map : &p->arr_map; e.name = id; e.idx = v->len; - s = bc_map_insert(map, &e, &i); - new = s != BC_STATUS_VEC_ITEM_EXISTS; + new = bc_map_insert(map, &e, &i); if (new) { bc_array_init(&data.v, var); @@ -4329,46 +4650,41 @@ void bc_program_search(BcProgram *p, char *id, BcVec **ret, int var) { ptr = bc_vec_item(map, i); if (new) ptr->name = xstrdup(e.name); - *ret = bc_vec_item(v, ptr->idx); + + return bc_vec_item(v, ptr->idx); } -BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, int hex) { +static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num) { BcStatus s = BC_STATUS_SUCCESS; + BcNum *n = &r->d.n; switch (r->t) { - case BC_RESULT_STR: - case BC_RESULT_TEMP: - case BC_RESULT_IBASE: - case BC_RESULT_SCALE: - case BC_RESULT_OBASE: - { - *num = &r->d.n; - break; - } - case BC_RESULT_CONSTANT: { - char **str = bc_vec_item(&p->consts, r->d.id.idx); - size_t base_t, len = strlen(*str); - BcNum *base; + char *str = bc_program_str(p, r->d.id.idx, 0); + size_t len = strlen(str); - bc_num_init(&r->d.n, len); + bc_num_init(n, len); - hex = hex && len == 1; - base = hex ? &p->hexb : &p->ib; - base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t; - s = bc_num_parse(&r->d.n, *str, base, base_t); + s = bc_num_parse(n, str, &p->ib, p->ib_t, len == 1); if (s) { - bc_num_free(&r->d.n); + bc_num_free(n); return s; } - *num = &r->d.n; r->t = BC_RESULT_TEMP; - + } + // Fallthrough. + case BC_RESULT_STR: + case BC_RESULT_TEMP: + case BC_RESULT_IBASE: + case BC_RESULT_SCALE: + case BC_RESULT_OBASE: + { + *num = n; break; } @@ -4377,13 +4693,18 @@ BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, int hex) { case BC_RESULT_ARRAY_ELEM: { BcVec *v; + BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; - bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR); + v = bc_program_search(p, r->d.id.name, type); if (r->t == BC_RESULT_ARRAY_ELEM) { + + size_t idx = r->d.id.idx; + v = bc_vec_top(v); - 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); + + if (v->len <= idx) bc_array_expand(v, idx + 1); + *num = bc_vec_item(v, idx); } else *num = bc_vec_top(v); @@ -4401,85 +4722,120 @@ BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, int hex) { *num = &p->one; break; } + + case BC_RESULT_VOID: + { + s = bc_vm_err(BC_ERROR_EXEC_VOID_VAL); + break; + } } return s; } -BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln, - BcResult **r, BcNum **rn, int assign) +static BcStatus bc_program_operand(BcProgram *p, BcResult **r, + BcNum **n, size_t idx) { - BcStatus s; - int hex; - BcResultType lt, rt; - if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK; + *r = bc_vec_item_rev(&p->results, idx); - *r = bc_vec_item_rev(&p->results, 0); - *l = bc_vec_item_rev(&p->results, 1); + return bc_program_num(p, *r, n); +} - lt = (*l)->t; - rt = (*r)->t; - hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE); +static BcStatus bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln, + BcResult **r, BcNum **rn) +{ + BcStatus s; + BcResultType lt; - s = bc_program_num(p, *l, ln, 0); + s = bc_program_operand(p, l, ln, 1); if (s) return s; - s = bc_program_num(p, *r, rn, hex); + s = bc_program_operand(p, r, rn, 0); if (s) return s; + lt = (*l)->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 == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) { - s = bc_program_num(p, *l, ln, 0); - if (s) return s; - } + if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) + s = bc_program_num(p, *l, 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; + if (lt == BC_RESULT_STR) return bc_vm_err(BC_ERROR_EXEC_TYPE); return s; } -void bc_program_binOpRetire(BcProgram *p, BcResult *r) { +static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln, + BcResult **r, BcNum **rn) +{ + BcStatus s; + + s = bc_program_binPrep(p, l, ln, r, rn); + if (s) return s; + + s = bc_program_type_num(*l, *ln); + if (s) return s; + + return bc_program_type_num(*r, *rn); +} + +static BcStatus bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln, + BcResult **r, BcNum **rn) +{ + BcStatus s; + int good = 0; + BcResultType lt; + + s = bc_program_binPrep(p, l, ln, r, rn); + if (s) return s; + + lt = (*l)->t; + + if (lt == BC_RESULT_CONSTANT || lt == BC_RESULT_TEMP ||lt == BC_RESULT_ARRAY) + return bc_vm_err(BC_ERROR_EXEC_TYPE); + + if (lt == BC_RESULT_ONE) return bc_vm_err(BC_ERROR_EXEC_TYPE); + + if (!good) s = bc_program_type_num(*r, *rn); + + return s; +} + +static void bc_program_binOpRetire(BcProgram *p, BcResult *r) { r->t = BC_RESULT_TEMP; bc_vec_pop(&p->results); bc_vec_pop(&p->results); bc_vec_push(&p->results, r); } -BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) { +static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) { BcStatus s; - if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; - *r = bc_vec_top(&p->results); - - s = bc_program_num(p, *r, n, 0); + s = bc_program_operand(p, r, n, 0); if (s) return s; - if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE; - - return s; + return bc_program_type_num(*r, *n); } -void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) { +static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) { r->t = t; bc_vec_pop(&p->results); bc_vec_push(&p->results, r); } -BcStatus bc_program_op(BcProgram *p, char inst) { +static BcStatus bc_program_op(BcProgram *p, uchar inst) { BcStatus s; BcResult *opd1, *opd2, res; - BcNum *n1, *n2 = NULL; + BcNum *n1 = NULL, *n2 = NULL; + size_t idx = inst - BC_INST_POWER; - s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 0); + s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2); if (s) return s; - bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); + bc_num_init(&res.d.n, bc_program_opReqs[idx](n1, n2, p->scale)); - s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale); + s = bc_program_ops[idx](n1, n2, &res.d.n, p->scale); if (s) goto err; bc_program_binOpRetire(p, &res); @@ -4490,36 +4846,42 @@ err: return s; } -BcStatus bc_program_read(BcProgram *p) { +static BcStatus bc_program_read(BcProgram *p) { BcStatus s; BcParse parse; BcVec buf; BcInstPtr ip; size_t i; + char *file; BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ); for (i = 0; i < p->stack.len; ++i) { BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i); - if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ; + if (ip_ptr->func == BC_PROG_READ) + return bc_vm_err(BC_ERROR_EXEC_REC_READ); } + file = BC_VM->file; + bc_lex_file(&parse.l, bc_program_stdin_name); bc_vec_npop(&f->code, f->code.len); bc_vec_init(&buf, sizeof(char), NULL); s = bc_read_line(&buf, "read> "); - if (s) goto io_err; + if (s) { + if (s == BC_STATUS_EOF) s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR); + goto io_err; + } bc_parse_init(&parse, p, BC_PROG_READ); - bc_lex_file(&parse.l, bc_program_stdin_name); s = bc_parse_text(&parse, buf.v); if (s) goto exec_err; - s = bc_parse_expr(&parse, BC_PARSE_NOREAD, bc_parse_next_read); + s = bc_parse_expr(&parse, BC_PARSE_NOREAD); 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; + if (parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF) { + s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR); goto exec_err; } @@ -4530,156 +4892,90 @@ BcStatus bc_program_read(BcProgram *p) { // Update this pointer, just in case. f = bc_vec_item(&p->fns, BC_PROG_READ); - bc_vec_pushByte(&f->code, BC_INST_POP_EXEC); + bc_vec_pushByte(&f->code, BC_INST_RET); bc_vec_push(&p->stack, &ip); exec_err: bc_parse_free(&parse); io_err: bc_vec_free(&buf); + BC_VM->file = file; return s; } -size_t bc_program_index(char *code, size_t *bgn) { - - char amt = code[(*bgn)++], i = 0; - size_t res = 0; - - for (; i < amt; ++i, ++(*bgn)) - res |= (((size_t) ((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT)); - - return res; -} - -char* bc_program_name(char *code, size_t *bgn) { - - size_t i; - char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND); - - s = xmalloc(ptr - str + 1); - c = code[(*bgn)++]; - - for (i = 0; c && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i) - s[i] = c; - - s[i] = '\0'; - - return s; +static void bc_program_printChars(char *str) { + char *nl; + BC_VM->nchars += printf("%s", str); + nl = strrchr(str, '\n'); + if (nl) BC_VM->nchars = strlen(nl + 1); } -void bc_program_printString(char *str, size_t *nchars) { +static void bc_program_printString(char *str) { size_t i, len = strlen(str); - for (i = 0; i < len; ++i, ++(*nchars)) { + for (i = 0; i < len; ++i, ++BC_VM->nchars) { int c = str[i]; - if (c != '\\' || i == len - 1) bc_vm_putchar(c); - else { - - c = str[++i]; - - switch (c) { - - case 'a': - { - bc_vm_putchar('\a'); - break; - } - - case 'b': - { - bc_vm_putchar('\b'); - break; - } - - case '\\': - case 'e': - { - bc_vm_putchar('\\'); - break; - } - - case 'f': - { - bc_vm_putchar('\f'); - break; - } - - case 'n': - { - bc_vm_putchar('\n'); - *nchars = SIZE_MAX; - break; - } - - case 'r': - { - bc_vm_putchar('\r'); - break; - } + if (c == '\\' && i != len - 1) { - case 'q': - { - bc_vm_putchar('"'); - break; - } + char *ptr; - case 't': - { - bc_vm_putchar('\t'); - break; - } + c = str[++i]; + ptr = strchr(bc_program_esc_chars, c); - default: - { - // Just print the backslash and following character. - bc_vm_putchar('\\'); - ++(*nchars); - bc_vm_putchar(c); - break; - } + if (ptr) { + if (c == 'n') BC_VM->nchars = SIZE_MAX; + c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)]; + } + else { + // Just print the backslash. The following + // character will be printed later. + putchar('\\'); + ++BC_VM->nchars; } } + + putchar(c); } } -BcStatus bc_program_print(BcProgram *p, char inst, size_t idx) { +static BcStatus bc_program_print(BcProgram *p, uchar inst, size_t idx) { BcStatus s = BC_STATUS_SUCCESS; BcResult *r; - size_t len, i; char *str; - BcNum *num = NULL; + BcNum *n = NULL; int pop = inst != BC_INST_PRINT; - if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK; - r = bc_vec_item_rev(&p->results, idx); - s = bc_program_num(p, r, &num, 0); + + if (r->t == BC_RESULT_VOID) { + if (pop) return bc_vm_err(BC_ERROR_EXEC_VOID_VAL); + return s; + } + + s = bc_program_num(p, r, &n); if (s) return s; - if (BC_PROG_NUM(r, num)) { - s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len); - if (!s) bc_num_copy(&p->last, num); + if (BC_PROG_NUM(r, n)) { + s = bc_num_print(n, &p->ob, p->ob_t, !pop); + if (!s) bc_num_copy(&p->last, n); } else { - idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx; - str = *((char**) bc_vec_item(&p->strs, idx)); + size_t i = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx; - if (inst == BC_INST_PRINT_STR) { - for (i = 0, len = strlen(str); i < len; ++i) { - char c = str[i]; - bc_vm_putchar(c); - if (c == '\n') p->nchars = SIZE_MAX; - ++p->nchars; - } - } + str = bc_program_str(p, i, 1); + + if (inst == BC_INST_PRINT_STR) bc_program_printChars(str); else { - bc_program_printString(str, &p->nchars); - if (inst == BC_INST_PRINT) bc_vm_putchar('\n'); + bc_program_printString(str); + if (inst == BC_INST_PRINT) { + putchar('\n'); + BC_VM->nchars = 0; + } } } @@ -4688,7 +4984,17 @@ BcStatus bc_program_print(BcProgram *p, char inst, size_t idx) { return s; } -BcStatus bc_program_negate(BcProgram *p) { +void bc_program_negate(BcResult *r, BcNum *n) { + BcNum *rn = &r->d.n; + bc_num_copy(rn, n); + if (rn->len) rn->neg = !rn->neg; +} + +void bc_program_not(BcResult *r, BcNum *n) { + if (!BC_NUM_CMP_ZERO(n)) bc_num_one(&r->d.n); +} + +static BcStatus bc_program_unary(BcProgram *p, uchar inst) { BcStatus s; BcResult res, *ptr; @@ -4698,30 +5004,28 @@ BcStatus bc_program_negate(BcProgram *p) { if (s) return 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_unarys[inst - BC_INST_NEG](&res, num); bc_program_retire(p, &res, BC_RESULT_TEMP); return s; } -BcStatus bc_program_logical(BcProgram *p, char inst) { +static BcStatus bc_program_logical(BcProgram *p, uchar inst) { BcStatus s; BcResult *opd1, *opd2, res; - BcNum *n1, *n2; + BcNum *n1 = NULL, *n2 = NULL; int cond = 0; ssize_t cmp; - s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 0); + s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2); if (s) return s; bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); if (inst == BC_INST_BOOL_AND) - cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero); + cond = BC_NUM_CMP_ZERO(n1) && BC_NUM_CMP_ZERO(n2); else if (inst == BC_INST_BOOL_OR) - cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero); + cond = BC_NUM_CMP_ZERO(n1) || BC_NUM_CMP_ZERO(n2); else { cmp = bc_num_cmp(n1, n2); @@ -4748,7 +5052,7 @@ BcStatus bc_program_logical(BcProgram *p, char inst) { case BC_INST_REL_NE: { - cond = cmp; + cond = cmp != 0; break; } @@ -4766,107 +5070,114 @@ BcStatus bc_program_logical(BcProgram *p, char inst) { } } - (cond ? bc_num_one : bc_num_zero)(&res.d.n); + if (cond) bc_num_one(&res.d.n); bc_program_binOpRetire(p, &res); return s; } -BcStatus bc_program_copyToVar(BcProgram *p, char *name, int var) { - - BcStatus s; +static BcStatus bc_program_copyToVar(BcProgram *p, char *name, + BcType t, int last) +{ + BcStatus s = BC_STATUS_SUCCESS; BcResult *ptr, r; - BcVec *v; - BcNum *n; + BcVec *vec; + BcNum *n = NULL; + int var = (t == BC_TYPE_VAR); - if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; + if (!last) { - ptr = bc_vec_top(&p->results); - if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE; - bc_program_search(p, name, &v, var); + ptr = bc_vec_top(&p->results); - s = bc_program_num(p, ptr, &n, 0); + if (ptr->t == BC_RESULT_VAR || ptr->t == BC_RESULT_ARRAY) { + BcVec *v = bc_program_search(p, ptr->d.id.name, t); + n = bc_vec_item_rev(v, 1); + } + else s = bc_program_num(p, ptr, &n); + } + else s = bc_program_operand(p, &ptr, &n, 0); + + if (s) return s; + + s = bc_program_type_match(ptr, t); if (s) return s; + vec = bc_program_search(p, name, t); + // Do this once more to make sure that pointers were not invalidated. - bc_program_search(p, name, &v, var); + vec = bc_program_search(p, name, t); - if (var) { - bc_num_init(&r.d.n, BC_NUM_DEF_SIZE); - bc_num_copy(&r.d.n, n); - } + if (var) bc_num_createCopy(&r.d.n, n); else { - bc_array_init(&r.d.v, 1); - bc_array_copy(&r.d.v, (BcVec*) n); + + BcVec *v = (BcVec*) n, *rv = &r.d.v; + + bc_array_init(rv, 1); + bc_array_copy(rv, v); } - bc_vec_push(v, &r.d); + bc_vec_push(vec, &r.d); bc_vec_pop(&p->results); return s; } -BcStatus bc_program_assign(BcProgram *p, char inst) { +static BcStatus bc_program_assign(BcProgram *p, uchar inst) { BcStatus s; BcResult *left, *right, res; BcNum *l = NULL, *r = NULL; - unsigned long val, max; - int assign = inst == BC_INST_ASSIGN, ib, sc; + int ib, sc; - s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign); + s = bc_program_assignPrep(p, &left, &l, &right, &r); if (s) return s; - ib = left->t == BC_RESULT_IBASE; - sc = left->t == BC_RESULT_SCALE; - - if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP) - return BC_STATUS_PARSE_BAD_ASSIGN; - - if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero)) - return BC_STATUS_MATH_DIVIDE_BY_ZERO; - - if (assign) bc_num_copy(l, r); - else s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale); + ib = (left->t == BC_RESULT_IBASE); + sc = (left->t == BC_RESULT_SCALE); - if (s) return s; + if (inst == BC_INST_ASSIGN) bc_num_copy(l, r); + else { + s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale); + if (s) return s; + } if (ib || sc || left->t == BC_RESULT_OBASE) { size_t *ptr; + unsigned long val, max, min; + BcError e; s = bc_num_ulong(l, &val); if (s) return s; - s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE; + e = left->t - BC_RESULT_IBASE + BC_ERROR_EXEC_IBASE; if (sc) { max = BC_MAX_SCALE; + min = 0; ptr = &p->scale; } else { - if (val < BC_NUM_MIN_BASE) return s; - max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE; + max = ib ? BC_VM->max_ibase : BC_MAX_OBASE; + min = BC_NUM_MIN_BASE; ptr = ib ? &p->ib_t : &p->ob_t; } - if (val > max) return s; - if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l); + if (val > max || val < min) return bc_vm_verr(e, min, max); + if (!sc) bc_num_ulong2num(ib ? &p->ib : &p->ob, (unsigned long) val); *ptr = (size_t) val; s = BC_STATUS_SUCCESS; } - bc_num_init(&res.d.n, l->len); - bc_num_copy(&res.d.n, l); + bc_num_createCopy(&res.d.n, l); bc_program_binOpRetire(p, &res); return s; } -BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn, - int pop, int copy) -{ +static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn) { + BcStatus s = BC_STATUS_SUCCESS; BcResult r; char *name = bc_program_name(code, bgn); @@ -4879,11 +5190,12 @@ BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn, return s; } -BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn, char inst) +static BcStatus bc_program_pushArray(BcProgram *p, char *code, + size_t *bgn, uchar inst) { BcStatus s = BC_STATUS_SUCCESS; BcResult r; - BcNum *num; + BcNum *num = NULL; r.d.id.name = bc_program_name(code, bgn); @@ -4902,7 +5214,7 @@ BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn, char inst) if (s) goto err; if (temp > BC_MAX_DIM) { - s = BC_STATUS_EXEC_ARRAY_LEN; + s = bc_vm_verr(BC_ERROR_EXEC_ARRAY_LEN, BC_MAX_DIM); goto err; } @@ -4915,30 +5227,28 @@ err: return s; } -BcStatus bc_program_incdec(BcProgram *p, char inst) { +static BcStatus bc_program_incdec(BcProgram *p, uchar inst) { BcStatus s; BcResult *ptr, res, copy; BcNum *num = NULL; - char inst2 = inst; + uchar inst2; s = bc_program_prep(p, &ptr, &num); if (s) return s; if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { copy.t = BC_RESULT_TEMP; - bc_num_init(©.d.n, num->len); - bc_num_copy(©.d.n, num); + bc_num_createCopy(©.d.n, num); } res.t = BC_RESULT_ONE; - inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ? - BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS; + inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01); bc_vec_push(&p->results, &res); - bc_program_assign(p, inst); + bc_program_assign(p, inst2); - if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) { + if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { bc_vec_pop(&p->results); bc_vec_push(&p->results, ©); } @@ -4946,12 +5256,13 @@ BcStatus bc_program_incdec(BcProgram *p, char inst) { return s; } -BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) { - +static BcStatus bc_program_call(BcProgram *p, char *code, + size_t *idx) +{ BcStatus s = BC_STATUS_SUCCESS; BcInstPtr ip; size_t i, nparams = bc_program_index(code, idx); - BcFunc *func; + BcFunc *f; BcVec *v; BcId *a; BcResultData param; @@ -4959,30 +5270,41 @@ BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) { ip.idx = 0; ip.func = bc_program_index(code, idx); - func = bc_vec_item(&p->fns, ip.func); + f = bc_vec_item(&p->fns, ip.func); - if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC; - if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS; + if (!f->code.len) return bc_vm_verr(BC_ERROR_EXEC_UNDEF_FUNC, f->name); + if (nparams != f->nparams) + return bc_vm_verr(BC_ERROR_EXEC_PARAMS, f->nparams, nparams); ip.len = p->results.len - nparams; for (i = 0; i < nparams; ++i) { - a = bc_vec_item(&func->autos, nparams - 1 - i); + size_t j; + int last = 1; + + a = bc_vec_item(&f->autos, nparams - 1 - i); arg = bc_vec_top(&p->results); - if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR) - return BC_STATUS_EXEC_BAD_TYPE; + // If I have already pushed to a var, I need to make sure I + // get the previous version, not the already pushed one. + if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) { + for (j = 0; j < i && last; ++j) { + BcId *id = bc_vec_item(&f->autos, nparams - 1 - j); + last = (strcmp(arg->d.id.name, id->name) != 0 || + (!id->idx) != (arg->t == BC_RESULT_VAR)); + } + } - s = bc_program_copyToVar(p, a->name, a->idx); + s = bc_program_copyToVar(p, a->name, (BcType) a->idx, last); if (s) return s; } - for (; i < func->autos.len; ++i) { + for (; i < f->autos.len; ++i) { - a = bc_vec_item(&func->autos, i); - bc_program_search(p, a->name, &v, a->idx); + a = bc_vec_item(&f->autos, i); + v = bc_program_search(p, a->name, (BcType) a->idx); - if (a->idx) { + if (a->idx == BC_TYPE_VAR) { bc_num_init(¶m.n, BC_NUM_DEF_SIZE); bc_vec_push(v, ¶m.n); } @@ -4997,7 +5319,7 @@ BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) { return BC_STATUS_SUCCESS; } -BcStatus bc_program_return(BcProgram *p, char inst) { +static BcStatus bc_program_return(BcProgram *p, uchar inst) { BcStatus s; BcResult res; @@ -5005,26 +5327,21 @@ BcStatus bc_program_return(BcProgram *p, char inst) { size_t i; BcInstPtr *ip = bc_vec_top(&p->stack); - if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET)) - return BC_STATUS_EXEC_STACK; - f = bc_vec_item(&p->fns, ip->func); res.t = BC_RESULT_TEMP; if (inst == BC_INST_RET) { - BcNum *num; - BcResult *operand = bc_vec_top(&p->results); + BcNum *num = NULL; + BcResult *operand; - s = bc_program_num(p, operand, &num, 0); + s = bc_program_operand(p, &operand, &num, 0); if (s) return s; - bc_num_init(&res.d.n, num->len); - bc_num_copy(&res.d.n, num); - } - else { - bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); - bc_num_zero(&res.d.n); + + bc_num_createCopy(&res.d.n, num); } + else if (inst == BC_INST_RET_VOID) res.t = BC_RESULT_VOID; + else bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); // We need to pop arguments as well, so this takes that into account. for (i = 0; i < f->autos.len; ++i) { @@ -5032,7 +5349,7 @@ BcStatus bc_program_return(BcProgram *p, char inst) { BcVec *v; BcId *a = bc_vec_item(&f->autos, i); - bc_program_search(p, a->name, &v, a->idx); + v = bc_program_search(p, a->name, (BcType) a->idx); bc_vec_pop(v); } @@ -5053,49 +5370,48 @@ unsigned long bc_program_len(BcNum *n) { size_t i; if (n->rdx != n->len) return len; - for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i); + for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i); return len; } -BcStatus bc_program_builtin(BcProgram *p, char inst) { +static BcStatus bc_program_builtin(BcProgram *p, uchar inst) { BcStatus s; BcResult *opnd; - BcNum *num = NULL; BcResult res; - int len = inst == BC_INST_LENGTH; + BcNum *num = NULL, *resn = &res.d.n; + int len = (inst == BC_INST_LENGTH); - if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; - opnd = bc_vec_top(&p->results); - - s = bc_program_num(p, opnd, &num, 0); + s = bc_program_operand(p, &opnd, &num, 0); if (s) return s; - bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); - - if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale); - else if (len && opnd->t == BC_RESULT_ARRAY) { - s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec*) num)->len); + if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, resn, p->scale); + else if (inst == BC_INST_ABS) { + bc_num_createCopy(resn, num); + resn->neg = 0; } else { - BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale; - s = bc_num_ulong2num(&res.d.n, f(num)); - if (s) goto err; + + unsigned long val = 0; + + if (len) { + if (opnd->t == BC_RESULT_ARRAY) + val = (unsigned long) ((BcVec*) num)->len; + else val = bc_program_len(num); + } + else val = bc_program_scale(num); + + bc_num_createFromUlong(resn, val); } bc_program_retire(p, &res, BC_RESULT_TEMP); return s; - -err: - bc_num_free(&res.d.n); - return s; } -BcStatus bc_program_pushGlobal(BcProgram *p, char inst) { +static void bc_program_pushGlobal(BcProgram *p, uchar inst) { - BcStatus s; BcResult res; unsigned long val; @@ -5104,74 +5420,45 @@ BcStatus bc_program_pushGlobal(BcProgram *p, char inst) { else if (inst == BC_INST_SCALE) val = (unsigned long) p->scale; else val = (unsigned long) p->ob_t; - bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); - s = bc_num_ulong2num(&res.d.n, val); - if (s) goto err; + bc_num_createFromUlong(&res.d.n, val); bc_vec_push(&p->results, &res); - - return s; - -err: - bc_num_free(&res.d.n); - return s; } void bc_program_free(BcProgram *p) { - bc_num_free(&p->ib); - bc_num_free(&p->ob); - bc_num_free(&p->hexb); bc_vec_free(&p->fns); bc_vec_free(&p->fn_map); bc_vec_free(&p->vars); bc_vec_free(&p->var_map); bc_vec_free(&p->arrs); bc_vec_free(&p->arr_map); - bc_vec_free(&p->strs); - bc_vec_free(&p->consts); bc_vec_free(&p->results); bc_vec_free(&p->stack); bc_num_free(&p->last); - bc_num_free(&p->zero); - bc_num_free(&p->one); } -void bc_program_init(BcProgram *p, size_t line_len) { +void bc_program_init(BcProgram *p) { - size_t idx; BcInstPtr ip; memset(p, 0, sizeof(BcProgram)); memset(&ip, 0, sizeof(BcInstPtr)); - p->nchars = p->scale = 0; - p->len = line_len; - - bc_num_init(&p->ib, BC_NUM_DEF_SIZE); + bc_num_setup(&p->ib, p->ib_num, BC_NUM_LONG_LOG10); bc_num_ten(&p->ib); p->ib_t = 10; - bc_num_init(&p->ob, BC_NUM_DEF_SIZE); + bc_num_setup(&p->ob, p->ob_num, BC_NUM_LONG_LOG10); bc_num_ten(&p->ob); p->ob_t = 10; - bc_num_init(&p->hexb, BC_NUM_DEF_SIZE); - bc_num_ten(&p->hexb); - p->hexb.num[0] = 6; - - bc_num_init(&p->last, BC_NUM_DEF_SIZE); - bc_num_zero(&p->last); - - bc_num_init(&p->zero, BC_NUM_DEF_SIZE); - bc_num_zero(&p->zero); - - bc_num_init(&p->one, BC_NUM_DEF_SIZE); + bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP); bc_num_one(&p->one); + bc_num_init(&p->last, BC_NUM_DEF_SIZE); bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free); bc_map_init(&p->fn_map); - - bc_program_addFunc(p, xstrdup(bc_func_main), &idx); - bc_program_addFunc(p, xstrdup(bc_func_read), &idx); + bc_program_insertFunc(p, xstrdup(bc_func_main)); + bc_program_insertFunc(p, xstrdup(bc_func_read)); bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free); bc_map_init(&p->var_map); @@ -5179,42 +5466,38 @@ void bc_program_init(BcProgram *p, size_t line_len) { bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free); bc_map_init(&p->arr_map); - bc_vec_init(&p->strs, sizeof(char*), bc_string_free); - bc_vec_init(&p->consts, sizeof(char*), bc_string_free); bc_vec_init(&p->results, sizeof(BcResult), bc_result_free); bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL); bc_vec_push(&p->stack, &ip); } -void bc_program_addFunc(BcProgram *p, char *name, size_t *idx) { - - BcStatus s; - BcId entry, *entry_ptr; - BcFunc f; - - entry.name = name; - entry.idx = p->fns.len; +void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name) { + bc_func_init(f, name); + bc_vec_push(&p->fns, f); +} - s = bc_map_insert(&p->fn_map, &entry, idx); - if (s) free(name); +size_t bc_program_insertFunc(BcProgram *p, char *name) { - entry_ptr = bc_vec_item(&p->fn_map, *idx); - *idx = entry_ptr->idx; + BcId id, *id_ptr; + BcFunc f; + int new; + size_t idx; - if (s == BC_STATUS_VEC_ITEM_EXISTS) { + id.name = name; + id.idx = p->fns.len; - BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx); + new = bc_map_insert(&p->fn_map, &id, &idx); + id_ptr = bc_vec_item(&p->fn_map, idx); + idx = id_ptr->idx; - // We need to reset these, so the function can be repopulated. - func->nparams = 0; - bc_vec_npop(&func->autos, func->autos.len); - bc_vec_npop(&func->code, func->code.len); - bc_vec_npop(&func->labels, func->labels.len); - } - else { - bc_func_init(&f); - bc_vec_push(&p->fns, &f); + if (!new) { + BcFunc *func = bc_vec_item(&p->fns, id_ptr->idx); + bc_func_reset(func); + free(name); } + else bc_program_addFunc(p, &f, name); + + return idx; } BcStatus bc_program_reset(BcProgram *p, BcStatus s) { @@ -5229,15 +5512,13 @@ BcStatus bc_program_reset(BcProgram *p, BcStatus s) { ip = bc_vec_top(&p->stack); ip->idx = f->code.len; - if (!s && TT.signe && !TT.tty) return BC_STATUS_QUIT; - - TT.sigc += TT.signe; - TT.signe = TT.sig != TT.sigc; + if (BC_SIGTERM || (!s && BC_SIGINT && BC_I)) return BC_STATUS_QUIT; + BC_VM->sig = 0; - if (!s || s == BC_STATUS_EXEC_SIGNAL) { - if (TT.ttyin) { - bc_vm_puts(bc_program_ready_msg, stderr); - bc_vm_fflush(stderr); + if (!s || s == BC_STATUS_SIGNAL) { + if (BC_TTYIN) { + fputs(bc_program_ready_msg, stderr); + fflush(stderr); s = BC_STATUS_SUCCESS; } else s = BC_STATUS_QUIT; @@ -5251,15 +5532,15 @@ BcStatus bc_program_exec(BcProgram *p) { BcStatus s = BC_STATUS_SUCCESS; size_t idx; BcResult r, *ptr; - BcNum *num; BcInstPtr *ip = bc_vec_top(&p->stack); BcFunc *func = bc_vec_item(&p->fns, ip->func); char *code = func->code.v; int cond = 0; + BcNum *num; while (!s && ip->idx < func->code.len) { - char inst = code[(ip->idx)++]; + uchar inst = (uchar) code[(ip->idx)++]; switch (inst) { @@ -5267,7 +5548,7 @@ BcStatus bc_program_exec(BcProgram *p) { { s = bc_program_prep(p, &ptr, &num); if (s) return s; - cond = !bc_num_cmp(num, &p->zero); + cond = !BC_NUM_CMP_ZERO(num); bc_vec_pop(&p->results); } // Fallthrough. @@ -5303,11 +5584,19 @@ BcStatus bc_program_exec(BcProgram *p) { case BC_INST_RET: case BC_INST_RET0: + case BC_INST_RET_VOID: { s = bc_program_return(p, inst); break; } + case BC_INST_LAST: + { + r.t = BC_RESULT_LAST; + bc_vec_push(&p->results, &r); + break; + } + case BC_INST_BOOL_OR: case BC_INST_BOOL_AND: case BC_INST_REL_EQ: @@ -5329,7 +5618,7 @@ BcStatus bc_program_exec(BcProgram *p) { case BC_INST_VAR: { - s = bc_program_pushVar(p, code, &ip->idx, 0, 0); + s = bc_program_pushVar(p, code, &ip->idx); break; } @@ -5340,24 +5629,18 @@ BcStatus bc_program_exec(BcProgram *p) { break; } - case BC_INST_LAST: - { - r.t = BC_RESULT_LAST; - bc_vec_push(&p->results, &r); - break; - } - case BC_INST_IBASE: case BC_INST_SCALE: case BC_INST_OBASE: { - s = bc_program_pushGlobal(p, inst); + bc_program_pushGlobal(p, inst); break; } - case BC_INST_SCALE_FUNC: case BC_INST_LENGTH: + case BC_INST_SCALE_FUNC: case BC_INST_SQRT: + case BC_INST_ABS: { s = bc_program_builtin(p, inst); break; @@ -5373,14 +5656,7 @@ BcStatus bc_program_exec(BcProgram *p) { case BC_INST_POP: { - if (!BC_PROG_STACK(&p->results, 1)) s = BC_STATUS_EXEC_STACK; - else bc_vec_pop(&p->results); - break; - } - - case BC_INST_POP_EXEC: - { - bc_vec_pop(&p->stack); + bc_vec_pop(&p->results); break; } @@ -5411,21 +5687,10 @@ BcStatus bc_program_exec(BcProgram *p) { break; } - case BC_INST_BOOL_NOT: - { - s = bc_program_prep(p, &ptr, &num); - if (s) return s; - - bc_num_init(&r.d.n, BC_NUM_DEF_SIZE); - (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n); - bc_program_retire(p, &r, BC_RESULT_TEMP); - - break; - } - case BC_INST_NEG: + case BC_INST_BOOL_NOT: { - s = bc_program_negate(p); + s = bc_program_unary(p, inst); break; } @@ -5442,7 +5707,7 @@ BcStatus bc_program_exec(BcProgram *p) { } } - if ((s && s != BC_STATUS_QUIT) || TT.signe) s = bc_program_reset(p, s); + if ((s && s != BC_STATUS_QUIT) || BC_SIGNAL) s = bc_program_reset(p, s); // If the stack has changed, pointers may be invalid. ip = bc_vec_top(&p->stack); @@ -5453,48 +5718,72 @@ BcStatus bc_program_exec(BcProgram *p) { return s; } -void bc_vm_sig(int sig) { +static void bc_vm_sig(int sig) { int err = errno; - size_t len = strlen(bc_sig_msg); - if (sig == SIGINT && write(2, bc_sig_msg, len) == (ssize_t) len) { - TT.signe = TT.sig == TT.sigc; - TT.sig += TT.signe; + if (sig == SIGINT) { + size_t len = strlen(bc_sig_msg); + if (write(2, bc_sig_msg, len) != (ssize_t) len) sig = 0; } + BC_VM->sig = (uchar) sig; errno = err; } void bc_vm_info(void) { - bc_vm_printf(stdout, "%s %s\n", toys.which->name, "1.1"); - bc_vm_puts(bc_copyright, stdout); + printf("%s %s\n", toys.which->name, "1.1.0"); + fputs(bc_copyright, stdout); } -BcStatus bc_vm_error(BcStatus s, char *file, size_t line) { +static void bc_vm_printError(BcError e, char *fmt, + size_t line, va_list args) +{ + // Make sure all of stdout is written first. + fflush(stdout); - if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s; + fprintf(stderr, fmt, bc_errs[(size_t) bc_err_ids[e]]); + vfprintf(stderr, bc_err_msgs[e], args); - bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]); - bc_vm_printf(stderr, " %s", file); - bc_vm_printf(stderr, bc_err_line + 4 * !line, line); + // This is the condition for parsing vs runtime. + // If line is not 0, it is parsing. + if (line) { + fprintf(stderr, "\n %s", BC_VM->file); + fprintf(stderr, bc_err_line, line); + } + else { + BcInstPtr *ip = bc_vec_item_rev(&BC_VM->prog.stack, 0); + BcFunc *f = bc_vec_item(&BC_VM->prog.fns, ip->func); + fprintf(stderr, "\n Function: %s", f->name); + } - return s * (!TT.ttyin || !!strcmp(file, bc_program_stdin_name)); + fputs("\n\n", stderr); + fflush(stderr); } -BcStatus bc_vm_posixError(BcStatus s, char *file, size_t line, char *msg) -{ - int p = (int) (toys.optflags & FLAG_s), w = (int) (toys.optflags & FLAG_w); - char* fmt = p ? bc_err_fmt : bc_warn_fmt; +BcStatus bc_vm_error(BcError e, size_t line, ...) { - if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS; + va_list args; - bc_vm_printf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]); - if (msg) bc_vm_printf(stderr, " %s\n", msg); - bc_vm_printf(stderr, " %s", file); - bc_vm_printf(stderr, bc_err_line + 4 * !line, line); + va_start(args, line); + bc_vm_printError(e, bc_err_fmt, line, args); + va_end(args); - return s * (!TT.ttyin && !!p); + return BC_STATUS_ERROR; } -size_t bc_vm_envLen(char *var) { +BcStatus bc_vm_posixError(BcError e, size_t line, ...) { + + va_list args; + int p = (int) BC_S, w = (int) BC_W; + + if (!(p || w)) return BC_STATUS_SUCCESS; + + va_start(args, line); + bc_vm_printError(e, p ? bc_err_fmt : bc_warn_fmt, line, args); + va_end(args); + + return p ? BC_STATUS_ERROR : BC_STATUS_SUCCESS; +} + +static size_t bc_vm_envLen(char *var) { char *lenv = getenv(var); size_t i, len = BC_NUM_PRINT_WIDTH; @@ -5507,180 +5796,154 @@ size_t bc_vm_envLen(char *var) { for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]); if (num) { len = (size_t) atoi(lenv) - 1; - if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH; + if (len < 2 || len >= UINT16_MAX) len = BC_NUM_PRINT_WIDTH; } else len = BC_NUM_PRINT_WIDTH; return len; } -void bc_vm_exit(BcStatus s) { - bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]); - exit((int) s); +void bc_vm_shutdown(void) { + bc_program_free(&BC_VM->prog); + bc_parse_free(&BC_VM->prs); + free(BC_VM); } -void bc_vm_printf(FILE *f, char *fmt, ...) { +static void bc_vm_clean() { - va_list args; - int bad; - - va_start(args, fmt); - bad = vfprintf(f, fmt, args) < 0; - va_end(args); + BcProgram *prog = &BC_VM->prog; + BcVec *fns = &prog->fns; + BcFunc *f = bc_vec_item(fns, BC_PROG_MAIN); + BcInstPtr *ip = bc_vec_item(&prog->stack, 0); + int good = !BC_PARSE_NO_EXEC(&BC_VM->prs); - if (bad) bc_vm_exit(BC_STATUS_IO_ERR); -} - -void bc_vm_puts(char *str, FILE *f) { - if (fputs(str, f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); -} - -void bc_vm_putchar(int c) { - if (putchar(c) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); -} - -void bc_vm_fflush(FILE *f) { - if (fflush(f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); + // If this condition is 1, we can get rid of strings, + // constants, and code. This is an idea from busybox. + if (good && prog->stack.len == 1 && !prog->results.len && + ip->idx == f->code.len) + { + bc_vec_npop(&f->labels, f->labels.len); + bc_vec_npop(&f->strs, f->strs.len); + bc_vec_npop(&f->consts, f->consts.len); + bc_vec_npop(&f->code, f->code.len); + ip->idx = 0; + } } -BcStatus bc_vm_process(BcVm *vm, char *text) { +static BcStatus bc_vm_process(char *text, int is_stdin) { - BcStatus s = bc_parse_text(&vm->prs, text); - - s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line); - if (s) return s; - - while (vm->prs.l.t.t != BC_LEX_EOF) { - - s = bc_parse_parse(&vm->prs); - - if (s == BC_STATUS_LIMITS) { + BcStatus s; - bc_vm_putchar('\n'); - bc_vm_printf(stdout, "BC_BASE_MAX = %lu\n", BC_MAX_OBASE); - bc_vm_printf(stdout, "BC_DIM_MAX = %lu\n", BC_MAX_DIM); - bc_vm_printf(stdout, "BC_SCALE_MAX = %lu\n", BC_MAX_SCALE); - bc_vm_printf(stdout, "BC_STRING_MAX = %lu\n", BC_MAX_STRING); - bc_vm_printf(stdout, "BC_NAME_MAX = %lu\n", BC_MAX_NAME); - bc_vm_printf(stdout, "BC_NUM_MAX = %lu\n", BC_MAX_NUM); - bc_vm_printf(stdout, "Max Exponent = %lu\n", BC_MAX_EXP); - bc_vm_printf(stdout, "Number of Vars = %lu\n", BC_MAX_VARS); - bc_vm_putchar('\n'); + s = bc_parse_text(&BC_VM->prs, text); + if (s) goto err; - s = BC_STATUS_SUCCESS; - } - else { - if (s == BC_STATUS_QUIT) return s; - s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line); - if (s) return s; - } + while (BC_VM->prs.l.t != BC_LEX_EOF) { + s = bc_parse_parse(&BC_VM->prs); + if (s) goto err; } - if (BC_PARSE_CAN_EXEC(&vm->prs)) { - s = bc_program_exec(&vm->prog); - if (!s && TT.tty) bc_vm_fflush(stdout); - if (s && s != BC_STATUS_QUIT) - s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0); - } + if (BC_PARSE_NO_EXEC(&BC_VM->prs)) goto err; - return s; + s = bc_program_exec(&BC_VM->prog); + if (BC_I) fflush(stdout); + +err: + if (s || BC_SIGNAL) s = bc_program_reset(&BC_VM->prog, s); + bc_vm_clean(); + return s == BC_STATUS_QUIT || !BC_I || !is_stdin ? s : BC_STATUS_SUCCESS; } -BcStatus bc_vm_file(BcVm *vm, char *file) { +static BcStatus bc_vm_file(char *file) { BcStatus s; char *data; - BcFunc *main_func; - BcInstPtr *ip; - vm->prog.file = file; + bc_lex_file(&BC_VM->prs.l, file); s = bc_read_file(file, &data); - if (s) return bc_vm_error(s, file, 0); + if (s) return s; - bc_lex_file(&vm->prs.l, file); - s = bc_vm_process(vm, data); + s = bc_vm_process(data, 0); if (s) goto err; - main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN); - ip = bc_vec_item(&vm->prog.stack, 0); - - if (main_func->code.len < ip->idx) - s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE; + if (BC_PARSE_NO_EXEC(&BC_VM->prs)) + s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK); err: free(data); return s; } -BcStatus bc_vm_stdin(BcVm *vm) { +static BcStatus bc_vm_stdin(void) { BcStatus s = BC_STATUS_SUCCESS; BcVec buf, buffer; - char c; - size_t len, i, str = 0; - int comment = 0, notend; + size_t string = 0; + int comment = 0, done = 0; - vm->prog.file = bc_program_stdin_name; - bc_lex_file(&vm->prs.l, bc_program_stdin_name); + bc_lex_file(&BC_VM->prs.l, bc_program_stdin_name); - bc_vec_init(&buffer, sizeof(char), NULL); - bc_vec_init(&buf, sizeof(char), NULL); + bc_vec_init(&buffer, sizeof(uchar), NULL); + bc_vec_init(&buf, sizeof(uchar), NULL); bc_vec_pushByte(&buffer, '\0'); // This loop is complex because the vm tries not to send any lines that end // with a backslash to the parser. The reason for that is because the parser // treats a backslash+newline combo as whitespace, per the bc spec. In that // case, and for strings and comments, the parser will expect more stuff. - for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) { - - char *string = buf.v; + while (!done && (s = bc_read_line(&buf, ">>> ")) != BC_STATUS_ERROR && + buf.len > 1 && !BC_SIGNAL && s != BC_STATUS_SIGNAL) + { + char c2, *str = buf.v; + size_t i, len = buf.len - 1; - len = buf.len - 1; + done = (s == BC_STATUS_EOF); - if (len == 1) { - if (str && buf.v[0] == '"') str -= 1; - else if (buf.v[0] == '"') str += 1; + if (len >= 2 && str[len - 1] == '\n' && str[len - 2] == '\\') { + bc_vec_concat(&buffer, buf.v); + continue; } - else if (len > 1 || comment) { - for (i = 0; i < len; ++i) { + for (i = 0; i < len; ++i) { + + int notend = len > i + 1; + uchar c = (uchar) str[i]; - notend = len > i + 1; - c = string[i]; + if (!comment && (i - 1 > len || str[i - 1] != '\\')) string ^= c == '"'; - if ((i - 1 > len || string[i - 1] != '\\') && c == '"') str = !str; + if (!string && notend) { - if (c == '/' && notend && !comment && string[i + 1] == '*') { + c2 = str[i + 1]; + + if (c == '/' && !comment && c2 == '*') { comment = 1; - break; + ++i; } - else if (c == '*' && notend && comment && string[i + 1] == '/') + else if (c == '*' && comment && c2 == '/') { comment = 0; - } - - if (str || comment || string[len - 2] == '\\') { - bc_vec_concat(&buffer, buf.v); - continue; + ++i; + } } } bc_vec_concat(&buffer, buf.v); - s = bc_vm_process(vm, buffer.v); - if (s) goto err; - bc_vec_npop(&buffer, buffer.len); - } + if (string || comment) continue; + if (len >= 2 && str[len - 2] == '\\' && str[len - 1] == '\n') continue; - if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0); + s = bc_vm_process(buffer.v, 1); + if (s) goto err; - // I/O error will always happen when stdin is - // closed. It's not a problem in that case. - s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s; + bc_vec_empty(&buffer); + } - if (str) s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, - vm->prs.l.f, vm->prs.l.line); - else if (comment) s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, - vm->prs.l.f, vm->prs.l.line); + if (s && s != BC_STATUS_EOF) goto err; + else if (BC_SIGNAL && !s) s = BC_STATUS_SIGNAL; + else if (s != BC_STATUS_ERROR) { + if (comment) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_COMMENT); + else if (string) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_STRING); + else if (BC_PARSE_NO_EXEC(&BC_VM->prs)) + s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK); + } err: bc_vec_free(&buf); @@ -5688,74 +5951,62 @@ err: return s; } -BcStatus bc_vm_exec(BcVm *vm) { +static BcStatus bc_vm_load(char *name, char *text) { - BcStatus s = BC_STATUS_SUCCESS; - size_t i; + BcStatus s; - if (toys.optflags & FLAG_l) { + bc_lex_file(&BC_VM->prs.l, name); + s = bc_parse_text(&BC_VM->prs, text); - bc_lex_file(&vm->prs.l, bc_lib_name); - s = bc_parse_text(&vm->prs, bc_lib); + while (!s && BC_VM->prs.l.t != BC_LEX_EOF) s = bc_parse_parse(&BC_VM->prs); - while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = bc_parse_parse(&vm->prs); + return s; +} - if (s) return s; - s = bc_program_exec(&vm->prog); +static BcStatus bc_vm_exec(void) { + + BcStatus s = BC_STATUS_SUCCESS; + size_t i; + + if (toys.optflags & FLAG_l) { + s = bc_vm_load(bc_lib_name, bc_lib); if (s) return s; } - for (i = 0; !s && i < toys.optc; ++i) - s = bc_vm_file(vm, toys.optargs[i]); + for (i = 0; !s && i < toys.optc; ++i) s = bc_vm_file(toys.optargs[i]); if (s && s != BC_STATUS_QUIT) return s; - s = bc_vm_stdin(vm); - if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, ""); - - return s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s; -} - -void bc_vm_free(BcVm *vm) { - bc_program_free(&vm->prog); - bc_parse_free(&vm->prs); + return bc_vm_stdin(); } -BcStatus bc_vm_init(BcVm *vm) { +void bc_main(void) { - BcStatus s = BC_STATUS_SUCCESS; - size_t len = bc_vm_envLen("BC_LINE_LENGTH"); + BcStatus s; struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_handler = bc_vm_sig; sa.sa_flags = 0; sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); - memset(vm, 0, sizeof(BcVm)); + TT.vm = xzalloc(sizeof(BcVm)); + BC_VM->line_len = (uint16_t) bc_vm_envLen("BC_LINE_LENGTH"); - toys.optflags |= FLAG_s * (getenv("POSIXLY_CORRECT") != NULL); + bc_program_init(&BC_VM->prog); + bc_parse_init(&BC_VM->prs, &BC_VM->prog, BC_PROG_MAIN); - bc_program_init(&vm->prog, len); - bc_parse_init(&vm->prs, &vm->prog, BC_PROG_MAIN); - - return s; -} - -void bc_main(void) { - - BcStatus st; - BcVm vm; + toys.optflags |= FLAG_s * (getenv("POSIXLY_CORRECT") != NULL); + toys.optflags |= isatty(0) ? BC_FLAG_TTYIN : 0; + toys.optflags |= BC_TTYIN && isatty(1) ? FLAG_i : 0; - st = bc_vm_init(&vm); - if (st) goto exit; + BC_VM->max_ibase = !BC_S && !BC_W ? BC_NUM_MAX_POSIX_IBASE : BC_NUM_MAX_IBASE; - TT.ttyin = isatty(0); - TT.tty = TT.ttyin || (toys.optflags & FLAG_i) || isatty(1); + if (BC_I && !(toys.optflags & FLAG_q)) bc_vm_info(); - if (TT.ttyin && !(toys.optflags & FLAG_q)) bc_vm_info(); - st = bc_vm_exec(&vm); + s = bc_vm_exec(); -exit: - if (CFG_TOYBOX_FREE) bc_vm_free(&vm); - toys.exitval = (int) st; + if (CFG_TOYBOX_FREE) bc_vm_shutdown(); + toys.exitval = (int) (s != BC_STATUS_ERROR ? BC_STATUS_SUCCESS : s); } |