1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //usage:#define bc_trivial_usage
118 //usage: "EXPRESSION...\n"
119 //usage: "function_definition\n"
121 //usage:#define bc_full_usage "\n\n"
122 //usage: "See www.gnu.org/software/bc/manual/bc.html\n"
124 //usage:#define bc_example_usage
125 //usage: "3 + 4.129\n"
126 //usage: "1903 - 2893\n"
127 //usage: "-129 * 213.28935\n"
128 //usage: "12 / -1932\n"
130 //usage: "34 ^ 189\n"
131 //usage: "scale = 13\n"
132 //usage: "ibase = 2\n"
133 //usage: "obase = A\n"
135 //usage:#define dc_trivial_usage
136 //usage: "EXPRESSION..."
138 //usage:#define dc_full_usage "\n\n"
139 //usage: "Tiny RPN calculator. Operations:\n"
140 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141 //usage: "modular exponentiation,\n"
142 //usage: "p - print top of the stack (without popping),\n"
143 //usage: "f - print entire stack,\n"
144 //usage: "k - pop the value and set the precision.\n"
145 //usage: "i - pop the value and set input radix.\n"
146 //usage: "o - pop the value and set output radix.\n"
147 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
149 //usage:#define dc_example_usage
150 //usage: "$ dc 2 2 + p\n"
152 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
154 //usage: "$ dc 0 1 and p\n"
156 //usage: "$ dc 0 1 or p\n"
158 //usage: "$ echo 72 9 div 8 mul p | dc\n"
163 typedef enum BcStatus {
170 BC_STATUS_PATH_IS_DIR,
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
177 BC_STATUS_LEX_EXTENDED_REG,
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
234 BC_STATUS_INVALID_OPTION,
238 #define BC_ERR_IDX_VM (0)
239 #define BC_ERR_IDX_LEX (1)
240 #define BC_ERR_IDX_PARSE (2)
241 #define BC_ERR_IDX_MATH (3)
242 #define BC_ERR_IDX_EXEC (4)
243 #define BC_ERR_IDX_VEC (5)
245 #define BC_ERR_IDX_POSIX (6)
248 #define BC_VEC_INVALID_IDX ((size_t) -1)
249 #define BC_VEC_START_CAP (1 << 5)
251 typedef void (*BcVecFree)(void *);
252 typedef int (*BcVecCmp)(const void *, const void *);
254 typedef struct BcVec {
262 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
263 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
265 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
267 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
269 typedef signed char BcDig;
271 typedef struct BcNum {
279 #define BC_NUM_MIN_BASE ((unsigned long) 2)
280 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
281 #define BC_NUM_DEF_SIZE (16)
282 #define BC_NUM_PRINT_WIDTH (69)
284 #define BC_NUM_KARATSUBA_LEN (32)
286 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
287 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
288 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
289 #define BC_NUM_AREQ(a, b) \
290 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
291 #define BC_NUM_MREQ(a, b, scale) \
292 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
294 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
295 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
297 static void bc_num_init(BcNum *n, size_t req);
298 static void bc_num_expand(BcNum *n, size_t req);
299 static void bc_num_copy(BcNum *d, BcNum *s);
300 static void bc_num_free(void *num);
302 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
303 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
305 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
311 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
312 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
315 typedef enum BcInst {
345 BC_INST_ASSIGN_POWER,
346 BC_INST_ASSIGN_MULTIPLY,
347 BC_INST_ASSIGN_DIVIDE,
348 BC_INST_ASSIGN_MODULUS,
350 BC_INST_ASSIGN_MINUS,
396 BC_INST_PRINT_STREAM,
411 BC_INST_INVALID = -1,
416 typedef struct BcId {
421 typedef struct BcFunc {
428 typedef enum BcResultType {
433 BC_RESULT_ARRAY_ELEM,
442 // These are between to calculate ibase, obase, and last from instructions.
450 typedef union BcResultData {
456 typedef struct BcResult {
461 typedef struct BcInstPtr {
467 static void bc_array_expand(BcVec *a, size_t len);
468 static int bc_id_cmp(const void *e1, const void *e2);
470 // BC_LEX_NEG is not used in lexing; it is only for parsing.
471 typedef enum BcLexType {
499 BC_LEX_OP_ASSIGN_POWER,
500 BC_LEX_OP_ASSIGN_MULTIPLY,
501 BC_LEX_OP_ASSIGN_DIVIDE,
502 BC_LEX_OP_ASSIGN_MODULUS,
503 BC_LEX_OP_ASSIGN_PLUS,
504 BC_LEX_OP_ASSIGN_MINUS,
578 typedef BcStatus (*BcLexNext)(struct BcLex *);
580 typedef struct BcLex {
599 #define BC_PARSE_STREND ((char) UCHAR_MAX)
601 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
602 #define bc_parse_updateFunc(p, f) \
603 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
605 #define BC_PARSE_REL (1 << 0)
606 #define BC_PARSE_PRINT (1 << 1)
607 #define BC_PARSE_NOCALL (1 << 2)
608 #define BC_PARSE_NOREAD (1 << 3)
609 #define BC_PARSE_ARRAY (1 << 4)
611 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
612 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
614 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
615 #define BC_PARSE_FUNC_INNER(parse) \
616 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
618 #define BC_PARSE_FLAG_FUNC (1 << 1)
619 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
621 #define BC_PARSE_FLAG_BODY (1 << 2)
622 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
624 #define BC_PARSE_FLAG_LOOP (1 << 3)
625 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
627 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
628 #define BC_PARSE_LOOP_INNER(parse) \
629 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
631 #define BC_PARSE_FLAG_IF (1 << 5)
632 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
634 #define BC_PARSE_FLAG_ELSE (1 << 6)
635 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
637 #define BC_PARSE_FLAG_IF_END (1 << 7)
638 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
640 #define BC_PARSE_CAN_EXEC(parse) \
641 (!(BC_PARSE_TOP_FLAG(parse) & \
642 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
643 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
644 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
646 typedef struct BcOp {
651 typedef struct BcParseNext {
656 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
657 #define BC_PARSE_NEXT(a, ...) \
659 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
666 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
667 typedef BcStatus (*BcParseParse)(struct BcParse *);
668 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
670 typedef struct BcParse {
683 struct BcProgram *prog;
694 BcStatus bc_main(int argc, char *argv[]);
696 typedef struct BcLexKeyword {
702 #define BC_LEX_KW_ENTRY(a, b, c) \
704 .name = a, .len = (b), .posix = (c) \
707 static BcStatus bc_lex_token(BcLex *l);
709 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
710 #define BC_PARSE_LEAF(p, rparen) \
711 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
712 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
714 // We can calculate the conversion between tokens and exprs by subtracting the
715 // position of the first operator in the lex enum and adding the position of the
716 // first in the expr enum. Note: This only works for binary operators.
717 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
719 static BcStatus bc_parse_parse(BcParse *p);
720 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
726 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
728 BcStatus dc_main(int argc, char *argv[]);
730 static BcStatus dc_lex_token(BcLex *l);
732 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
733 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
737 typedef struct BcProgram {
776 BcParseInit parse_init;
777 BcParseExpr parse_expr;
781 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
783 #define BC_PROG_MAIN (0)
784 #define BC_PROG_READ (1)
787 #define BC_PROG_REQ_FUNCS (2)
790 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
791 #define BC_PROG_NUM(r, n) \
792 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
794 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
796 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
797 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
798 static BcStatus bc_program_exec(BcProgram *p);
800 #define BC_FLAG_X (1 << 0)
801 #define BC_FLAG_W (1 << 1)
802 #define BC_FLAG_V (1 << 2)
803 #define BC_FLAG_S (1 << 3)
804 #define BC_FLAG_Q (1 << 4)
805 #define BC_FLAG_L (1 << 5)
806 #define BC_FLAG_I (1 << 6)
808 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
809 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
811 #define BC_MAX_OBASE ((unsigned long) 999)
812 #define BC_MAX_DIM ((unsigned long) INT_MAX)
813 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
814 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
815 #define BC_MAX_NAME BC_MAX_STRING
816 #define BC_MAX_NUM BC_MAX_STRING
817 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
818 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
820 typedef struct BcVmExe {
827 typedef struct BcVm {
840 typedef struct BcGlobals {
853 #if ENABLE_FEATURE_BC_SIGNALS
862 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
866 static void bc_vm_exit(BcStatus s);
867 static void bc_vm_printf(FILE *restrict f, const char *fmt, ...);
868 static void bc_vm_puts(const char *str, FILE *restrict f);
869 static void bc_vm_putchar(int c);
870 static void bc_vm_fflush(FILE *restrict f);
872 static void bc_vm_info(const char *const help);
873 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
874 const char *env_len);
876 static BcGlobals bcg;
879 static const char bc_name[] = "bc";
880 # if ENABLE_FEATURE_BC_SIGNALS
881 static const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
886 static const char dc_name[] = "dc";
887 # if ENABLE_FEATURE_BC_SIGNALS
888 static const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
892 static const char bc_copyright[] =
893 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
894 "Report bugs at: https://github.com/gavinhoward/bc\n\n"
895 "This is free software with ABSOLUTELY NO WARRANTY.\n";
897 static const char* const bc_args_env_name = "BC_ENV_ARGS";
899 static const char bc_err_fmt[] = "\n%s error: %s\n";
900 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
901 static const char bc_err_line[] = ":%zu\n\n";
903 static const char *bc_errs[] = {
915 static const uint8_t bc_err_ids[] = {
916 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
917 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
921 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
922 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
923 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
928 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
929 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
930 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
931 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
933 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
935 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
936 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
937 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
939 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
942 static const char *bc_err_msgs[] = {
945 "memory allocation error",
948 "path is a directory:",
951 "string end could not be found",
952 "comment end could not be found",
961 "bad print statement",
962 "bad function definition",
963 "bad assignment: left side must be scale, ibase, "
964 "obase, last, var, or array element",
965 "no auto variable found",
966 "function parameter or auto var has the same name as another",
967 "block end could not be found",
970 "non integer number",
975 "could not open file:",
976 "mismatched parameters",
977 "undefined function",
978 "file is not executable:",
979 "number too long: must be [1, BC_NUM_MAX]",
980 "name too long: must be [1, BC_NAME_MAX]",
981 "string too long: must be [1, BC_STRING_MAX]",
982 "array too long; must be [1, BC_DIM_MAX]",
983 "bad ibase; must be [2, 16]",
984 "bad scale; must be [0, BC_SCALE_MAX]",
985 "bad read() expression",
986 "read() call inside of a read() call",
987 "variable is wrong type",
988 "bad obase; must be [2, BC_BASE_MAX]",
989 "signal caught and not handled",
990 "stack has too few elements",
992 "index is out of bounds",
993 "item already exists",
996 "POSIX only allows one character names; the following is bad:",
997 "POSIX does not allow '#' script comments",
998 "POSIX does not allow the following keyword:",
999 "POSIX does not allow a period ('.') as a shortcut for the last result",
1000 "POSIX requires parentheses around return expressions",
1001 "POSIX does not allow boolean operators; the following is bad:",
1002 "POSIX does not allow comparison operators outside if or loops",
1003 "POSIX requires exactly one comparison operator per condition",
1004 "POSIX does not allow an empty init expression in a for loop",
1005 "POSIX does not allow an empty condition expression in a for loop",
1006 "POSIX does not allow an empty update expression in a for loop",
1007 "POSIX requires the left brace be on the same line as the function header",
1012 static const char bc_func_main[] = "(main)";
1013 static const char bc_func_read[] = "(read)";
1016 static const BcLexKeyword bc_lex_kws[20] = {
1017 BC_LEX_KW_ENTRY("auto", 4, true),
1018 BC_LEX_KW_ENTRY("break", 5, true),
1019 BC_LEX_KW_ENTRY("continue", 8, false),
1020 BC_LEX_KW_ENTRY("define", 6, true),
1021 BC_LEX_KW_ENTRY("else", 4, false),
1022 BC_LEX_KW_ENTRY("for", 3, true),
1023 BC_LEX_KW_ENTRY("halt", 4, false),
1024 BC_LEX_KW_ENTRY("ibase", 5, true),
1025 BC_LEX_KW_ENTRY("if", 2, true),
1026 BC_LEX_KW_ENTRY("last", 4, false),
1027 BC_LEX_KW_ENTRY("length", 6, true),
1028 BC_LEX_KW_ENTRY("limits", 6, false),
1029 BC_LEX_KW_ENTRY("obase", 5, true),
1030 BC_LEX_KW_ENTRY("print", 5, false),
1031 BC_LEX_KW_ENTRY("quit", 4, true),
1032 BC_LEX_KW_ENTRY("read", 4, false),
1033 BC_LEX_KW_ENTRY("return", 6, true),
1034 BC_LEX_KW_ENTRY("scale", 5, true),
1035 BC_LEX_KW_ENTRY("sqrt", 4, true),
1036 BC_LEX_KW_ENTRY("while", 5, true),
1039 // This is an array that corresponds to token types. An entry is
1040 // true if the token is valid in an expression, false otherwise.
1041 static const bool bc_parse_exprs[] = {
1042 false, false, true, true, true, true, true, true, true, true, true, true,
1043 true, true, true, true, true, true, true, true, true, true, true, true,
1044 true, true, true, false, false, true, true, false, false, false, false,
1045 false, false, false, true, true, false, false, false, false, false, false,
1046 false, true, false, true, true, true, true, false, false, true, false, true,
1050 // This is an array of data for operators that correspond to token types.
1051 static const BcOp bc_parse_ops[] = {
1052 { 0, false }, { 0, false },
1055 { 3, true }, { 3, true }, { 3, true },
1056 { 4, true }, { 4, true },
1057 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1059 { 7, true }, { 7, true },
1060 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1061 { 5, false }, { 5, false },
1064 // These identify what tokens can come after expressions in certain cases.
1065 static const BcParseNext bc_parse_next_expr =
1066 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1067 static const BcParseNext bc_parse_next_param =
1068 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1069 static const BcParseNext bc_parse_next_print =
1070 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1071 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1072 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1073 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1074 static const BcParseNext bc_parse_next_read =
1075 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1079 static const BcLexType dc_lex_regs[] = {
1080 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1081 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1082 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1086 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1088 static const BcLexType dc_lex_tokens[] = {
1089 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1090 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1091 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1092 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1093 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1094 BC_LEX_INVALID, BC_LEX_INVALID,
1095 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1096 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1097 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1098 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1099 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1100 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1101 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1102 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1103 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1104 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1105 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1106 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1107 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1108 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1109 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1110 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1111 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1112 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1116 static const BcInst dc_parse_insts[] = {
1117 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1118 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1119 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1120 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1121 BC_INST_INVALID, BC_INST_INVALID,
1122 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1123 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1124 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1125 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1126 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1127 BC_INST_INVALID, BC_INST_INVALID,
1128 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1129 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1130 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1131 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1132 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1133 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1134 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1135 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1136 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1137 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1138 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1139 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1143 static const BcNumBinaryOp bc_program_ops[] = {
1144 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1147 static const char bc_program_stdin_name[] = "<stdin>";
1148 static const char bc_program_ready_msg[] = "ready for more input\n";
1151 static const char *bc_lib_name = "gen/lib.bc";
1153 static const char bc_lib[] = {
1154 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1155 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1156 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1157 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,
1158 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1159 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1160 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,
1161 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1162 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1163 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,
1164 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1165 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1166 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1167 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1168 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1169 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1170 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1171 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1172 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1173 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1174 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1175 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1176 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1177 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,
1178 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1179 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,
1180 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1181 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1182 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1183 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1184 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1185 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,
1186 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1187 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1188 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1189 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1190 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,
1191 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1192 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1193 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1194 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1195 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1196 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1197 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1198 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1199 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1200 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1201 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,
1202 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,
1203 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1204 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,
1205 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,
1206 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,
1207 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1208 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1209 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,
1210 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,
1211 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,
1212 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1213 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,
1214 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1215 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1216 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1217 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,
1218 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1219 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1220 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1221 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1222 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1223 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1224 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1225 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1226 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1227 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1228 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1229 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1230 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1231 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1232 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1233 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1237 static void bc_vec_grow(BcVec *v, size_t n)
1239 size_t cap = v->cap * 2;
1240 while (cap < v->len + n) cap *= 2;
1241 v->v = xrealloc(v->v, v->size * cap);
1245 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1248 v->cap = BC_VEC_START_CAP;
1251 v->v = xmalloc(esize * BC_VEC_START_CAP);
1254 static void bc_vec_expand(BcVec *v, size_t req)
1257 v->v = xrealloc(v->v, v->size * req);
1262 static void bc_vec_npop(BcVec *v, size_t n)
1267 size_t len = v->len - n;
1268 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1272 static void bc_vec_push(BcVec *v, const void *data)
1274 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1275 memmove(v->v + (v->size * v->len), data, v->size);
1279 static void bc_vec_pushByte(BcVec *v, char data)
1281 bc_vec_push(v, &data);
1284 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1287 bc_vec_push(v, data);
1292 if (v->len == v->cap) bc_vec_grow(v, 1);
1294 ptr = v->v + v->size * idx;
1296 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1297 memmove(ptr, data, v->size);
1301 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1303 bc_vec_npop(v, v->len);
1304 bc_vec_expand(v, len + 1);
1305 memcpy(v->v, str, len);
1308 bc_vec_pushByte(v, '\0');
1311 static void bc_vec_concat(BcVec *v, const char *str)
1315 if (v->len == 0) bc_vec_pushByte(v, '\0');
1317 len = v->len + strlen(str);
1319 if (v->cap < len) bc_vec_grow(v, len - v->len);
1325 static void *bc_vec_item(const BcVec *v, size_t idx)
1327 return v->v + v->size * idx;
1330 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1332 return v->v + v->size * (v->len - idx - 1);
1335 static void bc_vec_free(void *vec)
1337 BcVec *v = (BcVec *) vec;
1338 bc_vec_npop(v, v->len);
1342 static size_t bc_map_find(const BcVec *v, const void *ptr)
1344 size_t low = 0, high = v->len;
1346 while (low < high) {
1348 size_t mid = (low + high) / 2;
1349 BcId *id = bc_vec_item(v, mid);
1350 int result = bc_id_cmp(ptr, id);
1354 else if (result < 0)
1363 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1365 BcStatus s = BC_STATUS_SUCCESS;
1367 *i = bc_map_find(v, ptr);
1370 bc_vec_push(v, ptr);
1371 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1372 s = BC_STATUS_VEC_ITEM_EXISTS;
1374 bc_vec_pushAt(v, ptr, *i);
1379 static size_t bc_map_index(const BcVec *v, const void *ptr)
1381 size_t i = bc_map_find(v, ptr);
1382 if (i >= v->len) return BC_VEC_INVALID_IDX;
1383 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1386 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1391 if (bcg.ttyin && !bcg.posix) {
1392 bc_vm_puts(prompt, stderr);
1393 bc_vm_fflush(stderr);
1396 bc_vec_npop(vec, vec->len);
1404 #if ENABLE_FEATURE_BC_SIGNALS
1405 if (errno == EINTR) {
1411 bc_vm_puts(bc_program_ready_msg, stderr);
1412 if (!bcg.posix) bc_vm_puts(prompt, stderr);
1413 bc_vm_fflush(stderr);
1420 return BC_STATUS_IO_ERR;
1423 c = (signed char) i;
1424 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1425 bc_vec_push(vec, &c);
1428 bc_vec_pushByte(vec, '\0');
1430 return BC_STATUS_SUCCESS;
1433 static BcStatus bc_read_file(const char *path, char **buf)
1435 BcStatus s = BC_STATUS_BIN_FILE;
1436 size_t size = ((size_t) -1);
1439 *buf = xmalloc_open_read_close(path, &size);
1441 for (i = 0; i < size; ++i) {
1442 if (BC_READ_BIN_CHAR((*buf)[i]))
1446 return BC_STATUS_SUCCESS;
1453 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1454 static const char bc_args_lopt[] ALIGN1 =
1455 "extended-register\0"No_argument"x"
1456 "warn\0"No_argument"w"
1457 "version\0"No_argument"v"
1458 "standard\0"No_argument"s"
1459 "quiet\0"No_argument"q"
1460 "mathlib\0"No_argument"l"
1461 "interactive\0"No_argument"i";
1464 static const char bc_args_opt[] ALIGN1 = "xwvsqli";
1466 static BcStatus bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1468 BcStatus s = BC_STATUS_SUCCESS;
1470 bool do_exit = false;
1474 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1475 *flags = getopt32long(argv, bc_args_opt, bc_args_lopt);
1477 *flags = getopt32(argv, bc_args_opt);
1480 if ((*flags) & BC_FLAG_V) bc_vm_info(NULL);
1481 if (do_exit) exit((int) s);
1482 if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1484 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1489 static void bc_num_setToZero(BcNum *n, size_t scale)
1496 static void bc_num_zero(BcNum *n)
1498 bc_num_setToZero(n, 0);
1501 static void bc_num_one(BcNum *n)
1503 bc_num_setToZero(n, 0);
1508 static void bc_num_ten(BcNum *n)
1510 bc_num_setToZero(n, 0);
1516 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1520 for (i = 0; !bcg.signe && i < len; ++i) {
1521 for (a[i] -= b[i], j = 0; !bcg.signe && a[i + j] < 0;) {
1526 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1529 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1533 for (i = len - 1; !bcg.signe && i < len && !(c = a[i] - b[i]); --i);
1534 return BC_NUM_NEG(i + 1, c < 0);
1537 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1539 size_t i, min, a_int, b_int, diff;
1540 BcDig *max_num, *min_num;
1541 bool a_max, neg = false;
1544 if (a == b) return 0;
1545 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1546 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1556 a_int = BC_NUM_INT(a);
1557 b_int = BC_NUM_INT(b);
1559 a_max = (a->rdx > b->rdx);
1561 if (a_int != 0) return (ssize_t) a_int;
1565 diff = a->rdx - b->rdx;
1566 max_num = a->num + diff;
1571 diff = b->rdx - a->rdx;
1572 max_num = b->num + diff;
1576 cmp = bc_num_compare(max_num, min_num, b_int + min);
1577 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1579 for (max_num -= diff, i = diff - 1; !bcg.signe && i < diff; --i) {
1580 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1586 static void bc_num_truncate(BcNum *n, size_t places)
1588 if (places == 0) return;
1594 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1598 static void bc_num_extend(BcNum *n, size_t places)
1600 size_t len = n->len + places;
1604 if (n->cap < len) bc_num_expand(n, len);
1606 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1607 memset(n->num, 0, sizeof(BcDig) * places);
1614 static void bc_num_clean(BcNum *n)
1616 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1619 else if (n->len < n->rdx)
1623 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1626 bc_num_extend(n, scale - n->rdx);
1628 bc_num_truncate(n, n->rdx - scale);
1631 if (n->len != 0) n->neg = !neg1 != !neg2;
1634 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1639 b->len = n->len - idx;
1641 a->rdx = b->rdx = 0;
1643 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1644 memcpy(a->num, n->num, idx * sizeof(BcDig));
1655 static BcStatus bc_num_shift(BcNum *n, size_t places)
1657 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1658 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1660 if (n->rdx >= places)
1663 bc_num_extend(n, places - n->rdx);
1669 return BC_STATUS_SUCCESS;
1672 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1681 return bc_num_div(&one, a, b, scale);
1684 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1686 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1687 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1690 // Because this function doesn't need to use scale (per the bc spec),
1691 // I am hijacking it to say whether it's doing an add or a subtract.
1695 if (sub && c->len) c->neg = !c->neg;
1696 return BC_STATUS_SUCCESS;
1698 else if (b->len == 0) {
1700 return BC_STATUS_SUCCESS;
1704 c->rdx = BC_MAX(a->rdx, b->rdx);
1705 min_rdx = BC_MIN(a->rdx, b->rdx);
1708 if (a->rdx > b->rdx) {
1709 diff = a->rdx - b->rdx;
1711 ptr_a = a->num + diff;
1715 diff = b->rdx - a->rdx;
1718 ptr_b = b->num + diff;
1721 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1724 a_int = BC_NUM_INT(a);
1725 b_int = BC_NUM_INT(b);
1727 if (a_int > b_int) {
1738 for (carry = 0, i = 0; !bcg.signe && i < min_rdx + min_int; ++i, ++c->len) {
1739 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1741 ptr_c[i] = (BcDig)(in % 10);
1744 for (; !bcg.signe && i < max + min_rdx; ++i, ++c->len) {
1745 in = ((int) ptr[i]) + carry;
1747 ptr_c[i] = (BcDig)(in % 10);
1750 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1752 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1755 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1759 BcNum *minuend, *subtrahend;
1761 bool aneg, bneg, neg;
1763 // Because this function doesn't need to use scale (per the bc spec),
1764 // I am hijacking it to say whether it's doing an add or a subtract.
1768 if (sub && c->len) c->neg = !c->neg;
1769 return BC_STATUS_SUCCESS;
1771 else if (b->len == 0) {
1773 return BC_STATUS_SUCCESS;
1778 a->neg = b->neg = false;
1780 cmp = bc_num_cmp(a, b);
1786 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1787 return BC_STATUS_SUCCESS;
1796 if (sub) neg = !neg;
1801 bc_num_copy(c, minuend);
1804 if (c->rdx < subtrahend->rdx) {
1805 bc_num_extend(c, subtrahend->rdx - c->rdx);
1809 start = c->rdx - subtrahend->rdx;
1811 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1818 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1823 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1824 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1825 bool aone = BC_NUM_ONE(a);
1827 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
1828 if (a->len == 0 || b->len == 0) {
1830 return BC_STATUS_SUCCESS;
1832 else if (aone || BC_NUM_ONE(b)) {
1833 bc_num_copy(c, aone ? b : a);
1834 return BC_STATUS_SUCCESS;
1837 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1838 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1840 bc_num_expand(c, a->len + b->len + 1);
1842 memset(c->num, 0, sizeof(BcDig) * c->cap);
1843 c->len = carry = len = 0;
1845 for (i = 0; !bcg.signe && i < b->len; ++i) {
1847 for (j = 0; !bcg.signe && j < a->len; ++j) {
1848 int in = (int) c->num[i + j];
1849 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1851 c->num[i + j] = (BcDig)(in % 10);
1854 c->num[i + j] += (BcDig) carry;
1855 len = BC_MAX(len, i + j + !!carry);
1861 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1864 bc_num_init(&l1, max);
1865 bc_num_init(&h1, max);
1866 bc_num_init(&l2, max);
1867 bc_num_init(&h2, max);
1868 bc_num_init(&m1, max);
1869 bc_num_init(&m2, max);
1870 bc_num_init(&z0, max);
1871 bc_num_init(&z1, max);
1872 bc_num_init(&z2, max);
1873 bc_num_init(&temp, max + max);
1875 bc_num_split(a, max2, &l1, &h1);
1876 bc_num_split(b, max2, &l2, &h2);
1878 s = bc_num_add(&h1, &l1, &m1, 0);
1880 s = bc_num_add(&h2, &l2, &m2, 0);
1883 s = bc_num_k(&h1, &h2, &z0);
1885 s = bc_num_k(&m1, &m2, &z1);
1887 s = bc_num_k(&l1, &l2, &z2);
1890 s = bc_num_sub(&z1, &z0, &temp, 0);
1892 s = bc_num_sub(&temp, &z2, &z1, 0);
1895 s = bc_num_shift(&z0, max2 * 2);
1897 s = bc_num_shift(&z1, max2);
1899 s = bc_num_add(&z0, &z1, &temp, 0);
1901 s = bc_num_add(&temp, &z2, c, 0);
1917 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1921 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1923 scale = BC_MAX(scale, a->rdx);
1924 scale = BC_MAX(scale, b->rdx);
1925 scale = BC_MIN(a->rdx + b->rdx, scale);
1926 maxrdx = BC_MAX(maxrdx, scale);
1928 bc_num_init(&cpa, a->len);
1929 bc_num_init(&cpb, b->len);
1931 bc_num_copy(&cpa, a);
1932 bc_num_copy(&cpb, b);
1933 cpa.neg = cpb.neg = false;
1935 s = bc_num_shift(&cpa, maxrdx);
1937 s = bc_num_shift(&cpb, maxrdx);
1939 s = bc_num_k(&cpa, &cpb, c);
1943 bc_num_expand(c, c->len + maxrdx);
1945 if (c->len < maxrdx) {
1946 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1951 bc_num_retireMul(c, scale, a->neg, b->neg);
1959 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1961 BcStatus s = BC_STATUS_SUCCESS;
1968 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1969 else if (a->len == 0) {
1970 bc_num_setToZero(c, scale);
1971 return BC_STATUS_SUCCESS;
1973 else if (BC_NUM_ONE(b)) {
1975 bc_num_retireMul(c, scale, a->neg, b->neg);
1976 return BC_STATUS_SUCCESS;
1979 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1980 bc_num_copy(&cp, a);
1984 bc_num_expand(&cp, len + 2);
1985 bc_num_extend(&cp, len - cp.len);
1988 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1990 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1992 if (b->rdx == b->len) {
1993 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1997 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1999 // We want an extra zero in front to make things simpler.
2000 cp.num[cp.len++] = 0;
2003 bc_num_expand(c, cp.len);
2006 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
2011 for (i = end - 1; !bcg.signe && !s && i < end; --i) {
2013 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
2014 s = bc_num_subArrays(n, p, len);
2018 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
2024 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
2025 BcNum *restrict d, size_t scale, size_t ts)
2031 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2034 bc_num_setToZero(d, ts);
2035 return BC_STATUS_SUCCESS;
2038 bc_num_init(&temp, d->cap);
2039 bc_num_d(a, b, c, scale);
2041 if (scale != 0) scale = ts;
2043 s = bc_num_m(c, b, &temp, scale);
2045 s = bc_num_sub(a, &temp, d, scale);
2048 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2051 bc_num_retireMul(d, ts, a->neg, b->neg);
2059 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2063 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2065 bc_num_init(&c1, len);
2066 s = bc_num_r(a, b, &c1, c, scale, ts);
2072 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2074 BcStatus s = BC_STATUS_SUCCESS;
2077 size_t i, powrdx, resrdx;
2080 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2084 return BC_STATUS_SUCCESS;
2086 else if (a->len == 0) {
2087 bc_num_setToZero(c, scale);
2088 return BC_STATUS_SUCCESS;
2090 else if (BC_NUM_ONE(b)) {
2094 s = bc_num_inv(a, c, scale);
2101 s = bc_num_ulong(b, &pow);
2104 bc_num_init(©, a->len);
2105 bc_num_copy(©, a);
2107 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2111 for (powrdx = a->rdx; !bcg.signe && !(pow & 1); pow >>= 1) {
2113 s = bc_num_mul(©, ©, ©, powrdx);
2118 s = BC_STATUS_EXEC_SIGNAL;
2122 bc_num_copy(c, ©);
2124 for (resrdx = powrdx, pow >>= 1; !bcg.signe && pow != 0; pow >>= 1) {
2127 s = bc_num_mul(©, ©, ©, powrdx);
2132 s = bc_num_mul(c, ©, c, resrdx);
2138 s = bc_num_inv(c, c, scale);
2143 s = BC_STATUS_EXEC_SIGNAL;
2147 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2149 // We can't use bc_num_clean() here.
2150 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2151 if (zero) bc_num_setToZero(c, scale);
2158 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2159 BcNumBinaryOp op, size_t req)
2162 BcNum num2, *ptr_a, *ptr_b;
2167 memcpy(ptr_a, c, sizeof(BcNum));
2176 memcpy(ptr_b, c, sizeof(BcNum));
2184 bc_num_init(c, req);
2186 bc_num_expand(c, req);
2188 s = op(ptr_a, ptr_b, c, scale);
2190 if (init) bc_num_free(&num2);
2195 static bool bc_num_strValid(const char *val, size_t base)
2198 bool small, radix = false;
2199 size_t i, len = strlen(val);
2201 if (!len) return true;
2204 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2206 for (i = 0; i < len; ++i) {
2212 if (radix) return false;
2218 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2225 static void bc_num_parseDecimal(BcNum *n, const char *val)
2231 for (i = 0; val[i] == '0'; ++i);
2238 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2239 bc_num_expand(n, len);
2242 ptr = strchr(val, '.');
2244 // Explicitly test for NULL here to produce either a 0 or 1.
2245 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2248 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2249 n->num[n->len] = val[i] - '0';
2253 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2256 BcNum temp, mult, result;
2260 size_t i, digits, len = strlen(val);
2264 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2267 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2268 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2270 for (i = 0; i < len; ++i) {
2273 if (c == '.') break;
2275 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2277 s = bc_num_mul(n, base, &mult, 0);
2278 if (s) goto int_err;
2279 s = bc_num_ulong2num(&temp, v);
2280 if (s) goto int_err;
2281 s = bc_num_add(&mult, &temp, n, 0);
2282 if (s) goto int_err;
2287 if (c == 0) goto int_err;
2290 bc_num_init(&result, base->len);
2291 bc_num_zero(&result);
2294 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2299 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2301 s = bc_num_mul(&result, base, &result, 0);
2303 s = bc_num_ulong2num(&temp, v);
2305 s = bc_num_add(&result, &temp, &result, 0);
2307 s = bc_num_mul(&mult, base, &mult, 0);
2311 s = bc_num_div(&result, &mult, &result, digits);
2313 s = bc_num_add(n, &result, n, digits);
2317 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2323 bc_num_free(&result);
2329 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2331 if (*nchars == line_len - 1) {
2332 bc_vm_putchar('\\');
2333 bc_vm_putchar('\n');
2339 static void bc_num_printChar(size_t num, size_t width, bool radix,
2340 size_t *nchars, size_t line_len)
2342 (void) radix, (void) line_len;
2343 bc_vm_putchar((char) num);
2344 *nchars = *nchars + width;
2348 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2349 size_t *nchars, size_t line_len)
2353 bc_num_printNewline(nchars, line_len);
2354 bc_vm_putchar(radix ? '.' : ' ');
2357 bc_num_printNewline(nchars, line_len);
2358 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2361 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2363 bc_num_printNewline(nchars, line_len);
2366 bc_vm_putchar(((char) dig) + '0');
2370 static void bc_num_printHex(size_t num, size_t width, bool radix,
2371 size_t *nchars, size_t line_len)
2374 bc_num_printNewline(nchars, line_len);
2379 bc_num_printNewline(nchars, line_len);
2380 bc_vm_putchar(bb_hexdigits_upcase[num]);
2381 *nchars = *nchars + width;
2384 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2386 size_t i, rdx = n->rdx - 1;
2388 if (n->neg) bc_vm_putchar('-');
2389 (*nchars) += n->neg;
2391 for (i = n->len - 1; i < n->len; --i)
2392 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2395 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2396 size_t *nchars, size_t len, BcNumDigitOp print)
2400 BcNum intp, fracp, digit, frac_len;
2401 unsigned long dig, *ptr;
2406 print(0, width, false, nchars, len);
2407 return BC_STATUS_SUCCESS;
2410 bc_vec_init(&stack, sizeof(long), NULL);
2411 bc_num_init(&intp, n->len);
2412 bc_num_init(&fracp, n->rdx);
2413 bc_num_init(&digit, width);
2414 bc_num_init(&frac_len, BC_NUM_INT(n));
2415 bc_num_copy(&intp, n);
2416 bc_num_one(&frac_len);
2418 bc_num_truncate(&intp, intp.rdx);
2419 s = bc_num_sub(n, &intp, &fracp, 0);
2422 while (intp.len != 0) {
2423 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2425 s = bc_num_ulong(&digit, &dig);
2427 bc_vec_push(&stack, &dig);
2430 for (i = 0; i < stack.len; ++i) {
2431 ptr = bc_vec_item_rev(&stack, i);
2432 print(*ptr, width, false, nchars, len);
2435 if (!n->rdx) goto err;
2437 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2438 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2440 s = bc_num_ulong(&fracp, &dig);
2442 s = bc_num_ulong2num(&intp, dig);
2444 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2446 print(dig, width, radix, nchars, len);
2447 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2452 bc_num_free(&frac_len);
2453 bc_num_free(&digit);
2454 bc_num_free(&fracp);
2456 bc_vec_free(&stack);
2460 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2461 size_t *nchars, size_t line_len)
2468 if (neg) bc_vm_putchar('-');
2473 if (base_t <= BC_NUM_MAX_IBASE) {
2475 print = bc_num_printHex;
2478 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2479 print = bc_num_printDigits;
2482 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2489 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2491 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2495 static void bc_num_init(BcNum *n, size_t req)
2497 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2498 memset(n, 0, sizeof(BcNum));
2499 n->num = xmalloc(req);
2503 static void bc_num_expand(BcNum *n, size_t req)
2505 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2507 n->num = xrealloc(n->num, req);
2512 static void bc_num_free(void *num)
2514 free(((BcNum *) num)->num);
2517 static void bc_num_copy(BcNum *d, BcNum *s)
2520 bc_num_expand(d, s->cap);
2524 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2528 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2531 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2534 bc_num_parseDecimal(n, val);
2536 bc_num_parseBase(n, val, base);
2538 return BC_STATUS_SUCCESS;
2541 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2542 size_t *nchars, size_t line_len)
2544 BcStatus s = BC_STATUS_SUCCESS;
2546 bc_num_printNewline(nchars, line_len);
2552 else if (base_t == 10)
2553 bc_num_printDecimal(n, nchars, line_len);
2555 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2558 bc_vm_putchar('\n');
2565 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2570 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2572 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2574 unsigned long prev = *result, powprev = pow;
2576 *result += ((unsigned long) n->num[i]) * pow;
2579 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2582 return BC_STATUS_SUCCESS;
2585 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2593 if (val == 0) return BC_STATUS_SUCCESS;
2595 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2596 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2598 return BC_STATUS_SUCCESS;
2601 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2603 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2605 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2608 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2610 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2612 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2615 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2617 size_t req = BC_NUM_MREQ(a, b, scale);
2618 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2621 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2623 size_t req = BC_NUM_MREQ(a, b, scale);
2624 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2627 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2629 size_t req = BC_NUM_MREQ(a, b, scale);
2630 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2633 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2635 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2638 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2641 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2642 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2643 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2645 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2646 bc_num_expand(b, req);
2649 bc_num_setToZero(b, scale);
2650 return BC_STATUS_SUCCESS;
2653 return BC_STATUS_MATH_NEGATIVE;
2654 else if (BC_NUM_ONE(a)) {
2656 bc_num_extend(b, scale);
2657 return BC_STATUS_SUCCESS;
2660 scale = BC_MAX(scale, a->rdx) + 1;
2661 len = a->len + scale;
2663 bc_num_init(&num1, len);
2664 bc_num_init(&num2, len);
2665 bc_num_init(&half, BC_NUM_DEF_SIZE);
2671 bc_num_init(&f, len);
2672 bc_num_init(&fprime, len);
2678 pow = BC_NUM_INT(a);
2687 pow -= 2 - (pow & 1);
2689 bc_num_extend(x0, pow);
2691 // Make sure to move the radix back.
2695 x0->rdx = digs = digs1 = 0;
2697 len = BC_NUM_INT(x0) + resrdx - 1;
2699 while (!bcg.signe && (cmp != 0 || digs < len)) {
2701 s = bc_num_div(a, x0, &f, resrdx);
2703 s = bc_num_add(x0, &f, &fprime, resrdx);
2705 s = bc_num_mul(&fprime, &half, x1, resrdx);
2708 cmp = bc_num_cmp(x1, x0);
2709 digs = x1->len - (unsigned long long) llabs(cmp);
2711 if (cmp == cmp2 && digs == digs1)
2716 resrdx += times > 4;
2728 s = BC_STATUS_EXEC_SIGNAL;
2734 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2737 bc_num_free(&fprime);
2745 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2751 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2754 memcpy(&num2, c, sizeof(BcNum));
2756 bc_num_init(c, len);
2761 bc_num_expand(c, len);
2764 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2766 if (init) bc_num_free(&num2);
2772 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2775 BcNum base, exp, two, temp;
2777 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2778 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2779 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2781 bc_num_expand(d, c->len);
2782 bc_num_init(&base, c->len);
2783 bc_num_init(&exp, b->len);
2784 bc_num_init(&two, BC_NUM_DEF_SIZE);
2785 bc_num_init(&temp, b->len);
2791 s = bc_num_rem(a, c, &base, 0);
2793 bc_num_copy(&exp, b);
2795 while (exp.len != 0) {
2797 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2800 if (BC_NUM_ONE(&temp)) {
2801 s = bc_num_mul(d, &base, &temp, 0);
2803 s = bc_num_rem(&temp, c, d, 0);
2807 s = bc_num_mul(&base, &base, &temp, 0);
2809 s = bc_num_rem(&temp, c, &base, 0);
2822 static int bc_id_cmp(const void *e1, const void *e2)
2824 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2827 static void bc_id_free(void *id)
2829 free(((BcId *) id)->name);
2832 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2837 for (i = 0; i < f->autos.len; ++i) {
2838 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2839 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2845 bc_vec_push(&f->autos, &a);
2847 return BC_STATUS_SUCCESS;
2850 static void bc_func_init(BcFunc *f)
2852 bc_vec_init(&f->code, sizeof(char), NULL);
2853 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2854 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2858 static void bc_func_free(void *func)
2860 BcFunc *f = (BcFunc *) func;
2861 bc_vec_free(&f->code);
2862 bc_vec_free(&f->autos);
2863 bc_vec_free(&f->labels);
2866 static void bc_array_init(BcVec *a, bool nums)
2869 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2871 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2872 bc_array_expand(a, 1);
2875 static void bc_array_copy(BcVec *d, const BcVec *s)
2879 bc_vec_npop(d, d->len);
2880 bc_vec_expand(d, s->cap);
2883 for (i = 0; i < s->len; ++i) {
2884 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2885 bc_num_init(dnum, snum->len);
2886 bc_num_copy(dnum, snum);
2890 static void bc_array_expand(BcVec *a, size_t len)
2894 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2895 while (len > a->len) {
2896 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2897 bc_vec_push(a, &data.n);
2901 while (len > a->len) {
2902 bc_array_init(&data.v, true);
2903 bc_vec_push(a, &data.v);
2908 static void bc_string_free(void *string)
2910 free(*((char **) string));
2914 static void bc_result_copy(BcResult *d, BcResult *src)
2920 case BC_RESULT_TEMP:
2921 case BC_RESULT_IBASE:
2922 case BC_RESULT_SCALE:
2923 case BC_RESULT_OBASE:
2925 bc_num_init(&d->d.n, src->d.n.len);
2926 bc_num_copy(&d->d.n, &src->d.n);
2931 case BC_RESULT_ARRAY:
2932 case BC_RESULT_ARRAY_ELEM:
2934 d->d.id.name = xstrdup(src->d.id.name);
2938 case BC_RESULT_CONSTANT:
2939 case BC_RESULT_LAST:
2943 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2950 static void bc_result_free(void *result)
2952 BcResult *r = (BcResult *) result;
2956 case BC_RESULT_TEMP:
2957 case BC_RESULT_IBASE:
2958 case BC_RESULT_SCALE:
2959 case BC_RESULT_OBASE:
2961 bc_num_free(&r->d.n);
2966 case BC_RESULT_ARRAY:
2967 case BC_RESULT_ARRAY_ELEM:
2981 static void bc_lex_lineComment(BcLex *l)
2983 l->t.t = BC_LEX_WHITESPACE;
2984 while (l->i < l->len && l->buf[l->i++] != '\n');
2988 static void bc_lex_whitespace(BcLex *l)
2991 l->t.t = BC_LEX_WHITESPACE;
2992 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2995 static BcStatus bc_lex_number(BcLex *l, char start)
2997 const char *buf = l->buf + l->i;
2998 size_t len, hits = 0, bslashes = 0, i = 0, j;
3000 bool last_pt, pt = start == '.';
3003 l->t.t = BC_LEX_NUMBER;
3005 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
3006 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
3020 len = i + 1 * !last_pt - bslashes * 2;
3021 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
3023 bc_vec_npop(&l->t.v, l->t.v.len);
3024 bc_vec_expand(&l->t.v, len + 1);
3025 bc_vec_push(&l->t.v, &start);
3027 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
3031 // If we have hit a backslash, skip it. We don't have
3032 // to check for a newline because it's guaranteed.
3033 if (hits < bslashes && c == '\\') {
3039 bc_vec_push(&l->t.v, &c);
3042 bc_vec_pushByte(&l->t.v, '\0');
3045 return BC_STATUS_SUCCESS;
3048 static BcStatus bc_lex_name(BcLex *l)
3051 const char *buf = l->buf + l->i - 1;
3054 l->t.t = BC_LEX_NAME;
3056 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3058 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3059 bc_vec_string(&l->t.v, i, buf);
3061 // Increment the index. We minus 1 because it has already been incremented.
3064 return BC_STATUS_SUCCESS;
3067 static void bc_lex_init(BcLex *l, BcLexNext next)
3070 bc_vec_init(&l->t.v, sizeof(char), NULL);
3073 static void bc_lex_free(BcLex *l)
3075 bc_vec_free(&l->t.v);
3078 static void bc_lex_file(BcLex *l, const char *file)
3085 static BcStatus bc_lex_next(BcLex *l)
3090 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3092 l->line += l->newline;
3093 l->t.t = BC_LEX_EOF;
3095 l->newline = (l->i == l->len);
3096 if (l->newline) return BC_STATUS_SUCCESS;
3098 // Loop until failure or we don't have whitespace. This
3099 // is so the parser doesn't get inundated with whitespace.
3102 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3107 static BcStatus bc_lex_text(BcLex *l, const char *text)
3111 l->len = strlen(text);
3112 l->t.t = l->t.last = BC_LEX_INVALID;
3113 return bc_lex_next(l);
3117 static BcStatus bc_lex_identifier(BcLex *l)
3121 const char *buf = l->buf + l->i - 1;
3123 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3125 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3127 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3129 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3131 if (!bc_lex_kws[i].posix) {
3132 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3133 bc_lex_kws[i].name);
3137 // We minus 1 because the index has already been incremented.
3139 return BC_STATUS_SUCCESS;
3146 if (l->t.v.len - 1 > 1)
3147 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3152 static BcStatus bc_lex_string(BcLex *l)
3154 size_t len, nls = 0, i = l->i;
3157 l->t.t = BC_LEX_STR;
3159 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3163 return BC_STATUS_LEX_NO_STRING_END;
3167 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3168 bc_vec_string(&l->t.v, len, l->buf + l->i);
3173 return BC_STATUS_SUCCESS;
3176 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3178 if (l->buf[l->i] == '=') {
3186 static BcStatus bc_lex_comment(BcLex *l)
3189 const char *buf = l->buf;
3193 l->t.t = BC_LEX_WHITESPACE;
3195 for (i = ++l->i; !end; i += !end) {
3197 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3199 if (c == 0 || buf[i + 1] == '\0') {
3201 return BC_STATUS_LEX_NO_COMMENT_END;
3204 end = buf[i + 1] == '/';
3210 return BC_STATUS_SUCCESS;
3213 static BcStatus bc_lex_token(BcLex *l)
3215 BcStatus s = BC_STATUS_SUCCESS;
3216 char c = l->buf[l->i++], c2;
3218 // This is the workhorse of the lexer.
3225 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3235 bc_lex_whitespace(l);
3241 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3243 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3244 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3253 s = bc_lex_string(l);
3259 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3262 bc_lex_lineComment(l);
3269 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3278 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3282 l->t.t = BC_LEX_OP_BOOL_AND;
3285 l->t.t = BC_LEX_INVALID;
3286 s = BC_STATUS_LEX_BAD_CHAR;
3295 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3301 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3310 l->t.t = BC_LEX_OP_INC;
3313 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3319 l->t.t = BC_LEX_COMMA;
3328 l->t.t = BC_LEX_OP_DEC;
3331 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3337 if (isdigit(l->buf[l->i]))
3338 s = bc_lex_number(l, c);
3340 l->t.t = BC_LEX_KEY_LAST;
3341 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3350 s = bc_lex_comment(l);
3352 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3373 s = bc_lex_number(l, c);
3379 l->t.t = BC_LEX_SCOLON;
3385 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3391 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3397 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3404 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3410 if (l->buf[l->i] == '\n') {
3411 l->t.t = BC_LEX_WHITESPACE;
3415 s = BC_STATUS_LEX_BAD_CHAR;
3421 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3452 s = bc_lex_identifier(l);
3459 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3469 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3473 l->t.t = BC_LEX_OP_BOOL_OR;
3476 l->t.t = BC_LEX_INVALID;
3477 s = BC_STATUS_LEX_BAD_CHAR;
3485 l->t.t = BC_LEX_INVALID;
3486 s = BC_STATUS_LEX_BAD_CHAR;
3496 static BcStatus dc_lex_register(BcLex *l)
3498 BcStatus s = BC_STATUS_SUCCESS;
3500 if (isspace(l->buf[l->i - 1])) {
3501 bc_lex_whitespace(l);
3504 s = BC_STATUS_LEX_EXTENDED_REG;
3509 bc_vec_npop(&l->t.v, l->t.v.len);
3510 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3511 bc_vec_pushByte(&l->t.v, '\0');
3512 l->t.t = BC_LEX_NAME;
3518 static BcStatus dc_lex_string(BcLex *l)
3520 size_t depth = 1, nls = 0, i = l->i;
3523 l->t.t = BC_LEX_STR;
3524 bc_vec_npop(&l->t.v, l->t.v.len);
3526 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3528 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3529 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3532 if (depth) bc_vec_push(&l->t.v, &c);
3537 return BC_STATUS_LEX_NO_STRING_END;
3540 bc_vec_pushByte(&l->t.v, '\0');
3541 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3546 return BC_STATUS_SUCCESS;
3549 static BcStatus dc_lex_token(BcLex *l)
3551 BcStatus s = BC_STATUS_SUCCESS;
3552 char c = l->buf[l->i++], c2;
3555 for (i = 0; i < dc_lex_regs_len; ++i) {
3556 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3559 if (c >= '%' && c <= '~' &&
3560 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3565 // This is the workhorse of the lexer.
3570 l->t.t = BC_LEX_EOF;
3581 l->newline = (c == '\n');
3582 bc_lex_whitespace(l);
3591 l->t.t = BC_LEX_OP_REL_NE;
3593 l->t.t = BC_LEX_OP_REL_LE;
3595 l->t.t = BC_LEX_OP_REL_GE;
3597 return BC_STATUS_LEX_BAD_CHAR;
3605 bc_lex_lineComment(l);
3611 if (isdigit(l->buf[l->i]))
3612 s = bc_lex_number(l, c);
3614 s = BC_STATUS_LEX_BAD_CHAR;
3635 s = bc_lex_number(l, c);
3641 s = dc_lex_string(l);
3647 l->t.t = BC_LEX_INVALID;
3648 s = BC_STATUS_LEX_BAD_CHAR;
3657 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3659 bc_program_addFunc(p->prog, name, idx);
3660 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3663 static void bc_parse_pushName(BcParse *p, char *name)
3665 size_t i = 0, len = strlen(name);
3667 for (; i < len; ++i) bc_parse_push(p, name[i]);
3668 bc_parse_push(p, BC_PARSE_STREND);
3673 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3675 unsigned char amt, i, nums[sizeof(size_t)];
3677 for (amt = 0; idx; ++amt) {
3678 nums[amt] = (char) idx;
3679 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3682 bc_parse_push(p, amt);
3683 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3686 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3688 char *num = xstrdup(p->l.t.v.v);
3689 size_t idx = p->prog->consts.len;
3691 bc_vec_push(&p->prog->consts, &num);
3693 bc_parse_push(p, BC_INST_NUM);
3694 bc_parse_pushIndex(p, idx);
3697 (*prev) = BC_INST_NUM;
3700 static BcStatus bc_parse_text(BcParse *p, const char *text)
3704 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3706 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3707 p->l.t.t = BC_LEX_INVALID;
3710 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3713 return bc_lex_text(&p->l, text);
3716 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3718 if (p->fidx != BC_PROG_MAIN) {
3720 p->func->nparams = 0;
3721 bc_vec_npop(&p->func->code, p->func->code.len);
3722 bc_vec_npop(&p->func->autos, p->func->autos.len);
3723 bc_vec_npop(&p->func->labels, p->func->labels.len);
3725 bc_parse_updateFunc(p, BC_PROG_MAIN);
3729 p->l.t.t = BC_LEX_EOF;
3730 p->auto_part = (p->nbraces = 0);
3732 bc_vec_npop(&p->flags, p->flags.len - 1);
3733 bc_vec_npop(&p->exits, p->exits.len);
3734 bc_vec_npop(&p->conds, p->conds.len);
3735 bc_vec_npop(&p->ops, p->ops.len);
3737 return bc_program_reset(p->prog, s);
3740 static void bc_parse_free(BcParse *p)
3742 bc_vec_free(&p->flags);
3743 bc_vec_free(&p->exits);
3744 bc_vec_free(&p->conds);
3745 bc_vec_free(&p->ops);
3749 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3750 BcParseParse parse, BcLexNext next)
3752 memset(p, 0, sizeof(BcParse));
3754 bc_lex_init(&p->l, next);
3755 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3756 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3757 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3758 bc_vec_pushByte(&p->flags, 0);
3759 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3763 p->auto_part = (p->nbraces = 0);
3764 bc_parse_updateFunc(p, func);
3768 static BcStatus bc_parse_else(BcParse *p);
3769 static BcStatus bc_parse_stmt(BcParse *p);
3771 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3772 size_t *nexprs, bool next)
3774 BcStatus s = BC_STATUS_SUCCESS;
3776 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3777 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3779 while (p->ops.len > start) {
3781 t = BC_PARSE_TOP_OP(p);
3782 if (t == BC_LEX_LPAREN) break;
3784 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3785 if (l >= r && (l != r || !left)) break;
3787 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3788 bc_vec_pop(&p->ops);
3789 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3792 bc_vec_push(&p->ops, &type);
3793 if (next) s = bc_lex_next(&p->l);
3798 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3802 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3803 top = BC_PARSE_TOP_OP(p);
3805 while (top != BC_LEX_LPAREN) {
3807 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3809 bc_vec_pop(&p->ops);
3810 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3812 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3813 top = BC_PARSE_TOP_OP(p);
3816 bc_vec_pop(&p->ops);
3818 return bc_lex_next(&p->l);
3821 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3827 s = bc_lex_next(&p->l);
3830 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3832 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3833 s = bc_parse_expr(p, flags, bc_parse_next_param);
3836 comma = p->l.t.t == BC_LEX_COMMA;
3838 s = bc_lex_next(&p->l);
3843 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3844 bc_parse_push(p, BC_INST_CALL);
3845 bc_parse_pushIndex(p, nparams);
3847 return BC_STATUS_SUCCESS;
3850 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3853 BcId entry, *entry_ptr;
3858 s = bc_parse_params(p, flags);
3861 if (p->l.t.t != BC_LEX_RPAREN) {
3862 s = BC_STATUS_PARSE_BAD_TOKEN;
3866 idx = bc_map_index(&p->prog->fn_map, &entry);
3868 if (idx == BC_VEC_INVALID_IDX) {
3869 name = xstrdup(entry.name);
3870 bc_parse_addFunc(p, name, &idx);
3871 idx = bc_map_index(&p->prog->fn_map, &entry);
3877 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3878 bc_parse_pushIndex(p, entry_ptr->idx);
3880 return bc_lex_next(&p->l);
3887 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3892 name = xstrdup(p->l.t.v.v);
3893 s = bc_lex_next(&p->l);
3896 if (p->l.t.t == BC_LEX_LBRACKET) {
3898 s = bc_lex_next(&p->l);
3901 if (p->l.t.t == BC_LEX_RBRACKET) {
3903 if (!(flags & BC_PARSE_ARRAY)) {
3904 s = BC_STATUS_PARSE_BAD_EXP;
3908 *type = BC_INST_ARRAY;
3912 *type = BC_INST_ARRAY_ELEM;
3914 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3915 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3919 s = bc_lex_next(&p->l);
3921 bc_parse_push(p, *type);
3922 bc_parse_pushName(p, name);
3924 else if (p->l.t.t == BC_LEX_LPAREN) {
3926 if (flags & BC_PARSE_NOCALL) {
3927 s = BC_STATUS_PARSE_BAD_TOKEN;
3931 *type = BC_INST_CALL;
3932 s = bc_parse_call(p, name, flags);
3935 *type = BC_INST_VAR;
3936 bc_parse_push(p, BC_INST_VAR);
3937 bc_parse_pushName(p, name);
3947 static BcStatus bc_parse_read(BcParse *p)
3951 s = bc_lex_next(&p->l);
3953 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3955 s = bc_lex_next(&p->l);
3957 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3959 bc_parse_push(p, BC_INST_READ);
3961 return bc_lex_next(&p->l);
3964 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3969 s = bc_lex_next(&p->l);
3971 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3973 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3975 s = bc_lex_next(&p->l);
3978 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3981 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3983 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3984 bc_parse_push(p, *prev);
3986 return bc_lex_next(&p->l);
3989 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3993 s = bc_lex_next(&p->l);
3996 if (p->l.t.t != BC_LEX_LPAREN) {
3997 *type = BC_INST_SCALE;
3998 bc_parse_push(p, BC_INST_SCALE);
3999 return BC_STATUS_SUCCESS;
4002 *type = BC_INST_SCALE_FUNC;
4003 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
4005 s = bc_lex_next(&p->l);
4008 s = bc_parse_expr(p, flags, bc_parse_next_rel);
4010 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4011 bc_parse_push(p, BC_INST_SCALE_FUNC);
4013 return bc_lex_next(&p->l);
4016 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
4017 size_t *nexprs, uint8_t flags)
4022 BcInst etype = *prev;
4024 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
4025 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
4026 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
4028 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
4029 bc_parse_push(p, inst);
4030 s = bc_lex_next(&p->l);
4034 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
4037 s = bc_lex_next(&p->l);
4041 // Because we parse the next part of the expression
4042 // right here, we need to increment this.
4043 *nexprs = *nexprs + 1;
4049 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4053 case BC_LEX_KEY_IBASE:
4054 case BC_LEX_KEY_LAST:
4055 case BC_LEX_KEY_OBASE:
4057 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4058 s = bc_lex_next(&p->l);
4062 case BC_LEX_KEY_SCALE:
4064 s = bc_lex_next(&p->l);
4066 if (p->l.t.t == BC_LEX_LPAREN)
4067 s = BC_STATUS_PARSE_BAD_TOKEN;
4069 bc_parse_push(p, BC_INST_SCALE);
4075 s = BC_STATUS_PARSE_BAD_TOKEN;
4080 if (!s) bc_parse_push(p, inst);
4086 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4087 bool rparen, size_t *nexprs)
4091 BcInst etype = *prev;
4093 s = bc_lex_next(&p->l);
4096 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4097 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4100 *prev = BC_PARSE_TOKEN_INST(type);
4102 // We can just push onto the op stack because this is the largest
4103 // precedence operator that gets pushed. Inc/dec does not.
4104 if (type != BC_LEX_OP_MINUS)
4105 bc_vec_push(&p->ops, &type);
4107 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4112 static BcStatus bc_parse_string(BcParse *p, char inst)
4114 char *str = xstrdup(p->l.t.v.v);
4116 bc_parse_push(p, BC_INST_STR);
4117 bc_parse_pushIndex(p, p->prog->strs.len);
4118 bc_vec_push(&p->prog->strs, &str);
4119 bc_parse_push(p, inst);
4121 return bc_lex_next(&p->l);
4124 static BcStatus bc_parse_print(BcParse *p)
4130 s = bc_lex_next(&p->l);
4135 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4136 return BC_STATUS_PARSE_BAD_PRINT;
4138 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4140 if (type == BC_LEX_STR)
4141 s = bc_parse_string(p, BC_INST_PRINT_POP);
4143 s = bc_parse_expr(p, 0, bc_parse_next_print);
4145 bc_parse_push(p, BC_INST_PRINT_POP);
4150 comma = p->l.t.t == BC_LEX_COMMA;
4151 if (comma) s = bc_lex_next(&p->l);
4156 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4158 return bc_lex_next(&p->l);
4161 static BcStatus bc_parse_return(BcParse *p)
4167 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4169 s = bc_lex_next(&p->l);
4173 paren = t == BC_LEX_LPAREN;
4175 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4176 bc_parse_push(p, BC_INST_RET0);
4179 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4180 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4182 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4183 bc_parse_push(p, BC_INST_RET0);
4184 s = bc_lex_next(&p->l);
4188 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4189 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4193 bc_parse_push(p, BC_INST_RET);
4199 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4201 BcStatus s = BC_STATUS_SUCCESS;
4203 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4204 return BC_STATUS_PARSE_BAD_TOKEN;
4208 if (p->l.t.t == BC_LEX_RBRACE) {
4209 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4211 s = bc_lex_next(&p->l);
4215 return BC_STATUS_PARSE_BAD_TOKEN;
4218 if (BC_PARSE_IF(p)) {
4222 while (p->l.t.t == BC_LEX_NLINE) {
4223 s = bc_lex_next(&p->l);
4227 bc_vec_pop(&p->flags);
4229 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4230 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4232 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4234 else if (BC_PARSE_ELSE(p)) {
4239 bc_vec_pop(&p->flags);
4241 ip = bc_vec_top(&p->exits);
4242 label = bc_vec_item(&p->func->labels, ip->idx);
4243 *label = p->func->code.len;
4245 bc_vec_pop(&p->exits);
4247 else if (BC_PARSE_FUNC_INNER(p)) {
4248 bc_parse_push(p, BC_INST_RET0);
4249 bc_parse_updateFunc(p, BC_PROG_MAIN);
4250 bc_vec_pop(&p->flags);
4254 BcInstPtr *ip = bc_vec_top(&p->exits);
4255 size_t *label = bc_vec_top(&p->conds);
4257 bc_parse_push(p, BC_INST_JUMP);
4258 bc_parse_pushIndex(p, *label);
4260 label = bc_vec_item(&p->func->labels, ip->idx);
4261 *label = p->func->code.len;
4263 bc_vec_pop(&p->flags);
4264 bc_vec_pop(&p->exits);
4265 bc_vec_pop(&p->conds);
4271 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4273 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4274 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4275 flags |= BC_PARSE_FLAG_BODY;
4276 bc_vec_push(&p->flags, &flags);
4279 static void bc_parse_noElse(BcParse *p)
4283 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4285 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4287 ip = bc_vec_top(&p->exits);
4288 label = bc_vec_item(&p->func->labels, ip->idx);
4289 *label = p->func->code.len;
4291 bc_vec_pop(&p->exits);
4294 static BcStatus bc_parse_if(BcParse *p)
4299 s = bc_lex_next(&p->l);
4301 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4303 s = bc_lex_next(&p->l);
4305 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4307 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4309 s = bc_lex_next(&p->l);
4311 bc_parse_push(p, BC_INST_JUMP_ZERO);
4313 ip.idx = p->func->labels.len;
4314 ip.func = ip.len = 0;
4316 bc_parse_pushIndex(p, ip.idx);
4317 bc_vec_push(&p->exits, &ip);
4318 bc_vec_push(&p->func->labels, &ip.idx);
4319 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4321 return BC_STATUS_SUCCESS;
4324 static BcStatus bc_parse_else(BcParse *p)
4328 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4330 ip.idx = p->func->labels.len;
4331 ip.func = ip.len = 0;
4333 bc_parse_push(p, BC_INST_JUMP);
4334 bc_parse_pushIndex(p, ip.idx);
4338 bc_vec_push(&p->exits, &ip);
4339 bc_vec_push(&p->func->labels, &ip.idx);
4340 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4342 return bc_lex_next(&p->l);
4345 static BcStatus bc_parse_while(BcParse *p)
4350 s = bc_lex_next(&p->l);
4352 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4353 s = bc_lex_next(&p->l);
4356 ip.idx = p->func->labels.len;
4358 bc_vec_push(&p->func->labels, &p->func->code.len);
4359 bc_vec_push(&p->conds, &ip.idx);
4361 ip.idx = p->func->labels.len;
4365 bc_vec_push(&p->exits, &ip);
4366 bc_vec_push(&p->func->labels, &ip.idx);
4368 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4370 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4371 s = bc_lex_next(&p->l);
4374 bc_parse_push(p, BC_INST_JUMP_ZERO);
4375 bc_parse_pushIndex(p, ip.idx);
4376 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4378 return BC_STATUS_SUCCESS;
4381 static BcStatus bc_parse_for(BcParse *p)
4385 size_t cond_idx, exit_idx, body_idx, update_idx;
4387 s = bc_lex_next(&p->l);
4389 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4390 s = bc_lex_next(&p->l);
4393 if (p->l.t.t != BC_LEX_SCOLON)
4394 s = bc_parse_expr(p, 0, bc_parse_next_for);
4396 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4399 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4400 s = bc_lex_next(&p->l);
4403 cond_idx = p->func->labels.len;
4404 update_idx = cond_idx + 1;
4405 body_idx = update_idx + 1;
4406 exit_idx = body_idx + 1;
4408 bc_vec_push(&p->func->labels, &p->func->code.len);
4410 if (p->l.t.t != BC_LEX_SCOLON)
4411 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4413 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4416 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4418 s = bc_lex_next(&p->l);
4421 bc_parse_push(p, BC_INST_JUMP_ZERO);
4422 bc_parse_pushIndex(p, exit_idx);
4423 bc_parse_push(p, BC_INST_JUMP);
4424 bc_parse_pushIndex(p, body_idx);
4426 ip.idx = p->func->labels.len;
4428 bc_vec_push(&p->conds, &update_idx);
4429 bc_vec_push(&p->func->labels, &p->func->code.len);
4431 if (p->l.t.t != BC_LEX_RPAREN)
4432 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4434 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4438 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4439 bc_parse_push(p, BC_INST_JUMP);
4440 bc_parse_pushIndex(p, cond_idx);
4441 bc_vec_push(&p->func->labels, &p->func->code.len);
4447 bc_vec_push(&p->exits, &ip);
4448 bc_vec_push(&p->func->labels, &ip.idx);
4450 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4452 return BC_STATUS_SUCCESS;
4455 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4461 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4463 if (type == BC_LEX_KEY_BREAK) {
4465 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4467 i = p->exits.len - 1;
4468 ip = bc_vec_item(&p->exits, i);
4470 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4471 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4476 i = *((size_t *) bc_vec_top(&p->conds));
4478 bc_parse_push(p, BC_INST_JUMP);
4479 bc_parse_pushIndex(p, i);
4481 s = bc_lex_next(&p->l);
4484 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4485 return BC_STATUS_PARSE_BAD_TOKEN;
4487 return bc_lex_next(&p->l);
4490 static BcStatus bc_parse_func(BcParse *p)
4493 bool var, comma = false;
4497 s = bc_lex_next(&p->l);
4499 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4501 name = xstrdup(p->l.t.v.v);
4502 bc_parse_addFunc(p, name, &p->fidx);
4504 s = bc_lex_next(&p->l);
4506 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4507 s = bc_lex_next(&p->l);
4510 while (p->l.t.t != BC_LEX_RPAREN) {
4512 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4516 name = xstrdup(p->l.t.v.v);
4517 s = bc_lex_next(&p->l);
4520 var = p->l.t.t != BC_LEX_LBRACKET;
4524 s = bc_lex_next(&p->l);
4527 if (p->l.t.t != BC_LEX_RBRACKET) {
4528 s = BC_STATUS_PARSE_BAD_FUNC;
4532 s = bc_lex_next(&p->l);
4536 comma = p->l.t.t == BC_LEX_COMMA;
4538 s = bc_lex_next(&p->l);
4542 s = bc_func_insert(p->func, name, var);
4546 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4548 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4549 bc_parse_startBody(p, flags);
4551 s = bc_lex_next(&p->l);
4554 if (p->l.t.t != BC_LEX_LBRACE)
4555 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4564 static BcStatus bc_parse_auto(BcParse *p)
4567 bool comma, var, one;
4570 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4571 s = bc_lex_next(&p->l);
4574 p->auto_part = comma = false;
4575 one = p->l.t.t == BC_LEX_NAME;
4577 while (p->l.t.t == BC_LEX_NAME) {
4579 name = xstrdup(p->l.t.v.v);
4580 s = bc_lex_next(&p->l);
4583 var = p->l.t.t != BC_LEX_LBRACKET;
4586 s = bc_lex_next(&p->l);
4589 if (p->l.t.t != BC_LEX_RBRACKET) {
4590 s = BC_STATUS_PARSE_BAD_FUNC;
4594 s = bc_lex_next(&p->l);
4598 comma = p->l.t.t == BC_LEX_COMMA;
4600 s = bc_lex_next(&p->l);
4604 s = bc_func_insert(p->func, name, var);
4608 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4609 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4611 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4612 return BC_STATUS_PARSE_BAD_TOKEN;
4614 return bc_lex_next(&p->l);
4621 static BcStatus bc_parse_body(BcParse *p, bool brace)
4623 BcStatus s = BC_STATUS_SUCCESS;
4624 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4626 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4628 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4630 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4631 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4633 if (!p->auto_part) {
4634 s = bc_parse_auto(p);
4638 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4641 s = bc_parse_stmt(p);
4642 if (!s && !brace) s = bc_parse_endBody(p, false);
4648 static BcStatus bc_parse_stmt(BcParse *p)
4650 BcStatus s = BC_STATUS_SUCCESS;
4656 return bc_lex_next(&p->l);
4659 case BC_LEX_KEY_ELSE:
4661 p->auto_part = false;
4667 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4670 s = bc_lex_next(&p->l);
4673 return bc_parse_body(p, true);
4676 case BC_LEX_KEY_AUTO:
4678 return bc_parse_auto(p);
4683 p->auto_part = false;
4685 if (BC_PARSE_IF_END(p)) {
4687 return BC_STATUS_SUCCESS;
4689 else if (BC_PARSE_BODY(p))
4690 return bc_parse_body(p, false);
4700 case BC_LEX_OP_MINUS:
4701 case BC_LEX_OP_BOOL_NOT:
4705 case BC_LEX_KEY_IBASE:
4706 case BC_LEX_KEY_LAST:
4707 case BC_LEX_KEY_LENGTH:
4708 case BC_LEX_KEY_OBASE:
4709 case BC_LEX_KEY_READ:
4710 case BC_LEX_KEY_SCALE:
4711 case BC_LEX_KEY_SQRT:
4713 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4717 case BC_LEX_KEY_ELSE:
4719 s = bc_parse_else(p);
4725 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4731 s = bc_parse_endBody(p, true);
4737 s = bc_parse_string(p, BC_INST_PRINT_STR);
4741 case BC_LEX_KEY_BREAK:
4742 case BC_LEX_KEY_CONTINUE:
4744 s = bc_parse_loopExit(p, p->l.t.t);
4748 case BC_LEX_KEY_FOR:
4750 s = bc_parse_for(p);
4754 case BC_LEX_KEY_HALT:
4756 bc_parse_push(p, BC_INST_HALT);
4757 s = bc_lex_next(&p->l);
4767 case BC_LEX_KEY_LIMITS:
4769 s = bc_lex_next(&p->l);
4771 s = BC_STATUS_LIMITS;
4775 case BC_LEX_KEY_PRINT:
4777 s = bc_parse_print(p);
4781 case BC_LEX_KEY_QUIT:
4783 // Quit is a compile-time command. We don't exit directly,
4784 // so the vm can clean up. Limits do the same thing.
4789 case BC_LEX_KEY_RETURN:
4791 s = bc_parse_return(p);
4795 case BC_LEX_KEY_WHILE:
4797 s = bc_parse_while(p);
4803 s = BC_STATUS_PARSE_BAD_TOKEN;
4811 static BcStatus bc_parse_parse(BcParse *p)
4815 if (p->l.t.t == BC_LEX_EOF)
4816 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4817 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4818 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4819 s = bc_parse_func(p);
4822 s = bc_parse_stmt(p);
4824 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || bcg.signe)
4825 s = bc_parse_reset(p, s);
4830 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4832 BcStatus s = BC_STATUS_SUCCESS;
4833 BcInst prev = BC_INST_PRINT;
4834 BcLexType top, t = p->l.t.t;
4835 size_t nexprs = 0, ops_bgn = p->ops.len;
4836 uint32_t i, nparens, nrelops;
4837 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4839 paren_first = p->l.t.t == BC_LEX_LPAREN;
4840 nparens = nrelops = 0;
4841 paren_expr = rprn = done = get_token = assign = false;
4844 for (; !bcg.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4850 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4851 rprn = get_token = bin_last = false;
4855 case BC_LEX_OP_MINUS:
4857 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4858 rprn = get_token = false;
4859 bin_last = prev == BC_INST_MINUS;
4863 case BC_LEX_OP_ASSIGN_POWER:
4864 case BC_LEX_OP_ASSIGN_MULTIPLY:
4865 case BC_LEX_OP_ASSIGN_DIVIDE:
4866 case BC_LEX_OP_ASSIGN_MODULUS:
4867 case BC_LEX_OP_ASSIGN_PLUS:
4868 case BC_LEX_OP_ASSIGN_MINUS:
4869 case BC_LEX_OP_ASSIGN:
4871 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4872 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4873 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4875 s = BC_STATUS_PARSE_BAD_ASSIGN;
4880 case BC_LEX_OP_POWER:
4881 case BC_LEX_OP_MULTIPLY:
4882 case BC_LEX_OP_DIVIDE:
4883 case BC_LEX_OP_MODULUS:
4884 case BC_LEX_OP_PLUS:
4885 case BC_LEX_OP_REL_EQ:
4886 case BC_LEX_OP_REL_LE:
4887 case BC_LEX_OP_REL_GE:
4888 case BC_LEX_OP_REL_NE:
4889 case BC_LEX_OP_REL_LT:
4890 case BC_LEX_OP_REL_GT:
4891 case BC_LEX_OP_BOOL_NOT:
4892 case BC_LEX_OP_BOOL_OR:
4893 case BC_LEX_OP_BOOL_AND:
4895 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4896 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4898 return BC_STATUS_PARSE_BAD_EXP;
4901 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4902 prev = BC_PARSE_TOKEN_INST(t);
4903 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4904 rprn = get_token = false;
4905 bin_last = t != BC_LEX_OP_BOOL_NOT;
4912 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4915 paren_expr = rprn = bin_last = false;
4917 bc_vec_push(&p->ops, &t);
4924 if (bin_last || prev == BC_INST_BOOL_NOT)
4925 return BC_STATUS_PARSE_BAD_EXP;
4928 s = BC_STATUS_SUCCESS;
4933 else if (!paren_expr)
4934 return BC_STATUS_PARSE_EMPTY_EXP;
4937 paren_expr = rprn = true;
4938 get_token = bin_last = false;
4940 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4947 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4950 rprn = get_token = bin_last = false;
4951 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4959 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4961 bc_parse_number(p, &prev, &nexprs);
4962 paren_expr = get_token = true;
4963 rprn = bin_last = false;
4968 case BC_LEX_KEY_IBASE:
4969 case BC_LEX_KEY_LAST:
4970 case BC_LEX_KEY_OBASE:
4972 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4974 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4975 bc_parse_push(p, (char) prev);
4977 paren_expr = get_token = true;
4978 rprn = bin_last = false;
4984 case BC_LEX_KEY_LENGTH:
4985 case BC_LEX_KEY_SQRT:
4987 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4989 s = bc_parse_builtin(p, t, flags, &prev);
4991 rprn = get_token = bin_last = false;
4997 case BC_LEX_KEY_READ:
4999 if (BC_PARSE_LEAF(prev, rprn))
5000 return BC_STATUS_PARSE_BAD_EXP;
5001 else if (flags & BC_PARSE_NOREAD)
5002 s = BC_STATUS_EXEC_REC_READ;
5004 s = bc_parse_read(p);
5007 rprn = get_token = bin_last = false;
5009 prev = BC_INST_READ;
5014 case BC_LEX_KEY_SCALE:
5016 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
5018 s = bc_parse_scale(p, &prev, flags);
5020 rprn = get_token = bin_last = false;
5022 prev = BC_INST_SCALE;
5029 s = BC_STATUS_PARSE_BAD_TOKEN;
5034 if (!s && get_token) s = bc_lex_next(&p->l);
5038 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
5040 while (p->ops.len > ops_bgn) {
5042 top = BC_PARSE_TOP_OP(p);
5043 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5045 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5046 return BC_STATUS_PARSE_BAD_EXP;
5048 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5050 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5051 bc_vec_pop(&p->ops);
5054 s = BC_STATUS_PARSE_BAD_EXP;
5055 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5057 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5060 if (!(flags & BC_PARSE_REL) && nrelops) {
5061 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5064 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5065 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5069 if (flags & BC_PARSE_PRINT) {
5070 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5071 bc_parse_push(p, BC_INST_POP);
5077 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5079 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5082 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5084 return bc_parse_expr(p, flags, bc_parse_next_read);
5089 static BcStatus dc_parse_register(BcParse *p)
5094 s = bc_lex_next(&p->l);
5096 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5098 name = xstrdup(p->l.t.v.v);
5099 bc_parse_pushName(p, name);
5104 static BcStatus dc_parse_string(BcParse *p)
5106 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5107 size_t idx, len = p->prog->strs.len;
5109 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5112 str = xstrdup(p->l.t.v.v);
5113 bc_parse_push(p, BC_INST_STR);
5114 bc_parse_pushIndex(p, len);
5115 bc_vec_push(&p->prog->strs, &str);
5116 bc_parse_addFunc(p, name, &idx);
5118 return bc_lex_next(&p->l);
5121 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5125 bc_parse_push(p, inst);
5127 s = dc_parse_register(p);
5132 bc_parse_push(p, BC_INST_SWAP);
5133 bc_parse_push(p, BC_INST_ASSIGN);
5134 bc_parse_push(p, BC_INST_POP);
5137 return bc_lex_next(&p->l);
5140 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5144 bc_parse_push(p, inst);
5145 bc_parse_push(p, BC_INST_EXEC_COND);
5147 s = dc_parse_register(p);
5150 s = bc_lex_next(&p->l);
5153 if (p->l.t.t == BC_LEX_ELSE) {
5154 s = dc_parse_register(p);
5156 s = bc_lex_next(&p->l);
5159 bc_parse_push(p, BC_PARSE_STREND);
5164 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5166 BcStatus s = BC_STATUS_SUCCESS;
5169 bool assign, get_token = false;
5173 case BC_LEX_OP_REL_EQ:
5174 case BC_LEX_OP_REL_LE:
5175 case BC_LEX_OP_REL_GE:
5176 case BC_LEX_OP_REL_NE:
5177 case BC_LEX_OP_REL_LT:
5178 case BC_LEX_OP_REL_GT:
5180 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5187 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5193 s = dc_parse_string(p);
5200 if (t == BC_LEX_NEG) {
5201 s = bc_lex_next(&p->l);
5203 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5206 bc_parse_number(p, &prev, &p->nbraces);
5208 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5214 case BC_LEX_KEY_READ:
5216 if (flags & BC_PARSE_NOREAD)
5217 s = BC_STATUS_EXEC_REC_READ;
5219 bc_parse_push(p, BC_INST_READ);
5224 case BC_LEX_OP_ASSIGN:
5225 case BC_LEX_STORE_PUSH:
5227 assign = t == BC_LEX_OP_ASSIGN;
5228 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5229 s = dc_parse_mem(p, inst, true, assign);
5234 case BC_LEX_LOAD_POP:
5236 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5237 s = dc_parse_mem(p, inst, true, false);
5241 case BC_LEX_STORE_IBASE:
5242 case BC_LEX_STORE_SCALE:
5243 case BC_LEX_STORE_OBASE:
5245 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5246 s = dc_parse_mem(p, inst, false, true);
5252 s = BC_STATUS_PARSE_BAD_TOKEN;
5258 if (!s && get_token) s = bc_lex_next(&p->l);
5263 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5265 BcStatus s = BC_STATUS_SUCCESS;
5269 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5271 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5273 inst = dc_parse_insts[t];
5275 if (inst != BC_INST_INVALID) {
5276 bc_parse_push(p, inst);
5277 s = bc_lex_next(&p->l);
5280 s = dc_parse_token(p, t, flags);
5283 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5284 bc_parse_push(p, BC_INST_POP_EXEC);
5289 static BcStatus dc_parse_parse(BcParse *p)
5293 if (p->l.t.t == BC_LEX_EOF)
5294 s = BC_STATUS_LEX_EOF;
5296 s = dc_parse_expr(p, 0);
5298 if (s || bcg.signe) s = bc_parse_reset(p, s);
5303 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5305 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5309 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5318 v = var ? &p->vars : &p->arrs;
5319 map = var ? &p->var_map : &p->arr_map;
5323 s = bc_map_insert(map, &e, &i);
5324 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5327 bc_array_init(&data.v, var);
5328 bc_vec_push(v, &data.v);
5331 ptr = bc_vec_item(map, i);
5332 if (new) ptr->name = xstrdup(e.name);
5333 *ret = bc_vec_item(v, ptr->idx);
5336 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5338 BcStatus s = BC_STATUS_SUCCESS;
5343 case BC_RESULT_TEMP:
5344 case BC_RESULT_IBASE:
5345 case BC_RESULT_SCALE:
5346 case BC_RESULT_OBASE:
5352 case BC_RESULT_CONSTANT:
5354 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5355 size_t base_t, len = strlen(*str);
5358 bc_num_init(&r->d.n, len);
5360 hex = hex && len == 1;
5361 base = hex ? &p->hexb : &p->ib;
5362 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5363 s = bc_num_parse(&r->d.n, *str, base, base_t);
5366 bc_num_free(&r->d.n);
5371 r->t = BC_RESULT_TEMP;
5377 case BC_RESULT_ARRAY:
5378 case BC_RESULT_ARRAY_ELEM:
5382 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5384 if (r->t == BC_RESULT_ARRAY_ELEM) {
5386 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5387 *num = bc_vec_item(v, r->d.id.idx);
5390 *num = bc_vec_top(v);
5395 case BC_RESULT_LAST:
5411 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5412 BcResult **r, BcNum **rn, bool assign)
5416 BcResultType lt, rt;
5418 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5420 *r = bc_vec_item_rev(&p->results, 0);
5421 *l = bc_vec_item_rev(&p->results, 1);
5425 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5427 s = bc_program_num(p, *l, ln, false);
5429 s = bc_program_num(p, *r, rn, hex);
5432 // We run this again under these conditions in case any vector has been
5433 // reallocated out from under the BcNums or arrays we had.
5434 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5435 s = bc_program_num(p, *l, ln, false);
5439 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5440 return BC_STATUS_EXEC_BAD_TYPE;
5441 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5446 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5448 r->t = BC_RESULT_TEMP;
5449 bc_vec_pop(&p->results);
5450 bc_vec_pop(&p->results);
5451 bc_vec_push(&p->results, r);
5454 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5458 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5459 *r = bc_vec_top(&p->results);
5461 s = bc_program_num(p, *r, n, false);
5464 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5469 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5472 bc_vec_pop(&p->results);
5473 bc_vec_push(&p->results, r);
5476 static BcStatus bc_program_op(BcProgram *p, char inst)
5479 BcResult *opd1, *opd2, res;
5480 BcNum *n1, *n2 = NULL;
5482 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5484 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5486 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5488 bc_program_binOpRetire(p, &res);
5493 bc_num_free(&res.d.n);
5497 static BcStatus bc_program_read(BcProgram *p)
5504 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5506 for (i = 0; i < p->stack.len; ++i) {
5507 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5508 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5511 bc_vec_npop(&f->code, f->code.len);
5512 bc_vec_init(&buf, sizeof(char), NULL);
5514 s = bc_read_line(&buf, "read> ");
5517 p->parse_init(&parse, p, BC_PROG_READ);
5518 bc_lex_file(&parse.l, bc_program_stdin_name);
5520 s = bc_parse_text(&parse, buf.v);
5521 if (s) goto exec_err;
5522 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5523 if (s) goto exec_err;
5525 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5526 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5530 ip.func = BC_PROG_READ;
5532 ip.len = p->results.len;
5534 // Update this pointer, just in case.
5535 f = bc_vec_item(&p->fns, BC_PROG_READ);
5537 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5538 bc_vec_push(&p->stack, &ip);
5541 bc_parse_free(&parse);
5547 static size_t bc_program_index(char *code, size_t *bgn)
5549 char amt = code[(*bgn)++], i = 0;
5552 for (; i < amt; ++i, ++(*bgn))
5553 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5558 static char *bc_program_name(char *code, size_t *bgn)
5561 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5563 s = xmalloc(ptr - str + 1);
5566 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5574 static void bc_program_printString(const char *str, size_t *nchars)
5576 size_t i, len = strlen(str);
5580 bc_vm_putchar('\0');
5585 for (i = 0; i < len; ++i, ++(*nchars)) {
5589 if (c != '\\' || i == len - 1)
5599 bc_vm_putchar('\a');
5605 bc_vm_putchar('\b');
5612 bc_vm_putchar('\\');
5618 bc_vm_putchar('\f');
5624 bc_vm_putchar('\n');
5631 bc_vm_putchar('\r');
5643 bc_vm_putchar('\t');
5649 // Just print the backslash and following character.
5650 bc_vm_putchar('\\');
5660 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5662 BcStatus s = BC_STATUS_SUCCESS;
5667 bool pop = inst != BC_INST_PRINT;
5669 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5671 r = bc_vec_item_rev(&p->results, idx);
5672 s = bc_program_num(p, r, &num, false);
5675 if (BC_PROG_NUM(r, num)) {
5676 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5677 if (!s) bc_num_copy(&p->last, num);
5681 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5682 str = *((char **) bc_vec_item(&p->strs, idx));
5684 if (inst == BC_INST_PRINT_STR) {
5685 for (i = 0, len = strlen(str); i < len; ++i) {
5688 if (c == '\n') p->nchars = SIZE_MAX;
5693 bc_program_printString(str, &p->nchars);
5694 if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
5698 if (!s && pop) bc_vec_pop(&p->results);
5703 static BcStatus bc_program_negate(BcProgram *p)
5709 s = bc_program_prep(p, &ptr, &num);
5712 bc_num_init(&res.d.n, num->len);
5713 bc_num_copy(&res.d.n, num);
5714 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5716 bc_program_retire(p, &res, BC_RESULT_TEMP);
5721 static BcStatus bc_program_logical(BcProgram *p, char inst)
5724 BcResult *opd1, *opd2, res;
5729 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5731 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5733 if (inst == BC_INST_BOOL_AND)
5734 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5735 else if (inst == BC_INST_BOOL_OR)
5736 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5739 cmp = bc_num_cmp(n1, n2);
5743 case BC_INST_REL_EQ:
5749 case BC_INST_REL_LE:
5755 case BC_INST_REL_GE:
5761 case BC_INST_REL_NE:
5767 case BC_INST_REL_LT:
5773 case BC_INST_REL_GT:
5781 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5783 bc_program_binOpRetire(p, &res);
5789 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5795 memset(&n2, 0, sizeof(BcNum));
5796 n2.rdx = res.d.id.idx = r->d.id.idx;
5797 res.t = BC_RESULT_STR;
5800 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5802 bc_vec_pop(&p->results);
5805 bc_vec_pop(&p->results);
5807 bc_vec_push(&p->results, &res);
5808 bc_vec_push(v, &n2);
5810 return BC_STATUS_SUCCESS;
5814 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5821 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5823 ptr = bc_vec_top(&p->results);
5824 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5825 bc_program_search(p, name, &v, var);
5828 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5829 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5832 s = bc_program_num(p, ptr, &n, false);
5835 // Do this once more to make sure that pointers were not invalidated.
5836 bc_program_search(p, name, &v, var);
5839 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5840 bc_num_copy(&r.d.n, n);
5843 bc_array_init(&r.d.v, true);
5844 bc_array_copy(&r.d.v, (BcVec *) n);
5847 bc_vec_push(v, &r.d);
5848 bc_vec_pop(&p->results);
5853 static BcStatus bc_program_assign(BcProgram *p, char inst)
5856 BcResult *left, *right, res;
5857 BcNum *l = NULL, *r = NULL;
5858 unsigned long val, max;
5859 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5861 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5864 ib = left->t == BC_RESULT_IBASE;
5865 sc = left->t == BC_RESULT_SCALE;
5869 if (right->t == BC_RESULT_STR) {
5873 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5874 bc_program_search(p, left->d.id.name, &v, true);
5876 return bc_program_assignStr(p, right, v, false);
5880 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5881 return BC_STATUS_PARSE_BAD_ASSIGN;
5884 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5885 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5890 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5897 if (ib || sc || left->t == BC_RESULT_OBASE) {
5901 s = bc_num_ulong(l, &val);
5903 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5910 if (val < BC_NUM_MIN_BASE) return s;
5911 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5912 ptr = ib ? &p->ib_t : &p->ob_t;
5915 if (val > max) return s;
5916 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5918 *ptr = (size_t) val;
5919 s = BC_STATUS_SUCCESS;
5922 bc_num_init(&res.d.n, l->len);
5923 bc_num_copy(&res.d.n, l);
5924 bc_program_binOpRetire(p, &res);
5929 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5930 bool pop, bool copy)
5932 BcStatus s = BC_STATUS_SUCCESS;
5934 char *name = bc_program_name(code, bgn);
5935 #if ENABLE_DC // Exclude
5939 (void) pop, (void) copy;
5942 r.t = BC_RESULT_VAR;
5946 bc_program_search(p, name, &v, true);
5947 num = bc_vec_top(v);
5951 if (!BC_PROG_STACK(v, 2 - copy)) {
5953 return BC_STATUS_EXEC_STACK;
5959 if (!BC_PROG_STR(num)) {
5961 r.t = BC_RESULT_TEMP;
5963 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5964 bc_num_copy(&r.d.n, num);
5967 r.t = BC_RESULT_STR;
5968 r.d.id.idx = num->rdx;
5971 if (!copy) bc_vec_pop(v);
5975 bc_vec_push(&p->results, &r);
5980 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5983 BcStatus s = BC_STATUS_SUCCESS;
5987 r.d.id.name = bc_program_name(code, bgn);
5989 if (inst == BC_INST_ARRAY) {
5990 r.t = BC_RESULT_ARRAY;
5991 bc_vec_push(&p->results, &r);
5998 s = bc_program_prep(p, &operand, &num);
6000 s = bc_num_ulong(num, &temp);
6003 if (temp > BC_MAX_DIM) {
6004 s = BC_STATUS_EXEC_ARRAY_LEN;
6008 r.d.id.idx = (size_t) temp;
6009 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
6013 if (s) free(r.d.id.name);
6018 static BcStatus bc_program_incdec(BcProgram *p, char inst)
6021 BcResult *ptr, res, copy;
6025 s = bc_program_prep(p, &ptr, &num);
6028 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6029 copy.t = BC_RESULT_TEMP;
6030 bc_num_init(©.d.n, num->len);
6031 bc_num_copy(©.d.n, num);
6034 res.t = BC_RESULT_ONE;
6035 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6036 BC_INST_ASSIGN_PLUS :
6037 BC_INST_ASSIGN_MINUS;
6039 bc_vec_push(&p->results, &res);
6040 bc_program_assign(p, inst);
6042 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6043 bc_vec_pop(&p->results);
6044 bc_vec_push(&p->results, ©);
6050 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6052 BcStatus s = BC_STATUS_SUCCESS;
6054 size_t i, nparams = bc_program_index(code, idx);
6062 ip.func = bc_program_index(code, idx);
6063 func = bc_vec_item(&p->fns, ip.func);
6065 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6066 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6067 ip.len = p->results.len - nparams;
6069 for (i = 0; i < nparams; ++i) {
6071 a = bc_vec_item(&func->autos, nparams - 1 - i);
6072 arg = bc_vec_top(&p->results);
6074 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6075 return BC_STATUS_EXEC_BAD_TYPE;
6077 s = bc_program_copyToVar(p, a->name, a->idx);
6081 for (; i < func->autos.len; ++i) {
6083 a = bc_vec_item(&func->autos, i);
6084 bc_program_search(p, a->name, &v, a->idx);
6087 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6088 bc_vec_push(v, ¶m.n);
6091 bc_array_init(¶m.v, true);
6092 bc_vec_push(v, ¶m.v);
6096 bc_vec_push(&p->stack, &ip);
6098 return BC_STATUS_SUCCESS;
6101 static BcStatus bc_program_return(BcProgram *p, char inst)
6107 BcInstPtr *ip = bc_vec_top(&p->stack);
6109 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6110 return BC_STATUS_EXEC_STACK;
6112 f = bc_vec_item(&p->fns, ip->func);
6113 res.t = BC_RESULT_TEMP;
6115 if (inst == BC_INST_RET) {
6118 BcResult *operand = bc_vec_top(&p->results);
6120 s = bc_program_num(p, operand, &num, false);
6122 bc_num_init(&res.d.n, num->len);
6123 bc_num_copy(&res.d.n, num);
6126 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6127 bc_num_zero(&res.d.n);
6130 // We need to pop arguments as well, so this takes that into account.
6131 for (i = 0; i < f->autos.len; ++i) {
6134 BcId *a = bc_vec_item(&f->autos, i);
6136 bc_program_search(p, a->name, &v, a->idx);
6140 bc_vec_npop(&p->results, p->results.len - ip->len);
6141 bc_vec_push(&p->results, &res);
6142 bc_vec_pop(&p->stack);
6144 return BC_STATUS_SUCCESS;
6148 static unsigned long bc_program_scale(BcNum *n)
6150 return (unsigned long) n->rdx;
6153 static unsigned long bc_program_len(BcNum *n)
6155 unsigned long len = n->len;
6158 if (n->rdx != n->len) return len;
6159 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6164 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6170 bool len = inst == BC_INST_LENGTH;
6172 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6173 opnd = bc_vec_top(&p->results);
6175 s = bc_program_num(p, opnd, &num, false);
6179 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6182 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6184 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6186 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6187 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6191 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6194 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6196 str = bc_vec_item(&p->strs, idx);
6197 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6202 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6203 s = bc_num_ulong2num(&res.d.n, f(num));
6207 bc_program_retire(p, &res, BC_RESULT_TEMP);
6212 bc_num_free(&res.d.n);
6217 static BcStatus bc_program_divmod(BcProgram *p)
6220 BcResult *opd1, *opd2, res, res2;
6221 BcNum *n1, *n2 = NULL;
6223 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6226 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6227 bc_num_init(&res2.d.n, n2->len);
6229 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6232 bc_program_binOpRetire(p, &res2);
6233 res.t = BC_RESULT_TEMP;
6234 bc_vec_push(&p->results, &res);
6239 bc_num_free(&res2.d.n);
6240 bc_num_free(&res.d.n);
6244 static BcStatus bc_program_modexp(BcProgram *p)
6247 BcResult *r1, *r2, *r3, res;
6248 BcNum *n1, *n2, *n3;
6250 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6251 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6254 r1 = bc_vec_item_rev(&p->results, 2);
6255 s = bc_program_num(p, r1, &n1, false);
6257 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6259 // Make sure that the values have their pointers updated, if necessary.
6260 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6262 if (r1->t == r2->t) {
6263 s = bc_program_num(p, r2, &n2, false);
6267 if (r1->t == r3->t) {
6268 s = bc_program_num(p, r3, &n3, false);
6273 bc_num_init(&res.d.n, n3->len);
6274 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6277 bc_vec_pop(&p->results);
6278 bc_program_binOpRetire(p, &res);
6283 bc_num_free(&res.d.n);
6287 static BcStatus bc_program_stackLen(BcProgram *p)
6291 size_t len = p->results.len;
6293 res.t = BC_RESULT_TEMP;
6295 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6296 s = bc_num_ulong2num(&res.d.n, len);
6298 bc_vec_push(&p->results, &res);
6303 bc_num_free(&res.d.n);
6307 static BcStatus bc_program_asciify(BcProgram *p)
6311 BcNum *num = NULL, n;
6312 char *str, *str2, c;
6313 size_t len = p->strs.len, idx;
6316 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6317 r = bc_vec_top(&p->results);
6319 s = bc_program_num(p, r, &num, false);
6322 if (BC_PROG_NUM(r, num)) {
6324 bc_num_init(&n, BC_NUM_DEF_SIZE);
6325 bc_num_copy(&n, num);
6326 bc_num_truncate(&n, n.rdx);
6328 s = bc_num_mod(&n, &p->strmb, &n, 0);
6329 if (s) goto num_err;
6330 s = bc_num_ulong(&n, &val);
6331 if (s) goto num_err;
6338 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6339 str2 = *((char **) bc_vec_item(&p->strs, idx));
6347 str2 = xstrdup(str);
6348 bc_program_addFunc(p, str2, &idx);
6350 if (idx != len + BC_PROG_REQ_FUNCS) {
6352 for (idx = 0; idx < p->strs.len; ++idx) {
6353 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6362 bc_vec_push(&p->strs, &str);
6364 res.t = BC_RESULT_STR;
6366 bc_vec_pop(&p->results);
6367 bc_vec_push(&p->results, &res);
6369 return BC_STATUS_SUCCESS;
6376 static BcStatus bc_program_printStream(BcProgram *p)
6384 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6385 r = bc_vec_top(&p->results);
6387 s = bc_program_num(p, r, &n, false);
6390 if (BC_PROG_NUM(r, n))
6391 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6393 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6394 str = *((char **) bc_vec_item(&p->strs, idx));
6395 bc_vm_printf(stdout, "%s", str);
6401 static BcStatus bc_program_nquit(BcProgram *p)
6408 s = bc_program_prep(p, &opnd, &num);
6410 s = bc_num_ulong(num, &val);
6413 bc_vec_pop(&p->results);
6415 if (p->stack.len < val)
6416 return BC_STATUS_EXEC_STACK;
6417 else if (p->stack.len == val)
6418 return BC_STATUS_QUIT;
6420 bc_vec_npop(&p->stack, val);
6425 static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6428 BcStatus s = BC_STATUS_SUCCESS;
6438 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6440 r = bc_vec_top(&p->results);
6445 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6447 if (code[*bgn] == BC_PARSE_STREND)
6450 else_name = bc_program_name(code, bgn);
6452 exec = r->d.n.len != 0;
6456 else if (else_name != NULL) {
6462 bc_program_search(p, name, &v, true);
6469 if (!exec) goto exit;
6470 if (!BC_PROG_STR(n)) {
6471 s = BC_STATUS_EXEC_BAD_TYPE;
6479 if (r->t == BC_RESULT_STR)
6481 else if (r->t == BC_RESULT_VAR) {
6482 s = bc_program_num(p, r, &n, false);
6483 if (s || !BC_PROG_STR(n)) goto exit;
6490 fidx = sidx + BC_PROG_REQ_FUNCS;
6492 str = bc_vec_item(&p->strs, sidx);
6493 f = bc_vec_item(&p->fns, fidx);
6495 if (f->code.len == 0) {
6497 p->parse_init(&prs, p, fidx);
6498 s = bc_parse_text(&prs, *str);
6500 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6503 if (prs.l.t.t != BC_LEX_EOF) {
6504 s = BC_STATUS_PARSE_BAD_EXP;
6508 bc_parse_free(&prs);
6512 ip.len = p->results.len;
6515 bc_vec_pop(&p->results);
6516 bc_vec_push(&p->stack, &ip);
6518 return BC_STATUS_SUCCESS;
6521 bc_parse_free(&prs);
6522 f = bc_vec_item(&p->fns, fidx);
6523 bc_vec_npop(&f->code, f->code.len);
6525 bc_vec_pop(&p->results);
6530 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6536 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6537 if (inst == BC_INST_IBASE)
6538 val = (unsigned long) p->ib_t;
6539 else if (inst == BC_INST_SCALE)
6540 val = (unsigned long) p->scale;
6542 val = (unsigned long) p->ob_t;
6544 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6545 s = bc_num_ulong2num(&res.d.n, val);
6547 bc_vec_push(&p->results, &res);
6552 bc_num_free(&res.d.n);
6556 static void bc_program_free(BcProgram *p)
6558 bc_num_free(&p->ib);
6559 bc_num_free(&p->ob);
6560 bc_num_free(&p->hexb);
6562 bc_num_free(&p->strmb);
6564 bc_vec_free(&p->fns);
6565 bc_vec_free(&p->fn_map);
6566 bc_vec_free(&p->vars);
6567 bc_vec_free(&p->var_map);
6568 bc_vec_free(&p->arrs);
6569 bc_vec_free(&p->arr_map);
6570 bc_vec_free(&p->strs);
6571 bc_vec_free(&p->consts);
6572 bc_vec_free(&p->results);
6573 bc_vec_free(&p->stack);
6574 bc_num_free(&p->last);
6575 bc_num_free(&p->zero);
6576 bc_num_free(&p->one);
6579 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6585 memset(p, 0, sizeof(BcProgram));
6586 memset(&ip, 0, sizeof(BcInstPtr));
6588 p->nchars = p->scale = 0;
6590 p->parse_init = init;
6591 p->parse_expr = expr;
6593 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6597 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6601 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6602 bc_num_ten(&p->hexb);
6606 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6607 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6610 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6611 bc_num_zero(&p->last);
6613 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6614 bc_num_zero(&p->zero);
6616 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6617 bc_num_one(&p->one);
6619 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6620 bc_map_init(&p->fn_map);
6622 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6623 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6625 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6626 bc_map_init(&p->var_map);
6628 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6629 bc_map_init(&p->arr_map);
6631 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6632 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6633 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6634 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6635 bc_vec_push(&p->stack, &ip);
6638 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6641 BcId entry, *entry_ptr;
6645 entry.idx = p->fns.len;
6647 s = bc_map_insert(&p->fn_map, &entry, idx);
6650 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6651 *idx = entry_ptr->idx;
6653 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6655 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6657 // We need to reset these, so the function can be repopulated.
6659 bc_vec_npop(&func->autos, func->autos.len);
6660 bc_vec_npop(&func->code, func->code.len);
6661 bc_vec_npop(&func->labels, func->labels.len);
6665 bc_vec_push(&p->fns, &f);
6669 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6674 bc_vec_npop(&p->stack, p->stack.len - 1);
6675 bc_vec_npop(&p->results, p->results.len);
6677 f = bc_vec_item(&p->fns, 0);
6678 ip = bc_vec_top(&p->stack);
6679 ip->idx = f->code.len;
6681 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
6683 bcg.sigc += bcg.signe;
6684 bcg.signe = bcg.sig != bcg.sigc;
6686 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6688 bc_vm_puts(bc_program_ready_msg, stderr);
6689 bc_vm_fflush(stderr);
6690 s = BC_STATUS_SUCCESS;
6699 static BcStatus bc_program_exec(BcProgram *p)
6701 BcStatus s = BC_STATUS_SUCCESS;
6705 BcInstPtr *ip = bc_vec_top(&p->stack);
6706 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6707 char *code = func->code.v;
6710 while (!s && ip->idx < func->code.len) {
6712 char inst = code[(ip->idx)++];
6717 case BC_INST_JUMP_ZERO:
6719 s = bc_program_prep(p, &ptr, &num);
6721 cond = !bc_num_cmp(num, &p->zero);
6722 bc_vec_pop(&p->results);
6728 idx = bc_program_index(code, &ip->idx);
6729 addr = bc_vec_item(&func->labels, idx);
6730 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6736 s = bc_program_call(p, code, &ip->idx);
6740 case BC_INST_INC_PRE:
6741 case BC_INST_DEC_PRE:
6742 case BC_INST_INC_POST:
6743 case BC_INST_DEC_POST:
6745 s = bc_program_incdec(p, inst);
6758 s = bc_program_return(p, inst);
6762 case BC_INST_BOOL_OR:
6763 case BC_INST_BOOL_AND:
6765 case BC_INST_REL_EQ:
6766 case BC_INST_REL_LE:
6767 case BC_INST_REL_GE:
6768 case BC_INST_REL_NE:
6769 case BC_INST_REL_LT:
6770 case BC_INST_REL_GT:
6772 s = bc_program_logical(p, inst);
6778 s = bc_program_read(p);
6784 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6788 case BC_INST_ARRAY_ELEM:
6791 s = bc_program_pushArray(p, code, &ip->idx, inst);
6797 r.t = BC_RESULT_LAST;
6798 bc_vec_push(&p->results, &r);
6806 s = bc_program_pushGlobal(p, inst);
6810 case BC_INST_SCALE_FUNC:
6811 case BC_INST_LENGTH:
6814 s = bc_program_builtin(p, inst);
6820 r.t = BC_RESULT_CONSTANT;
6821 r.d.id.idx = bc_program_index(code, &ip->idx);
6822 bc_vec_push(&p->results, &r);
6828 if (!BC_PROG_STACK(&p->results, 1))
6829 s = BC_STATUS_EXEC_STACK;
6831 bc_vec_pop(&p->results);
6835 case BC_INST_POP_EXEC:
6837 bc_vec_pop(&p->stack);
6842 case BC_INST_PRINT_POP:
6843 case BC_INST_PRINT_STR:
6845 s = bc_program_print(p, inst, 0);
6851 r.t = BC_RESULT_STR;
6852 r.d.id.idx = bc_program_index(code, &ip->idx);
6853 bc_vec_push(&p->results, &r);
6858 case BC_INST_MULTIPLY:
6859 case BC_INST_DIVIDE:
6860 case BC_INST_MODULUS:
6864 s = bc_program_op(p, inst);
6868 case BC_INST_BOOL_NOT:
6870 s = bc_program_prep(p, &ptr, &num);
6873 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6874 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6875 bc_program_retire(p, &r, BC_RESULT_TEMP);
6882 s = bc_program_negate(p);
6887 case BC_INST_ASSIGN_POWER:
6888 case BC_INST_ASSIGN_MULTIPLY:
6889 case BC_INST_ASSIGN_DIVIDE:
6890 case BC_INST_ASSIGN_MODULUS:
6891 case BC_INST_ASSIGN_PLUS:
6892 case BC_INST_ASSIGN_MINUS:
6894 case BC_INST_ASSIGN:
6896 s = bc_program_assign(p, inst);
6900 case BC_INST_MODEXP:
6902 s = bc_program_modexp(p);
6906 case BC_INST_DIVMOD:
6908 s = bc_program_divmod(p);
6912 case BC_INST_EXECUTE:
6913 case BC_INST_EXEC_COND:
6915 cond = inst == BC_INST_EXEC_COND;
6916 s = bc_program_execStr(p, code, &ip->idx, cond);
6920 case BC_INST_PRINT_STACK:
6922 for (idx = 0; !s && idx < p->results.len; ++idx)
6923 s = bc_program_print(p, BC_INST_PRINT, idx);
6927 case BC_INST_CLEAR_STACK:
6929 bc_vec_npop(&p->results, p->results.len);
6933 case BC_INST_STACK_LEN:
6935 s = bc_program_stackLen(p);
6939 case BC_INST_DUPLICATE:
6941 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6942 ptr = bc_vec_top(&p->results);
6943 bc_result_copy(&r, ptr);
6944 bc_vec_push(&p->results, &r);
6952 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6954 ptr = bc_vec_item_rev(&p->results, 0);
6955 ptr2 = bc_vec_item_rev(&p->results, 1);
6956 memcpy(&r, ptr, sizeof(BcResult));
6957 memcpy(ptr, ptr2, sizeof(BcResult));
6958 memcpy(ptr2, &r, sizeof(BcResult));
6963 case BC_INST_ASCIIFY:
6965 s = bc_program_asciify(p);
6969 case BC_INST_PRINT_STREAM:
6971 s = bc_program_printStream(p);
6976 case BC_INST_PUSH_VAR:
6978 bool copy = inst == BC_INST_LOAD;
6979 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6983 case BC_INST_PUSH_TO_VAR:
6985 char *name = bc_program_name(code, &ip->idx);
6986 s = bc_program_copyToVar(p, name, true);
6993 if (p->stack.len <= 2)
6996 bc_vec_npop(&p->stack, 2);
7002 s = bc_program_nquit(p);
7008 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
7010 // If the stack has changed, pointers may be invalid.
7011 ip = bc_vec_top(&p->stack);
7012 func = bc_vec_item(&p->fns, ip->func);
7013 code = func->code.v;
7019 #if ENABLE_FEATURE_BC_SIGNALS
7020 static void bc_vm_sig(int sig)
7023 size_t len = strlen(bcg.sig_msg);
7024 if (sig == SIGINT && write(2, bcg.sig_msg, len) == (ssize_t) len) {
7025 bcg.signe = bcg.sig == bcg.sigc;
7026 bcg.sig += bcg.signe;
7032 static void bc_vm_info(const char *const help)
7034 bc_vm_printf(stdout, "%s %s\n", bcg.name, "1.1");
7035 bc_vm_puts(bc_copyright, stdout);
7036 if (help) bc_vm_printf(stdout, help, bcg.name);
7039 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
7041 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
7043 bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7044 bc_vm_printf(stderr, " %s", file);
7045 bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
7047 return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
7051 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7054 int p = (int) bcg.posix, w = (int) bcg.warn;
7055 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7057 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7059 bc_vm_printf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7060 if (msg) bc_vm_printf(stderr, " %s\n", msg);
7061 bc_vm_printf(stderr, " %s", file);
7062 bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
7064 return s * (!bcg.ttyin && !!p);
7067 static BcStatus bc_vm_envArgs(BcVm *vm)
7069 BcStatus s = BC_STATUS_SUCCESS;
7071 char *env_args = getenv(bc_args_env_name), *buf;
7073 if (!env_args) return s;
7075 vm->env_args = xstrdup(env_args);
7078 bc_vec_init(&v, sizeof(char *), NULL);
7079 bc_vec_push(&v, &bc_args_env_name);
7082 if (!isspace(*buf)) {
7083 bc_vec_push(&v, &buf);
7084 while (*buf != 0 && !isspace(*buf)) ++buf;
7085 if (*buf != 0) (*(buf++)) = '\0';
7091 s = bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
7099 static size_t bc_vm_envLen(const char *var)
7101 char *lenv = getenv(var);
7102 size_t i, len = BC_NUM_PRINT_WIDTH;
7105 if (!lenv) return len;
7109 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7111 len = (size_t) atoi(lenv) - 1;
7112 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7115 len = BC_NUM_PRINT_WIDTH;
7120 static void bc_vm_exit(BcStatus s)
7122 bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7126 static void bc_vm_printf(FILE *restrict f, const char *fmt, ...)
7131 va_start(args, fmt);
7132 bad = vfprintf(f, fmt, args) < 0;
7135 if (bad) bc_vm_exit(BC_STATUS_IO_ERR);
7138 static void bc_vm_puts(const char *str, FILE *restrict f)
7140 if (fputs(str, f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7143 static void bc_vm_putchar(int c)
7145 if (putchar(c) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7148 static void bc_vm_fflush(FILE *restrict f)
7150 if (fflush(f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7153 static BcStatus bc_vm_process(BcVm *vm, const char *text)
7155 BcStatus s = bc_parse_text(&vm->prs, text);
7157 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7160 while (vm->prs.l.t.t != BC_LEX_EOF) {
7162 s = vm->prs.parse(&vm->prs);
7164 if (s == BC_STATUS_LIMITS) {
7166 bc_vm_putchar('\n');
7167 bc_vm_printf(stdout, "BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7168 bc_vm_printf(stdout, "BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7169 bc_vm_printf(stdout, "BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7170 bc_vm_printf(stdout, "BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7171 bc_vm_printf(stdout, "BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7172 bc_vm_printf(stdout, "BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7173 bc_vm_printf(stdout, "Max Exponent = %lu\n", BC_MAX_EXP);
7174 bc_vm_printf(stdout, "Number of Vars = %lu\n", BC_MAX_VARS);
7175 bc_vm_putchar('\n');
7177 s = BC_STATUS_SUCCESS;
7180 if (s == BC_STATUS_QUIT) return s;
7181 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7186 if (BC_PARSE_CAN_EXEC(&vm->prs)) {
7187 s = bc_program_exec(&vm->prog);
7188 if (!s && bcg.tty) bc_vm_fflush(stdout);
7189 if (s && s != BC_STATUS_QUIT)
7190 s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
7196 static BcStatus bc_vm_file(BcVm *vm, const char *file)
7203 vm->prog.file = file;
7204 s = bc_read_file(file, &data);
7205 if (s) return bc_vm_error(s, file, 0);
7207 bc_lex_file(&vm->prs.l, file);
7208 s = bc_vm_process(vm, data);
7211 main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN);
7212 ip = bc_vec_item(&vm->prog.stack, 0);
7214 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7221 static BcStatus bc_vm_stdin(BcVm *vm)
7223 BcStatus s = BC_STATUS_SUCCESS;
7226 size_t len, i, str = 0;
7227 bool comment = false, notend;
7229 vm->prog.file = bc_program_stdin_name;
7230 bc_lex_file(&vm->prs.l, bc_program_stdin_name);
7232 bc_vec_init(&buffer, sizeof(char), NULL);
7233 bc_vec_init(&buf, sizeof(char), NULL);
7234 bc_vec_pushByte(&buffer, '\0');
7236 // This loop is complex because the vm tries not to send any lines that end
7237 // with a backslash to the parser. The reason for that is because the parser
7238 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7239 // case, and for strings and comments, the parser will expect more stuff.
7240 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7242 char *string = buf.v;
7247 if (str && buf.v[0] == vm->exe.send)
7249 else if (buf.v[0] == vm->exe.sbgn)
7252 else if (len > 1 || comment) {
7254 for (i = 0; i < len; ++i) {
7256 notend = len > i + 1;
7259 if (i - 1 > len || string[i - 1] != '\\') {
7260 if (vm->exe.sbgn == vm->exe.send)
7261 str ^= c == vm->exe.sbgn;
7262 else if (c == vm->exe.send)
7264 else if (c == vm->exe.sbgn)
7268 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7272 else if (c == '*' && notend && comment && string[i + 1] == '/')
7276 if (str || comment || string[len - 2] == '\\') {
7277 bc_vec_concat(&buffer, buf.v);
7282 bc_vec_concat(&buffer, buf.v);
7283 s = bc_vm_process(vm, buffer.v);
7286 bc_vec_npop(&buffer, buffer.len);
7289 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
7291 // I/O error will always happen when stdin is
7292 // closed. It's not a problem in that case.
7293 s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
7296 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, vm->prs.l.f,
7299 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, vm->prs.l.f,
7304 bc_vec_free(&buffer);
7308 static BcStatus bc_vm_exec(BcVm *vm)
7310 BcStatus s = BC_STATUS_SUCCESS;
7314 if (vm->flags & BC_FLAG_L) {
7316 bc_lex_file(&vm->prs.l, bc_lib_name);
7317 s = bc_parse_text(&vm->prs, bc_lib);
7319 while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = vm->prs.parse(&vm->prs);
7322 s = bc_program_exec(&vm->prog);
7327 for (i = 0; !s && i < vm->files.len; ++i)
7328 s = bc_vm_file(vm, *((char **) bc_vec_item(&vm->files, i)));
7329 if (s && s != BC_STATUS_QUIT) return s;
7331 if (bcg.bc || !vm->files.len) s = bc_vm_stdin(vm);
7332 if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, "");
7334 return s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
7337 static void bc_vm_free(BcVm *vm)
7339 bc_vec_free(&vm->files);
7340 bc_program_free(&vm->prog);
7341 bc_parse_free(&vm->prs);
7345 static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
7347 BcStatus s = BC_STATUS_SUCCESS;
7348 size_t len = bc_vm_envLen(env_len);
7349 #if ENABLE_FEATURE_BC_SIGNALS
7350 struct sigaction sa;
7352 sigemptyset(&sa.sa_mask);
7353 sa.sa_handler = bc_vm_sig;
7355 sigaction(SIGINT, &sa, NULL);
7358 memset(vm, 0, sizeof(BcVm));
7362 vm->env_args = NULL;
7364 bc_vec_init(&vm->files, sizeof(char *), NULL);
7367 vm->flags |= BC_FLAG_S * bcg.bc * (getenv("POSIXLY_CORRECT") != NULL);
7368 if (bcg.bc) s = bc_vm_envArgs(vm);
7371 bc_program_init(&vm->prog, len, exe.init, exe.exp);
7372 exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN);
7377 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
7378 const char *env_len)
7383 st = bc_vm_init(&vm, exe, env_len);
7385 st = bc_args(argc, argv, &vm.flags, &vm.files);
7388 bcg.ttyin = isatty(0);
7389 bcg.tty = bcg.ttyin || (vm.flags & BC_FLAG_I) || isatty(1);
7392 bcg.posix = vm.flags & BC_FLAG_S;
7393 bcg.warn = vm.flags & BC_FLAG_W;
7396 bcg.exreg = vm.flags & BC_FLAG_X;
7399 if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info(NULL);
7400 st = bc_vm_exec(&vm);
7408 BcStatus bc_main(int argc, char *argv[])
7414 # if ENABLE_FEATURE_BC_SIGNALS
7415 bcg.sig_msg = bc_sig_msg;
7418 exec.init = bc_parse_init;
7419 exec.exp = bc_parse_expression;
7420 exec.sbgn = exec.send = '"';
7422 return bc_vm_run(argc, argv, exec, "BC_LINE_LENGTH");
7427 BcStatus dc_main(int argc, char *argv[])
7433 # if ENABLE_FEATURE_BC_SIGNALS
7434 bcg.sig_msg = dc_sig_msg;
7437 exec.init = dc_parse_init;
7438 exec.exp = dc_parse_expr;
7442 return bc_vm_run(argc, argv, exec, "DC_LINE_LENGTH");