From 1ee1c71e9dbcb534d2bf8aa03a60d0fb9e077f23 Mon Sep 17 00:00:00 2001 From: Gavin Howard Date: Sat, 3 Nov 2018 10:36:37 -0600 Subject: Update bc for 1.1 release --- toys/pending/bc.c | 6200 ++++++++++++++++++++++++++--------------------------- 1 file changed, 3036 insertions(+), 3164 deletions(-) (limited to 'toys/pending/bc.c') diff --git a/toys/pending/bc.c b/toys/pending/bc.c index 0130d80a..f2a8d1ec 100644 --- a/toys/pending/bc.c +++ b/toys/pending/bc.c @@ -37,6 +37,7 @@ config BC GLOBALS( long tty; + long ttyin; unsigned long sig; unsigned long sigc; @@ -48,143 +49,142 @@ typedef enum BcStatus { BC_STATUS_SUCCESS, - BC_STATUS_MALLOC_FAIL, + BC_STATUS_ALLOC_ERR, BC_STATUS_IO_ERR, - BC_STATUS_BINARY_FILE, + BC_STATUS_BIN_FILE, + BC_STATUS_PATH_IS_DIR, - BC_STATUS_LEX_BAD_CHARACTER, + 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_EXPR, + 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_NEG_SQRT, 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_SIGACTION_FAIL, - BC_STATUS_EXEC_BAD_SCALE, - BC_STATUS_EXEC_BAD_IBASE, - BC_STATUS_EXEC_BAD_OBASE, + 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_NESTED_READ, + BC_STATUS_EXEC_REC_READ, BC_STATUS_EXEC_BAD_TYPE, + BC_STATUS_EXEC_BAD_OBASE, BC_STATUS_EXEC_SIGNAL, - - BC_STATUS_POSIX_NAME_LEN, - BC_STATUS_POSIX_SCRIPT_COMMENT, - BC_STATUS_POSIX_BAD_KEYWORD, - BC_STATUS_POSIX_DOT_LAST, - BC_STATUS_POSIX_RETURN_PARENS, - BC_STATUS_POSIX_BOOL_OPS, - BC_STATUS_POSIX_REL_OUTSIDE, - BC_STATUS_POSIX_MULTIPLE_REL, - BC_STATUS_POSIX_NO_FOR_INIT, - BC_STATUS_POSIX_NO_FOR_COND, - BC_STATUS_POSIX_NO_FOR_UPDATE, - BC_STATUS_POSIX_HEADER_BRACE, + 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, + BC_STATUS_QUIT, BC_STATUS_LIMITS, } BcStatus; -#define BC_ERR_IDX_BC (0) +#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_POSIX (5) +#define BC_ERR_IDX_VEC (5) +#define BC_ERR_IDX_POSIX (6) -#define BC_VEC_INITIAL_CAP (32) +#define BC_VEC_START_CAP (1<<5) -typedef void (*BcVecFreeFunc)(void*); -typedef int (*BcVecCmpFunc)(void*, void*); +typedef void (*BcVecFree)(void*); +typedef int (*BcVecCmp)(const void*, const void*); typedef struct BcVec { - - uint8_t *array; + char *v; size_t len; size_t cap; size_t size; - - BcVecFreeFunc dtor; - + BcVecFree dtor; } BcVec; -typedef struct BcVecO { - - BcVec vec; - BcVecCmpFunc cmp; +#define bc_vec_pop(v) (bc_vec_npop((v), 1)) +#define bc_vec_top(v) (bc_vec_item_rev((v), 0)) -} BcVecO; +#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free)) -#define bc_veco_item(v, idx) (bc_vec_item(&(v)->vec, (idx))) -#define bc_veco_free(v) (bc_vec_free(&(v)->vec)) +#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~')) -typedef signed char BcDigit; +typedef signed char BcDig; typedef struct BcNum { - - BcDigit *num; + BcDig *restrict num; size_t rdx; size_t len; size_t cap; int neg; - } BcNum; -#define BC_NUM_MIN_BASE (2) -#define BC_NUM_MAX_INPUT_BASE (16) +#define BC_NUM_MIN_BASE ((unsigned long) 2) +#define BC_NUM_MAX_IBASE ((unsigned long) 16) #define BC_NUM_DEF_SIZE (16) - #define BC_NUM_PRINT_WIDTH (69) -#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1) - -typedef BcStatus (*BcNumUnaryFunc)(BcNum*, BcNum*, size_t); -typedef BcStatus (*BcNumBinaryFunc)(BcNum*, BcNum*, BcNum*, size_t); -typedef BcStatus (*BcNumDigitFunc)(size_t, size_t, int, size_t*, size_t); +#define BC_NUM_KARATSUBA_LEN (32) -BcStatus bc_num_init(BcNum *n, size_t request); -BcStatus bc_num_expand(BcNum *n, size_t request); -BcStatus bc_num_copy(BcNum *d, BcNum *s); +#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) + +typedef BcStatus (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t); +typedef void (*BcNumDigitOp)(size_t, size_t, int, size_t*, size_t); + +void bc_num_init(BcNum *n, size_t req); +void bc_num_expand(BcNum *n, size_t req); +void bc_num_copy(BcNum *d, BcNum *s); void bc_num_free(void *num); BcStatus bc_num_ulong(BcNum *n, unsigned long *result); BcStatus bc_num_ulong2num(BcNum *n, unsigned long val); -BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *result, size_t scale); -BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *result, size_t scale); -BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *result, size_t scale); -BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *result, size_t scale); -BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *result, size_t scale); -BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *result, size_t scale); - -ssize_t bc_num_cmp(BcNum *a, BcNum *b); - -void bc_num_zero(BcNum *n); -void bc_num_one(BcNum *n); -void bc_num_ten(BcNum *n); +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); +BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale); +BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale); +BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale); +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); typedef enum BcInst { @@ -221,113 +221,104 @@ typedef enum BcInst { BC_INST_ASSIGN_MINUS, BC_INST_ASSIGN, - BC_INST_PUSH_NUM, - BC_INST_PUSH_VAR, - BC_INST_PUSH_ARRAY_ELEM, - - BC_INST_CALL, + BC_INST_NUM, + BC_INST_VAR, + BC_INST_ARRAY_ELEM, + BC_INST_ARRAY, BC_INST_SCALE_FUNC, - BC_INST_PUSH_IBASE, - BC_INST_PUSH_SCALE, - BC_INST_PUSH_LAST, + BC_INST_IBASE, + BC_INST_SCALE, + BC_INST_LAST, BC_INST_LENGTH, BC_INST_READ, - BC_INST_PUSH_OBASE, + BC_INST_OBASE, BC_INST_SQRT, BC_INST_PRINT, - BC_INST_PRINT_EXPR, + BC_INST_PRINT_POP, BC_INST_STR, BC_INST_PRINT_STR, BC_INST_JUMP, BC_INST_JUMP_ZERO, - BC_INST_POP, + BC_INST_CALL, - BC_INST_RETURN, - BC_INST_RETURN_ZERO, + BC_INST_RET, + BC_INST_RET0, BC_INST_HALT, -} BcInst; + BC_INST_POP, + BC_INST_POP_EXEC, -typedef struct BcEntry { +} BcInst; +typedef struct BcId { char *name; size_t idx; - -} BcEntry; - -typedef struct BcAuto { - - char *name; - int var; - -} BcAuto; +} BcId; typedef struct BcFunc { - BcVec code; BcVec labels; size_t nparams; BcVec autos; - } BcFunc; typedef enum BcResultType { BC_RESULT_TEMP, - BC_RESULT_CONSTANT, - - BC_RESULT_ARRAY_AUTO, - BC_RESULT_VAR_AUTO, - BC_RESULT_VAR, + BC_RESULT_ARRAY_ELEM, BC_RESULT_ARRAY, + BC_RESULT_STR, + + BC_RESULT_IBASE, BC_RESULT_SCALE, BC_RESULT_LAST, - BC_RESULT_IBASE, - BC_RESULT_OBASE, + // These are between to calculate ibase, obase, and last from instructions. + BC_RESULT_CONSTANT, BC_RESULT_ONE, -} BcResultType; - -typedef struct BcResult { - - BcResultType type; - - union { + BC_RESULT_OBASE, - BcNum num; - BcVec array; - BcEntry id; +} BcResultType; - } data; +typedef union BcResultData { + BcNum n; + BcVec v; + BcId id; +} BcResultData; +typedef struct BcResult { + BcResultType t; + BcResultData d; } BcResult; typedef struct BcInstPtr { - size_t func; size_t idx; size_t len; - } BcInstPtr; -void bc_auto_free(void *auto1); +void bc_array_expand(BcVec *a, size_t len); +int bc_id_cmp(const void *e1, const void *e2); -// BC_LEX_OP_NEGATE is not used in lexing; it is only for parsing. -typedef enum BcLexToken { +// BC_LEX_NEG is not used in lexing; it is only for parsing. +typedef enum BcLexType { + + BC_LEX_EOF, + BC_LEX_INVALID, BC_LEX_OP_INC, BC_LEX_OP_DEC, - BC_LEX_OP_NEG, + BC_LEX_NEG, BC_LEX_OP_POWER, BC_LEX_OP_MULTIPLY, @@ -336,12 +327,12 @@ typedef enum BcLexToken { BC_LEX_OP_PLUS, BC_LEX_OP_MINUS, - BC_LEX_OP_REL_EQUAL, - BC_LEX_OP_REL_LESS_EQ, - BC_LEX_OP_REL_GREATER_EQ, - BC_LEX_OP_REL_NOT_EQ, - BC_LEX_OP_REL_LESS, - BC_LEX_OP_REL_GREATER, + BC_LEX_OP_REL_EQ, + BC_LEX_OP_REL_LE, + BC_LEX_OP_REL_GE, + BC_LEX_OP_REL_NE, + BC_LEX_OP_REL_LT, + BC_LEX_OP_REL_GT, BC_LEX_OP_BOOL_NOT, BC_LEX_OP_BOOL_OR, @@ -355,22 +346,21 @@ typedef enum BcLexToken { BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_ASSIGN, - BC_LEX_NEWLINE, - + BC_LEX_NLINE, BC_LEX_WHITESPACE, - BC_LEX_LEFT_PAREN, - BC_LEX_RIGHT_PAREN, + BC_LEX_LPAREN, + BC_LEX_RPAREN, - BC_LEX_LEFT_BRACKET, + BC_LEX_LBRACKET, BC_LEX_COMMA, - BC_LEX_RIGHT_BRACKET, + BC_LEX_RBRACKET, - BC_LEX_LEFT_BRACE, - BC_LEX_SEMICOLON, - BC_LEX_RIGHT_BRACE, + BC_LEX_LBRACE, + BC_LEX_SCOLON, + BC_LEX_RBRACE, - BC_LEX_STRING, + BC_LEX_STR, BC_LEX_NAME, BC_LEX_NUMBER, @@ -395,162 +385,100 @@ typedef enum BcLexToken { BC_LEX_KEY_SQRT, BC_LEX_KEY_WHILE, - BC_LEX_EOF, - BC_LEX_INVALID, - -} BcLexToken; +} BcLexType; typedef struct BcLex { - const char *buffer; - size_t idx; + const char *buf; + size_t i; size_t line; - int newline; - const char *file; + const char *f; size_t len; + int newline; struct { - BcLexToken type; - char *string; - } token; + BcLexType t; + BcLexType last; + BcVec v; + } t; } BcLex; -typedef struct BcLexKeyword { - - const char name[9]; - const char len; - const int posix; - -} BcLexKeyword; - -#define BC_LEX_KW_ENTRY(a, b, c) { .name = a, .len = (b), .posix = (c) } - -#define BC_PROGRAM_BUF_SIZE (1024) - -typedef struct BcProgram { - - BcVec ip_stack; - - size_t line_len; - - size_t scale; - - BcNum ibase; - size_t ibase_t; - BcNum obase; - size_t obase_t; - - BcVec results; - BcVec stack; - - BcVec funcs; - BcVecO func_map; - - BcVec vars; - BcVecO var_map; - - BcVec arrays; - BcVecO array_map; - - BcVec strings; - BcVec constants; - - const char *file; - - BcNum last; - - BcNum zero; - BcNum one; - - size_t nchars; - -} BcProgram; - -#define BC_PROGRAM_MAIN (0) -#define BC_PROGRAM_READ (1) - -#define BC_PROGRAM_SEARCH_VAR (1<<0) -#define BC_PROGRAM_SEARCH_ARRAY (1<<1) +#define BC_PARSE_STREND ((char) UCHAR_MAX) -typedef unsigned long (*BcProgramBuiltInFunc)(BcNum*); -typedef void (*BcNumInitFunc)(BcNum*); +#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)))) -BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx); -BcStatus bc_program_reset(BcProgram *p, BcStatus status); +#define BC_PARSE_REL (1<<0) +#define BC_PARSE_PRINT (1<<1) +#define BC_PARSE_NOCALL (1<<2) +#define BC_PARSE_NOREAD (1<<3) +#define BC_PARSE_ARRAY (1<<4) -BcStatus bc_program_exec(BcProgram *p); - -#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 (0x01) +#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_FUNC_INNER(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 (0x02) - -#define BC_PARSE_FUNC(parse) \ +#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 (0x04) - -#define BC_PARSE_BODY(parse) \ +#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 (0x08) - -#define BC_PARSE_LOOP(parse) \ +#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 (0x10) - +#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 (0x20) - -#define BC_PARSE_IF(parse) \ +#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 (0x40) - -#define BC_PARSE_ELSE(parse) \ +#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 (0x80) - -#define BC_PARSE_IF_END(parse) \ +#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) \ +#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_BODY | \ BC_PARSE_FLAG_LOOP | \ BC_PARSE_FLAG_LOOP_INNER | \ BC_PARSE_FLAG_IF | \ BC_PARSE_FLAG_ELSE | \ BC_PARSE_FLAG_IF_END))) -// 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_TO_INST(type) ((type) - BC_LEX_OP_NEG + BC_INST_NEG) - typedef struct BcOp { - - uint8_t prec; + char prec; int left; - } BcOp; +typedef struct BcParseNext { + uint32_t len; + BcLexType tokens[4]; +} BcParseNext; + +#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ } +#define BC_PARSE_NEXT(a, ...) { .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) } + +struct BcProgram; + typedef struct BcParse { - BcLex lex; + BcLex l; BcVec flags; @@ -559,82 +487,164 @@ typedef struct BcParse { BcVec ops; - BcProgram *prog; - size_t func; - - size_t num_braces; + struct BcProgram *prog; + BcFunc *func; + size_t fidx; + size_t nbraces; int auto_part; } BcParse; -#define BC_PARSE_EXPR_POSIX_REL (1<<0) -#define BC_PARSE_EXPR_PRINT (1<<1) -#define BC_PARSE_EXPR_NOCALL (1<<2) -#define BC_PARSE_EXPR_NOREAD (1<<3) +typedef struct BcLexKeyword { + const char name[9]; + const char len; + const int posix; +} BcLexKeyword; + +#define BC_LEX_KW_ENTRY(a, b, c) { .name = a, .len = (b), .posix = (c) } -BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags); +BcStatus bc_lex_token(BcLex *l); -#define maxof_BASE (999) -#define maxof_DIM (INT_MAX) -#define maxof_SCALE (LONG_MAX) -#define maxof_STRING (INT_MAX) +#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_BUF_SIZE (1024) +// 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)) -typedef struct Bc { +BcStatus bc_parse_parse(BcParse *p); +BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next); - BcParse parse; +typedef struct BcProgram { + + size_t len; + size_t scale; + + BcNum ib; + size_t ib_t; + BcNum ob; + size_t ob_t; + + BcNum hexb; + + BcVec results; + BcVec stack; + + BcVec fns; + BcVec fn_map; + + BcVec vars; + BcVec var_map; + + BcVec arrs; + BcVec arr_map; + + BcVec strs; + BcVec consts; + + const char *file; + + BcNum last; + BcNum zero; + BcNum one; + + size_t nchars; + +} BcProgram; + +#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n)) + +#define BC_PROG_MAIN (0) +#define BC_PROG_READ (1) + +#define BC_PROG_STR(n) (!(n)->num && !(n)->cap) +#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*); + +void bc_program_addFunc(BcProgram *p, char *name, size_t *idx); +BcStatus bc_program_reset(BcProgram *p, BcStatus s); +BcStatus bc_program_exec(BcProgram *p); + +#define BC_MAX_OBASE ((unsigned long) 999) +#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_VARS ((unsigned long) SIZE_MAX - 1) + +typedef struct BcVm { + + BcParse prs; BcProgram prog; -} Bc; +} BcVm; + +BcStatus bc_vm_posixError(BcStatus s, const char *file, + size_t line, const char *msg); -BcStatus bc_error(BcStatus st); -BcStatus bc_error_file(BcStatus st, const char *file, size_t line); +void bc_vm_exit(BcStatus s); +void bc_vm_printf(FILE *restrict f, const char *fmt, ...); +void bc_vm_puts(const char *str, FILE *restrict f); +void bc_vm_putchar(int c); +void bc_vm_fflush(FILE *restrict f); -BcStatus bc_posix_error(BcStatus s, const char *file, - size_t line, const char *msg); +// clang-format off -BcStatus bc_io_fread(const char *path, char **buf); +const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n"; -const char *bc_header = - "bc 1.0\n" - "bc copyright (c) 2018 Gavin D. Howard and contributors\n" +const char bc_copyright[] = + "Copyright (c) 2018 Gavin D. Howard and contributors\n" "Report bugs at: https://github.com/gavinhoward/bc\n\n" - "This is free software with ABSOLUTELY NO WARRANTY.\n\n"; + "This is free software with ABSOLUTELY NO WARRANTY.\n"; -const char bc_err_fmt[] = "\n%s error: %s\n\n"; +const char bc_err_fmt[] = "\n%s error: %s\n"; +const char bc_warn_fmt[] = "\n%s warning: %s\n"; +const char bc_err_line[] = ":%zu\n\n"; const char *bc_errs[] = { - "bc", + "VM", "Lex", "Parse", "Math", "Runtime", + "Vector", "POSIX", }; -const uint8_t bc_err_indices[] = { - BC_ERR_IDX_BC, BC_ERR_IDX_BC, BC_ERR_IDX_BC, BC_ERR_IDX_BC, +const 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, 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_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_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, }; -const char *bc_err_descs[] = { +const char *bc_err_msgs[] = { + NULL, "memory allocation error", "I/O error", - "file is not text", + "file is not text:", + "path is a directory:", "bad character", "string end could not be found", @@ -643,33 +653,40 @@ const char *bc_err_descs[] = { "bad token", "bad expression", + "empty expression", "bad print statement", "bad function definition", - "bad assignment: left must be scale, ibase, " + "bad assignment: left side must be scale, ibase, " "obase, last, var, or array element", "no auto variable found", "function parameter or auto var has the same name as another", + "block end could not be found", "negative number", "non integer number", "overflow", "divide by zero", - "negative square root", "bad number string", - "could not open file", + "could not open file:", "mismatched parameters", "undefined function", - "file is not executable", - "could not install signal handler", - "bad scale; must be [0, BC_SCALE_MAX]", - "bad ibase; must be [2, 16]", - "bad obase; must be [2, BC_BASE_MAX]", + "file is not executable:", + "number too long: must be [1, BC_NUM_MAX]", + "name too long: must be [1, BC_NAME_MAX]", "string too long: must be [1, BC_STRING_MAX]", "array too long; must be [1, BC_DIM_MAX]", + "bad ibase; must be [2, 16]", + "bad scale; must be [0, BC_SCALE_MAX]", "bad read() expression", "read() call inside of a read() call", "variable is wrong type", + "bad obase; must be [2, BC_BASE_MAX]", + "signal caught and not handled", + "stack has too few elements", + + "index is out of bounds", + "item already exists", "POSIX only allows one character names; the following is bad:", "POSIX does not allow '#' script comments", @@ -683,14 +700,13 @@ const char *bc_err_descs[] = { "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", -}; -const char bc_sig_msg[34] = "\ninterrupt (type \"quit\" to exit)\n"; +}; -const char bc_lang_func_main[7] = "(main)"; -const char bc_lang_func_read[7] = "(read)"; +const char bc_func_main[] = "(main)"; +const char bc_func_read[] = "(read)"; -const BcLexKeyword bc_lex_keywords[20] = { +const BcLexKeyword bc_lex_kws[20] = { BC_LEX_KW_ENTRY("auto", 4, 1), BC_LEX_KW_ENTRY("break", 5, 1), BC_LEX_KW_ENTRY("continue", 8, 0), @@ -713,16 +729,15 @@ const BcLexKeyword bc_lex_keywords[20] = { BC_LEX_KW_ENTRY("while", 5, 1), }; -const char bc_num_hex_digits[] = "0123456789ABCDEF"; - // This is an array that corresponds to token types. An entry is // 1 if the token is valid in an expression, 0 otherwise. -const int bc_parse_token_exprs[] = { - 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, 0, 0, +const 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, }; // This is an array of data for operators that correspond to token types. @@ -733,56 +748,72 @@ const BcOp bc_parse_ops[] = { { 3, 1 }, { 3, 1 }, { 3, 1 }, { 4, 1 }, { 4, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, { 6, 1 }, - { 7, 0 }, - { 8, 1 }, { 8, 1 }, - { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, + { 1, 0 }, + { 7, 1 }, { 7, 1 }, + { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, { 5, 0 }, + { 5, 0 }, { 5, 0 }, }; -const char bc_program_byte_fmt[] = "%02x"; +// These identify what tokens can come after expressions in certain cases. +const BcParseNext bc_parse_next_expr = + BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF); +const BcParseNext bc_parse_next_param = + BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA); +const BcParseNext bc_parse_next_print = + BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF); +const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN); +const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET); +const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON); +const BcParseNext bc_parse_next_read = + BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF); + +const char bc_num_hex_digits[] = "0123456789ABCDEF"; -const BcNumBinaryFunc bc_program_math_ops[] = { +const BcNumBinaryOp bc_program_ops[] = { bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub, }; const char bc_program_stdin_name[] = ""; -const char bc_program_ready_prompt[] = "ready for more input\n"; -const char *bc_lib_name = "lib.bc"; +const char bc_program_ready_msg[] = "ready for more input\n"; + +// clang-format on +const char *bc_lib_name = "gen/lib.bc"; const 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,115,43,55,43,48,46,52,53,42,120,10,9,115,99, + 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,59,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,102,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,109,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,55,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, - 110,42,61,109,10,9,9,118,61,110,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,51,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,45,61,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41, + 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, @@ -791,293 +822,257 @@ const char bc_lib[] = { 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,43,61,49,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,61,54,52,41,123,10,9,9,9,114,101,116,117,114,110,40,46, + 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,54,55,41,123,10,9,9,105,102,40,115,99,97,108,101, - 60,61,54,52,41,123,10,9,9,9,114,101,116,117,114,110,40,46,50,54,48,57,49,51, - 53,54,57,50,51,50,57,52,48,53,55,57,53,57,54,55,56,53,50,54,55,55,55,55,57, - 56,54,53,54,51,57,55,55,52,55,52,48,50,51,57,56,56,50,52,52,53,56,50,50,51, - 50,57,56,56,50,57,49,55,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,54,55,41,123,10,9,9,115,99,97,108,101, - 43,61,53,10,9,9,97,61,97,40,46,50,54,55,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,54,55,41,123,10,9,9,109, - 43,61,49,10,9,9,120,61,40,120,45,46,50,54,55,41,47,40,49,43,46,50,54,55,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,102,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,40,50,94,110,42,97,41,10, - 9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,52,10,9,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,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,115,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,114,101,116,117,114,110,40,45,97,42,114,47,49,41,10,9,114,101,116,117,114, - 110,40,97,42,114,47,49,41,10,125,10,0 + 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 }; -BcStatus bc_vec_double(BcVec *vec) { - - uint8_t *ptr = realloc(vec->array, vec->size * (vec->cap * 2)); - if (!ptr) return BC_STATUS_MALLOC_FAIL; - - vec->array = ptr; - vec->cap *= 2; - - return BC_STATUS_SUCCESS; +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); + v->cap = cap; } -BcStatus bc_vec_init(BcVec *vec, size_t esize, BcVecFreeFunc dtor) { - - vec->size = esize; - vec->cap = BC_VEC_INITIAL_CAP; - vec->len = 0; - vec->dtor = dtor; - - vec->array = malloc(esize * BC_VEC_INITIAL_CAP); - if (!vec->array) return BC_STATUS_MALLOC_FAIL; - - return BC_STATUS_SUCCESS; +void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor) { + v->size = esize; + v->cap = BC_VEC_START_CAP; + v->len = 0; + v->dtor = dtor; + v->v = xmalloc(esize * BC_VEC_START_CAP); } -BcStatus bc_vec_expand(BcVec *vec, size_t request) { - - uint8_t *ptr; - - if (vec->cap >= request) return BC_STATUS_SUCCESS; - - ptr = realloc(vec->array, vec->size * request); - if (!ptr) return BC_STATUS_MALLOC_FAIL; - - vec->array = ptr; - vec->cap = request; - - return BC_STATUS_SUCCESS; +void bc_vec_expand(BcVec *v, size_t req) { + if (v->cap < req) { + v->v = xrealloc(v->v, v->size * req); + v->cap = req; + } } -BcStatus bc_vec_push(BcVec *vec, void *data) { - - BcStatus status; - size_t size; - - if (vec->len == vec->cap && (status = bc_vec_double(vec))) return status; +void bc_vec_npop(BcVec *v, size_t n) { + if (!v->dtor) v->len -= n; + else { + size_t len = v->len - n; + while (v->len > len) v->dtor(v->v + (v->size * --v->len)); + } +} - size = vec->size; - memmove(vec->array + (size * vec->len++), data, size); +void bc_vec_push(BcVec *v, const 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; +} - return BC_STATUS_SUCCESS; +void bc_vec_pushByte(BcVec *v, char data) { + bc_vec_push(v, &data); } -BcStatus bc_vec_pushByte(BcVec *vec, uint8_t data) { +void bc_vec_pushAt(BcVec *v, const void *data, size_t idx) { + + if (idx == v->len) bc_vec_push(v, data); + else { - BcStatus status; + char *ptr; - if (vec->len == vec->cap && (status = bc_vec_double(vec))) return status; + if (v->len == v->cap) bc_vec_grow(v, 1); - vec->array[vec->len++] = data; + ptr = v->v + v->size * idx; - return BC_STATUS_SUCCESS; + memmove(ptr + v->size, ptr, v->size * (v->len++ - idx)); + memmove(ptr, data, v->size); + } } -BcStatus bc_vec_pushAt(BcVec *vec, void *data, size_t idx) { +void bc_vec_string(BcVec *v, size_t len, const char *str) { - BcStatus status; - uint8_t *ptr; + bc_vec_npop(v, v->len); + bc_vec_expand(v, len + 1); + memcpy(v->v, str, len); + v->len = len; - if (idx == vec->len) return bc_vec_push(vec, data); - if (vec->len == vec->cap && (status = bc_vec_double(vec))) return status; + bc_vec_pushByte(v, '\0'); +} - ptr = vec->array + vec->size * idx; +void bc_vec_concat(BcVec *v, const char *str) { - memmove(ptr + vec->size, ptr, vec->size * (vec->len++ - idx)); - memmove(ptr, data, vec->size); + size_t len; - return BC_STATUS_SUCCESS; -} + if (v->len == 0) bc_vec_pushByte(v, '\0'); -void* bc_vec_top(const BcVec *vec) { - return vec->array + vec->size * (vec->len - 1); -} + len = v->len + strlen(str); -void* bc_vec_item(const BcVec *vec, size_t idx) { - return vec->array + vec->size * idx; -} + if (v->cap < len) bc_vec_grow(v, len - v->len); + strcat(v->v, str); -void* bc_vec_item_rev(const BcVec *vec, size_t idx) { - return vec->array + vec->size * (vec->len - idx - 1); + v->len = len; } -void bc_vec_pop(BcVec *vec) { - vec->len -= 1; - if (vec->dtor) vec->dtor(vec->array + (vec->size * vec->len)); +void* bc_vec_item(const BcVec *v, size_t idx) { + return v->v + v->size * idx; } -void bc_vec_npop(BcVec *vec, size_t n) { - if (!vec->dtor) vec->len -= n; - else { - size_t len = vec->len - n; - while (vec->len > len) bc_vec_pop(vec); - } +void* bc_vec_item_rev(const BcVec *v, size_t idx) { + return v->v + v->size * (v->len - idx - 1); } void bc_vec_free(void *vec) { - - size_t i; - BcVec *s = (BcVec*) vec; - - if (!s) return; - - if (s->dtor) { - for (i = 0; i < s->len; ++i) s->dtor(s->array + (i * s->size)); - } - - free(s->array); - memset(s, 0, sizeof(BcVec)); + BcVec *v = (BcVec*) vec; + bc_vec_npop(v, v->len); + free(v->v); } -size_t bc_veco_find(const BcVecO* vec, void *data) { - - size_t low, high; +size_t bc_map_find(const BcVec *v, const void *ptr) { - low = 0; - high = vec->vec.len; + size_t low = 0, high = v->len; while (low < high) { size_t mid = (low + high) / 2; - uint8_t *ptr = bc_vec_item(&vec->vec, mid); - int result = vec->cmp(data, ptr); + BcId *id = bc_vec_item(v, mid); + int result = bc_id_cmp(ptr, id); - if (!result) return mid; - - if (result < 0) high = mid; + if (result == 0) return mid; + else if (result < 0) high = mid; else low = mid + 1; } return low; } -BcStatus bc_veco_init(BcVecO* vec, size_t esize, - BcVecFreeFunc dtor, BcVecCmpFunc cmp) -{ - vec->cmp = cmp; - return bc_vec_init(&vec->vec, esize, dtor); -} - -BcStatus bc_veco_insert(BcVecO* vec, void *data, size_t *idx) { +BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i) { - BcStatus status; + BcStatus s = BC_STATUS_SUCCESS; - *idx = bc_veco_find(vec, data); + *i = bc_map_find(v, ptr); - if (*idx > vec->vec.len) return BC_STATUS_VEC_OUT_OF_BOUNDS; - if (*idx != vec->vec.len && !vec->cmp(data, bc_vec_item(&vec->vec, *idx))) - return BC_STATUS_VEC_ITEM_EXISTS; - - if (*idx >= vec->vec.len) { - *idx = vec->vec.len; - status = bc_vec_push(&vec->vec, data); - } - else status = bc_vec_pushAt(&vec->vec, data, *idx); + 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 bc_vec_pushAt(v, ptr, *i); - return status; + return s; } -size_t bc_veco_index(const BcVecO* v, void *data) { - size_t i; - i = bc_veco_find(v, data); - if (i >= v->vec.len || v->cmp(data, bc_vec_item(&v->vec, i))) return -1; - return i; +size_t bc_map_index(const BcVec* v, const void *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; } -BcStatus bc_io_getline(char **buf, size_t *n) { - - char *temp; - int c; - size_t size, i; - - if (TT.tty && fputs(">>> ", stdout) == EOF) return BC_STATUS_IO_ERR; +BcStatus bc_read_line(BcVec *vec, const char* prompt) { - for (i = 0, c = 0; c != '\n'; ++i) { + int i; + signed char c = 0; - if (i == *n) { + if (TT.ttyin && !(toys.optflags & FLAG_s)) { + bc_vm_puts(prompt, stderr); + bc_vm_fflush(stderr); + } - size = *n * 2; + bc_vec_npop(vec, vec->len); - if (size > (1 << 20) || !(temp = realloc(*buf, size + 1))) - return BC_STATUS_MALLOC_FAIL; + while (c != '\n') { - *buf = temp; - *n = size; - } + i = fgetc(stdin); - if ((c = fgetc(stdin)) == EOF) { + if (i == EOF) { if (errno == EINTR) { TT.sigc = TT.sig; TT.signe = 0; - --i; - fprintf(stderr, "%s", bc_program_ready_prompt); - fflush(stderr); - - if (TT.tty && fputs(">>> ", stdout) == EOF) return BC_STATUS_IO_ERR; + 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); + } continue; } - else return BC_STATUS_IO_ERR; + + return BC_STATUS_IO_ERR; } - else if (!c || (iscntrl(c) && !isspace(c)) || c > SCHAR_MAX) - return BC_STATUS_BINARY_FILE; - (*buf)[i] = c; + c = (signed char) i; + if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE; + bc_vec_push(vec, &c); } - (*buf)[i] = '\0'; + bc_vec_pushByte(vec, '\0'); return BC_STATUS_SUCCESS; } -BcStatus bc_io_fread(const char *path, char **buf) { +BcStatus bc_read_file(const char *path, char **buf) { - BcStatus st; + BcStatus s = BC_STATUS_IO_ERR; FILE *f; size_t size, read; + long res; + struct stat pstat; - if (!(f = fopen(path, "r"))) return BC_STATUS_EXEC_FILE_ERR; + f = fopen(path, "r"); + if (!f) bc_vm_exit(BC_STATUS_EXEC_FILE_ERR); + if (fstat(fileno(f), &pstat) == -1) goto malloc_err; - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - - if (!(*buf = malloc(size + 1))) { - st = BC_STATUS_MALLOC_FAIL; + if (S_ISDIR(pstat.st_mode)) { + s = BC_STATUS_PATH_IS_DIR; goto malloc_err; } - if ((read = fread(*buf, 1, size, f)) != size) { - st = BC_STATUS_IO_ERR; - goto read_err; - } + if (fseek(f, 0, SEEK_END) == -1) goto malloc_err; + res = ftell(f); + if (res < 0) goto malloc_err; + if (fseek(f, 0, SEEK_SET) == -1) goto malloc_err; + + size = (size_t) res; + *buf = xmalloc(size + 1); + + read = fread(*buf, 1, size, f); + 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; + } + fclose(f); return BC_STATUS_SUCCESS; @@ -1086,55 +1081,72 @@ read_err: free(*buf); malloc_err: fclose(f); - return st; + return s; } -BcStatus bc_num_subArrays(BcDigit *n1, BcDigit *n2, size_t len) { - size_t i, j; - for (i = 0; !TT.signe && i < len; ++i) { - for (n1[i] -= n2[i], j = 0; !TT.signe && n1[i + j] < 0;) { - n1[i + j++] += 10; - n1[i + j] -= 1; - } - } - return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; -} +void bc_num_setToZero(BcNum *n, size_t scale) { + n->len = 0; + n->neg = 0; + n->rdx = scale; +} + +void bc_num_zero(BcNum *n) { + bc_num_setToZero(n, 0); +} + +void bc_num_one(BcNum *n) { + bc_num_setToZero(n, 0); + n->len = 1; + n->num[0] = 1; +} + +void bc_num_ten(BcNum *n) { + bc_num_setToZero(n, 0); + n->len = 2; + n->num[0] = 0; + n->num[1] = 1; +} + +BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict 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;) { + a[i + j++] += 10; + a[i + j] -= 1; + } + } + return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; +} -ssize_t bc_num_compare(BcDigit *n1, BcDigit *n2, size_t len) { +ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len) { size_t i; - BcDigit c; - for (c = 0, i = len - 1; !TT.signe && !(c = n1[i] - n2[i]) && i < len; --i); - return (c < 0 ? -1 : 1) * (ssize_t) (i + 1); + int c = 0; + for (i = len - 1; !TT.signe && i < len && !(c = a[i] - b[i]); --i); + return BC_NUM_NEG(i + 1, c < 0); } ssize_t bc_num_cmp(BcNum *a, BcNum *b) { size_t i, min, a_int, b_int, diff; - BcDigit *max_num, *min_num; - int a_max; - int cmp, neg; - - if (!a) return !b ? 0 : !b->neg * -2 + 1; - else if (!b) return a->neg * -2 + 1; - - neg = 1; + BcDig *max_num, *min_num; + int a_max, neg = 0; + 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->neg) { - if (b->neg) neg = -1; + if (b->neg) neg = 1; else return -1; } else if (b->neg) return 1; - if (!a->len) return (!b->neg * -2 + 1) * !!b->len; - else if (!b->len) return a->neg * -2 + 1; - - a_int = a->len - a->rdx; - b_int = b->len - b->rdx; + a_int = BC_NUM_INT(a); + b_int = BC_NUM_INT(b); a_int -= b_int; + a_max = (a->rdx > b->rdx); - if (a_int) return a_int; - - a_max = a->rdx > b->rdx; + if (a_int) return (ssize_t) a_int; if (a_max) { min = b->rdx; @@ -1150,10 +1162,10 @@ ssize_t bc_num_cmp(BcNum *a, BcNum *b) { } cmp = bc_num_compare(max_num, min_num, b_int + min); - if (cmp) return cmp * (!a_max * -2 + 1) * neg; + if (cmp) return BC_NUM_NEG(cmp, (!a_max) != neg); for (max_num -= diff, i = diff - 1; !TT.signe && i < diff; --i) { - if (max_num[i]) return neg * (!a_max * -2 + 1); + if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg); } return 0; @@ -1161,67 +1173,116 @@ ssize_t bc_num_cmp(BcNum *a, BcNum *b) { void bc_num_truncate(BcNum *n, size_t places) { - BcDigit *ptr; + if (places == 0) return; - if (!places) return; - - ptr = n->num + places; - n->len -= places; n->rdx -= places; - memmove(n->num, ptr, n->len * sizeof(BcDigit)); - memset(n->num + n->len, 0, sizeof(BcDigit) * (n->cap - n->len)); + if (n->len) { + n->len -= places; + memmove(n->num, n->num + places, n->len * sizeof(BcDig)); + } } -BcStatus bc_num_extend(BcNum *n, size_t places) { +void bc_num_extend(BcNum *n, size_t places) { - BcStatus status; - BcDigit *ptr; - size_t len; + size_t len = n->len + places; - if (!places) return BC_STATUS_SUCCESS; + if (places) { - len = n->len + places; - if (n->cap < len && (status = bc_num_expand(n, len))) return status; + if (n->cap < len) bc_num_expand(n, len); - ptr = n->num + places; - memmove(ptr, n->num, sizeof(BcDigit) * n->len); - memset(n->num, 0, sizeof(BcDigit) * places); + memmove(n->num + places, n->num, sizeof(BcDig) * n->len); + memset(n->num, 0, sizeof(BcDig) * places); - n->len += places; - n->rdx += places; + n->len += places; + n->rdx += 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; +} + +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; +} + +void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a, + BcNum *restrict b) +{ + if (idx < n->len) { + + b->len = n->len - idx; + a->len = idx; + a->rdx = b->rdx = 0; + + memcpy(b->num, n->num + idx, b->len * sizeof(BcDig)); + memcpy(a->num, n->num, idx * sizeof(BcDig)); + } + else { + bc_num_zero(b); + bc_num_copy(a, n); + } + + bc_num_clean(a); + bc_num_clean(b); +} + +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 (n->rdx >= places) n->rdx -= places; + else { + bc_num_extend(n, places - n->rdx); + n->rdx = 0; + } + + bc_num_clean(n); return BC_STATUS_SUCCESS; } BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) { - BcStatus status; BcNum one; + BcDig num[2]; - if ((status = bc_num_init(&one, BC_NUM_DEF_SIZE))) return status; - + one.cap = 2; + one.num = num; bc_num_one(&one); - status = bc_num_div(&one, a, b, scale); - bc_num_free(&one); - return status; + return bc_num_div(&one, a, b, scale); } -BcStatus bc_num_alg_a(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { - BcDigit *ptr, *ptr_a, *ptr_b, *ptr_c; + BcDig *ptr, *ptr_a, *ptr_b, *ptr_c; size_t i, max, min_rdx, min_int, diff, a_int, b_int; - BcDigit carry; + int carry, in; - (void) scale; + // 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) return bc_num_copy(c, b); - else if (!b->len) return bc_num_copy(c, a); + if (a->len == 0) { + bc_num_copy(c, b); + if (sub && c->len) c->neg = !c->neg; + return BC_STATUS_SUCCESS; + } + else if (b->len == 0) { + bc_num_copy(c, a); + return BC_STATUS_SUCCESS; + } c->neg = a->neg; - memset(c->num, 0, c->cap * sizeof(BcDigit)); - c->rdx = maxof(a->rdx, b->rdx); min_rdx = minof(a->rdx, b->rdx); c->len = 0; @@ -1242,8 +1303,8 @@ BcStatus bc_num_alg_a(BcNum *a, BcNum *b, BcNum *c, size_t scale) { for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i]; ptr_c += diff; - a_int = a->len - a->rdx; - b_int = b->len - b->rdx; + a_int = BC_NUM_INT(a); + b_int = BC_NUM_INT(b); if (a_int > b_int) { min_int = b_int; @@ -1257,42 +1318,42 @@ BcStatus bc_num_alg_a(BcNum *a, BcNum *b, BcNum *c, size_t scale) { } for (carry = 0, i = 0; !TT.signe && i < min_rdx + min_int; ++i, ++c->len) { - ptr_c[i] = ptr_a[i] + ptr_b[i] + carry; - carry = ptr_c[i] / 10; - ptr_c[i] %= 10; + in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry; + carry = in / 10; + ptr_c[i] = (BcDig) (in % 10); } for (; !TT.signe && i < max + min_rdx; ++i, ++c->len) { - ptr_c[i] += ptr[i] + carry; - carry = ptr_c[i] / 10; - ptr_c[i] %= 10; + in = ((int) ptr[i]) + carry; + carry = in / 10; + ptr_c[i] = (BcDig) (in % 10); } - if (TT.signe) return BC_STATUS_EXEC_SIGNAL; - - if (carry) c->num[c->len++] = carry; + if (carry) c->num[c->len++] = (BcDig) carry; - return BC_STATUS_SUCCESS; + return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; } -BcStatus bc_num_alg_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { +BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) { - BcStatus status; - int cmp; + BcStatus s; + ssize_t cmp; BcNum *minuend, *subtrahend; size_t start; int aneg, bneg, neg; // Because this function doesn't need to use scale (per the bc spec), - // I am hijacking it to tell this function whether it is doing an add - // or a subtract. + // I am hijacking it to say whether it's doing an add or a subtract. - if (!a->len) { - status = bc_num_copy(c, b); - c->neg = !b->neg; - return status; + if (a->len == 0) { + bc_num_copy(c, b); + if (sub && c->len) c->neg = !c->neg; + return BC_STATUS_SUCCESS; + } + else if (b->len == 0) { + bc_num_copy(c, a); + return BC_STATUS_SUCCESS; } - else if (!b->len) return bc_num_copy(c, a); aneg = a->neg; bneg = b->neg; @@ -1303,213 +1364,293 @@ BcStatus bc_num_alg_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) { a->neg = aneg; b->neg = bneg; - if (!cmp) { - bc_num_zero(c); + if (cmp == 0) { + bc_num_setToZero(c, maxof(a->rdx, b->rdx)); return BC_STATUS_SUCCESS; } else if (cmp > 0) { - neg = sub && a->neg; + neg = a->neg; minuend = a; subtrahend = b; } else { - neg = sub && !b->neg; + neg = b->neg; + if (sub) neg = !neg; minuend = b; subtrahend = a; } - if ((status = bc_num_copy(c, minuend))) return status; + bc_num_copy(c, minuend); c->neg = neg; if (c->rdx < subtrahend->rdx) { - if ((status = bc_num_extend(c, subtrahend->rdx - c->rdx))) return status; + bc_num_extend(c, subtrahend->rdx - c->rdx); start = 0; } else start = c->rdx - subtrahend->rdx; - status = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len); + s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len); - while (c->len > c->rdx && !c->num[c->len - 1]) --c->len; + bc_num_clean(c); - return status; + return s; } -BcStatus bc_num_alg_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b, BcNum *restrict c) { - BcStatus status; - BcDigit carry; - size_t i, j, len; + BcStatus s; + int carry; + size_t i, j, len, 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 (!a->len || !b->len) { + if (TT.signe) return BC_STATUS_EXEC_SIGNAL; + if (a->len == 0 || b->len == 0) { bc_num_zero(c); return BC_STATUS_SUCCESS; } - else if (BC_NUM_ONE(a)) { - status = bc_num_copy(c, b); - if (a->neg) c->neg = !c->neg; - return status; - } - else if (BC_NUM_ONE(b)) { - status = bc_num_copy(c, a); - if (b->neg) c->neg = !c->neg; - return status; + else if (aone || BC_NUM_ONE(b)) { + bc_num_copy(c, aone ? b : a); + return BC_STATUS_SUCCESS; } - scale = maxof(scale, a->rdx); - scale = maxof(scale, b->rdx); - c->rdx = a->rdx + b->rdx; - - memset(c->num, 0, sizeof(BcDigit) * c->cap); - c->len = carry = len = 0; + if (a->len + b->len < BC_NUM_KARATSUBA_LEN || + a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN) + { + bc_num_expand(c, a->len + b->len + 1); - for (i = 0; !TT.signe && i < b->len; ++i) { + memset(c->num, 0, sizeof(BcDig) * c->cap); + c->len = carry = len = 0; - for (j = 0; !TT.signe && j < a->len; ++j) { - c->num[i + j] += a->num[j] * b->num[i] + carry; - carry = c->num[i + j] / 10; - c->num[i + j] %= 10; - } + for (i = 0; !TT.signe && i < b->len; ++i) { - if (TT.signe) return BC_STATUS_EXEC_SIGNAL; + 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); + } - if (carry) { - c->num[i + j] += carry; + c->num[i + j] += (BcDig) carry; + len = maxof(len, i + j + !!carry); carry = 0; - len = maxof(len, i + j + 1); } - else len = maxof(len, i + j); - } - if (TT.signe) return BC_STATUS_EXEC_SIGNAL; + c->len = len; + + return TT.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS; + } + + bc_num_init(&l1, max); + bc_num_init(&h1, max); + bc_num_init(&l2, max); + bc_num_init(&h2, max); + bc_num_init(&m1, max); + bc_num_init(&m2, max); + bc_num_init(&z0, max); + bc_num_init(&z1, max); + bc_num_init(&z2, max); + bc_num_init(&temp, max + max); + + bc_num_split(a, max2, &l1, &h1); + bc_num_split(b, max2, &l2, &h2); + + s = bc_num_add(&h1, &l1, &m1, 0); + if (s) goto err; + s = bc_num_add(&h2, &l2, &m2, 0); + if (s) goto err; + + s = bc_num_k(&h1, &h2, &z0); + if (s) goto err; + s = bc_num_k(&m1, &m2, &z1); + if (s) goto err; + s = bc_num_k(&l1, &l2, &z2); + if (s) goto err; + + s = bc_num_sub(&z1, &z0, &temp, 0); + if (s) goto err; + s = bc_num_sub(&temp, &z2, &z1, 0); + if (s) goto err; + + s = bc_num_shift(&z0, max2 * 2); + if (s) goto err; + s = bc_num_shift(&z1, max2); + if (s) goto err; + s = bc_num_add(&z0, &z1, &temp, 0); + if (s) goto err; + s = bc_num_add(&temp, &z2, c, 0); + +err: + bc_num_free(&temp); + bc_num_free(&z2); + bc_num_free(&z1); + bc_num_free(&z0); + bc_num_free(&m2); + bc_num_free(&m1); + bc_num_free(&h2); + bc_num_free(&l2); + bc_num_free(&h1); + bc_num_free(&l1); + return s; +} - c->len = maxof(len, c->rdx); - c->neg = !a->neg != !b->neg; +BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - if (scale < c->rdx) bc_num_truncate(c, c->rdx - scale); - while (c->len > c->rdx && !c->num[c->len - 1]) --c->len; + BcStatus s; + BcNum cpa, cpb; + size_t maxrdx = maxof(a->rdx, b->rdx); - return BC_STATUS_SUCCESS; -} + scale = maxof(scale, a->rdx); + scale = maxof(scale, b->rdx); + scale = minof(a->rdx + b->rdx, scale); + maxrdx = maxof(maxrdx, scale); -BcStatus bc_num_alg_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) { + bc_num_init(&cpa, a->len); + bc_num_init(&cpb, b->len); - BcStatus status; - BcDigit *ptr, *bptr, q; - size_t len, end, i; - BcNum copy; - int zero; + bc_num_copy(&cpa, a); + bc_num_copy(&cpb, b); + cpa.neg = cpb.neg = 0; - if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO; - else if (!a->len) { - bc_num_zero(c); - return BC_STATUS_SUCCESS; + s = bc_num_shift(&cpa, maxrdx); + if (s) goto err; + s = bc_num_shift(&cpb, maxrdx); + if (s) goto err; + s = bc_num_k(&cpa, &cpb, c); + if (s) goto err; + + maxrdx += scale; + bc_num_expand(c, c->len + maxrdx); + + if (c->len < maxrdx) { + memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig)); + c->len += maxrdx; } - else if (BC_NUM_ONE(b)) { - if ((status = bc_num_copy(c, a))) return status; - if (b->neg) c->neg = !c->neg; + c->rdx = maxrdx; + bc_num_retireMul(c, scale, a->neg, b->neg); - if (c->rdx < scale) status = bc_num_extend(c, scale - c->rdx); - else bc_num_truncate(c, c->rdx - scale); +err: + bc_num_free(&cpb); + bc_num_free(&cpa); + return s; +} - return status; - } +BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - if ((status = bc_num_init(©, a->len + b->rdx + scale + 1))) return status; - if ((status = bc_num_copy(©, a))) goto err; + BcStatus s = BC_STATUS_SUCCESS; + BcDig *n, *p, q; + size_t len, end, i; + BcNum cp; + int zero = 1; - if ((len = b->len) > copy.len) { - if ((status = bc_num_expand(©, len + 2))) goto err; - if ((status = bc_num_extend(©, len - copy.len))) goto err; + if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO; + else if (a->len == 0) { + bc_num_setToZero(c, scale); + return BC_STATUS_SUCCESS; + } + else if (BC_NUM_ONE(b)) { + bc_num_copy(c, a); + bc_num_retireMul(c, scale, a->neg, b->neg); + return BC_STATUS_SUCCESS; } - if (b->rdx > copy.rdx && (status = bc_num_extend(©, b->rdx - copy.rdx))) - goto err; + bc_num_init(&cp, BC_NUM_MREQ(a, b, scale)); + bc_num_copy(&cp, a); + len = b->len; - copy.rdx -= b->rdx; + if (len > cp.len) { + bc_num_expand(&cp, len + 2); + bc_num_extend(&cp, len - cp.len); + } - if (scale > copy.rdx && (status = bc_num_extend(©, scale - copy.rdx))) - goto err; + if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx); + cp.rdx -= b->rdx; + if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx); if (b->rdx == b->len) { - int zero; - for (zero = 1, i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1]; - if (i == len) return BC_STATUS_MATH_DIVIDE_BY_ZERO; + for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1]; len -= i - 1; } - if (copy.cap == copy.len && (status = bc_num_expand(©, copy.len + 1))) - goto err; + if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1); // We want an extra zero in front to make things simpler. - copy.num[copy.len++] = 0; - end = copy.len - len; + cp.num[cp.len++] = 0; + end = cp.len - len; - if ((status = bc_num_expand(c, copy.len))) goto err; + bc_num_expand(c, cp.len); bc_num_zero(c); - c->rdx = copy.rdx; - c->len = copy.len; - bptr = b->num; - - for (i = end - 1; !TT.signe && i < end; --i) { - - ptr = copy.num + i; - - q = 0; - for (; (!status && ptr[len]) || bc_num_compare(ptr, bptr, len) >= 0; ++q) - status = bc_num_subArrays(ptr, bptr, len); - + 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) { + n = cp.num + i; + 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; } - if (status) goto err; - - c->neg = !a->neg != !b->neg; - while (c->len > c->rdx && !c->num[c->len - 1]) --c->len; - if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale); - - for (i = 0, zero = 1; zero && i < c->len; ++i) zero = !c->num[i]; - if (zero) bc_num_zero(c); + if (!s) bc_num_retireMul(c, scale, a->neg, b->neg); + bc_num_free(&cp); -err: - bc_num_free(©); - return status; + return s; } -BcStatus bc_num_alg_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) { - - BcStatus status; - BcNum c1, c2; - size_t len; +BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c, + BcNum *restrict d, size_t scale, size_t ts) +{ + BcStatus s; + BcNum temp; + int neg; - if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO; + if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO; - if (!a->len) { - bc_num_zero(c); + if (a->len == 0) { + bc_num_setToZero(d, ts); return BC_STATUS_SUCCESS; } - len = a->len + b->len + scale; + bc_num_init(&temp, d->cap); + bc_num_d(a, b, c, scale); + + if (scale) scale = ts; + + s = bc_num_m(c, b, &temp, scale); + if (s) goto err; + s = bc_num_sub(a, &temp, d, scale); + if (s) goto err; - if ((status = bc_num_init(&c1, len))) return status; - if ((status = bc_num_init(&c2, len))) goto c2_err; - if ((status = bc_num_div(a, b, &c1, scale))) goto err; + if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx); - c->rdx = maxof(scale + b->rdx, a->rdx); - if ((status = bc_num_mul(&c1, b, &c2, scale))) goto err; - status = bc_num_sub(a, &c2, c, scale); + neg = d->neg; + bc_num_retireMul(d, ts, a->neg, b->neg); + d->neg = neg; err: - bc_num_free(&c2); -c2_err: + bc_num_free(&temp); + return s; +} + +BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { + + BcStatus s; + BcNum c1; + size_t ts = maxof(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts); + + bc_num_init(&c1, len); + s = bc_num_r(a, b, &c1, c, scale, ts); bc_num_free(&c1); - return status; + + return s; } -BcStatus bc_num_alg_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { +BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) { - BcStatus status; + BcStatus s = BC_STATUS_SUCCESS; BcNum copy; unsigned long pow; size_t i, powrdx, resrdx; @@ -1517,28 +1658,28 @@ BcStatus bc_num_alg_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { if (b->rdx) return BC_STATUS_MATH_NON_INTEGER; - if (!b->len) { + if (b->len == 0) { bc_num_one(c); return BC_STATUS_SUCCESS; } - else if (!a->len) { - bc_num_zero(c); + else if (a->len == 0) { + bc_num_setToZero(c, scale); return BC_STATUS_SUCCESS; } else if (BC_NUM_ONE(b)) { - - if (!b->neg) status = bc_num_copy(c, a); - else status = bc_num_inv(a, c, scale); - - return status; + if (!b->neg) bc_num_copy(c, a); + else s = bc_num_inv(a, c, scale); + return s; } neg = b->neg; b->neg = 0; - if ((status = bc_num_ulong(b, &pow))) return status; - if ((status = bc_num_init(©, a->len))) return status; - if ((status = bc_num_copy(©, a))) goto err; + s = bc_num_ulong(b, &pow); + if (s) return s; + + bc_num_init(©, a->len); + bc_num_copy(©, a); if (!neg) scale = minof(a->rdx * pow, maxof(scale, a->rdx)); @@ -1546,100 +1687,100 @@ BcStatus bc_num_alg_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) { for (powrdx = a->rdx; !TT.signe && !(pow & 1); pow >>= 1) { powrdx <<= 1; - if ((status = bc_num_mul(©, ©, ©, powrdx))) goto err; + s = bc_num_mul(©, ©, ©, powrdx); + if (s) goto err; } - if ((status = bc_num_copy(c, ©))) goto err; if (TT.signe) { - status = BC_STATUS_EXEC_SIGNAL; + s = BC_STATUS_EXEC_SIGNAL; goto err; } - resrdx = powrdx; + bc_num_copy(c, ©); - for (pow >>= 1; !TT.signe && pow != 0; pow >>= 1) { + for (resrdx = powrdx, pow >>= 1; !TT.signe && pow; pow >>= 1) { powrdx <<= 1; - - if ((status = bc_num_mul(©, ©, ©, powrdx))) goto err; + s = bc_num_mul(©, ©, ©, powrdx); + if (s) goto err; if (pow & 1) { resrdx += powrdx; - if ((status = bc_num_mul(c, ©, c, resrdx))) goto err; + s = bc_num_mul(c, ©, c, resrdx); + if (s) goto err; } } - if (neg && (status = bc_num_inv(c, c, scale))) goto err; + if (neg) { + s = bc_num_inv(c, c, scale); + if (s) goto err; + } + if (TT.signe) { - status = BC_STATUS_EXEC_SIGNAL; + s = BC_STATUS_EXEC_SIGNAL; goto err; } if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale); + // We can't use bc_num_clean() here. for (zero = 1, i = 0; zero && i < c->len; ++i) zero = !c->num[i]; - if (zero) bc_num_zero(c); + if (zero) bc_num_setToZero(c, scale); err: bc_num_free(©); - return status; + return s; } -BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, - BcNumBinaryFunc op, size_t req) +BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale, + BcNumBinaryOp op, size_t req) { - BcStatus status; + BcStatus s; BcNum num2, *ptr_a, *ptr_b; int init = 0; if (c == a) { - memcpy(&num2, c, sizeof(BcNum)); ptr_a = &num2; + memcpy(ptr_a, c, sizeof(BcNum)); init = 1; } else ptr_a = a; if (c == b) { - - if (c == a) { - ptr_b = ptr_a; - } - else { - memcpy(&num2, c, sizeof(BcNum)); - ptr_b = &num2; + ptr_b = &num2; + if (c != a) { + memcpy(ptr_b, c, sizeof(BcNum)); init = 1; } } else ptr_b = b; - if (init) status = bc_num_init(c, req); - else status = bc_num_expand(c, req); + if (init) bc_num_init(c, req); + else bc_num_expand(c, req); - if (status) goto err; - status = op(ptr_a, ptr_b, c, scale); + s = op(ptr_a, ptr_b, c, scale); -err: - if (c == a || c == b) bc_num_free(&num2); - return status; + if (init) bc_num_free(&num2); + + return s; } int bc_num_strValid(const char *val, size_t base) { - size_t len, i; - BcDigit c, b; - int small, radix; - - radix = 0; - len = strlen(val); + BcDig b; + int small, radix = 0; + size_t i, len = strlen(val); if (!len) return 1; small = base <= 10; - b = small ? base + '0' : base - 9 + 'A'; + b = (BcDig) (small ? base + '0' : base - 10 + 'A'); for (i = 0; i < len; ++i) { - if ((c = val[i]) == '.') { + BcDig c = val[i]; + + if (c == '.') { if (radix) return 0; @@ -1654,9 +1795,8 @@ int bc_num_strValid(const char *val, size_t base) { return 1; } -BcStatus bc_num_parseDecimal(BcNum *n, const char *val) { +void bc_num_parseDecimal(BcNum *n, const char *val) { - BcStatus status; size_t len, i; const char *ptr; int zero = 1; @@ -1669,75 +1809,85 @@ BcStatus bc_num_parseDecimal(BcNum *n, const char *val) { if (len) { for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.'; - if ((status = bc_num_expand(n, len))) return status; - } - - if (zero) { - memset(n->num, 0, sizeof(BcDigit) * n->cap); - n->neg = 0; - return BC_STATUS_SUCCESS; + bc_num_expand(n, len); } ptr = strchr(val, '.'); // Explicitly test for NULL here to produce either a 0 or 1. - n->rdx = (ptr != NULL) * ((val + len) - (ptr + 1)); - - for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.')) - n->num[n->len] = val[i] - '0'; + n->rdx = (size_t) ((ptr != NULL) * ((val + len) - (ptr + 1))); - return BC_STATUS_SUCCESS; + if (!zero) { + for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.')) + n->num[n->len] = val[i] - '0'; + } } -BcStatus bc_num_parseBase(BcNum *n, const char *val, BcNum *base) { +void bc_num_parseBase(BcNum *n, const char *val, BcNum *base) { - BcStatus status; + BcStatus s; BcNum temp, mult, result; - size_t i, len, digits; - BcDigit c; - int zero; + BcDig c = '\0'; + int zero = 1; unsigned long v; + size_t i, digits, len = strlen(val); - len = strlen(val); bc_num_zero(n); - for (zero = 1, i = 0; zero && i < len; ++i) - zero = (val[i] == '.' || val[i] == '0'); - if (zero) return BC_STATUS_SUCCESS; + 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 ((status = bc_num_init(&temp, BC_NUM_DEF_SIZE))) return status; - if ((status = bc_num_init(&mult, BC_NUM_DEF_SIZE))) goto mult_err; + for (i = 0; i < len; ++i) { - for (i = 0; i < len && (c = val[i]) != '.'; ++i) { + c = val[i]; + if (c == '.') break; - v = c <= '9' ? c - '0' : c - 'A' + 10; + v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); - if ((status = bc_num_mul(n, base, &mult, 0))) goto int_err; - if ((status = bc_num_ulong2num(&temp, v))) goto int_err; - if ((status = bc_num_add(&mult, &temp, n, 0))) goto int_err; + s = bc_num_mul(n, base, &mult, 0); + if (s) goto int_err; + s = bc_num_ulong2num(&temp, v); + if (s) goto int_err; + s = bc_num_add(&mult, &temp, n, 0); + if (s) goto int_err; } - if (i == len && !(c = val[i])) goto int_err; - if ((status = bc_num_init(&result, base->len))) goto int_err; + if (i == len) { + c = val[i]; + if (c == 0) goto int_err; + } + bc_num_init(&result, base->len); bc_num_zero(&result); bc_num_one(&mult); - for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) { + for (i += 1, digits = 0; i < len; ++i, ++digits) { - v = c <= '9' ? c - '0' : c - 'A' + 10; + c = val[i]; + if (c == 0) break; - if ((status = bc_num_mul(&result, base, &result, 0))) goto err; - if ((status = bc_num_ulong2num(&temp, v))) goto err; - if ((status = bc_num_add(&result, &temp, &result, 0))) goto err; - if ((status = bc_num_mul(&mult, base, &mult, 0))) goto err; + v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); + + s = bc_num_mul(&result, base, &result, 0); + if (s) goto err; + s = bc_num_ulong2num(&temp, v); + if (s) goto err; + s = bc_num_add(&result, &temp, &result, 0); + if (s) goto err; + s = bc_num_mul(&mult, base, &mult, 0); + if (s) goto err; } - if ((status = bc_num_div(&result, &mult, &result, digits))) goto err; - if ((status = bc_num_add(n, &result, n, digits))) goto err; + s = bc_num_div(&result, &mult, &result, digits); + if (s) goto err; + s = bc_num_add(n, &result, n, digits); + if (s) goto err; if (n->len) { - if (n->rdx < digits && n->len) status = bc_num_extend(n, digits - n->rdx); + if (n->rdx < digits) bc_num_extend(n, digits - n->rdx); } else bc_num_zero(n); @@ -1745,261 +1895,233 @@ err: bc_num_free(&result); int_err: bc_num_free(&mult); -mult_err: bc_num_free(&temp); - return status; } -BcStatus bc_num_printDigits(size_t num, size_t width, int radix, - size_t *nchars, size_t line_len) -{ - size_t exp, pow, div; - +void bc_num_printNewline(size_t *nchars, size_t line_len) { if (*nchars == line_len - 1) { - if (putchar('\\') == EOF) return BC_STATUS_IO_ERR; - if (putchar('\n') == EOF) return BC_STATUS_IO_ERR; + bc_vm_putchar('\\'); + bc_vm_putchar('\n'); *nchars = 0; } +} - if (*nchars || radix) { - if (putchar(radix ? '.' : ' ') == EOF) return BC_STATUS_IO_ERR; - ++(*nchars); - } +void bc_num_printDigits(size_t num, size_t width, int radix, + size_t *nchars, size_t line_len) +{ + size_t exp, pow, div; + + bc_num_printNewline(nchars, line_len); + bc_vm_putchar(radix ? '.' : ' '); + ++(*nchars); + bc_num_printNewline(nchars, line_len); for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10); for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) { - - if (*nchars == line_len - 1) { - if (putchar('\\') == EOF) return BC_STATUS_IO_ERR; - if (putchar('\n') == EOF) return BC_STATUS_IO_ERR; - *nchars = 0; - } - + bc_num_printNewline(nchars, line_len); div = num / pow; num -= div * pow; - - if (putchar(((char) div) + '0') == EOF) return BC_STATUS_IO_ERR; + bc_vm_putchar(((char) div) + '0'); } - - return BC_STATUS_SUCCESS; } -BcStatus bc_num_printHex(size_t num, size_t width, int radix, - size_t *nchars, size_t line_len) +void bc_num_printHex(size_t num, size_t width, int radix, + size_t *nchars, size_t line_len) { - width += !!radix; - if (*nchars + width >= line_len) { - if (putchar('\\') == EOF) return BC_STATUS_IO_ERR; - if (putchar('\n') == EOF) return BC_STATUS_IO_ERR; - *nchars = 0; - } - if (radix && putchar('.') == EOF) return BC_STATUS_IO_ERR; - if (putchar(bc_num_hex_digits[num]) == EOF) return BC_STATUS_IO_ERR; + if (radix) { + bc_num_printNewline(nchars, line_len); + bc_vm_putchar('.'); + *nchars += 1; + } + bc_num_printNewline(nchars, line_len); + bc_vm_putchar(bc_num_hex_digits[num]); *nchars = *nchars + width; - - return BC_STATUS_SUCCESS; } -BcStatus bc_num_printDecimal(BcNum *n, size_t *nchars, size_t line_len) { - - BcStatus status; - size_t i; - - if (n->neg) { - if (putchar('-') == EOF) return BC_STATUS_IO_ERR; - ++(*nchars); - } +void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len) { - status = BC_STATUS_SUCCESS; + size_t i, rdx = n->rdx - 1; - for (i = n->len - 1; !status && i < n->len; --i) - status = bc_num_printHex(n->num[i], 1, i == n->rdx - 1, nchars, line_len); + if (n->neg) bc_vm_putchar('-'); + (*nchars) += n->neg; - return status; + for (i = n->len - 1; i < n->len; --i) + bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len); } -BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t, - size_t *nchars, size_t line_len) +BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, size_t *nchars, + size_t len, BcNumDigitOp print) { - BcStatus status; + BcStatus s; BcVec stack; BcNum intp, fracp, digit, frac_len; - size_t width, i; - BcNumDigitFunc print; unsigned long dig, *ptr; - int neg, radix; - - neg = n->neg; - n->neg = 0; - - if (neg && putchar('-') == EOF) return BC_STATUS_IO_ERR; - nchars += neg; + size_t i; + int radix; - if (base_t <= BC_NUM_MAX_INPUT_BASE) { - width = 1; - print = bc_num_printHex; - } - else { - width = (size_t) floor(log10((double) (base_t - 1)) + 1.0); - print = bc_num_printDigits; + if (n->len == 0) { + print(0, width, 0, nchars, len); + return BC_STATUS_SUCCESS; } - if ((status = bc_vec_init(&stack, sizeof(long), NULL))) return status; - if ((status = bc_num_init(&intp, n->len))) goto int_err; - if ((status = bc_num_init(&fracp, n->rdx))) goto frac_err; - if ((status = bc_num_init(&digit, width))) goto digit_err; - if ((status = bc_num_copy(&intp, n))) goto frac_len_err; + bc_vec_init(&stack, sizeof(long), NULL); + bc_num_init(&intp, n->len); + bc_num_init(&fracp, n->rdx); + bc_num_init(&digit, width); + bc_num_init(&frac_len, BC_NUM_INT(n)); + bc_num_copy(&intp, n); + bc_num_one(&frac_len); bc_num_truncate(&intp, intp.rdx); - if ((status = bc_num_sub(n, &intp, &fracp, 0))) goto frac_len_err; + s = bc_num_sub(n, &intp, &fracp, 0); + if (s) goto err; while (intp.len) { - if ((status = bc_num_mod(&intp, base, &digit, 0))) goto frac_len_err; - if ((status = bc_num_ulong(&digit, &dig))) goto frac_len_err; - if ((status = bc_vec_push(&stack, &dig))) goto frac_len_err; - if ((status = bc_num_div(&intp, base, &intp, 0))) goto frac_len_err; + s = bc_num_divmod(&intp, base, &intp, &digit, 0); + if (s) goto err; + s = bc_num_ulong(&digit, &dig); + if (s) goto err; + bc_vec_push(&stack, &dig); } for (i = 0; i < stack.len; ++i) { ptr = bc_vec_item_rev(&stack, i); - status = print(*ptr, width, 0, nchars, line_len); - if (status) goto frac_len_err; + print(*ptr, width, 0, nchars, len); } - if (!n->rdx || (status = bc_num_init(&frac_len, n->len - n->rdx))) - goto frac_len_err; - - bc_num_one(&frac_len); + if (!n->rdx) goto err; for (radix = 1; frac_len.len <= n->rdx; radix = 0) { - if ((status = bc_num_mul(&fracp, base, &fracp, n->rdx))) goto err; - if ((status = bc_num_ulong(&fracp, &dig))) goto err; - if ((status = bc_num_ulong2num(&intp, dig))) goto err; - if ((status = bc_num_sub(&fracp, &intp, &fracp, 0))) goto err; - if ((status = print(dig, width, radix, nchars, line_len))) goto err; - if ((status = bc_num_mul(&frac_len, base, &frac_len, 0))) goto err; + s = bc_num_mul(&fracp, base, &fracp, n->rdx); + if (s) goto err; + s = bc_num_ulong(&fracp, &dig); + if (s) goto err; + s = bc_num_ulong2num(&intp, dig); + if (s) goto err; + s = bc_num_sub(&fracp, &intp, &fracp, 0); + if (s) goto err; + print(dig, width, radix, nchars, len); + s = bc_num_mul(&frac_len, base, &frac_len, 0); + if (s) goto err; } err: - n->neg = neg; bc_num_free(&frac_len); -frac_len_err: bc_num_free(&digit); -digit_err: bc_num_free(&fracp); -frac_err: bc_num_free(&intp); -int_err: bc_vec_free(&stack); - return status; + return s; } -BcStatus bc_num_init(BcNum *n, size_t request) { - - memset(n, 0, sizeof(BcNum)); - - request = request >= BC_NUM_DEF_SIZE ? request : BC_NUM_DEF_SIZE; - if (!(n->num = malloc(request))) return BC_STATUS_MALLOC_FAIL; +BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t, + size_t *nchars, size_t line_len) +{ + BcStatus s; + size_t width, i; + BcNumDigitOp print; + int neg = n->neg; - n->cap = request; + if (neg) bc_vm_putchar('-'); + (*nchars) += neg; - return BC_STATUS_SUCCESS; -} + n->neg = 0; -BcStatus bc_num_expand(BcNum *n, size_t request) { + if (base_t <= BC_NUM_MAX_IBASE) { + width = 1; + print = bc_num_printHex; + } + else { + for (i = base_t - 1, width = 0; i; i /= 10, ++width); + print = bc_num_printDigits; + } - BcDigit *temp; + s = bc_num_printNum(n, base, width, nchars, line_len, print); + n->neg = neg; - if (request <= n->cap) return BC_STATUS_SUCCESS; - if (!(temp = realloc(n->num, request))) return BC_STATUS_MALLOC_FAIL; + return s; +} - memset(temp + n->cap, 0, sizeof(char) * (request - n->cap)); - n->num = temp; - n->cap = request; +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; +} - return BC_STATUS_SUCCESS; +void bc_num_expand(BcNum *n, size_t req) { + req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; + if (req > n->cap) { + n->num = xrealloc(n->num, req); + n->cap = req; + } } void bc_num_free(void *num) { - BcNum *n = (BcNum*) num; - if (n && n->num) free(n->num); + free(((BcNum*) num)->num); } -BcStatus bc_num_copy(BcNum *d, BcNum *s) { +void bc_num_copy(BcNum *d, BcNum *s) { - BcStatus status; - - if (d == s) return BC_STATUS_SUCCESS; - if ((status = bc_num_expand(d, s->cap))) return status; - - d->len = s->len; - d->neg = s->neg; - d->rdx = s->rdx; - - memcpy(d->num, s->num, sizeof(BcDigit) * d->len); - memset(d->num + d->len, 0, sizeof(BcDigit) * (d->cap - d->len)); - - return BC_STATUS_SUCCESS; + 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); + } } BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, size_t base_t) { - BcStatus status; - if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING; - if (base_t == 10) status = bc_num_parseDecimal(n, val); - else status = bc_num_parseBase(n, val, base); + if (base_t == 10) bc_num_parseDecimal(n, val); + else bc_num_parseBase(n, val, base); - return status; + return BC_STATUS_SUCCESS; } BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, int newline, size_t *nchars, size_t line_len) { - BcStatus status; + BcStatus s = BC_STATUS_SUCCESS; - if (*nchars >= line_len) { - if (putchar('\\') == EOF) return BC_STATUS_IO_ERR; - if (putchar('\n') == EOF) return BC_STATUS_IO_ERR; - *nchars = 0; - } + bc_num_printNewline(nchars, line_len); - if (!n->len) { - if (putchar('0') == EOF) return BC_STATUS_IO_ERR; + if (n->len == 0) { + bc_vm_putchar('0'); ++(*nchars); - status = BC_STATUS_SUCCESS; } - else if (base_t == 10) status = bc_num_printDecimal(n, nchars, line_len); - else status = bc_num_printBase(n, base, base_t, nchars, line_len); - - if (status) return status; + 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 (newline) { - if (putchar('\n') == EOF) return BC_STATUS_IO_ERR; + bc_vm_putchar('\n'); *nchars = 0; } - return status; + return s; } BcStatus bc_num_ulong(BcNum *n, unsigned long *result) { size_t i; - unsigned long prev, pow; + unsigned long pow; if (n->neg) return BC_STATUS_MATH_NEGATIVE; for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) { - prev = *result; - *result += n->num[i] * pow; + unsigned long prev = *result, powprev = pow; + + *result += ((unsigned long) n->num[i]) * pow; pow *= 10; - if (*result < prev) return BC_STATUS_MATH_OVERFLOW; + if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW; } return BC_STATUS_SUCCESS; @@ -2007,145 +2129,130 @@ BcStatus bc_num_ulong(BcNum *n, unsigned long *result) { BcStatus bc_num_ulong2num(BcNum *n, unsigned long val) { - BcStatus status; - size_t len, i; - BcDigit *ptr; + size_t len; + BcDig *ptr; + unsigned long i; bc_num_zero(n); - if (!val) { - memset(n->num, 0, sizeof(char) * n->cap); - return BC_STATUS_SUCCESS; - } - - len = (size_t) ceil(log10(((double) ULONG_MAX) + 1.0f)); + if (val == 0) return BC_STATUS_SUCCESS; - if ((status = bc_num_expand(n, len))) return status; - - for (ptr = n->num, i = 0; val; ++i, ++n->len) { - ptr[i] = (char) (val % 10); - val /= 10; - } + for (len = 1, i = ULONG_MAX; i; i /= 10, ++len) + 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; } -BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *result, size_t scale) { +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; - BcNumBinaryFunc op = (!a->neg == !b->neg) ? bc_num_alg_a : bc_num_alg_s; - return bc_num_binary(a, b, result, 0, op, a->len + b->len + 1); + return bc_num_binary(a, b, c, 0, op, BC_NUM_AREQ(a, b)); } -BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *result, size_t 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; - BcNumBinaryFunc op = (!a->neg == !b->neg) ? bc_num_alg_s : bc_num_alg_a; - return bc_num_binary(a, b, result, 1, op, a->len + b->len + 1); + return bc_num_binary(a, b, c, 1, op, BC_NUM_AREQ(a, b)); } -BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *result, size_t scale) { - return bc_num_binary(a, b, result, scale, bc_num_alg_m, - a->len + b->len + scale + 1); +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); } -BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *result, size_t scale) { - return bc_num_binary(a, b, result, scale, bc_num_alg_d, - a->len + b->len + scale + 1); +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); } -BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *result, size_t scale) { - return bc_num_binary(a, b, result, scale, bc_num_alg_mod, - a->len + b->len + scale + 1); +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); } -BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *result, size_t scale) { - return bc_num_binary(a, b, result, scale, bc_num_alg_p, - (a->len + 1) * (b->len + 1)); +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); } -BcStatus bc_num_sqrt(BcNum *a, BcNum *result, size_t scale) { - - BcStatus status; - BcNum a2, *ptr_a, num1, num2, two, f, fprime, *x0, *x1, *temp; - size_t pow, len, digits, resrdx, req; - int cmp; - - req = a->rdx + (a->len - a->rdx) * 2 + 1; +BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale) { - if (result == a) { - memcpy(&a2, result, sizeof(BcNum)); - ptr_a = &a2; - status = bc_num_init(result, req); - } - else { - ptr_a = a; - status = bc_num_expand(result, req); - } + BcStatus s; + BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; + size_t pow, len, digs, digs1, resrdx, req, times = 0; + ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX; - if (status) goto init_err; + req = maxof(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1; + bc_num_expand(b, req); - if (!ptr_a->len) { - bc_num_zero(result); + if (a->len == 0) { + bc_num_setToZero(b, scale); return BC_STATUS_SUCCESS; } - else if (ptr_a->neg) return BC_STATUS_MATH_NEG_SQRT; + else if (a->neg) return BC_STATUS_MATH_NEGATIVE; else if (BC_NUM_ONE(a)) { - bc_num_one(result); - return bc_num_extend(result, scale); + bc_num_one(b); + bc_num_extend(b, scale); + return BC_STATUS_SUCCESS; } - memset(result->num, 0, result->cap * sizeof(BcDigit)); - len = ptr_a->len; - - scale = maxof(scale, ptr_a->rdx) + 1; - - if ((status = bc_num_init(&num1, len))) return status; - if ((status = bc_num_init(&num2, num1.len))) goto num2_err; - if ((status = bc_num_init(&two, BC_NUM_DEF_SIZE))) goto two_err; + scale = maxof(scale, a->rdx) + 1; + len = a->len + scale; - bc_num_one(&two); - two.num[0] = 2; + bc_num_init(&num1, len); + bc_num_init(&num2, len); + bc_num_init(&half, BC_NUM_DEF_SIZE); - len += scale; + bc_num_one(&half); + half.num[0] = 5; + half.rdx = 1; - if ((status = bc_num_init(&f, len))) goto f_err; - if ((status = bc_num_init(&fprime, len + scale))) goto fprime_err; + bc_num_init(&f, len); + bc_num_init(&fprime, len); x0 = &num1; x1 = &num2; bc_num_one(x0); - - pow = ptr_a->len - ptr_a->rdx; + pow = BC_NUM_INT(a); if (pow) { - if (pow & 1) { - x0->num[0] = 2; - pow -= 1; - } - else { - x0->num[0] = 6; - pow -= 2; - } + if (pow & 1) x0->num[0] = 2; + else x0->num[0] = 6; + + pow -= 2 - (pow & 1); - if ((status = bc_num_extend(x0, pow))) goto err; + bc_num_extend(x0, pow); + + // Make sure to move the radix back. + x0->rdx -= pow; } - cmp = 1; - x0->rdx = digits = 0; - resrdx = scale + 1; - len = (x0->len - x0->rdx) + resrdx; + x0->rdx = digs = digs1 = 0; + resrdx = scale + 2; + len = BC_NUM_INT(x0) + resrdx - 1; - while (!TT.signe && cmp && digits <= len) { + while (!TT.signe && (cmp || digs < len)) { - if ((status = bc_num_mul(x0, x0, &f, resrdx))) goto err; - if ((status = bc_num_sub(&f, a, &f, resrdx))) goto err; - if ((status = bc_num_mul(x0, &two, &fprime, resrdx))) goto err; - if ((status = bc_num_div(&f, &fprime, &f, resrdx))) goto err; - if ((status = bc_num_sub(x0, &f, x1, resrdx))) goto err; + s = bc_num_div(a, x0, &f, resrdx); + if (s) goto err; + s = bc_num_add(x0, &f, &fprime, resrdx); + if (s) goto err; + s = bc_num_mul(&fprime, &half, x1, resrdx); + if (s) goto err; cmp = bc_num_cmp(x1, x0); - digits = x1->len - llabs(cmp); + digs = x1->len - (unsigned long long) llabs(cmp); + + if (cmp == cmp2 && digs == digs1) times += 1; + else times = 0; + + resrdx += times > 4; + + cmp2 = cmp1; + cmp1 = cmp; + digs1 = digs; temp = x0; x0 = x1; @@ -2153,183 +2260,151 @@ BcStatus bc_num_sqrt(BcNum *a, BcNum *result, size_t scale) { } if (TT.signe) { - status = BC_STATUS_EXEC_SIGNAL; + s = BC_STATUS_EXEC_SIGNAL; goto err; } - if ((status = bc_num_copy(result, x0))) goto err; - - if (result->rdx > --scale) bc_num_truncate(result, result->rdx - scale); - else if (result->rdx < scale) - status = bc_num_extend(result, scale - result->rdx); + bc_num_copy(b, x0); + scale -= 1; + if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale); err: bc_num_free(&fprime); -fprime_err: bc_num_free(&f); -f_err: - bc_num_free(&two); -two_err: + bc_num_free(&half); bc_num_free(&num2); -num2_err: bc_num_free(&num1); -init_err: - if (result == a) bc_num_free(&a2); - return status; + return s; } -void bc_num_zero(BcNum *n) { - if (!n) return; - memset(n->num, 0, n->cap * sizeof(char)); - n->neg = 0; - n->len = 0; - n->rdx = 0; +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); + + if (c == a) { + memcpy(&num2, c, sizeof(BcNum)); + ptr_a = &num2; + bc_num_init(c, len); + init = 1; + } + else { + ptr_a = a; + bc_num_expand(c, len); + } + + s = bc_num_r(ptr_a, b, c, d, scale, ts); + + if (init) bc_num_free(&num2); + + return s; } -void bc_num_one(BcNum *n) { - if (!n) return; - bc_num_zero(n); - n->len = 1; - n->num[0] = 1; +int bc_id_cmp(const void *e1, const void *e2) { + return strcmp(((const BcId*) e1)->name, ((const BcId*) e2)->name); } -void bc_num_ten(BcNum *n) { - if (!n) return; - bc_num_zero(n); - n->len = 2; - n->num[0] = 0; - n->num[1] = 1; +void bc_id_free(void *id) { + free(((BcId*) id)->name); } BcStatus bc_func_insert(BcFunc *f, char *name, int var) { - BcAuto a; + BcId a; size_t i; for (i = 0; i < f->autos.len; ++i) { - if (!strcmp(name, ((BcAuto*) bc_vec_item(&f->autos, i))->name)) + if (!strcmp(name, ((BcId*) bc_vec_item(&f->autos, i))->name)) return BC_STATUS_PARSE_DUPLICATE_LOCAL; } - a.var = var; + a.idx = var; a.name = name; - return bc_vec_push(&f->autos, &a); -} - -BcStatus bc_func_init(BcFunc *f) { - - BcStatus status; - - if ((status = bc_vec_init(&f->code, sizeof(uint8_t), NULL))) return status; - if ((status = bc_vec_init(&f->autos, sizeof(BcAuto), bc_auto_free))) goto err; - if ((status = bc_vec_init(&f->labels, sizeof(size_t), NULL))) goto label_err; - - f->nparams = 0; + bc_vec_push(&f->autos, &a); return BC_STATUS_SUCCESS; +} -label_err: - bc_vec_free(&f->autos); -err: - bc_vec_free(&f->code); - return status; +void bc_func_init(BcFunc *f) { + bc_vec_init(&f->code, sizeof(char), NULL); + bc_vec_init(&f->autos, sizeof(BcId), bc_id_free); + bc_vec_init(&f->labels, sizeof(size_t), NULL); + f->nparams = 0; } void bc_func_free(void *func) { - BcFunc *f = (BcFunc*) func; - - if (!f) return; - bc_vec_free(&f->code); bc_vec_free(&f->autos); bc_vec_free(&f->labels); } -BcStatus bc_array_copy(BcVec *d, BcVec *s) { +void bc_array_init(BcVec *a, int nums) { + if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free); + else bc_vec_init(a, sizeof(BcVec), bc_vec_free); + bc_array_expand(a, 1); +} + +void bc_array_copy(BcVec *d, const BcVec *s) { - BcStatus status; size_t i; - BcNum *dnum, *snum; bc_vec_npop(d, d->len); - - if ((status = bc_vec_expand(d, s->cap))) return status; - + bc_vec_expand(d, s->cap); d->len = s->len; - for (i = 0; !status && i < s->len; ++i) { - - dnum = bc_vec_item(d, i); - snum = bc_vec_item(s, i); - - if ((status = bc_num_init(dnum, snum->len))) return status; - if ((status = bc_num_copy(dnum, snum))) bc_num_free(dnum); + 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); } - - return status; } -BcStatus bc_array_expand(BcVec *a, size_t len) { +void bc_array_expand(BcVec *a, size_t len) { - BcStatus status = BC_STATUS_SUCCESS; - BcNum num; + BcResultData data; - while (!status && len > a->len) { - if ((status = bc_num_init(&num, BC_NUM_DEF_SIZE))) return status; - bc_num_zero(&num); - if ((status = bc_vec_push(a, &num))) bc_num_free(&num); + if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) { + while (len > a->len) { + bc_num_init(&data.n, BC_NUM_DEF_SIZE); + bc_vec_push(a, &data.n); + } + } + else { + while (len > a->len) { + bc_array_init(&data.v, 1); + bc_vec_push(a, &data.v); + } } - - return status; } void bc_string_free(void *string) { - char **s = string; - if (s) free(*s); -} - -int bc_entry_cmp(void *entry1, void *entry2) { - return strcmp(((BcEntry*) entry1)->name, ((BcEntry*) entry2)->name); -} - -void bc_entry_free(void *entry) { - BcEntry *e = entry; - if (e) free(e->name); -} - -void bc_auto_free(void *auto1) { - BcAuto *a = (BcAuto*) auto1; - if (a && a->name) free(a->name); + free(*((char**) string)); } void bc_result_free(void *result) { BcResult *r = (BcResult*) result; - if (!r) return; - - switch (r->type) { + switch (r->t) { case BC_RESULT_TEMP: + case BC_RESULT_IBASE: case BC_RESULT_SCALE: - case BC_RESULT_VAR_AUTO: - { - bc_num_free(&r->data.num); - break; - } - - case BC_RESULT_ARRAY_AUTO: + case BC_RESULT_OBASE: { - bc_vec_free(&r->data.array); + bc_num_free(&r->d.n); break; } case BC_RESULT_VAR: case BC_RESULT_ARRAY: + case BC_RESULT_ARRAY_ELEM: { - if (r->data.id.name) free(r->data.id.name); + free(r->d.id.name); break; } @@ -2341,198 +2416,242 @@ void bc_result_free(void *result) { } } -BcStatus bc_lex_string(BcLex *lex) { +void bc_lex_lineComment(BcLex *l) { + l->t.t = BC_LEX_WHITESPACE; + while (l->i < l->len && l->buf[l->i++] != '\n'); + --l->i; +} - const char *start; - size_t newlines, len, i, j; +void bc_lex_whitespace(BcLex *l) { char c; + l->t.t = BC_LEX_WHITESPACE; + for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]); +} - newlines = 0; - lex->token.type = BC_LEX_STRING; - i = lex->idx; +BcStatus bc_lex_number(BcLex *l, char start) { - for (c = lex->buffer[i]; c != '"' && c != '\0'; c = lex->buffer[++i]) { - if (c == '\n') ++newlines; - } + const 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 == '.'; - if (c == '\0') { - lex->idx = i; - return BC_STATUS_LEX_NO_STRING_END; + last_pt = pt; + l->t.t = BC_LEX_NUMBER; + + 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; + } + + c = buf[++i]; } - len = i - lex->idx; - if (!(lex->token.string = malloc(len + 1))) return BC_STATUS_MALLOC_FAIL; + len = i + 1 * !last_pt - bslashes * 2; + if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN; + + 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); - start = lex->buffer + lex->idx; + for (buf -= 1, j = 1; j < len + hits * 2; ++j) { + + c = buf[j]; + + // 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; + } - for (j = 0; j < len; ++j) lex->token.string[j] = start[j]; + bc_vec_push(&l->t.v, &c); + } - lex->token.string[len] = '\0'; - lex->idx = i + 1; - lex->line += newlines; + bc_vec_pushByte(&l->t.v, '\0'); + l->i += i; return BC_STATUS_SUCCESS; } -BcStatus bc_lex_comment(BcLex *lex) { +BcStatus bc_lex_name(BcLex *l) { - size_t newlines, i; - const char *buffer; - char c; - int end; + size_t i = 0; + const char *buf = l->buf + l->i - 1; + char c = buf[i]; - newlines = 0; - lex->token.type = BC_LEX_WHITESPACE; - end = 0; + l->t.t = BC_LEX_NAME; - buffer = lex->buffer; + while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i]; - for (i = ++lex->idx; !end; i += !end) { + if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN; + bc_vec_string(&l->t.v, i, buf); - while ((c = buffer[i]) != '*' && c != '\0') { - if (c == '\n') ++newlines; - c = buffer[++i]; - } + // Increment the index. We minus 1 because it has already been incremented. + l->i += i - 1; - if (c == '\0' || buffer[i + 1] == '\0') { - lex->idx = i; - return BC_STATUS_LEX_NO_COMMENT_END; - } + return BC_STATUS_SUCCESS; +} - end = buffer[i + 1] == '/'; - } +void bc_lex_init(BcLex *l) { + + bc_vec_init(&l->t.v, sizeof(char), NULL); +} - lex->idx = i + 2; - lex->line += newlines; +void bc_lex_free(BcLex *l) { + bc_vec_free(&l->t.v); +} - return BC_STATUS_SUCCESS; +void bc_lex_file(BcLex *l, const char *file) { + l->line = 1; + l->newline = 0; + l->f = file; } -BcStatus bc_lex_number(BcLex *lex, char start) { +BcStatus bc_lex_next(BcLex *l) { - const char *buffer, *buf; - size_t backslashes, len, hits, i, j; - char c; - int point; + BcStatus s; - lex->token.type = BC_LEX_NUMBER; - point = start == '.'; - buffer = lex->buffer + lex->idx; - backslashes = 0; - i = 0; - c = buffer[i]; + l->t.last = l->t.t; + if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF; - while (c && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || - (c == '.' && !point) || (c == '\\' && buffer[i + 1] == '\n'))) - { - if (c == '\\') { - ++i; - backslashes += 1; - } + l->line += l->newline; + l->t.t = BC_LEX_EOF; - c = buffer[++i]; - } + l->newline = (l->i == l->len); + if (l->newline) 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); - len = i + 1 * (*(buffer + i - 1) != '.'); + return s; +} - lex->token.string = malloc(len - backslashes * 2 + 1); - if (!lex->token.string) return BC_STATUS_MALLOC_FAIL; +BcStatus bc_lex_text(BcLex *l, const char *text) { + l->buf = text; + l->i = 0; + l->len = strlen(text); + l->t.t = l->t.last = BC_LEX_INVALID; + return bc_lex_next(l); +} - lex->token.string[0] = start; - buf = buffer - 1; - hits = 0; +BcStatus bc_lex_identifier(BcLex *l) { - for (j = 1; j < len; ++j) { + BcStatus s; + size_t i; + const char *buf = l->buf + l->i - 1; - c = buf[j]; + for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) { - // If we have hit a backslash, skip it. - // We don't have to check for a newline - // because it's guaranteed. - if (hits < backslashes && c == '\\') { - ++hits; - ++j; - continue; - } + unsigned long len = (unsigned long) bc_lex_kws[i].len; + + if (strncmp(buf, bc_lex_kws[i].name, len) == 0) { - lex->token.string[j - (hits * 2)] = c; + l->t.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 (s) return s; + } + + // We minus 1 because the index has already been incremented. + l->i += len - 1; + return BC_STATUS_SUCCESS; + } } - lex->token.string[j - (hits * 2)] = '\0'; - lex->idx += i; + s = bc_lex_name(l); + if (s) return s; - return BC_STATUS_SUCCESS; + if (l->t.v.len - 1 > 1) + s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf); + + return s; } -BcStatus bc_lex_name(BcLex *lex) { +BcStatus bc_lex_string(BcLex *l) { - BcStatus status; - const char *buffer; - size_t i; + size_t len, nls = 0, i = l->i; char c; - buffer = lex->buffer + lex->idx - 1; + l->t.t = BC_LEX_STR; - for (i = 0; i < sizeof(bc_lex_keywords) / sizeof(bc_lex_keywords[0]); ++i) { + for (c = l->buf[i]; c && c != '"'; c = l->buf[++i]) nls += (c == '\n'); - if (!strncmp(buffer, bc_lex_keywords[i].name, bc_lex_keywords[i].len)) { + if (c == '\0') { + l->i = i; + return BC_STATUS_LEX_NO_STRING_END; + } - lex->token.type = BC_LEX_KEY_AUTO + i; + 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 (!bc_lex_keywords[i].posix && - (status = bc_posix_error(BC_STATUS_POSIX_BAD_KEYWORD, lex->file, - lex->line, bc_lex_keywords[i].name))) - { - return status; - } + l->i = i + 1; + l->line += nls; - // We need to minus one because the - // index has already been incremented. - lex->idx += bc_lex_keywords[i].len - 1; + return BC_STATUS_SUCCESS; +} - return BC_STATUS_SUCCESS; - } +void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) { + if (l->buf[l->i] == '=') { + ++l->i; + l->t.t = with; } + else l->t.t = without; +} + +BcStatus bc_lex_comment(BcLex *l) { - lex->token.type = BC_LEX_NAME; + size_t i, nls = 0; + const char *buf = l->buf; + int end = 0; + char c; - i = 0; - c = buffer[i]; + l->t.t = BC_LEX_WHITESPACE; - while ((c >= 'a' && c<= 'z') || (c >= '0' && c <= '9') || c == '_') - c = buffer[++i]; + for (i = ++l->i; !end; i += !end) { - if (i > 1 && (status = bc_posix_error(BC_STATUS_POSIX_NAME_LEN, - lex->file, lex->line, buffer))) - { - return status; - } + for (c = buf[i]; c != '*' && c; c = buf[++i]) nls += (c == '\n'); - if (!(lex->token.string = malloc(i + 1))) return BC_STATUS_MALLOC_FAIL; + if (c == 0 || buf[i + 1] == '\0') { + l->i = i; + return BC_STATUS_LEX_NO_COMMENT_END; + } - strncpy(lex->token.string, buffer, i); - lex->token.string[i] = '\0'; + end = buf[i + 1] == '/'; + } - // Increment the index. It is minus one - // because it has already been incremented. - lex->idx += i - 1; + l->i = i + 2; + l->line += nls; return BC_STATUS_SUCCESS; } -BcStatus bc_lex_token(BcLex *lex) { +BcStatus bc_lex_token(BcLex *l) { - BcStatus status = BC_STATUS_SUCCESS; - char c, c2; + BcStatus s = BC_STATUS_SUCCESS; + char c = l->buf[l->i++], c2; // This is the workhorse of the lexer. - switch ((c = lex->buffer[lex->idx++])) { + switch (c) { case '\0': case '\n': { - lex->newline = 1; - lex->token.type = BC_LEX_NEWLINE + (!c) * (BC_LEX_EOF - BC_LEX_NEWLINE); + l->newline = 1; + l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE; break; } @@ -2541,34 +2660,18 @@ BcStatus bc_lex_token(BcLex *lex) { case '\f': case '\r': case ' ': - case '\\': { - lex->token.type = BC_LEX_WHITESPACE; - c = lex->buffer[lex->idx]; - - while ((isspace(c) && c != '\n') || c == '\\') - c = lex->buffer[++lex->idx]; - + bc_lex_whitespace(l); break; } case '!': { - c2 = lex->buffer[lex->idx]; - - if (c2 == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_REL_NOT_EQ; - } - else { + bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT); - if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, - lex->file, lex->line, "!"))) - { - return status; - } - - lex->token.type = 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 (s) return s; } break; @@ -2576,50 +2679,40 @@ BcStatus bc_lex_token(BcLex *lex) { case '"': { - status = bc_lex_string(lex); + s = bc_lex_string(l); break; } case '#': { - if ((status = bc_posix_error(BC_STATUS_POSIX_SCRIPT_COMMENT, - lex->file, lex->line, NULL))) - { - return status; - } + s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL); + if (s) return s; - lex->token.type = BC_LEX_WHITESPACE; - while (++lex->idx < lex->len && lex->buffer[lex->idx] != '\n'); + bc_lex_lineComment(l); break; } case '%': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_MODULUS; - } - else lex->token.type = BC_LEX_OP_MODULUS; + bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS); break; } case '&': { - if ((c2 = lex->buffer[lex->idx]) == '&') { + c2 = l->buf[l->i]; + if (c2 == '&') { - if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, - lex->file, lex->line, "&&"))) - { - return status; - } + s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&"); + if (s) return s; - ++lex->idx; - lex->token.type = BC_LEX_OP_BOOL_AND; + ++l->i; + l->t.t = BC_LEX_OP_BOOL_AND; } else { - lex->token.type = BC_LEX_INVALID; - status = BC_STATUS_LEX_BAD_CHARACTER; + l->t.t = BC_LEX_INVALID; + s = BC_STATUS_LEX_BAD_CHAR; } break; @@ -2628,74 +2721,59 @@ BcStatus bc_lex_token(BcLex *lex) { case '(': case ')': { - lex->token.type = c - '(' + BC_LEX_LEFT_PAREN; + l->t.t = (BcLexType) (c - '(' + BC_LEX_LPAREN); break; } case '*': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_MULTIPLY; - } - else lex->token.type = BC_LEX_OP_MULTIPLY; + bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY); break; } case '+': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_PLUS; - } - else if (c2 == '+') { - ++lex->idx; - lex->token.type = BC_LEX_OP_INC; + c2 = l->buf[l->i]; + if (c2 == '+') { + ++l->i; + l->t.t = BC_LEX_OP_INC; } - else lex->token.type = BC_LEX_OP_PLUS; + else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS); break; } case ',': { - lex->token.type = BC_LEX_COMMA; + l->t.t = BC_LEX_COMMA; break; } case '-': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_MINUS; + c2 = l->buf[l->i]; + if (c2 == '-') { + ++l->i; + l->t.t = BC_LEX_OP_DEC; } - else if (c2 == '-') { - ++lex->idx; - lex->token.type = BC_LEX_OP_DEC; - } - else lex->token.type = BC_LEX_OP_MINUS; + else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS); break; } case '.': { - c2 = lex->buffer[lex->idx]; - if (isdigit(c2)) status = bc_lex_number(lex, c); + if (isdigit(l->buf[l->i])) s = bc_lex_number(l, c); else { - status = bc_posix_error(BC_STATUS_POSIX_DOT_LAST, - lex->file, lex->line, NULL); - lex->token.type = BC_LEX_KEY_LAST; + l->t.t = BC_LEX_KEY_LAST; + s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL); } break; } case '/': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_DIVIDE; - } - else if (c2 == '*') status = bc_lex_comment(lex); - else lex->token.type = BC_LEX_OP_DIVIDE; + c2 = l->buf[l->i]; + if (c2 =='*') s = bc_lex_comment(l); + else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE); break; } @@ -2709,72 +2787,61 @@ BcStatus bc_lex_token(BcLex *lex) { case '7': case '8': case '9': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': { - status = bc_lex_number(lex, c); + s = bc_lex_number(l, c); break; } case ';': { - lex->token.type = BC_LEX_SEMICOLON; + l->t.t = BC_LEX_SCOLON; break; } case '<': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_REL_LESS_EQ; - } - else lex->token.type = BC_LEX_OP_REL_LESS; + bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT); break; } case '=': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_REL_EQUAL; - } - else lex->token.type = BC_LEX_OP_ASSIGN; + bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN); break; } case '>': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_REL_GREATER_EQ; - } - else lex->token.type = BC_LEX_OP_REL_GREATER; + bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT); break; } - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': + case '[': + case ']': { - status = bc_lex_number(lex, c); + l->t.t = (BcLexType) (c - '[' + BC_LEX_LBRACKET); break; } - case '[': - case ']': + case '\\': { - lex->token.type = c - '[' + BC_LEX_LEFT_BRACKET; + if (l->buf[l->i] == '\n') { + l->t.t = BC_LEX_WHITESPACE; + ++l->i; + } + else s = BC_STATUS_LEX_BAD_CHAR; break; } case '^': { - if ((c2 = lex->buffer[lex->idx]) == '=') { - ++lex->idx; - lex->token.type = BC_LEX_OP_ASSIGN_POWER; - } - else lex->token.type = BC_LEX_OP_POWER; + bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER); break; } @@ -2805,33 +2872,32 @@ BcStatus bc_lex_token(BcLex *lex) { case 'y': case 'z': { - status = bc_lex_name(lex); + s = bc_lex_identifier(l); break; } case '{': case '}': { - lex->token.type = c - '{' + BC_LEX_LEFT_BRACE; + l->t.t = (BcLexType) (c - '{' + BC_LEX_LBRACE); break; } case '|': { - if ((c2 = lex->buffer[lex->idx]) == '|') { + c2 = l->buf[l->i]; - if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, - lex->file, lex->line, "||"))) - { - return status; - } + if (c2 == '|') { - ++lex->idx; - lex->token.type = BC_LEX_OP_BOOL_OR; + s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||"); + if (s) return s; + + ++l->i; + l->t.t = BC_LEX_OP_BOOL_OR; } else { - lex->token.type = BC_LEX_INVALID; - status = BC_STATUS_LEX_BAD_CHARACTER; + l->t.t = BC_LEX_INVALID; + s = BC_STATUS_LEX_BAD_CHAR; } break; @@ -2839,337 +2905,392 @@ BcStatus bc_lex_token(BcLex *lex) { default: { - lex->token.type = BC_LEX_INVALID; - status = BC_STATUS_LEX_BAD_CHARACTER; + l->t.t = BC_LEX_INVALID; + s = BC_STATUS_LEX_BAD_CHAR; break; } } - return status; + return s; } -void bc_lex_init(BcLex *lex, const char *file) { - lex->line = 1; - lex->newline = 0; - lex->file = file; +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); } -BcStatus bc_lex_next(BcLex *lex) { - - BcStatus status; - - if (lex->token.type == BC_LEX_EOF) return BC_STATUS_LEX_EOF; +void bc_parse_pushName(BcParse *p, char *name) { - if (lex->idx == lex->len) { - lex->newline = 1; - lex->token.type = BC_LEX_EOF; - return BC_STATUS_SUCCESS; - } - - if (lex->newline) { - ++lex->line; - lex->newline = 0; - } + size_t i = 0, len = strlen(name); - // Loop until failure or we don't have whitespace. This - // is so the parser doesn't get inundated with whitespace. - do { - lex->token.string = NULL; - status = bc_lex_token(lex); - } while (!status && lex->token.type == BC_LEX_WHITESPACE); + for (; i < len; ++i) bc_parse_push(p, name[i]); + bc_parse_push(p, BC_PARSE_STREND); - return status; + free(name); } -BcStatus bc_lex_text(BcLex *lex, const char *text) { - lex->buffer = text; - lex->idx = 0; - lex->len = strlen(text); - lex->token.type = BC_LEX_INVALID; - return bc_lex_next(lex); -} +void bc_parse_pushIndex(BcParse *p, size_t idx) { -BcStatus bc_parse_else(BcParse *p, BcVec *code); -BcStatus bc_parse_stmt(BcParse *p, BcVec *code); + unsigned char amt, i, nums[sizeof(size_t)]; -BcStatus bc_parse_pushName(BcVec *code, char *name) { + for (amt = 0; idx; ++amt) { + nums[amt] = (char) idx; + idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT; + } - BcStatus status; - size_t len, i; + bc_parse_push(p, amt); + for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]); +} - status = BC_STATUS_SUCCESS; - len = strlen(name); +void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs) { - for (i = 0; !status && i < len; ++i) - status = bc_vec_pushByte(code, (uint8_t) name[i]); + char *num = xstrdup(p->l.t.v.v); + size_t idx = p->prog->consts.len; - if (status) return status; + bc_vec_push(&p->prog->consts, &num); - free(name); + bc_parse_push(p, BC_INST_NUM); + bc_parse_pushIndex(p, idx); - return bc_vec_pushByte(code, (uint8_t) ':'); + ++(*nexs); + (*prev) = BC_INST_NUM; } -BcStatus bc_parse_pushIndex(BcVec *code, size_t idx) { +BcStatus bc_parse_text(BcParse *p, const char *text) { - BcStatus status; - uint8_t amt, i, nums[sizeof(size_t)]; + BcStatus s; - for (amt = 0; idx; ++amt) { - nums[amt] = (uint8_t) idx; - idx = (idx & ~(UINT8_MAX)) >> sizeof(uint8_t) * CHAR_BIT; - } + p->func = bc_vec_item(&p->prog->fns, p->fidx); - if ((status = bc_vec_pushByte(code, amt))) return status; - for (i = 0; !status && i < amt; ++i) status = bc_vec_pushByte(code, nums[i]); + 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 status; + return bc_lex_text(&p->l, text); } -BcStatus bc_parse_operator(BcParse *p, BcVec *code, BcVec *ops, BcLexToken t, - uint32_t *num_exprs, int next) -{ - BcStatus status; - BcLexToken top; - uint8_t lp, rp; - int rleft; - - rp = bc_parse_ops[t].prec; - rleft = bc_parse_ops[t].left; +BcStatus bc_parse_reset(BcParse *p, BcStatus s) { - while (ops->len && - (top = *((BcLexToken*) bc_vec_top(ops))) != BC_LEX_LEFT_PAREN && - ((lp = bc_parse_ops[top].prec) < rp || (lp == rp && rleft))) - { - status = bc_vec_pushByte(code, BC_PARSE_TOKEN_TO_INST(top)); - if (status) return status; - - bc_vec_pop(ops); + if (p->fidx != BC_PROG_MAIN) { - *num_exprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_OP_NEG; - } + 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); - if ((status = bc_vec_push(ops, &t))) return status; - if (next && (status = bc_lex_next(&p->lex)) && p->lex.token.string) { - free(p->lex.token.string); - p->lex.token.string = NULL; + bc_parse_updateFunc(p, BC_PROG_MAIN); } - return status; -} - -BcStatus bc_parse_rightParen(BcParse *p, BcVec *code, - BcVec *ops, uint32_t *nexs) -{ - BcStatus status; - BcLexToken top; - - if (!ops->len) return BC_STATUS_PARSE_BAD_EXPR; + p->l.i = p->l.len; + p->l.t.t = BC_LEX_EOF; + p->auto_part = (p->nbraces = 0); - while ((top = *((BcLexToken*) bc_vec_top(ops))) != BC_LEX_LEFT_PAREN) { + bc_vec_npop(&p->flags, p->flags.len - 1); + bc_vec_npop(&p->exits, p->exits.len); + bc_vec_npop(&p->conds, p->conds.len); + bc_vec_npop(&p->ops, p->ops.len); - status = bc_vec_pushByte(code, BC_PARSE_TOKEN_TO_INST(top)); - if (status) return status; + return bc_program_reset(p->prog, s); +} - bc_vec_pop(ops); - *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_OP_NEG; +void bc_parse_free(BcParse *p) { + bc_vec_free(&p->flags); + bc_vec_free(&p->exits); + bc_vec_free(&p->conds); + bc_vec_free(&p->ops); + 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); + 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); + + p->prog = prog; + p->auto_part = (p->nbraces = 0); + bc_parse_updateFunc(p, func); +} + +BcStatus bc_parse_else(BcParse *p); +BcStatus bc_parse_stmt(BcParse *p); + +BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start, + size_t *nexprs, int next) +{ + 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; + + while (p->ops.len > start) { + + t = BC_PARSE_TOP_OP(p); + if (t == BC_LEX_LPAREN) break; - if (!ops->len) return BC_STATUS_PARSE_BAD_EXPR; + l = bc_parse_ops[t - BC_LEX_OP_INC].prec; + 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; + } + + 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) { + + BcLexType top; + + if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP; + top = BC_PARSE_TOP_OP(p); + + while (top != 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; + + if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP; + top = BC_PARSE_TOP_OP(p); } - bc_vec_pop(ops); + bc_vec_pop(&p->ops); - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); } -BcStatus bc_parse_params(BcParse *p, BcVec *code, uint8_t flags) { +BcStatus bc_parse_params(BcParse *p, uint8_t flags) { - BcStatus status; + BcStatus s; int comma = 0; size_t nparams; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - for (nparams = 0; p->lex.token.type != BC_LEX_RIGHT_PAREN; ++nparams) { + for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) { - status = bc_parse_expr(p, code, flags & ~(BC_PARSE_EXPR_PRINT)); - if (status) return status; + flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY; + s = bc_parse_expr(p, flags, bc_parse_next_param); + if (s) return s; - if (p->lex.token.type == BC_LEX_COMMA) { - comma = 1; - if ((status = bc_lex_next(&p->lex))) return status; + comma = p->l.t.t == BC_LEX_COMMA; + if (comma) { + s = bc_lex_next(&p->l); + if (s) return s; } - else comma = 0; } if (comma) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_vec_pushByte(code, BC_INST_CALL))) return status; + bc_parse_push(p, BC_INST_CALL); + bc_parse_pushIndex(p, nparams); - return bc_parse_pushIndex(code, nparams); + return BC_STATUS_SUCCESS; } -BcStatus bc_parse_call(BcParse *p, BcVec *code, char *name, uint8_t flags) { +BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) { - BcStatus status; - BcEntry entry, *entry_ptr; + BcStatus s; + BcId entry, *entry_ptr; size_t idx; entry.name = name; - if ((status = bc_parse_params(p, code, flags))) goto err; + s = bc_parse_params(p, flags); + if (s) goto err; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) { - status = BC_STATUS_PARSE_BAD_TOKEN; + if (p->l.t.t != BC_LEX_RPAREN) { + s = BC_STATUS_PARSE_BAD_TOKEN; goto err; } - idx = bc_veco_index(&p->prog->func_map, &entry); + idx = bc_map_index(&p->prog->fn_map, &entry); - if (idx == -1) { - if ((status = bc_program_addFunc(p->prog, name, &idx))) return status; - name = NULL; + 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); } else free(name); - entry_ptr = bc_veco_item(&p->prog->func_map, idx); - if ((status = bc_parse_pushIndex(code, entry_ptr->idx))) return status; + entry_ptr = bc_vec_item(&p->prog->fn_map, idx); + bc_parse_pushIndex(p, entry_ptr->idx); - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); err: - if (name) free(name); - return status; + free(name); + return s; } -BcStatus bc_parse_name(BcParse *p, BcVec *code, BcInst *type, uint8_t flags) -{ - BcStatus status; +BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) { + + BcStatus s; char *name; - name = p->lex.token.string; + name = xstrdup(p->l.t.v.v); + s = bc_lex_next(&p->l); + if (s) goto err; - if ((status = bc_lex_next(&p->lex))) goto err; + if (p->l.t.t == BC_LEX_LBRACKET) { - if (p->lex.token.type == BC_LEX_LEFT_BRACKET) { + s = bc_lex_next(&p->l); + if (s) goto err; - *type = BC_INST_PUSH_ARRAY_ELEM; + if (p->l.t.t == BC_LEX_RBRACKET) { - if ((status = bc_lex_next(&p->lex))) goto err; - if ((status = bc_parse_expr(p, code, flags))) goto err; + if (!(flags & BC_PARSE_ARRAY)) { + s = BC_STATUS_PARSE_BAD_EXP; + goto err; + } - if (p->lex.token.type != BC_LEX_RIGHT_BRACKET) { - status = BC_STATUS_PARSE_BAD_TOKEN; - goto err; + *type = BC_INST_ARRAY; } + else { - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_ARRAY_ELEM))) goto err; + *type = BC_INST_ARRAY_ELEM; + + flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL); + s = bc_parse_expr(p, flags, bc_parse_next_elem); + if (s) goto err; + } - status = bc_parse_pushName(code, name); + s = bc_lex_next(&p->l); + if (s) goto err; + bc_parse_push(p, *type); + bc_parse_pushName(p, name); } - else if (p->lex.token.type == BC_LEX_LEFT_PAREN) { + else if (p->l.t.t == BC_LEX_LPAREN) { - if (flags & BC_PARSE_EXPR_NOCALL) { - status = BC_STATUS_PARSE_BAD_TOKEN; + if (flags & BC_PARSE_NOCALL) { + s = BC_STATUS_PARSE_BAD_TOKEN; goto err; } *type = BC_INST_CALL; - status = bc_parse_call(p, code, name, flags); + s = bc_parse_call(p, name, flags); } else { - *type = BC_INST_PUSH_VAR; - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_VAR))) goto err; - status = bc_parse_pushName(code, name); + *type = BC_INST_VAR; + bc_parse_push(p, BC_INST_VAR); + bc_parse_pushName(p, name); } - return status; + return s; err: free(name); - return status; + return s; } -BcStatus bc_parse_read(BcParse *p, BcVec *code) { +BcStatus bc_parse_read(BcParse *p) { - BcStatus status; + BcStatus s; - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + 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 ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_vec_pushByte(code, BC_INST_READ))) return status; + bc_parse_push(p, BC_INST_READ); - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); } -BcStatus bc_parse_builtin(BcParse *p, BcVec *code, - BcLexToken type, uint8_t flags) +BcStatus bc_parse_builtin(BcParse *p, BcLexType type, + uint8_t flags, BcInst *prev) { - BcStatus status; - uint8_t inst; + BcStatus s; - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + 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 ((status = bc_lex_next(&p->lex))) return status; + flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY; - status = bc_parse_expr(p, code, flags & ~(BC_PARSE_EXPR_PRINT)); - if (status) return status; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; - inst = type == BC_LEX_KEY_LENGTH ? BC_INST_LENGTH : BC_INST_SQRT; - if ((status = bc_vec_pushByte(code, inst))) return status; + s = bc_parse_expr(p, flags, bc_parse_next_rel); + if (s) return s; - return bc_lex_next(&p->lex); + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + + *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT; + bc_parse_push(p, *prev); + + return bc_lex_next(&p->l); } -BcStatus bc_parse_scale(BcParse *p, BcVec *code, BcInst *type, uint8_t flags) { +BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) { - BcStatus status; + BcStatus s; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) { - *type = BC_INST_PUSH_SCALE; - return bc_vec_pushByte(code, BC_INST_PUSH_SCALE); + if (p->l.t.t != BC_LEX_LPAREN) { + *type = BC_INST_SCALE; + bc_parse_push(p, BC_INST_SCALE); + return BC_STATUS_SUCCESS; } *type = BC_INST_SCALE_FUNC; + flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL); - if ((status = bc_lex_next(&p->lex))) return status; - if ((status = bc_parse_expr(p, code, flags))) return status; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_vec_pushByte(code, BC_INST_SCALE_FUNC))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - return bc_lex_next(&p->lex); + s = bc_parse_expr(p, flags, bc_parse_next_rel); + if (s) return s; + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + bc_parse_push(p, BC_INST_SCALE_FUNC); + + return bc_lex_next(&p->l); } -BcStatus bc_parse_incdec(BcParse *p, BcVec *code, BcInst *prev, - uint32_t *nexprs, uint8_t flags) +BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, int *paren_expr, + size_t *nexprs, uint8_t flags) { - BcStatus status; - BcLexToken type; - BcInst etype; - uint8_t inst; - - etype = *prev; + BcStatus s; + BcLexType type; + char inst; + BcInst etype = *prev; - if (etype == BC_INST_PUSH_VAR || etype == BC_INST_PUSH_ARRAY_ELEM || - etype == BC_INST_PUSH_SCALE || etype == BC_INST_PUSH_LAST || - etype == BC_INST_PUSH_IBASE || etype == BC_INST_PUSH_OBASE) + 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->lex.token.type != BC_LEX_OP_INC); - if ((status = bc_vec_pushByte(code, inst))) return status; - status = bc_lex_next(&p->lex); + *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC); + bc_parse_push(p, inst); + s = bc_lex_next(&p->l); } else { - *prev = inst = BC_INST_INC_PRE + (p->lex.token.type != BC_LEX_OP_INC); + *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC); + *paren_expr = 1; - if ((status = bc_lex_next(&p->lex))) return status; - type = p->lex.token.type; + s = bc_lex_next(&p->l); + if (s) return s; + type = p->l.t.t; // Because we parse the next part of the expression // right here, we need to increment this. @@ -3179,222 +3300,173 @@ BcStatus bc_parse_incdec(BcParse *p, BcVec *code, BcInst *prev, case BC_LEX_NAME: { - status = bc_parse_name(p, code, prev, flags | BC_PARSE_EXPR_NOCALL); + s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL); break; } case BC_LEX_KEY_IBASE: - { - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_IBASE))) return status; - status = bc_lex_next(&p->lex); - break; - } - case BC_LEX_KEY_LAST: - { - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_LAST))) return status; - status = bc_lex_next(&p->lex); - break; - } - case BC_LEX_KEY_OBASE: { - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_OBASE))) return status; - status = bc_lex_next(&p->lex); + bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE); + s = bc_lex_next(&p->l); break; } case BC_LEX_KEY_SCALE: { - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type == BC_LEX_LEFT_PAREN) - return BC_STATUS_PARSE_BAD_TOKEN; - - status = bc_vec_pushByte(code, BC_INST_PUSH_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: { - return BC_STATUS_PARSE_BAD_TOKEN; + s = BC_STATUS_PARSE_BAD_TOKEN; + break; } } - if (status) return status; - status = bc_vec_pushByte(code, inst); + if (!s) bc_parse_push(p, inst); } - return status; + return s; } -BcStatus bc_parse_minus(BcParse *p, BcVec *exs, BcVec *ops, BcInst *prev, - int rparen, uint32_t *nexprs) +BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn, + int rparen, size_t *nexprs) { - BcStatus status; - BcLexToken type; - BcInst etype; - - if ((status = bc_lex_next(&p->lex))) return status; - - etype = *prev; - type = p->lex.token.type; + BcStatus s; + BcLexType type; + BcInst etype = *prev; - if (type != BC_LEX_NAME && type != BC_LEX_NUMBER && - type != BC_LEX_KEY_SCALE && type != BC_LEX_KEY_LAST && - type != BC_LEX_KEY_IBASE && type != BC_LEX_KEY_OBASE && - type != BC_LEX_LEFT_PAREN && type != BC_LEX_OP_MINUS && - type != BC_LEX_OP_INC && type != BC_LEX_OP_DEC && - type != BC_LEX_OP_BOOL_NOT) - { - return BC_STATUS_PARSE_BAD_TOKEN; - } + 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_PUSH_NUM && etype <= BC_INST_SQRT) ? - BC_LEX_OP_MINUS : BC_LEX_OP_NEG; - *prev = BC_PARSE_TOKEN_TO_INST(type); + (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ? + BC_LEX_OP_MINUS : BC_LEX_NEG; + *prev = BC_PARSE_TOKEN_INST(type); - if (type == BC_LEX_OP_MINUS) - status = bc_parse_operator(p, exs, ops, type, nexprs, 0); - else - // We can just push onto the op stack because this is the largest - // precedence operator that gets pushed. Inc/dec does not. - status = bc_vec_push(ops, &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); - return status; + return s; } -BcStatus bc_parse_string(BcParse *p, BcVec *code) { - - BcStatus status; - size_t len; - - if (strlen(p->lex.token.string) > (unsigned long) maxof_STRING) { - status = BC_STATUS_EXEC_STRING_LEN; - goto err; - } - - len = p->prog->strings.len; +BcStatus bc_parse_string(BcParse *p, char inst) { - if ((status = bc_vec_push(&p->prog->strings, &p->lex.token.string))) goto err; - if ((status = bc_vec_pushByte(code, BC_INST_STR))) return status; - if ((status = bc_parse_pushIndex(code, len))) return status; + char *str = xstrdup(p->l.t.v.v); - return bc_lex_next(&p->lex); + bc_parse_push(p, BC_INST_STR); + bc_parse_pushIndex(p, p->prog->strs.len); + bc_vec_push(&p->prog->strs, &str); + bc_parse_push(p, inst); -err: - free(p->lex.token.string); - return status; + return bc_lex_next(&p->l); } -BcStatus bc_parse_print(BcParse *p, BcVec *code) { +BcStatus bc_parse_print(BcParse *p) { - BcStatus status; - BcLexToken type; - int comma; + BcStatus s; + BcLexType type; + int comma = 0; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - type = p->lex.token.type; + type = p->l.t.t; - if (type == BC_LEX_SEMICOLON || type == BC_LEX_NEWLINE) + if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE) return BC_STATUS_PARSE_BAD_PRINT; - comma = 0; - - while (!status && type != BC_LEX_SEMICOLON && type != BC_LEX_NEWLINE) { - - if (type == BC_LEX_STRING) { - - size_t len = p->prog->strings.len; - - status = bc_vec_push(&p->prog->strings, &p->lex.token.string); - if (status) { - free(p->lex.token.string); - return status; - } + while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) { - if ((status = bc_vec_pushByte(code, BC_INST_PRINT_STR))) return status; - status = bc_parse_pushIndex(code, len); - } + if (type == BC_LEX_STR) s = bc_parse_string(p, BC_INST_PRINT_POP); else { - if ((status = bc_parse_expr(p, code, 0))) return status; - status = bc_vec_pushByte(code, BC_INST_PRINT_EXPR); + s = bc_parse_expr(p, 0, bc_parse_next_print); + if (s) return s; + bc_parse_push(p, BC_INST_PRINT_POP); } - if (status) return status; - if ((status = bc_lex_next(&p->lex))) return status; - - if (p->lex.token.type == BC_LEX_COMMA) { - comma = 1; - status = bc_lex_next(&p->lex); - } - else comma = 0; + if (s) return s; - type = p->lex.token.type; + comma = p->l.t.t == BC_LEX_COMMA; + if (comma) s = bc_lex_next(&p->l); + type = p->l.t.t; } - if (status) return status; + if (s) return s; if (comma) return BC_STATUS_PARSE_BAD_TOKEN; - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); } -BcStatus bc_parse_return(BcParse *p, BcVec *code) { +BcStatus bc_parse_return(BcParse *p) { - BcStatus status; + BcStatus s; + BcLexType t; + int paren; if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - if (p->lex.token.type != BC_LEX_NEWLINE && - p->lex.token.type != BC_LEX_SEMICOLON && - p->lex.token.type != BC_LEX_LEFT_PAREN && - (status = bc_posix_error(BC_STATUS_POSIX_RETURN_PARENS, - p->lex.file, p->lex.line, NULL))) - { - return status; - } + t = p->l.t.t; + paren = t == BC_LEX_LPAREN; - if (p->lex.token.type == BC_LEX_NEWLINE || - p->lex.token.type == BC_LEX_SEMICOLON) - { - status = bc_vec_pushByte(code, BC_INST_RETURN_ZERO); - } + if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON) bc_parse_push(p, BC_INST_RET0); else { - if ((status = bc_parse_expr(p, code, 0))) return status; - status = bc_vec_pushByte(code, BC_INST_RETURN); - } - return status; -} + 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_lex_next(&p->l); + if (s) return s; + } -BcStatus bc_parse_endBody(BcParse *p, BcVec *code, int brace) { + 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 (s) return s; + } - BcStatus status = BC_STATUS_SUCCESS; - uint8_t *flag_ptr; + bc_parse_push(p, BC_INST_RET); + } - if (p->flags.len <= 1 || p->num_braces == 0) return BC_STATUS_PARSE_BAD_TOKEN; + return s; +} - if (brace) { +BcStatus bc_parse_endBody(BcParse *p, int brace) { - if (p->lex.token.type == BC_LEX_RIGHT_BRACE) { + BcStatus s = BC_STATUS_SUCCESS; - if (!p->num_braces) return BC_STATUS_PARSE_BAD_TOKEN; + if (p->flags.len <= 1 || (brace && p->nbraces == 0)) + return BC_STATUS_PARSE_BAD_TOKEN; - --p->num_braces; + if (brace) { - if ((status = bc_lex_next(&p->lex))) return status; + if (p->l.t.t == BC_LEX_RBRACE) { + if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN; + --p->nbraces; + s = bc_lex_next(&p->l); + if (s) return s; } else return BC_STATUS_PARSE_BAD_TOKEN; } if (BC_PARSE_IF(p)) { - while (p->lex.token.type == BC_LEX_NEWLINE) { - if ((status = bc_lex_next(&p->lex))) return status; + uint8_t *flag_ptr; + + while (p->l.t.t == BC_LEX_NLINE) { + s = bc_lex_next(&p->l); + if (s) return s; } bc_vec_pop(&p->flags); @@ -3402,438 +3474,424 @@ BcStatus bc_parse_endBody(BcParse *p, BcVec *code, int brace) { flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END); - if (p->lex.token.type == BC_LEX_KEY_ELSE) status = bc_parse_else(p, code); + if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p); } else if (BC_PARSE_ELSE(p)) { BcInstPtr *ip; - BcFunc *func; size_t *label; bc_vec_pop(&p->flags); ip = bc_vec_top(&p->exits); - func = bc_vec_item(&p->prog->funcs, p->func); - label = bc_vec_item(&func->labels, ip->idx); - *label = code->len; + label = bc_vec_item(&p->func->labels, ip->idx); + *label = p->func->code.len; bc_vec_pop(&p->exits); } else if (BC_PARSE_FUNC_INNER(p)) { - p->func = 0; - if ((status = bc_vec_pushByte(code, BC_INST_RETURN_ZERO))) return status; + bc_parse_push(p, BC_INST_RET0); + bc_parse_updateFunc(p, BC_PROG_MAIN); bc_vec_pop(&p->flags); } else { - BcInstPtr *ip; - BcFunc *func; - size_t *label; - - if ((status = bc_vec_pushByte(code, BC_INST_JUMP))) return status; - - ip = bc_vec_top(&p->exits); - label = bc_vec_top(&p->conds); + BcInstPtr *ip = bc_vec_top(&p->exits); + size_t *label = bc_vec_top(&p->conds); - if ((status = bc_parse_pushIndex(code, *label))) return status; + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, *label); - func = bc_vec_item(&p->prog->funcs, p->func); - label = bc_vec_item(&func->labels, ip->idx); - *label = code->len; + label = bc_vec_item(&p->func->labels, ip->idx); + *label = p->func->code.len; bc_vec_pop(&p->flags); bc_vec_pop(&p->exits); bc_vec_pop(&p->conds); } - return status; + return s; } -BcStatus bc_parse_startBody(BcParse *p, uint8_t flags) { +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)); flags |= BC_PARSE_FLAG_BODY; - return bc_vec_push(&p->flags, &flags); + bc_vec_push(&p->flags, &flags); } -void bc_parse_noElse(BcParse *p, BcVec *code) { +void bc_parse_noElse(BcParse *p) { - uint8_t *flag_ptr; BcInstPtr *ip; - BcFunc *func; size_t *label; + uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); - flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END)); ip = bc_vec_top(&p->exits); - func = bc_vec_item(&p->prog->funcs, p->func); - label = bc_vec_item(&func->labels, ip->idx); - *label = code->len; + label = bc_vec_item(&p->func->labels, ip->idx); + *label = p->func->code.len; bc_vec_pop(&p->exits); } -BcStatus bc_parse_if(BcParse *p, BcVec *code) { +BcStatus bc_parse_if(BcParse *p) { - BcStatus status; + BcStatus s; BcInstPtr ip; - BcFunc *func; - - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; - status = bc_parse_expr(p, code, BC_PARSE_EXPR_POSIX_REL); - if (status) return status; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + 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 ((status = bc_lex_next(&p->lex))) return status; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP_ZERO))) return status; + s = bc_lex_next(&p->l); + if (s) return s; + s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); + if (s) return s; + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; - func = bc_vec_item(&p->prog->funcs, p->func); + s = bc_lex_next(&p->l); + if (s) return s; + bc_parse_push(p, BC_INST_JUMP_ZERO); - ip.idx = func->labels.len; - ip.func = 0; - ip.len = 0; + ip.idx = p->func->labels.len; + ip.func = ip.len = 0; - if ((status = bc_parse_pushIndex(code, ip.idx))) return status; - if ((status = bc_vec_push(&p->exits, &ip))) return status; - if ((status = bc_vec_push(&func->labels, &ip.idx))) return status; + bc_parse_pushIndex(p, ip.idx); + bc_vec_push(&p->exits, &ip); + bc_vec_push(&p->func->labels, &ip.idx); + bc_parse_startBody(p, BC_PARSE_FLAG_IF); - return bc_parse_startBody(p, BC_PARSE_FLAG_IF); + return BC_STATUS_SUCCESS; } -BcStatus bc_parse_else(BcParse *p, BcVec *code) { +BcStatus bc_parse_else(BcParse *p) { - BcStatus status; BcInstPtr ip; - BcFunc *func; if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN; - func = bc_vec_item(&p->prog->funcs, p->func); - - ip.idx = func->labels.len; - ip.func = 0; - ip.len = 0; + ip.idx = p->func->labels.len; + ip.func = ip.len = 0; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP))) return status; - if ((status = bc_parse_pushIndex(code, ip.idx))) return status; + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, ip.idx); - bc_parse_noElse(p, code); + bc_parse_noElse(p); - if ((status = bc_vec_push(&p->exits, &ip))) return status; - if ((status = bc_vec_push(&func->labels, &ip.idx))) return status; - if ((status = bc_lex_next(&p->lex))) return status; + bc_vec_push(&p->exits, &ip); + bc_vec_push(&p->func->labels, &ip.idx); + bc_parse_startBody(p, BC_PARSE_FLAG_ELSE); - return bc_parse_startBody(p, BC_PARSE_FLAG_ELSE); + return bc_lex_next(&p->l); } -BcStatus bc_parse_while(BcParse *p, BcVec *code) { +BcStatus bc_parse_while(BcParse *p) { - BcStatus status; - BcFunc *func; + BcStatus s; BcInstPtr ip; - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; + if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; - func = bc_vec_item(&p->prog->funcs, p->func); - ip.idx = func->labels.len; + ip.idx = p->func->labels.len; - if ((status = bc_vec_push(&func->labels, &code->len))) return status; - if ((status = bc_vec_push(&p->conds, &ip.idx))) return status; + bc_vec_push(&p->func->labels, &p->func->code.len); + bc_vec_push(&p->conds, &ip.idx); - ip.idx = func->labels.len; + ip.idx = p->func->labels.len; ip.func = 1; ip.len = 0; - if ((status = bc_vec_push(&p->exits, &ip))) return status; - if ((status = bc_vec_push(&func->labels, &ip.idx))) return status; + bc_vec_push(&p->exits, &ip); + bc_vec_push(&p->func->labels, &ip.idx); - if ((status = bc_parse_expr(p, code, BC_PARSE_EXPR_POSIX_REL))) return status; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel); + if (s) return s; + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; - if ((status = bc_lex_next(&p->lex))) return status; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP_ZERO))) return status; - if ((status = bc_parse_pushIndex(code, ip.idx))) return status; + bc_parse_push(p, BC_INST_JUMP_ZERO); + bc_parse_pushIndex(p, ip.idx); + bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); - return bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); + return BC_STATUS_SUCCESS; } -BcStatus bc_parse_for(BcParse *p, BcVec *code) { +BcStatus bc_parse_for(BcParse *p) { - BcStatus status; - BcFunc *func; + BcStatus s; BcInstPtr ip; size_t cond_idx, exit_idx, body_idx, update_idx; - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; + if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; - if (p->lex.token.type != BC_LEX_SEMICOLON) - status = bc_parse_expr(p, code, 0); - else - status = bc_posix_error(BC_STATUS_POSIX_NO_FOR_INIT, - p->lex.file, p->lex.line, NULL); + 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 (status) return status; - if (p->lex.token.type != BC_LEX_SEMICOLON) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; + if (s) return s; + if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN; + s = bc_lex_next(&p->l); + if (s) return s; - func = bc_vec_item(&p->prog->funcs, p->func); - - cond_idx = func->labels.len; + cond_idx = p->func->labels.len; update_idx = cond_idx + 1; body_idx = update_idx + 1; exit_idx = body_idx + 1; - if ((status = bc_vec_push(&func->labels, &code->len))) return status; + bc_vec_push(&p->func->labels, &p->func->code.len); - if (p->lex.token.type != BC_LEX_SEMICOLON) - status = bc_parse_expr(p, code, BC_PARSE_EXPR_POSIX_REL); - else status = bc_posix_error(BC_STATUS_POSIX_NO_FOR_COND, - p->lex.file, p->lex.line, NULL); + 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); - if (status) return status; - if (p->lex.token.type != BC_LEX_SEMICOLON) return BC_STATUS_PARSE_BAD_TOKEN; + if (s) return s; + if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP_ZERO))) return status; - if ((status = bc_parse_pushIndex(code, exit_idx))) return status; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP))) return status; - if ((status = bc_parse_pushIndex(code, body_idx))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - ip.idx = func->labels.len; + bc_parse_push(p, BC_INST_JUMP_ZERO); + bc_parse_pushIndex(p, exit_idx); + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, body_idx); - if ((status = bc_vec_push(&p->conds, &update_idx))) return status; - if ((status = bc_vec_push(&func->labels, &code->len))) return status; + ip.idx = p->func->labels.len; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) - status = bc_parse_expr(p, code, 0); - else - status = bc_posix_error(BC_STATUS_POSIX_NO_FOR_UPDATE, - p->lex.file, p->lex.line, NULL); + bc_vec_push(&p->conds, &update_idx); + bc_vec_push(&p->func->labels, &p->func->code.len); - if (status) return status; + 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->lex.token.type != BC_LEX_RIGHT_PAREN) { - status = bc_parse_expr(p, code, BC_PARSE_EXPR_POSIX_REL); - if (status) return status; - } + if (s) return s; - if (p->lex.token.type != BC_LEX_RIGHT_PAREN) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_vec_pushByte(code, BC_INST_JUMP))) return status; - if ((status = bc_parse_pushIndex(code, cond_idx))) return status; - if ((status = bc_vec_push(&func->labels, &code->len))) return status; + if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN; + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, cond_idx); + bc_vec_push(&p->func->labels, &p->func->code.len); ip.idx = exit_idx; ip.func = 1; ip.len = 0; - if ((status = bc_vec_push(&p->exits, &ip))) return status; - if ((status = bc_vec_push(&func->labels, &ip.idx))) return status; - if ((status = bc_lex_next(&p->lex))) return status; + 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); - return bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER); + return BC_STATUS_SUCCESS; } -BcStatus bc_parse_loopExit(BcParse *p, BcVec *code, BcLexToken type) { +BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) { - BcStatus status; - size_t idx, top; + BcStatus s; + size_t i; BcInstPtr *ip; if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN; if (type == BC_LEX_KEY_BREAK) { - if (!p->exits.len) return BC_STATUS_PARSE_BAD_TOKEN; - - top = p->exits.len - 1; - ip = bc_vec_item(&p->exits, top); + if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN; - while (top < p->exits.len && ip && !ip->func) - ip = bc_vec_item(&p->exits, top--); + i = p->exits.len - 1; + ip = bc_vec_item(&p->exits, i); - if (top >= p->exits.len || !ip) return BC_STATUS_PARSE_BAD_TOKEN; + 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; - idx = ip->idx; + i = ip->idx; } - else idx = *((size_t*) bc_vec_top(&p->conds)); + else i = *((size_t*) bc_vec_top(&p->conds)); - if ((status = bc_vec_pushByte(code, BC_INST_JUMP))) return status; - if ((status = bc_parse_pushIndex(code, idx))) return status; - if ((status = bc_lex_next(&p->lex))) return status; + bc_parse_push(p, BC_INST_JUMP); + bc_parse_pushIndex(p, i); - if (p->lex.token.type != BC_LEX_SEMICOLON && - p->lex.token.type != BC_LEX_NEWLINE) - { + 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->lex); + return bc_lex_next(&p->l); } BcStatus bc_parse_func(BcParse *p) { - BcStatus status; - BcFunc *fptr; + BcStatus s; int var, comma = 0; uint8_t flags; char *name; - if ((status = bc_lex_next(&p->lex))) return status; + 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 = p->lex.token.string; + name = xstrdup(p->l.t.v.v); + bc_parse_addFunc(p, name, &p->fidx); - if (p->lex.token.type != BC_LEX_NAME) { - status = BC_STATUS_PARSE_BAD_FUNC; - goto err; - } + s = bc_lex_next(&p->l); + if (s) return s; + if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC; + s = bc_lex_next(&p->l); + if (s) return s; - status = bc_program_addFunc(p->prog, name, &p->func); - if (status) goto err; + while (p->l.t.t != BC_LEX_RPAREN) { - fptr = bc_vec_item(&p->prog->funcs, p->func); + if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC; - if ((status = bc_lex_next(&p->lex))) return status; - if (p->lex.token.type != BC_LEX_LEFT_PAREN) return BC_STATUS_PARSE_BAD_FUNC; - if ((status = bc_lex_next(&p->lex))) return status; + ++p->func->nparams; - while (!status && p->lex.token.type != BC_LEX_RIGHT_PAREN) { + name = xstrdup(p->l.t.v.v); + s = bc_lex_next(&p->l); + if (s) goto err; - if (p->lex.token.type != BC_LEX_NAME) { - status = BC_STATUS_PARSE_BAD_FUNC; - goto err; - } + var = p->l.t.t != BC_LEX_LBRACKET; - ++fptr->nparams; - name = p->lex.token.string; + if (!var) { - if ((status = bc_lex_next(&p->lex))) goto err; + s = bc_lex_next(&p->l); + if (s) goto err; - var = p->lex.token.type != BC_LEX_LEFT_BRACKET; + if (p->l.t.t != BC_LEX_RBRACKET) { + s = BC_STATUS_PARSE_BAD_FUNC; + goto err; + } - if (!var) { - if ((status = bc_lex_next(&p->lex))) goto err; - if (p->lex.token.type != BC_LEX_RIGHT_BRACKET) - return BC_STATUS_PARSE_BAD_FUNC; - if ((status = bc_lex_next(&p->lex))) goto err; + s = bc_lex_next(&p->l); + if (s) goto err; } - comma = p->lex.token.type == BC_LEX_COMMA; - if (comma && (status = bc_lex_next(&p->lex))) goto err; + comma = p->l.t.t == BC_LEX_COMMA; + if (comma) { + s = bc_lex_next(&p->l); + if (s) goto err; + } - if ((status = bc_func_insert(fptr, name, var))) goto err; + s = bc_func_insert(p->func, name, var); + if (s) goto err; } if (comma) return BC_STATUS_PARSE_BAD_FUNC; flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY; + bc_parse_startBody(p, flags); - if ((status = bc_parse_startBody(p, flags))) return status; - if ((status = bc_lex_next(&p->lex))) return status; + s = bc_lex_next(&p->l); + if (s) return s; - if (p->lex.token.type != BC_LEX_LEFT_BRACE) - return bc_posix_error(BC_STATUS_POSIX_HEADER_BRACE, - p->lex.file, p->lex.line, NULL); + if (p->l.t.t != BC_LEX_LBRACE) + s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL); - return status; + return s; err: free(name); - return status; + return s; } BcStatus bc_parse_auto(BcParse *p) { - BcStatus status; + BcStatus s; int comma, var, one; char *name; - BcFunc *func; if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN; - if ((status = bc_lex_next(&p->lex))) return status; - - p->auto_part = comma = one = 0; - func = bc_vec_item(&p->prog->funcs, p->func); - - while (!status && p->lex.token.type == BC_LEX_NAME) { + s = bc_lex_next(&p->l); + if (s) return s; - name = p->lex.token.string; + p->auto_part = comma = 0; + one = p->l.t.t == BC_LEX_NAME; - if ((status = bc_lex_next(&p->lex))) return status; + while (p->l.t.t == BC_LEX_NAME) { - one = 1; - - var = p->lex.token.type != BC_LEX_LEFT_BRACKET; + name = xstrdup(p->l.t.v.v); + s = bc_lex_next(&p->l); + if (s) goto err; + var = p->l.t.t != BC_LEX_LBRACKET; if (!var) { - if ((status = bc_lex_next(&p->lex))) goto err; - if (p->lex.token.type != BC_LEX_RIGHT_BRACKET) - return BC_STATUS_PARSE_BAD_FUNC; + s = bc_lex_next(&p->l); + if (s) goto err; + + if (p->l.t.t != BC_LEX_RBRACKET) { + s = BC_STATUS_PARSE_BAD_FUNC; + goto err; + } - if ((status = bc_lex_next(&p->lex))) goto err; + s = bc_lex_next(&p->l); + if (s) goto err; } - comma = p->lex.token.type == BC_LEX_COMMA; - if (comma && (status = bc_lex_next(&p->lex))) goto err; + comma = p->l.t.t == BC_LEX_COMMA; + if (comma) { + s = bc_lex_next(&p->l); + if (s) goto err; + } - if ((status = bc_func_insert(func, name, var))) goto err; + s = bc_func_insert(p->func, name, var); + if (s) goto err; } - if (status) return status; if (comma) return BC_STATUS_PARSE_BAD_FUNC; if (!one) return BC_STATUS_PARSE_NO_AUTO; - if (p->lex.token.type != BC_LEX_NEWLINE && - p->lex.token.type != BC_LEX_SEMICOLON) - { + if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN; - } - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); err: free(name); - return status; + return s; } -BcStatus bc_parse_body(BcParse *p, BcVec *code, int brace) { +BcStatus bc_parse_body(BcParse *p, int brace) { - BcStatus status; - uint8_t *flag_ptr; + BcStatus s = BC_STATUS_SUCCESS; + uint8_t *flag_ptr = bc_vec_top(&p->flags); - flag_ptr = bc_vec_top(&p->flags); *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 = 1; - status = bc_lex_next(&p->lex); + p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO; + + if (!p->auto_part) { + s = bc_parse_auto(p); + if (s) return s; + } + + if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l); } else { - if ((status = bc_parse_stmt(p, code))) return status; - if (!brace) status = bc_parse_endBody(p, code, 0); + s = bc_parse_stmt(p); + if (!s && !brace) s = bc_parse_endBody(p, 0); } - return status; + return s; } -BcStatus bc_parse_stmt(BcParse *p, BcVec *code) { +BcStatus bc_parse_stmt(BcParse *p) { - BcStatus status; + BcStatus s = BC_STATUS_SUCCESS; - switch (p->lex.token.type) { + switch (p->l.t.t) { - case BC_LEX_NEWLINE: + case BC_LEX_NLINE: { - return bc_lex_next(&p->lex); + return bc_lex_next(&p->l); } case BC_LEX_KEY_ELSE: @@ -3842,14 +3900,15 @@ BcStatus bc_parse_stmt(BcParse *p, BcVec *code) { break; } - case BC_LEX_LEFT_BRACE: + case BC_LEX_LBRACE: { if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN; - ++p->num_braces; - if ((status = bc_lex_next(&p->lex))) return status; + ++p->nbraces; + s = bc_lex_next(&p->l); + if (s) return s; - return bc_parse_body(p, code, 1); + return bc_parse_body(p, 1); } case BC_LEX_KEY_AUTO: @@ -3862,22 +3921,22 @@ BcStatus bc_parse_stmt(BcParse *p, BcVec *code) { p->auto_part = 0; if (BC_PARSE_IF_END(p)) { - bc_parse_noElse(p, code); + bc_parse_noElse(p); return BC_STATUS_SUCCESS; } - else if (BC_PARSE_BODY(p)) return bc_parse_body(p, code, 0); + else if (BC_PARSE_BODY(p)) return bc_parse_body(p, 0); break; } } - switch (p->lex.token.type) { + switch (p->l.t.t) { case BC_LEX_OP_INC: case BC_LEX_OP_DEC: case BC_LEX_OP_MINUS: case BC_LEX_OP_BOOL_NOT: - case BC_LEX_LEFT_PAREN: + case BC_LEX_LPAREN: case BC_LEX_NAME: case BC_LEX_NUMBER: case BC_LEX_KEY_IBASE: @@ -3888,234 +3947,153 @@ BcStatus bc_parse_stmt(BcParse *p, BcVec *code) { case BC_LEX_KEY_SCALE: case BC_LEX_KEY_SQRT: { - status = bc_parse_expr(p, code, BC_PARSE_EXPR_PRINT); + s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr); break; } case BC_LEX_KEY_ELSE: { - status = bc_parse_else(p, code); + s = bc_parse_else(p); break; } - case BC_LEX_SEMICOLON: + case BC_LEX_SCOLON: { - status = BC_STATUS_SUCCESS; - - while (!status && p->lex.token.type == BC_LEX_SEMICOLON) - status = bc_lex_next(&p->lex); - + while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l); break; } - case BC_LEX_RIGHT_BRACE: + case BC_LEX_RBRACE: { - status = bc_parse_endBody(p, code, 1); + s = bc_parse_endBody(p, 1); break; } - case BC_LEX_STRING: + case BC_LEX_STR: { - status = bc_parse_string(p, code); + s = bc_parse_string(p, BC_INST_PRINT_STR); break; } case BC_LEX_KEY_BREAK: case BC_LEX_KEY_CONTINUE: { - status = bc_parse_loopExit(p, code, p->lex.token.type); + s = bc_parse_loopExit(p, p->l.t.t); break; } case BC_LEX_KEY_FOR: { - status = bc_parse_for(p, code); + s = bc_parse_for(p); break; } case BC_LEX_KEY_HALT: { - if ((status = bc_vec_pushByte(code, BC_INST_HALT))) return status; - status = bc_lex_next(&p->lex); + bc_parse_push(p, BC_INST_HALT); + s = bc_lex_next(&p->l); break; } case BC_LEX_KEY_IF: { - status = bc_parse_if(p, code); + s = bc_parse_if(p); break; } case BC_LEX_KEY_LIMITS: { - if ((status = bc_lex_next(&p->lex))) return status; - status = BC_STATUS_LIMITS; + s = bc_lex_next(&p->l); + if (s) return s; + s = BC_STATUS_LIMITS; break; } case BC_LEX_KEY_PRINT: { - status = bc_parse_print(p, code); + s = bc_parse_print(p); break; } case BC_LEX_KEY_QUIT: { - // Quit is a compile-time command, so we send an exit command. We don't - // exit directly, so the vm can clean up. Limits do the same thing. - status = BC_STATUS_QUIT; + // Quit is a compile-time command. We don't exit directly, + // so the vm can clean up. Limits do the same thing. + s = BC_STATUS_QUIT; break; } case BC_LEX_KEY_RETURN: { - if ((status = bc_parse_return(p, code))) return status; + s = bc_parse_return(p); break; } case BC_LEX_KEY_WHILE: { - status = bc_parse_while(p, code); - break; - } - - case BC_LEX_EOF: - { - status = (p->flags.len > 0) * BC_STATUS_LEX_BAD_CHARACTER; + s = bc_parse_while(p); break; } default: { - status = BC_STATUS_PARSE_BAD_TOKEN; + s = BC_STATUS_PARSE_BAD_TOKEN; break; } } - return status; -} - -BcStatus bc_parse_init(BcParse *p, BcProgram *program) { - - BcStatus status; - uint8_t flags = 0; - - if ((status = bc_vec_init(&p->flags, sizeof(uint8_t), NULL))) return status; - if ((status = bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL))) goto exit_err; - if ((status = bc_vec_init(&p->conds, sizeof(size_t), NULL))) goto cond_err; - if ((status = bc_vec_push(&p->flags, &flags))) goto push_err; - if ((status = bc_vec_init(&p->ops, sizeof(BcLexToken), NULL))) goto push_err; - - p->prog = program; - p->func = p->num_braces = 0; - p->auto_part = 0; - - return status; - -push_err: - bc_vec_free(&p->conds); -cond_err: - bc_vec_free(&p->exits); -exit_err: - bc_vec_free(&p->flags); - return status; + return s; } BcStatus bc_parse_parse(BcParse *p) { - BcStatus status; + BcStatus s; - if (p->lex.token.type == BC_LEX_EOF) status = BC_STATUS_LEX_EOF; - else if (p->lex.token.type == BC_LEX_KEY_DEFINE) { + 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; - status = bc_parse_func(p); - } - else { - BcFunc *func = bc_vec_item(&p->prog->funcs, p->func); - status = bc_parse_stmt(p, &func->code); + s = bc_parse_func(p); } + else s = bc_parse_stmt(p); - if (status || TT.signe) { - - if (p->func) { - - BcFunc *func = bc_vec_item(&p->prog->funcs, p->func); - - func->nparams = 0; - bc_vec_npop(&func->code, func->code.len); - bc_vec_npop(&func->autos, func->autos.len); - bc_vec_npop(&func->labels, func->labels.len); - - p->func = 0; - } - - p->lex.idx = p->lex.len; - p->lex.token.type = BC_LEX_EOF; - p->auto_part = 0; - p->num_braces = 0; - - bc_vec_npop(&p->flags, p->flags.len - 1); - bc_vec_npop(&p->exits, p->exits.len); - bc_vec_npop(&p->conds, p->conds.len); - bc_vec_npop(&p->ops, p->ops.len); - - status = bc_program_reset(p->prog, status); - } + if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || TT.signe) + s = bc_parse_reset(p, s); - return status; + return s; } -void bc_parse_free(BcParse *p) { +BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) { - if (!p) return; + BcStatus s = BC_STATUS_SUCCESS; + BcInst prev = BC_INST_PRINT; + BcLexType top, t = p->l.t.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; - bc_vec_free(&p->flags); - bc_vec_free(&p->exits); - bc_vec_free(&p->conds); - bc_vec_free(&p->ops); + paren_first = p->l.t.t == BC_LEX_LPAREN; + nparens = nrelops = 0; + paren_expr = rprn = done = get_token = assign = 0; + bin_last = 1; - if ((p->lex.token.type == BC_LEX_STRING || p->lex.token.type == BC_LEX_NAME || - p->lex.token.type == BC_LEX_NUMBER) && p->lex.token.string) + for (; !TT.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) { - free(p->lex.token.string); - } -} - -BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags) { - - BcStatus status; - uint32_t nexprs, nparens, ops_start, nrelops; - int paren_first, paren_expr, rparen, done, get_token, assign; - BcInst prev; - BcLexToken type, top; - - status = BC_STATUS_SUCCESS; - prev = BC_INST_PRINT; - - ops_start = p->ops.len; - paren_first = p->lex.token.type == BC_LEX_LEFT_PAREN; - nexprs = nparens = nrelops = 0; - paren_expr = rparen = done = get_token = assign = 0; - - type = p->lex.token.type; - - while (!TT.signe && !status && !done && bc_parse_token_exprs[type]) { - - switch (type) { + switch (t) { case BC_LEX_OP_INC: case BC_LEX_OP_DEC: { - status = bc_parse_incdec(p, code, &prev, &nexprs, flags); - rparen = get_token = 0; + s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags); + rprn = get_token = bin_last = 0; break; } case BC_LEX_OP_MINUS: { - status = bc_parse_minus(p, code, &p->ops, &prev, - rparen, &nexprs); - rparen = get_token = 0; + s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs); + rprn = get_token = 0; + bin_last = prev == BC_INST_MINUS; break; } @@ -4126,93 +4104,99 @@ BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags) { case BC_LEX_OP_ASSIGN_PLUS: case BC_LEX_OP_ASSIGN_MINUS: case BC_LEX_OP_ASSIGN: - if (prev != BC_INST_PUSH_VAR && prev != BC_INST_PUSH_ARRAY_ELEM && - prev != BC_INST_PUSH_SCALE && prev != BC_INST_PUSH_IBASE && - prev != BC_INST_PUSH_OBASE && prev != BC_INST_PUSH_LAST) + { + 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) { - status = BC_STATUS_PARSE_BAD_ASSIGN; + s = BC_STATUS_PARSE_BAD_ASSIGN; break; } - // Fallthrough. + } + // Fallthrough. case BC_LEX_OP_POWER: case BC_LEX_OP_MULTIPLY: case BC_LEX_OP_DIVIDE: case BC_LEX_OP_MODULUS: case BC_LEX_OP_PLUS: - case BC_LEX_OP_REL_EQUAL: - case BC_LEX_OP_REL_LESS_EQ: - case BC_LEX_OP_REL_GREATER_EQ: - case BC_LEX_OP_REL_NOT_EQ: - case BC_LEX_OP_REL_LESS: - case BC_LEX_OP_REL_GREATER: + case BC_LEX_OP_REL_EQ: + case BC_LEX_OP_REL_LE: + case BC_LEX_OP_REL_GE: + case BC_LEX_OP_REL_NE: + case BC_LEX_OP_REL_LT: + case BC_LEX_OP_REL_GT: case BC_LEX_OP_BOOL_NOT: case BC_LEX_OP_BOOL_OR: case BC_LEX_OP_BOOL_AND: { - if (type >= BC_LEX_OP_REL_EQUAL && type <= BC_LEX_OP_REL_GREATER) - nrelops += 1; + 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; + } - prev = BC_PARSE_TOKEN_TO_INST(type); - status = bc_parse_operator(p, code, &p->ops, type, &nexprs, 1); - rparen = get_token = 0; + 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; break; } - case BC_LEX_LEFT_PAREN: + case BC_LEX_LPAREN: { + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + ++nparens; - paren_expr = rparen = 0; + paren_expr = rprn = bin_last = 0; get_token = 1; - status = bc_vec_push(&p->ops, &type); + bc_vec_push(&p->ops, &t); + break; } - case BC_LEX_RIGHT_PAREN: + case BC_LEX_RPAREN: { + if (bin_last || prev == BC_INST_BOOL_NOT) + return BC_STATUS_PARSE_BAD_EXP; + if (nparens == 0) { - status = BC_STATUS_SUCCESS; + s = BC_STATUS_SUCCESS; done = 1; get_token = 0; break; } - else if (!paren_expr) { - status = BC_STATUS_PARSE_BAD_EXPR; - goto err; - } + else if (!paren_expr) return BC_STATUS_PARSE_EMPTY_EXP; --nparens; - paren_expr = rparen = 1; - get_token = 0; + paren_expr = rprn = 1; + get_token = bin_last = 0; - status = bc_parse_rightParen(p, code, &p->ops, &nexprs); + s = bc_parse_rightParen(p, ops_bgn, &nexprs); break; } case BC_LEX_NAME: { + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + paren_expr = 1; - rparen = get_token = 0; - status = bc_parse_name(p, code, &prev, flags & ~(BC_PARSE_EXPR_NOCALL)); + rprn = get_token = bin_last = 0; + s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL); ++nexprs; + break; } case BC_LEX_NUMBER: { - size_t idx = p->prog->constants.len; - - status = bc_vec_push(&p->prog->constants, &p->lex.token.string); - if (status) goto err; - - if ((status = bc_vec_pushByte(code, BC_INST_PUSH_NUM))) return status; - if ((status = bc_parse_pushIndex(code, idx))) return status; + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + bc_parse_number(p, &prev, &nexprs); paren_expr = get_token = 1; - rparen = 0; - ++nexprs; - prev = BC_INST_PUSH_NUM; + rprn = bin_last = 0; break; } @@ -4221,13 +4205,14 @@ BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags) { case BC_LEX_KEY_LAST: case BC_LEX_KEY_OBASE: { - uint8_t inst = type - BC_LEX_KEY_IBASE + BC_INST_PUSH_IBASE; - status = bc_vec_pushByte(code, inst); + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + + prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE); + bc_parse_push(p, (char) prev); paren_expr = get_token = 1; - rparen = 0; + rprn = bin_last = 0; ++nexprs; - prev = BC_INST_PUSH_OBASE; break; } @@ -4235,21 +4220,24 @@ BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags) { case BC_LEX_KEY_LENGTH: case BC_LEX_KEY_SQRT: { - status = bc_parse_builtin(p, code, type, flags); + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + + s = bc_parse_builtin(p, t, flags, &prev); paren_expr = 1; - rparen = get_token = 0; + rprn = get_token = bin_last = 0; ++nexprs; - prev = type == BC_LEX_KEY_LENGTH ? BC_INST_LENGTH : BC_INST_SQRT; + break; } case BC_LEX_KEY_READ: { - if (flags & BC_PARSE_EXPR_NOREAD) status = BC_STATUS_EXEC_NESTED_READ; - else status = bc_parse_read(p, code); + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + else if (flags & BC_PARSE_NOREAD) s = BC_STATUS_EXEC_REC_READ; + else s = bc_parse_read(p); paren_expr = 1; - rparen = get_token = 0; + rprn = get_token = bin_last = 0; ++nexprs; prev = BC_INST_READ; @@ -4258,244 +4246,155 @@ BcStatus bc_parse_expr(BcParse *p, BcVec *code, uint8_t flags) { case BC_LEX_KEY_SCALE: { - status = bc_parse_scale(p, code, &prev, flags); + if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP; + + s = bc_parse_scale(p, &prev, flags); paren_expr = 1; - rparen = get_token = 0; + rprn = get_token = bin_last = 0; ++nexprs; - prev = BC_INST_PUSH_SCALE; + prev = BC_INST_SCALE; + break; } default: { - status = BC_STATUS_PARSE_BAD_TOKEN; + s = BC_STATUS_PARSE_BAD_TOKEN; break; } } - if (status) goto err; - if (get_token) status = bc_lex_next(&p->lex); - - type = p->lex.token.type; - } - - if (status) goto err; - if (TT.signe) { - status = BC_STATUS_EXEC_SIGNAL; - goto err; + if (!s && get_token) s = bc_lex_next(&p->l); } - status = BC_STATUS_SUCCESS; + if (s) return s; + if (TT.signe) return BC_STATUS_EXEC_SIGNAL; - while (!status && p->ops.len > ops_start) { + while (p->ops.len > ops_bgn) { - top = *((BcLexToken*) bc_vec_top(&p->ops)); + top = BC_PARSE_TOP_OP(p); assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN; - if (top == BC_LEX_LEFT_PAREN || top == BC_LEX_RIGHT_PAREN) { - status = BC_STATUS_PARSE_BAD_EXPR; - goto err; - } + if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN) + return BC_STATUS_PARSE_BAD_EXP; - if ((status = bc_vec_pushByte(code, BC_PARSE_TOKEN_TO_INST(top)))) goto err; + bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); - nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_OP_NEG; + nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG; bc_vec_pop(&p->ops); } - if (nexprs != 1) { - status = BC_STATUS_PARSE_BAD_EXPR; - goto err; - } + s = BC_STATUS_PARSE_BAD_EXP; + if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s; - if (!(flags & BC_PARSE_EXPR_POSIX_REL) && nrelops && - (status = bc_posix_error(BC_STATUS_POSIX_REL_OUTSIDE, - p->lex.file, p->lex.line, NULL))) - { - goto err; - } - else if ((flags & BC_PARSE_EXPR_POSIX_REL) && nrelops != 1 && - (status = bc_posix_error(BC_STATUS_POSIX_MULTIPLE_REL, - p->lex.file, p->lex.line, NULL))) - { - goto err; - } + for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i]; + if (s) return s; - if (flags & BC_PARSE_EXPR_PRINT) { - if (paren_first || !assign) status = bc_vec_pushByte(code, BC_INST_PRINT); - else status = bc_vec_pushByte(code, BC_INST_POP); + if (!(flags & BC_PARSE_REL) && nrelops) { + s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL); + 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); + if (s) return s; } - return status; - -err: - - if (p->lex.token.string) { - free(p->lex.token.string); - p->lex.token.string = NULL; + if (flags & BC_PARSE_PRINT) { + if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT); + bc_parse_push(p, BC_INST_POP); } - return status; + return s; } -BcStatus bc_program_search(BcProgram *p, BcResult *result, - BcNum **ret, uint8_t flags) -{ - BcStatus status; - BcEntry entry, *entry_ptr; - BcVec *vec; - BcVecO *veco; - size_t idx, ip_idx; - BcAuto *a; - int var; - - for (ip_idx = 0; ip_idx < p->stack.len - 1; ++ip_idx) { +void bc_program_search(BcProgram *p, char *id, BcVec **ret, int var) { - BcFunc *func; - BcInstPtr *ip; + BcStatus s; + BcId e, *ptr; + BcVec *v, *map; + size_t i; + BcResultData data; + int new; - ip = bc_vec_item_rev(&p->stack, ip_idx); - if (ip->func == BC_PROGRAM_READ || ip->func == BC_PROGRAM_MAIN) continue; + v = var ? &p->vars : &p->arrs; + map = var ? &p->var_map : &p->arr_map; - func = bc_vec_item(&p->funcs, ip->func); + e.name = id; + e.idx = v->len; + s = bc_map_insert(map, &e, &i); + new = s != BC_STATUS_VEC_ITEM_EXISTS; - for (idx = 0; idx < func->autos.len; ++idx) { + if (new) { + bc_array_init(&data.v, var); + bc_vec_push(v, &data.v); + } - a = bc_vec_item(&func->autos, idx); + ptr = bc_vec_item(map, i); + if (new) ptr->name = xstrdup(e.name); + *ret = bc_vec_item(v, ptr->idx); +} - if (!strcmp(a->name, result->data.id.name)) { +BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, int hex) { - BcResult *r; - uint8_t cond; + BcStatus s = BC_STATUS_SUCCESS; - cond = flags & BC_PROGRAM_SEARCH_VAR; - - if (!a->var != !cond) return BC_STATUS_EXEC_BAD_TYPE; - - r = bc_vec_item(&p->results, ip->len + idx); - - if (cond || flags & BC_PROGRAM_SEARCH_ARRAY) *ret = &r->data.num; - else { - status = bc_array_expand(&r->data.array, result->data.id.idx + 1); - if (status) return status; - *ret = bc_vec_item(&r->data.array, result->data.id.idx); - } - - return BC_STATUS_SUCCESS; - } - } - } - - var = flags & BC_PROGRAM_SEARCH_VAR; - vec = var ? &p->vars : &p->arrays; - veco = var ? &p->var_map : &p->array_map; - - entry.name = result->data.id.name; - entry.idx = vec->len; - - status = bc_veco_insert(veco, &entry, &idx); - - if (status != BC_STATUS_VEC_ITEM_EXISTS) { - - // We use this because it has a union of BcNum and BcVec. - BcResult data; - size_t len; - - if (status) return status; - - len = strlen(entry.name) + 1; - - if (!(result->data.id.name = malloc(len))) return BC_STATUS_MALLOC_FAIL; - - strcpy(result->data.id.name, entry.name); - - if (flags & BC_PROGRAM_SEARCH_VAR) - status = bc_num_init(&data.data.num, BC_NUM_DEF_SIZE); - else status = bc_vec_init(&data.data.array, sizeof(BcNum), bc_num_free); - - if (status) return status; - if ((status = bc_vec_push(vec, &data.data))) return status; - } - - entry_ptr = bc_veco_item(veco, idx); - - if (var) *ret = bc_vec_item(vec, entry_ptr->idx); - else { - - BcVec *ptr = bc_vec_item(vec, entry_ptr->idx); - - if (flags & BC_PROGRAM_SEARCH_ARRAY) { - *ret = (BcNum*) ptr; - return BC_STATUS_SUCCESS; - } - - if ((status = bc_array_expand(ptr, result->data.id.idx + 1))) return status; - - *ret = bc_vec_item(ptr, result->data.id.idx); - } - - return BC_STATUS_SUCCESS; -} - -BcStatus bc_program_num(BcProgram *p, BcResult *result, BcNum** num, int hex) { - - BcStatus status = BC_STATUS_SUCCESS; - - switch (result->type) { + switch (r->t) { + case BC_RESULT_STR: case BC_RESULT_TEMP: + case BC_RESULT_IBASE: case BC_RESULT_SCALE: + case BC_RESULT_OBASE: { - *num = &result->data.num; + *num = &r->d.n; break; } case BC_RESULT_CONSTANT: { - char** s; - size_t len, base; - - s = bc_vec_item(&p->constants, result->data.id.idx); - len = strlen(*s); + char **str = bc_vec_item(&p->consts, r->d.id.idx); + size_t base_t, len = strlen(*str); + BcNum *base; - if ((status = bc_num_init(&result->data.num, len))) return status; + bc_num_init(&r->d.n, len); - base = hex && len == 1 ? BC_NUM_MAX_INPUT_BASE : p->ibase_t; + 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); - if ((status = bc_num_parse(&result->data.num, *s, &p->ibase, base))) { - bc_num_free(&result->data.num); - return status; + if (s) { + bc_num_free(&r->d.n); + return s; } - *num = &result->data.num; - result->type = BC_RESULT_TEMP; + *num = &r->d.n; + r->t = BC_RESULT_TEMP; break; } case BC_RESULT_VAR: case BC_RESULT_ARRAY: + case BC_RESULT_ARRAY_ELEM: { - uint8_t flags = result->type == BC_RESULT_VAR ? BC_PROGRAM_SEARCH_VAR : 0; - status = bc_program_search(p, result, num, flags); - break; - } + BcVec *v; - case BC_RESULT_LAST: - { - *num = &p->last; - break; - } + bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR); + + if (r->t == BC_RESULT_ARRAY_ELEM) { + 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); + } + else *num = bc_vec_top(v); - case BC_RESULT_IBASE: - { - *num = &p->ibase; break; } - case BC_RESULT_OBASE: + case BC_RESULT_LAST: { - *num = &p->obase; + *num = &p->last; break; } @@ -4504,338 +4403,333 @@ BcStatus bc_program_num(BcProgram *p, BcResult *result, BcNum** num, int hex) { *num = &p->one; break; } - - default: - { - // This is here to prevent compiler warnings in release mode. - *num = &result->data.num; - break; - } } - return status; + return s; } -BcStatus bc_program_binaryOpPrep(BcProgram *p, BcResult **left, BcNum **lval, - BcResult **right, BcNum **rval) +BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln, + BcResult **r, BcNum **rn, int assign) { - BcStatus status; - BcResult *l, *r; + BcStatus s; int hex; + BcResultType lt, rt; - r = bc_vec_item_rev(&p->results, 0); - l = bc_vec_item_rev(&p->results, 1); + if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK; - *left = l; - *right = r; + *r = bc_vec_item_rev(&p->results, 0); + *l = bc_vec_item_rev(&p->results, 1); - hex = l->type == BC_RESULT_IBASE || l->type == BC_RESULT_OBASE; + lt = (*l)->t; + rt = (*r)->t; + hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE); - if ((status = bc_program_num(p, l, lval, 0))) return status; - if ((status = bc_program_num(p, r, rval, hex))) return status; + s = bc_program_num(p, *l, ln, 0); + if (s) return s; + s = bc_program_num(p, *r, rn, hex); + if (s) return s; - return BC_STATUS_SUCCESS; + // 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 (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR)) + return BC_STATUS_EXEC_BAD_TYPE; + if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE; + + return s; } -BcStatus bc_program_binaryOpRetire(BcProgram *p, BcResult *result, - BcResultType type) -{ - result->type = type; +void bc_program_binOpRetire(BcProgram *p, BcResult *r) { + r->t = BC_RESULT_TEMP; bc_vec_pop(&p->results); bc_vec_pop(&p->results); - return bc_vec_push(&p->results, result); + bc_vec_push(&p->results, r); } -BcStatus bc_program_unaryOpPrep(BcProgram *p, BcResult **result, BcNum **val) { +BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) { - BcStatus status; - BcResult *r; + BcStatus s; - r = bc_vec_item_rev(&p->results, 0); + if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; + *r = bc_vec_top(&p->results); - if ((status = bc_program_num(p, r, val, 0))) return status; + s = bc_program_num(p, *r, n, 0); + if (s) return s; - *result = r; + if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE; - return BC_STATUS_SUCCESS; + return s; } -BcStatus bc_program_unaryOpRetire(BcProgram *p, BcResult *result, - BcResultType type) -{ - result->type = type; +void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) { + r->t = t; bc_vec_pop(&p->results); - return bc_vec_push(&p->results, result); + bc_vec_push(&p->results, r); } -BcStatus bc_program_op(BcProgram *p, uint8_t inst) { - - BcStatus status; - BcResult *operand1, *operand2, res; - BcNum *num1, *num2; - BcNumBinaryFunc op; +BcStatus bc_program_op(BcProgram *p, char inst) { - status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2); - if (status) return status; + BcStatus s; + BcResult *opd1, *opd2, res; + BcNum *n1, *n2 = NULL; - if ((status = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return status; + s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 0); + if (s) return s; + bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); - op = bc_program_math_ops[inst - BC_INST_POWER]; - if ((status = op(num1, num2, &res.data.num, p->scale))) goto err; - if ((status = bc_program_binaryOpRetire(p, &res, BC_RESULT_TEMP))) goto err; + s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale); + if (s) goto err; + bc_program_binOpRetire(p, &res); - return status; + return s; err: - bc_num_free(&res.data.num); - return status; + bc_num_free(&res.d.n); + return s; } BcStatus bc_program_read(BcProgram *p) { - BcStatus status; + BcStatus s; BcParse parse; - char *buffer; - size_t size; - BcFunc *func; + BcVec buf; BcInstPtr ip; + size_t i; + BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ); - func = bc_vec_item(&p->funcs, BC_PROGRAM_READ); - func->code.len = 0; - - if (!(buffer = malloc(BC_PROGRAM_BUF_SIZE + 1))) return BC_STATUS_MALLOC_FAIL; + 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; + } - size = BC_PROGRAM_BUF_SIZE; + bc_vec_npop(&f->code, f->code.len); + bc_vec_init(&buf, sizeof(char), NULL); - if ((status = bc_io_getline(&buffer, &size)))goto io_err; + s = bc_read_line(&buf, "read> "); + if (s) goto io_err; - if ((status = bc_parse_init(&parse, p))) goto io_err; - bc_lex_init(&parse.lex, ""); - if ((status = bc_lex_text(&parse.lex, buffer))) goto exec_err; + bc_parse_init(&parse, p, BC_PROG_READ); + bc_lex_file(&parse.l, bc_program_stdin_name); - if ((status = bc_parse_expr(&parse, &func->code, BC_PARSE_EXPR_NOREAD))) return status; + s = bc_parse_text(&parse, buf.v); + if (s) goto exec_err; + s = bc_parse_expr(&parse, BC_PARSE_NOREAD, bc_parse_next_read); + if (s) goto exec_err; - if (parse.lex.token.type != BC_LEX_NEWLINE && - parse.lex.token.type != BC_LEX_EOF) - { - status = BC_STATUS_EXEC_BAD_READ_EXPR; + if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) { + s = BC_STATUS_EXEC_BAD_READ_EXPR; goto exec_err; } - ip.func = BC_PROGRAM_READ; + ip.func = BC_PROG_READ; ip.idx = 0; ip.len = p->results.len; - if ((status = bc_vec_push(&p->stack, &ip))) goto exec_err; - if ((status = bc_program_exec(p))) goto exec_err; + // Update this pointer, just in case. + f = bc_vec_item(&p->fns, BC_PROG_READ); - bc_vec_pop(&p->stack); + bc_vec_pushByte(&f->code, BC_INST_POP_EXEC); + bc_vec_push(&p->stack, &ip); exec_err: bc_parse_free(&parse); io_err: - free(buffer); - return status; + bc_vec_free(&buf); + return s; } -size_t bc_program_index(uint8_t *code, size_t *start) { +size_t bc_program_index(char *code, size_t *bgn) { - uint8_t bytes, i; - size_t result; + char amt = code[(*bgn)++], i = 0; + size_t res = 0; - for (bytes = code[(*start)++], result = 0, i = 0; i < bytes; ++i) - result |= (((size_t) code[(*start)++]) << (i * CHAR_BIT)); + for (; i < amt; ++i, ++(*bgn)) + res |= (((size_t) ((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT)); - return result; + return res; } -char* bc_program_name(uint8_t *code, size_t *start) { - - char byte, *s, *string, *ptr; - size_t len, i; - - string = (char*) (code + *start); - ptr = strchr((char*) string, ':'); +char* bc_program_name(char *code, size_t *bgn) { - if (ptr) len = ((unsigned long) ptr) - ((unsigned long) string); - else len = strlen(string); + size_t i; + char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND); - if (!(s = malloc(len + 1))) return NULL; + s = xmalloc(ptr - str + 1); + c = code[(*bgn)++]; - for (byte = code[(*start)++], i = 0; byte && byte != ':'; ++i) { - s[i] = byte; - byte = code[(*start)++]; - } + for (i = 0; c && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i) + s[i] = c; s[i] = '\0'; return s; } -BcStatus bc_program_printString(const char *str, size_t *nchars) { +void bc_program_printString(const char *str, size_t *nchars) { - char c, c2; - size_t len, i; - int err; + size_t i, len = strlen(str); - len = strlen(str); + for (i = 0; i < len; ++i, ++(*nchars)) { - for (i = 0; i < len; ++i, ++(*nchars)) { + int c = str[i]; - if ((c = str[i]) != '\\') err = putchar(c); + if (c != '\\' || i == len - 1) bc_vm_putchar(c); else { - ++i; - c2 = str[i]; + c = str[++i]; - switch (c2) { + switch (c) { case 'a': { - err = putchar('\a'); + bc_vm_putchar('\a'); break; } case 'b': { - err = putchar('\b'); + bc_vm_putchar('\b'); break; } + case '\\': case 'e': { - err = putchar('\\'); + bc_vm_putchar('\\'); break; } case 'f': { - err = putchar('\f'); + bc_vm_putchar('\f'); break; } case 'n': { - err = putchar('\n'); + bc_vm_putchar('\n'); *nchars = SIZE_MAX; break; } case 'r': { - err = putchar('\r'); + bc_vm_putchar('\r'); break; } case 'q': { - err = putchar('"'); + bc_vm_putchar('"'); break; } case 't': { - err = putchar('\t'); + bc_vm_putchar('\t'); break; } default: { - // Do nothing. - err = 0; + // Just print the backslash and following character. + bc_vm_putchar('\\'); + ++(*nchars); + bc_vm_putchar(c); break; } } } - - if (err == EOF) return BC_STATUS_IO_ERR; } - - return BC_STATUS_SUCCESS; } -BcStatus bc_program_push(BcProgram *p, uint8_t *code, size_t *start, int var) { +BcStatus bc_program_print(BcProgram *p, char inst, size_t idx) { - BcStatus status; - BcResult result; + BcStatus s = BC_STATUS_SUCCESS; + BcResult *r; + size_t len, i; + char *str; + BcNum *num = NULL; + int pop = inst != BC_INST_PRINT; - result.data.id.name = bc_program_name(code, start); + if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK; - if (var) { - result.type = BC_RESULT_VAR; - status = bc_vec_push(&p->results, &result); + r = bc_vec_item_rev(&p->results, idx); + s = bc_program_num(p, r, &num, 0); + 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); } else { - BcResult *operand; - BcNum *num; - unsigned long temp; - - if ((status = bc_program_unaryOpPrep(p, &operand, &num))) goto err; - if ((status = bc_num_ulong(num, &temp))) goto err; + idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx; + str = *((char**) bc_vec_item(&p->strs, idx)); - if (temp > (unsigned long) maxof_DIM) { - status = BC_STATUS_EXEC_ARRAY_LEN; - goto err; + 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; + } + } + else { + bc_program_printString(str, &p->nchars); + if (inst == BC_INST_PRINT) bc_vm_putchar('\n'); } - - result.data.id.idx = (size_t) temp; - - status = bc_program_unaryOpRetire(p, &result, BC_RESULT_ARRAY); } - if (status) goto err; - - return status; + if (!s && pop) bc_vec_pop(&p->results); -err: - free(result.data.id.name); - return status; + return s; } BcStatus bc_program_negate(BcProgram *p) { - BcStatus status; - BcResult result, *ptr; - BcNum *num; - - if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status; - if ((status = bc_num_init(&result.data.num, num->len))) return status; - if ((status = bc_num_copy(&result.data.num, num))) goto err; + BcStatus s; + BcResult res, *ptr; + BcNum *num = NULL; - result.data.num.neg = !result.data.num.neg; + s = bc_program_prep(p, &ptr, &num); + if (s) return s; - if ((status = bc_program_unaryOpRetire(p, &result, BC_RESULT_TEMP))) goto err; + 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; - return status; + bc_program_retire(p, &res, BC_RESULT_TEMP); -err: - bc_num_free(&result.data.num); - return status; + return s; } -BcStatus bc_program_logical(BcProgram *p, uint8_t inst) { +BcStatus bc_program_logical(BcProgram *p, char inst) { - BcStatus status; - BcResult *operand1, *operand2, res; - BcNum *num1, *num2; - int cond; - int cmp; - - status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2); - if (status) return status; + BcStatus s; + BcResult *opd1, *opd2, res; + BcNum *n1, *n2; + int cond = 0; + ssize_t cmp; - if ((status = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return status; + s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 0); + if (s) return s; + bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); if (inst == BC_INST_BOOL_AND) - cond = bc_num_cmp(num1, &p->zero) && bc_num_cmp(num2, &p->zero); + cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero); else if (inst == BC_INST_BOOL_OR) - cond = bc_num_cmp(num1, &p->zero) || bc_num_cmp(num2, &p->zero); + cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero); else { - cmp = bc_num_cmp(num1, num2); + cmp = bc_num_cmp(n1, n2); switch (inst) { + case BC_INST_REL_EQ: { cond = cmp == 0; @@ -4856,7 +4750,7 @@ BcStatus bc_program_logical(BcProgram *p, uint8_t inst) { case BC_INST_REL_NE: { - cond = cmp != 0; + cond = cmp; break; } @@ -4871,442 +4765,447 @@ BcStatus bc_program_logical(BcProgram *p, uint8_t inst) { cond = cmp > 0; break; } - - default: - { - // This is here to silence a compiler warning in release mode. - cond = 0; - break; - } } } - (cond ? bc_num_one : bc_num_zero)(&res.data.num); + (cond ? bc_num_one : bc_num_zero)(&res.d.n); - if ((status = bc_program_binaryOpRetire(p, &res, BC_RESULT_TEMP))) goto err; + bc_program_binOpRetire(p, &res); - return status; + return s; +} -err: - bc_num_free(&res.data.num); - return status; +BcStatus bc_program_copyToVar(BcProgram *p, char *name, int var) { + + BcStatus s; + BcResult *ptr, r; + BcVec *v; + BcNum *n; + + if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; + + 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); + + s = bc_program_num(p, ptr, &n, 0); + if (s) return s; + + // Do this once more to make sure that pointers were not invalidated. + bc_program_search(p, name, &v, var); + + if (var) { + bc_num_init(&r.d.n, BC_NUM_DEF_SIZE); + bc_num_copy(&r.d.n, n); + } + else { + bc_array_init(&r.d.v, 1); + bc_array_copy(&r.d.v, (BcVec*) n); + } + + bc_vec_push(v, &r.d); + bc_vec_pop(&p->results); + + return s; } -BcStatus bc_program_assign(BcProgram *p, uint8_t inst) { +BcStatus bc_program_assign(BcProgram *p, char inst) { - BcStatus status; + BcStatus s; BcResult *left, *right, res; - BcNum *l, *r; - BcNumBinaryFunc op; + BcNum *l = NULL, *r = NULL; unsigned long val, max; - size_t *ptr; + int assign = inst == BC_INST_ASSIGN, ib, sc; - status = bc_program_binaryOpPrep(p, &left, &l, &right, &r); - if (status) return status; + s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign); + if (s) return s; - if (left->type == BC_RESULT_CONSTANT || left->type == BC_RESULT_TEMP) + 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 (inst == BC_INST_ASSIGN) status = bc_num_copy(l, r); - else { - op = bc_program_math_ops[inst - BC_INST_ASSIGN_POWER]; - status = op(l, r, l, p->scale); - } + if (assign) bc_num_copy(l, r); + else s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale); - if (status) return status; + if (s) return s; - if (left->type == BC_RESULT_IBASE || left->type == BC_RESULT_OBASE) { + if (ib || sc || left->t == BC_RESULT_OBASE) { - ptr = left->type == BC_RESULT_IBASE ? &p->ibase_t : &p->obase_t; - max = left->type == BC_RESULT_IBASE ? BC_NUM_MAX_INPUT_BASE : maxof_BASE; + size_t *ptr; - if ((status = bc_num_ulong(l, &val))) return status; + s = bc_num_ulong(l, &val); + if (s) return s; + s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE; - if (val < BC_NUM_MIN_BASE || val > max) - return left->type - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE; + if (sc) { + max = BC_MAX_SCALE; + ptr = &p->scale; + } + else { + if (val < BC_NUM_MIN_BASE) return s; + max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE; + ptr = ib ? &p->ib_t : &p->ob_t; + } + + if (val > max) return s; + if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l); *ptr = (size_t) val; + s = BC_STATUS_SUCCESS; } - else if (left->type == BC_RESULT_SCALE) { - if ((status = bc_num_ulong(l, &val))) return status; - if (val > (unsigned long) maxof_SCALE) return BC_STATUS_EXEC_BAD_SCALE; + bc_num_init(&res.d.n, l->len); + bc_num_copy(&res.d.n, l); + bc_program_binOpRetire(p, &res); - p->scale = (size_t) val; - } + return s; +} - if ((status = bc_num_init(&res.data.num, l->len))) return status; - if ((status = bc_num_copy(&res.data.num, l))) goto err; +BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn, + int pop, int copy) +{ + BcStatus s = BC_STATUS_SUCCESS; + BcResult r; + char *name = bc_program_name(code, bgn); - if ((status = bc_program_binaryOpRetire(p, &res, BC_RESULT_TEMP))) goto err; + r.t = BC_RESULT_VAR; + r.d.id.name = name; - return status; + bc_vec_push(&p->results, &r); -err: - bc_num_free(&res.data.num); - return status; + return s; } -BcStatus bc_program_call(BcProgram *p, uint8_t *code, size_t *idx) { +BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn, char inst) +{ + BcStatus s = BC_STATUS_SUCCESS; + BcResult r; + BcNum *num; - BcStatus status; - BcInstPtr ip; - size_t nparams, i; - BcFunc *func; - BcAuto *auto_ptr; - BcResult param, *arg; + r.d.id.name = bc_program_name(code, bgn); - status = BC_STATUS_SUCCESS; - nparams = bc_program_index(code, idx); + if (inst == BC_INST_ARRAY) { + r.t = BC_RESULT_ARRAY; + bc_vec_push(&p->results, &r); + } + else { - ip.idx = 0; - ip.len = p->results.len; - ip.func = bc_program_index(code, idx); + BcResult *operand; + unsigned long temp; - func = bc_vec_item(&p->funcs, ip.func); + s = bc_program_prep(p, &operand, &num); + if (s) goto err; + s = bc_num_ulong(num, &temp); + if (s) goto err; - if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC; - if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS; + if (temp > BC_MAX_DIM) { + s = BC_STATUS_EXEC_ARRAY_LEN; + goto err; + } - for (i = 0; i < nparams; ++i) { + r.d.id.idx = (size_t) temp; + bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM); + } + +err: + if (s) free(r.d.id.name); + return s; +} - auto_ptr = bc_vec_item(&func->autos, i); - arg = bc_vec_item_rev(&p->results, nparams - 1); - param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO; +BcStatus bc_program_incdec(BcProgram *p, char inst) { - if (auto_ptr->var) { + BcStatus s; + BcResult *ptr, res, copy; + BcNum *num = NULL; + char inst2 = inst; - BcNum *n; + s = bc_program_prep(p, &ptr, &num); + if (s) return s; - if ((status = bc_program_num(p, arg, &n, 0))) return status; - if ((status = bc_num_init(¶m.data.num, n->len))) return status; + 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); + } - status = bc_num_copy(¶m.data.num, n); - } - else { + res.t = BC_RESULT_ONE; + inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ? + BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS; - BcVec *a; + bc_vec_push(&p->results, &res); + bc_program_assign(p, inst); - if (arg->type != BC_RESULT_VAR || arg->type != BC_RESULT_ARRAY) - return BC_STATUS_EXEC_BAD_TYPE; + if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) { + bc_vec_pop(&p->results); + bc_vec_push(&p->results, ©); + } - status = bc_program_search(p, arg, (BcNum**) &a, BC_PROGRAM_SEARCH_ARRAY); - if (status) return status; + return s; +} - status = bc_vec_init(¶m.data.array, sizeof(BcNum), bc_num_free); - if (status) return status; +BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) { - status = bc_array_copy(¶m.data.array, a); - } + BcStatus s = BC_STATUS_SUCCESS; + BcInstPtr ip; + size_t i, nparams = bc_program_index(code, idx); + BcFunc *func; + BcVec *v; + BcId *a; + BcResultData param; + BcResult *arg; - if (status || (status = bc_vec_push(&p->results, ¶m))) goto err; - } + ip.idx = 0; + ip.func = bc_program_index(code, idx); + func = bc_vec_item(&p->fns, ip.func); - for (; !status && i < func->autos.len; ++i) { + if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC; + if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS; + ip.len = p->results.len - nparams; - auto_ptr = bc_vec_item_rev(&func->autos, i); - param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO; + for (i = 0; i < nparams; ++i) { - if (auto_ptr->var) status = bc_num_init(¶m.data.num, BC_NUM_DEF_SIZE); - else status = bc_vec_init(¶m.data.array, sizeof(BcNum), bc_num_free); + a = bc_vec_item(&func->autos, nparams - 1 - i); + arg = bc_vec_top(&p->results); - if (status) return status; + if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR) + return BC_STATUS_EXEC_BAD_TYPE; - status = bc_vec_push(&p->results, ¶m); + s = bc_program_copyToVar(p, a->name, a->idx); + if (s) return s; } - if (status) goto err; + for (; i < func->autos.len; ++i) { - return bc_vec_push(&p->stack, &ip); + a = bc_vec_item(&func->autos, i); + bc_program_search(p, a->name, &v, a->idx); -err: - bc_result_free(¶m); - return status; + if (a->idx) { + bc_num_init(¶m.n, BC_NUM_DEF_SIZE); + bc_vec_push(v, ¶m.n); + } + else { + bc_array_init(¶m.v, 1); + bc_vec_push(v, ¶m.v); + } + } + + bc_vec_push(&p->stack, &ip); + + return BC_STATUS_SUCCESS; } -BcStatus bc_program_return(BcProgram *p, uint8_t inst) { +BcStatus bc_program_return(BcProgram *p, char inst) { - BcStatus status; - BcResult result, *operand; - BcInstPtr *ip; - BcFunc *func; + BcStatus s; + BcResult res; + BcFunc *f; + size_t i; + BcInstPtr *ip = bc_vec_top(&p->stack); - ip = bc_vec_top(&p->stack); - func = bc_vec_item(&p->funcs, ip->func); + if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET)) + return BC_STATUS_EXEC_STACK; - result.type = BC_RESULT_TEMP; + f = bc_vec_item(&p->fns, ip->func); + res.t = BC_RESULT_TEMP; - if (inst == BC_INST_RETURN) { + if (inst == BC_INST_RET) { BcNum *num; + BcResult *operand = bc_vec_top(&p->results); - operand = bc_vec_top(&p->results); - - if ((status = bc_program_num(p, operand, &num, 0))) return status; - if ((status = bc_num_init(&result.data.num, num->len))) return status; - if ((status = bc_num_copy(&result.data.num, num))) goto err; + s = bc_program_num(p, operand, &num, 0); + if (s) return s; + bc_num_init(&res.d.n, num->len); + bc_num_copy(&res.d.n, num); } else { - status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE); - if (status) return status; - bc_num_zero(&result.data.num); + bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); + bc_num_zero(&res.d.n); } // We need to pop arguments as well, so this takes that into account. - bc_vec_npop(&p->results, p->results.len - (ip->len - func->nparams)); + for (i = 0; i < f->autos.len; ++i) { - if ((status = bc_vec_push(&p->results, &result))) goto err; - bc_vec_pop(&p->stack); + BcVec *v; + BcId *a = bc_vec_item(&f->autos, i); - return status; + bc_program_search(p, a->name, &v, a->idx); + bc_vec_pop(v); + } -err: - bc_num_free(&result.data.num); - return status; + bc_vec_npop(&p->results, p->results.len - ip->len); + bc_vec_push(&p->results, &res); + bc_vec_pop(&p->stack); + + return BC_STATUS_SUCCESS; } unsigned long bc_program_scale(BcNum *n) { return (unsigned long) n->rdx; } -unsigned long bc_program_length(BcNum *n) { +unsigned long bc_program_len(BcNum *n) { - size_t i; unsigned long len = n->len; + size_t i; - if (n->rdx == n->len) { - for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i); - } + if (n->rdx != n->len) return len; + for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i); return len; } -BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) { +BcStatus bc_program_builtin(BcProgram *p, char inst) { - BcStatus status; - BcResult *operand; - BcNum *num1; - BcResult result; + BcStatus s; + BcResult *opnd; + BcNum *num = NULL; + BcResult res; + int len = inst == BC_INST_LENGTH; - if ((status = bc_program_unaryOpPrep(p, &operand, &num1))) return status; - if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status; + if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK; + opnd = bc_vec_top(&p->results); - if (inst == BC_INST_SQRT) - status = bc_num_sqrt(num1, &result.data.num, p->scale); - else { + s = bc_program_num(p, opnd, &num, 0); + if (s) return s; - BcProgramBuiltInFunc func; - unsigned long ans; + bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); - func = inst == BC_INST_LENGTH ? bc_program_length : bc_program_scale; - ans = func(num1); - - status = bc_num_ulong2num(&result.data.num, ans); + 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); + } + else { + BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale; + s = bc_num_ulong2num(&res.d.n, f(num)); + if (s) goto err; } - if (status || (status = bc_program_unaryOpRetire(p, &result, BC_RESULT_TEMP))) - goto err; + bc_program_retire(p, &res, BC_RESULT_TEMP); - return status; + return s; err: - bc_num_free(&result.data.num); - return status; + bc_num_free(&res.d.n); + return s; } -BcStatus bc_program_pushScale(BcProgram *p) { +BcStatus bc_program_pushGlobal(BcProgram *p, char inst) { - BcStatus status; - BcResult result; + BcStatus s; + BcResult res; + unsigned long val; - result.type = BC_RESULT_SCALE; + res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE; + if (inst == BC_INST_IBASE) val = (unsigned long) p->ib_t; + else if (inst == BC_INST_SCALE) val = (unsigned long) p->scale; + else val = (unsigned long) p->ob_t; - if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status; - status = bc_num_ulong2num(&result.data.num, (unsigned long) p->scale); - if (status || (status = bc_vec_push(&p->results, &result))) goto err; + bc_num_init(&res.d.n, BC_NUM_DEF_SIZE); + s = bc_num_ulong2num(&res.d.n, val); + if (s) goto err; + bc_vec_push(&p->results, &res); - return status; + return s; err: - bc_num_free(&result.data.num); - return status; + bc_num_free(&res.d.n); + return s; } -BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) { - - BcStatus status; - BcResult *ptr, result, copy; - BcNum *num; - - if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status; - - if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { - copy.type = BC_RESULT_TEMP; - if ((status = bc_num_init(©.data.num, num->len))) return status; - } - - result.type = BC_RESULT_ONE; - inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ? - BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS; - - if ((status = bc_vec_push(&p->results, &result))) goto err; - if ((status = bc_program_assign(p, inst))) goto err; - - if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { - bc_vec_pop(&p->results); - if ((status = bc_vec_push(&p->results, ©))) goto err; - } - - return status; - -err: - - if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) - bc_num_free(©.data.num); - - return status; +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); } -BcStatus bc_program_init(BcProgram *p, size_t line_len) { +void bc_program_init(BcProgram *p, size_t line_len) { - BcStatus s; size_t idx; - char *main_name, *read_name; BcInstPtr ip; - main_name = read_name = NULL; + memset(p, 0, sizeof(BcProgram)); + memset(&ip, 0, sizeof(BcInstPtr)); + p->nchars = p->scale = 0; - p->line_len = line_len; + p->len = line_len; + + bc_num_init(&p->ib, BC_NUM_DEF_SIZE); + bc_num_ten(&p->ib); + p->ib_t = 10; - if ((s = bc_num_init(&p->ibase, BC_NUM_DEF_SIZE))) return s; - bc_num_ten(&p->ibase); - p->ibase_t = 10; + bc_num_init(&p->ob, BC_NUM_DEF_SIZE); + bc_num_ten(&p->ob); + p->ob_t = 10; - if ((s = bc_num_init(&p->obase, BC_NUM_DEF_SIZE))) goto obase_err; - bc_num_ten(&p->obase); - p->obase_t = 10; + bc_num_init(&p->hexb, BC_NUM_DEF_SIZE); + bc_num_ten(&p->hexb); + p->hexb.num[0] = 6; - if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto last_err; + bc_num_init(&p->last, BC_NUM_DEF_SIZE); bc_num_zero(&p->last); - if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto zero_err; + bc_num_init(&p->zero, BC_NUM_DEF_SIZE); bc_num_zero(&p->zero); - if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto one_err; + bc_num_init(&p->one, BC_NUM_DEF_SIZE); bc_num_one(&p->one); - if ((s = bc_vec_init(&p->funcs, sizeof(BcFunc), bc_func_free))) goto func_err; + bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free); + bc_map_init(&p->fn_map); - s = bc_veco_init(&p->func_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp); - if (s) goto func_map_err; - - if (!(main_name = malloc(sizeof(bc_lang_func_main)))) { - s = BC_STATUS_MALLOC_FAIL; - goto name_err; - } - - strcpy(main_name, bc_lang_func_main); - s = bc_program_addFunc(p, main_name, &idx); - main_name = NULL; - if (s || idx != BC_PROGRAM_MAIN) goto read_err; - - if (!(read_name = malloc(sizeof(bc_lang_func_read)))) { - s = BC_STATUS_MALLOC_FAIL; - goto read_err; - } + bc_program_addFunc(p, xstrdup(bc_func_main), &idx); + bc_program_addFunc(p, xstrdup(bc_func_read), &idx); - strcpy(read_name, bc_lang_func_read); - s = bc_program_addFunc(p, read_name, &idx); - read_name = NULL; - if (s || idx != BC_PROGRAM_READ) goto var_err; + bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free); + bc_map_init(&p->var_map); - if ((s = bc_vec_init(&p->vars, sizeof(BcNum), bc_num_free))) goto var_err; - s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp); - if (s) goto var_map_err; + bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free); + bc_map_init(&p->arr_map); - if ((s = bc_vec_init(&p->arrays, sizeof(BcVec), bc_vec_free))) goto array_err; - s = bc_veco_init(&p->array_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp); - if (s) goto array_map_err; - - s = bc_vec_init(&p->strings, sizeof(char*), bc_string_free); - if (s) goto string_err; - - s = bc_vec_init(&p->constants, sizeof(char*), bc_string_free); - if (s) goto const_err; - - s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free); - if (s) goto expr_err; - - if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto stack_err; - - memset(&ip, 0, sizeof(BcInstPtr)); - - if ((s = bc_vec_push(&p->stack, &ip))) goto push_err; - - return s; - -push_err: - bc_vec_free(&p->stack); -stack_err: - bc_vec_free(&p->results); -expr_err: - bc_vec_free(&p->constants); -const_err: - bc_vec_free(&p->strings); -string_err: - bc_veco_free(&p->array_map); -array_map_err: - bc_vec_free(&p->arrays); -array_err: - bc_veco_free(&p->var_map); -var_map_err: - bc_vec_free(&p->vars); -var_err: - if (read_name) free(read_name); -read_err: - if (main_name) free(main_name); -name_err: - bc_veco_free(&p->func_map); -func_map_err: - bc_vec_free(&p->funcs); -func_err: - bc_num_free(&p->one); -one_err: - bc_num_free(&p->zero); -zero_err: - bc_num_free(&p->last); -last_err: - bc_num_free(&p->obase); -obase_err: - bc_num_free(&p->ibase); - return s; + 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); } -BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) { +void bc_program_addFunc(BcProgram *p, char *name, size_t *idx) { - BcStatus status; - BcEntry entry, *entry_ptr; + BcStatus s; + BcId entry, *entry_ptr; BcFunc f; entry.name = name; - entry.idx = p->funcs.len; + entry.idx = p->fns.len; - if ((status = bc_veco_insert(&p->func_map, &entry, idx))) { - free(name); - if (status != BC_STATUS_VEC_ITEM_EXISTS) return status; - } + s = bc_map_insert(&p->fn_map, &entry, idx); + if (s) free(name); - entry_ptr = bc_veco_item(&p->func_map, *idx); + entry_ptr = bc_vec_item(&p->fn_map, *idx); *idx = entry_ptr->idx; - if (status == BC_STATUS_VEC_ITEM_EXISTS) { - - BcFunc *func = bc_vec_item(&p->funcs, entry_ptr->idx); + if (s == BC_STATUS_VEC_ITEM_EXISTS) { - status = BC_STATUS_SUCCESS; + BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx); // We need to reset these, so the function can be repopulated. func->nparams = 0; @@ -5315,208 +5214,191 @@ BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) { bc_vec_npop(&func->labels, func->labels.len); } else { - if ((status = bc_func_init(&f))) return status; - if ((status = bc_vec_push(&p->funcs, &f))) bc_func_free(&f); + bc_func_init(&f); + bc_vec_push(&p->fns, &f); } - - return status; } -BcStatus bc_program_reset(BcProgram *p, BcStatus status) { +BcStatus bc_program_reset(BcProgram *p, BcStatus s) { - BcFunc *func; + BcFunc *f; BcInstPtr *ip; bc_vec_npop(&p->stack, p->stack.len - 1); bc_vec_npop(&p->results, p->results.len); - func = bc_vec_item(&p->funcs, 0); + f = bc_vec_item(&p->fns, 0); ip = bc_vec_top(&p->stack); - ip->idx = func->code.len; + ip->idx = f->code.len; - if (!status && TT.signe && !TT.tty) return BC_STATUS_QUIT; + if (!s && TT.signe && !TT.tty) return BC_STATUS_QUIT; TT.sigc += TT.signe; TT.signe = TT.sig != TT.sigc; - if ((!status || status == BC_STATUS_EXEC_SIGNAL) && TT.tty) { - status = BC_STATUS_SUCCESS; - fprintf(stderr, "%s", bc_program_ready_prompt); - fflush(stderr); + if (!s || s == BC_STATUS_EXEC_SIGNAL) { + if (TT.ttyin) { + bc_vm_puts(bc_program_ready_msg, stderr); + bc_vm_fflush(stderr); + s = BC_STATUS_SUCCESS; + } + else s = BC_STATUS_QUIT; } - return status; + return s; } BcStatus bc_program_exec(BcProgram *p) { - BcStatus status; - uint8_t *code; - size_t idx, len, *addr; - BcResult result; - BcResult *ptr; + BcStatus s = BC_STATUS_SUCCESS; + size_t idx; + BcResult r, *ptr; BcNum *num; - BcFunc *func; - BcInstPtr *ip; - int cond; - const char **string, *s; + BcInstPtr *ip = bc_vec_top(&p->stack); + BcFunc *func = bc_vec_item(&p->fns, ip->func); + char *code = func->code.v; + int cond = 0; - status = BC_STATUS_SUCCESS; - cond = 0; + while (!s && ip->idx < func->code.len) { - ip = bc_vec_top(&p->stack); - func = bc_vec_item(&p->funcs, ip->func); - code = func->code.array; - - while (!status && !TT.sig_other && ip->idx < func->code.len) { - - uint8_t inst = code[(ip->idx)++]; + char inst = code[(ip->idx)++]; switch (inst) { - case BC_INST_CALL: - { - status = bc_program_call(p, code, &ip->idx); - break; - } - - case BC_INST_RETURN: - case BC_INST_RETURN_ZERO: - { - status = bc_program_return(p, inst); - break; - } - - case BC_INST_READ: - { - status = bc_program_read(p); - break; - } - case BC_INST_JUMP_ZERO: { - if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status; + s = bc_program_prep(p, &ptr, &num); + if (s) return s; cond = !bc_num_cmp(num, &p->zero); bc_vec_pop(&p->results); } // Fallthrough. case BC_INST_JUMP: { + size_t *addr; idx = bc_program_index(code, &ip->idx); addr = bc_vec_item(&func->labels, idx); if (inst == BC_INST_JUMP || cond) ip->idx = *addr; break; } - case BC_INST_PUSH_VAR: - case BC_INST_PUSH_ARRAY_ELEM: + case BC_INST_CALL: { - status = bc_program_push(p, code, &ip->idx, inst == BC_INST_PUSH_VAR); + s = bc_program_call(p, code, &ip->idx); break; } - case BC_INST_PUSH_LAST: + case BC_INST_INC_PRE: + case BC_INST_DEC_PRE: + case BC_INST_INC_POST: + case BC_INST_DEC_POST: { - result.type = BC_RESULT_LAST; - status = bc_vec_push(&p->results, &result); + s = bc_program_incdec(p, inst); break; } - case BC_INST_PUSH_SCALE: + case BC_INST_HALT: { - status = bc_program_pushScale(p); + s = BC_STATUS_QUIT; break; } - case BC_INST_PUSH_IBASE: + case BC_INST_RET: + case BC_INST_RET0: { - result.type = BC_RESULT_IBASE; - status = bc_vec_push(&p->results, &result); + s = bc_program_return(p, inst); break; } - case BC_INST_PUSH_OBASE: + case BC_INST_BOOL_OR: + case BC_INST_BOOL_AND: + case BC_INST_REL_EQ: + case BC_INST_REL_LE: + case BC_INST_REL_GE: + case BC_INST_REL_NE: + case BC_INST_REL_LT: + case BC_INST_REL_GT: { - result.type = BC_RESULT_OBASE; - status = bc_vec_push(&p->results, &result); + s = bc_program_logical(p, inst); break; } - case BC_INST_SCALE_FUNC: - case BC_INST_LENGTH: - case BC_INST_SQRT: + case BC_INST_READ: { - status = bc_program_builtin(p, inst); + s = bc_program_read(p); break; } - case BC_INST_PUSH_NUM: + case BC_INST_VAR: { - result.type = BC_RESULT_CONSTANT; - result.data.id.idx = bc_program_index(code, &ip->idx); - status = bc_vec_push(&p->results, &result); + s = bc_program_pushVar(p, code, &ip->idx, 0, 0); break; } - case BC_INST_POP: + case BC_INST_ARRAY_ELEM: + case BC_INST_ARRAY: { - bc_vec_pop(&p->results); + s = bc_program_pushArray(p, code, &ip->idx, inst); break; } - case BC_INST_INC_POST: - case BC_INST_DEC_POST: - case BC_INST_INC_PRE: - case BC_INST_DEC_PRE: + case BC_INST_LAST: { - status = bc_program_incdec(p, inst); + r.t = BC_RESULT_LAST; + bc_vec_push(&p->results, &r); break; } - case BC_INST_HALT: + case BC_INST_IBASE: + case BC_INST_SCALE: + case BC_INST_OBASE: { - status = BC_STATUS_QUIT; + s = bc_program_pushGlobal(p, inst); break; } - case BC_INST_PRINT: - case BC_INST_PRINT_EXPR: + case BC_INST_SCALE_FUNC: + case BC_INST_LENGTH: + case BC_INST_SQRT: { - if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status; - - status = bc_num_print(num, &p->obase, p->obase_t, inst == BC_INST_PRINT, - &p->nchars, p->line_len); - if (status) return status; - if ((status = bc_num_copy(&p->last, num))) return status; - - bc_vec_pop(&p->results); - + s = bc_program_builtin(p, inst); break; } - case BC_INST_STR: + case BC_INST_NUM: { - idx = bc_program_index(code, &ip->idx); - string = bc_vec_item(&p->strings, idx); - - s = *string; - len = strlen(s); + r.t = BC_RESULT_CONSTANT; + r.d.id.idx = bc_program_index(code, &ip->idx); + bc_vec_push(&p->results, &r); + break; + } - for (idx = 0; idx < len; ++idx) { - char c = s[idx]; - if (putchar(c) == EOF) return BC_STATUS_IO_ERR; - if (c == '\n') p->nchars = SIZE_MAX; - ++p->nchars; - } + 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); break; } + case BC_INST_PRINT: + case BC_INST_PRINT_POP: case BC_INST_PRINT_STR: { - idx = bc_program_index(code, &ip->idx); - string = bc_vec_item(&p->strings, idx); - status = bc_program_printString(*string, &p->nchars); + s = bc_program_print(p, inst, 0); + break; + } + + case BC_INST_STR: + { + r.t = BC_RESULT_STR; + r.d.id.idx = bc_program_index(code, &ip->idx); + bc_vec_push(&p->results, &r); break; } @@ -5527,46 +5409,25 @@ BcStatus bc_program_exec(BcProgram *p) { case BC_INST_PLUS: case BC_INST_MINUS: { - status = bc_program_op(p, inst); - break; - } - - case BC_INST_REL_EQ: - case BC_INST_REL_LE: - case BC_INST_REL_GE: - case BC_INST_REL_NE: - case BC_INST_REL_LT: - case BC_INST_REL_GT: - { - status = bc_program_logical(p, inst); + s = bc_program_op(p, inst); break; } case BC_INST_BOOL_NOT: { - if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status; - status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE); - if (status) return status; + s = bc_program_prep(p, &ptr, &num); + if (s) return s; - if (bc_num_cmp(num, &p->zero)) bc_num_one(&result.data.num); - else bc_num_zero(&result.data.num); - - status = bc_program_unaryOpRetire(p, &result, BC_RESULT_TEMP); - if (status) bc_num_free(&result.data.num); + 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_BOOL_OR: - case BC_INST_BOOL_AND: - { - status = bc_program_logical(p, inst); - break; - } - case BC_INST_NEG: { - status = bc_program_negate(p); + s = bc_program_negate(p); break; } @@ -5578,315 +5439,326 @@ BcStatus bc_program_exec(BcProgram *p) { case BC_INST_ASSIGN_MINUS: case BC_INST_ASSIGN: { - status = bc_program_assign(p, inst); - break; - } - - default: - { + s = bc_program_assign(p, inst); break; } } - if ((status && status != BC_STATUS_QUIT) || TT.signe) - status = bc_program_reset(p, status); + if ((s && s != BC_STATUS_QUIT) || TT.signe) s = bc_program_reset(p, s); - // We need to update because if the stack changes, pointers may be invalid. + // If the stack has changed, pointers may be invalid. ip = bc_vec_top(&p->stack); - func = bc_vec_item(&p->funcs, ip->func); - code = func->code.array; + func = bc_vec_item(&p->fns, ip->func); + code = func->code.v; } - return status; + return s; } -void bc_program_free(BcProgram *p) { +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; + } + errno = err; +} - if (!p) return; +void bc_vm_info(void) { + bc_vm_printf(stdout, "%s %s\n", toys.which->name, "1.1"); + bc_vm_puts(bc_copyright, stdout); +} - bc_num_free(&p->ibase); - bc_num_free(&p->obase); +BcStatus bc_vm_error(BcStatus s, const char *file, size_t line) { - bc_vec_free(&p->funcs); - bc_veco_free(&p->func_map); + if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s; - bc_vec_free(&p->vars); - bc_veco_free(&p->var_map); + 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); - bc_vec_free(&p->arrays); - bc_veco_free(&p->array_map); + return s * (!TT.ttyin || !!strcmp(file, bc_program_stdin_name)); +} - bc_vec_free(&p->strings); - bc_vec_free(&p->constants); +BcStatus bc_vm_posixError(BcStatus s, const char *file, + size_t line, const char *msg) +{ + int p = (int) (toys.optflags & FLAG_s), w = (int) (toys.optflags & FLAG_w); + const char* const fmt = p ? bc_err_fmt : bc_warn_fmt; - bc_vec_free(&p->results); - bc_vec_free(&p->stack); + if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS; - bc_num_free(&p->last); - bc_num_free(&p->zero); - bc_num_free(&p->one); + 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); - memset(p, 0, sizeof(BcProgram)); + return s * (!TT.ttyin && !!p); } -void bc_sig(int sig) { - if (sig == SIGINT) { - if (write(2, bc_sig_msg, sizeof(bc_sig_msg) - 1) >= 0) - TT.sig += (TT.signe = TT.sig == TT.sigc); +size_t bc_vm_envLen(const char *var) { + + char *lenv = getenv(var); + size_t i, len = BC_NUM_PRINT_WIDTH; + int num; + + if (!lenv) return len; + + len = strlen(lenv); + + 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; } - else TT.sig_other = 1; -} + else len = BC_NUM_PRINT_WIDTH; -BcStatus bc_error(BcStatus s) { - if (!s || s >= BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS; - fprintf(stderr, bc_err_fmt, bc_errs[bc_err_indices[s]], bc_err_descs[s]); - return s * !TT.tty; + return len; } -BcStatus bc_error_file(BcStatus s, const char *file, size_t line) { - if (!s || !file || s >= BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS; - fprintf(stderr, bc_err_fmt, bc_errs[bc_err_indices[s]], bc_err_descs[s]); - fprintf(stderr, " %s", file); - fprintf(stderr, &":%d\n\n"[3 * !line], line); - return s * !TT.tty; +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); } -BcStatus bc_posix_error(BcStatus s, const char *file, - size_t line, const char *msg) -{ - int p = (int) (toys.optflags & FLAG_s), w = (int) (toys.optflags & FLAG_w); +void bc_vm_printf(FILE *restrict f, const char *fmt, ...) { - if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN || !file) - return BC_STATUS_SUCCESS; + va_list args; + int bad; + + va_start(args, fmt); + bad = vfprintf(f, fmt, args) < 0; + va_end(args); - fprintf(stderr, "\n%s %s: %s\n", bc_errs[bc_err_indices[s]], - p ? "error" : "warning", bc_err_descs[s]); + if (bad) bc_vm_exit(BC_STATUS_IO_ERR); +} - if (msg) fprintf(stderr, " %s\n", msg); - fprintf(stderr, " %s", file); - fprintf(stderr, &":%d\n\n"[3 * !line], line); +void bc_vm_puts(const char *str, FILE *restrict f) { + if (fputs(str, f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); +} - return s * !!p; +void bc_vm_putchar(int c) { + if (putchar(c) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); } -BcStatus bc_process(Bc *bc, const char *text) { +void bc_vm_fflush(FILE *restrict f) { + if (fflush(f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR); +} - BcStatus s = bc_lex_text(&bc->parse.lex, text); +BcStatus bc_vm_process(BcVm *vm, const char *text) { - if (s && (s = bc_error_file(s, bc->parse.lex.file, bc->parse.lex.line))) - return s; + BcStatus s = bc_parse_text(&vm->prs, text); - while (bc->parse.lex.token.type != BC_LEX_EOF) { + s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line); + if (s) return s; - if ((s = bc_parse_parse(&bc->parse)) == BC_STATUS_LIMITS) { + while (vm->prs.l.t.t != BC_LEX_EOF) { - s = BC_STATUS_IO_ERR; + s = bc_parse_parse(&vm->prs); - if (putchar('\n') == EOF) return s; + if (s == BC_STATUS_LIMITS) { - if (printf("BC_BASE_MAX = %zu\n", (size_t) maxof_BASE) < 0 || - printf("BC_DIM_MAX = %zu\n", (size_t) maxof_DIM) < 0 || - printf("BC_SCALE_MAX = %zu\n", (size_t) maxof_SCALE) < 0 || - printf("BC_STRING_MAX = %zu\n", (size_t) maxof_STRING) < 0 || - printf("Max Exponent = %ld\n", (long) LONG_MAX) < 0 || - printf("Number of Vars = %zu\n", (size_t) SIZE_MAX) < 0) - { - return 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'); - if (putchar('\n') == EOF) return s; + s = BC_STATUS_SUCCESS; } - else if (s == BC_STATUS_QUIT || TT.sig_other || - (s && (s = bc_error_file(s, bc->parse.lex.file, bc->parse.lex.line)))) - { - return s; + 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; } } - if (BC_PARSE_CAN_EXEC(&bc->parse)) { - s = bc_program_exec(&bc->prog); - if (TT.tty) fflush(stdout); - if (s && s != BC_STATUS_QUIT) s = bc_error(s); + 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); } return s; } -BcStatus bc_file(Bc *bc, const char *file) { +BcStatus bc_vm_file(BcVm *vm, const char *file) { BcStatus s; char *data; BcFunc *main_func; BcInstPtr *ip; - bc->prog.file = file; - if ((s = bc_io_fread(file, &data))) return s; + vm->prog.file = file; + s = bc_read_file(file, &data); + if (s) return bc_vm_error(s, file, 0); - bc_lex_init(&bc->parse.lex, file); - if ((s = bc_process(bc, data))) goto err; + bc_lex_file(&vm->prs.l, file); + s = bc_vm_process(vm, data); + if (s) goto err; - main_func = bc_vec_item(&bc->prog.funcs, BC_PROGRAM_MAIN); - ip = bc_vec_item(&bc->prog.stack, 0); + 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 (main_func->code.len < ip->idx) + s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE; err: free(data); return s; } -BcStatus bc_concat(char **buffer, size_t *n, char *buf, size_t total_len) { - - if (total_len > *n) { - - char *temp = realloc(*buffer, total_len + 1); - if (!temp) return BC_STATUS_MALLOC_FAIL; - - *buffer = temp; - *n = total_len; - } - - strcat(*buffer, buf); - - return BC_STATUS_SUCCESS; -} - -BcStatus bc_stdin(Bc *bc) { +BcStatus bc_vm_stdin(BcVm *vm) { - BcStatus s; - char *buf, *buffer, c; - size_t n, bufn, slen, total_len, len, i; - int string, comment, notend; + BcStatus s = BC_STATUS_SUCCESS; + BcVec buf, buffer; + char c; + size_t len, i, str = 0; + int comment = 0, notend; - bc->prog.file = bc_program_stdin_name; - bc_lex_init(&bc->parse.lex, bc_program_stdin_name); + vm->prog.file = bc_program_stdin_name; + bc_lex_file(&vm->prs.l, bc_program_stdin_name); - n = bufn = BC_BUF_SIZE; + bc_vec_init(&buffer, sizeof(char), NULL); + bc_vec_init(&buf, sizeof(char), NULL); + bc_vec_pushByte(&buffer, '\0'); - if (!(buffer = malloc(BC_BUF_SIZE + 1))) return BC_STATUS_MALLOC_FAIL; + // 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, ">>> ")) { - if (!(buf = malloc(BC_BUF_SIZE + 1))) { - s = BC_STATUS_MALLOC_FAIL; - goto buf_err; - } + char *string = buf.v; - buffer[0] = '\0'; - string = comment = 0; - s = BC_STATUS_SUCCESS; + len = buf.len - 1; - // The following 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. - while ((!s || s != BC_STATUS_QUIT) && - !((s = bc_io_getline(&buf, &bufn)) && s != BC_STATUS_BINARY_FILE)) - { - if (s == BC_STATUS_BINARY_FILE) { - putchar('\a'); - s = BC_STATUS_SUCCESS; - continue; + if (len == 1) { + if (str && buf.v[0] == '"') str -= 1; + else if (buf.v[0] == '"') str += 1; } - - len = strlen(buf); - slen = strlen(buffer); - total_len = slen + len; - - if (len == 1 && buf[0] == '"') string = !string; else if (len > 1 || comment) { for (i = 0; i < len; ++i) { notend = len > i + 1; + c = string[i]; + + if ((i - 1 > len || string[i - 1] != '\\') && c == '"') str = !str; - if ((c = buf[i]) == '"') string = !string; - else if (c == '/' && notend && !comment && buf[i + 1] == '*') { + if (c == '/' && notend && !comment && string[i + 1] == '*') { comment = 1; break; } - else if (c == '*' && notend && comment && buf[i + 1] == '/') + else if (c == '*' && notend && comment && string[i + 1] == '/') comment = 0; } - if (string || comment || buf[len - 2] == '\\') { - if ((s = bc_concat(&buffer, &n, buf, total_len))) goto exit_err; + if (str || comment || string[len - 2] == '\\') { + bc_vec_concat(&buffer, buf.v); continue; } } - if ((s = bc_concat(&buffer, &n, buf, total_len))) goto exit_err; + bc_vec_concat(&buffer, buf.v); + s = bc_vm_process(vm, buffer.v); + if (s) goto err; - s = bc_process(bc, buffer); - buffer[0] = '\0'; + bc_vec_npop(&buffer, buffer.len); } + if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0); + // I/O error will always happen when stdin is // closed. It's not a problem in that case. - s = s == BC_STATUS_IO_ERR ? BC_STATUS_SUCCESS : s; + s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s; + + 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); -exit_err: - free(buf); -buf_err: - free(buffer); +err: + bc_vec_free(&buf); + bc_vec_free(&buffer); return s; } -void bc_main(void) { +BcStatus bc_vm_exec(BcVm *vm) { - BcStatus status; - Bc bc; - struct sigaction sa; - size_t i, len; - char *lenv; - int num; + BcStatus s = BC_STATUS_SUCCESS; + size_t i; - TT.tty = (toys.optflags & FLAG_i) || (isatty(0) && isatty(1)); + if (toys.optflags & FLAG_l) { + + bc_lex_file(&vm->prs.l, bc_lib_name); + s = bc_parse_text(&vm->prs, bc_lib); - if ((lenv = getenv("BC_LINE_LENGTH"))) { - len = strlen(lenv); - for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]); - if (!num || (len = (size_t) atoi(lenv) - 1) < 2) len = BC_NUM_PRINT_WIDTH; + while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = bc_parse_parse(&vm->prs); + + if (s) return s; + s = bc_program_exec(&vm->prog); + if (s) return s; } - else len = BC_NUM_PRINT_WIDTH; - if ((toys.exitval = bc_program_init(&bc.prog, len))) return; - if ((status = bc_parse_init(&bc.parse, &bc.prog))) goto parse_err; + for (i = 0; !s && i < toys.optc; ++i) + s = bc_vm_file(vm, 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); +} + +BcStatus bc_vm_init(BcVm *vm) { + + BcStatus s = BC_STATUS_SUCCESS; + size_t len = bc_vm_envLen("BC_LINE_LENGTH"); + struct sigaction sa; sigemptyset(&sa.sa_mask); - sa.sa_handler = bc_sig; + sa.sa_handler = bc_vm_sig; sa.sa_flags = 0; + sigaction(SIGINT, &sa, NULL); - if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGPIPE, &sa, NULL) < 0 || - sigaction(SIGHUP, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0) - { - status = BC_STATUS_EXEC_SIGACTION_FAIL; - goto err; - } + memset(vm, 0, sizeof(BcVm)); - if (TT.tty && !(toys.optflags & FLAG_q) && printf("%s", bc_header) < 0) { - status = BC_STATUS_IO_ERR; - goto err; - } + toys.optflags |= FLAG_s * (getenv("POSIXLY_CORRECT") != NULL); - if (toys.optflags & FLAG_l) { + bc_program_init(&vm->prog, len); + bc_parse_init(&vm->prs, &vm->prog, BC_PROG_MAIN); - bc_lex_init(&bc.parse.lex, bc_lib_name); - if ((status = bc_lex_text(&bc.parse.lex, bc_lib))) goto err; + return s; +} - while (!status && bc.parse.lex.token.type != BC_LEX_EOF) - status = bc_parse_parse(&bc.parse); +void bc_main(void) { - if (status || (status = bc_program_exec(&bc.prog))) goto err; - } + BcStatus st; + BcVm vm; - for (i = 0; !TT.sig_other && !status && i < toys.optc; ++i) - status = bc_file(&bc, toys.optargs[i]); - if (status || TT.sig_other) goto err; + st = bc_vm_init(&vm); + if (st) goto exit; - status = bc_stdin(&bc); + TT.ttyin = isatty(0); + TT.tty = TT.ttyin || (toys.optflags & FLAG_i) || isatty(1); -err: - if (CFG_TOYBOX_FREE) bc_parse_free(&bc.parse); -parse_err: - bc_program_free(&bc.prog); - toys.exitval = status == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : status; + if (TT.ttyin && !(toys.optflags & FLAG_q)) bc_vm_info(); + st = bc_vm_exec(&vm); + +exit: + if (CFG_TOYBOX_FREE) bc_vm_free(&vm); + toys.exitval = (int) st; } -- cgit v1.2.3