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 *);
253 typedef struct BcVec {
261 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
262 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
264 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
266 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
268 typedef signed char BcDig;
270 typedef struct BcNum {
278 #define BC_NUM_MIN_BASE ((unsigned long) 2)
279 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
280 #define BC_NUM_DEF_SIZE (16)
281 #define BC_NUM_PRINT_WIDTH (69)
283 #define BC_NUM_KARATSUBA_LEN (32)
285 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
286 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
287 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
288 #define BC_NUM_AREQ(a, b) \
289 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
290 #define BC_NUM_MREQ(a, b, scale) \
291 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
293 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
294 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
296 static void bc_num_init(BcNum *n, size_t req);
297 static void bc_num_expand(BcNum *n, size_t req);
298 static void bc_num_copy(BcNum *d, BcNum *s);
299 static void bc_num_free(void *num);
301 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
302 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
304 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
311 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
314 typedef enum BcInst {
344 BC_INST_ASSIGN_POWER,
345 BC_INST_ASSIGN_MULTIPLY,
346 BC_INST_ASSIGN_DIVIDE,
347 BC_INST_ASSIGN_MODULUS,
349 BC_INST_ASSIGN_MINUS,
395 BC_INST_PRINT_STREAM,
410 BC_INST_INVALID = -1,
415 typedef struct BcId {
420 typedef struct BcFunc {
427 typedef enum BcResultType {
432 BC_RESULT_ARRAY_ELEM,
441 // These are between to calculate ibase, obase, and last from instructions.
449 typedef union BcResultData {
455 typedef struct BcResult {
460 typedef struct BcInstPtr {
466 static void bc_array_expand(BcVec *a, size_t len);
467 static int bc_id_cmp(const void *e1, const void *e2);
469 // BC_LEX_NEG is not used in lexing; it is only for parsing.
470 typedef enum BcLexType {
498 BC_LEX_OP_ASSIGN_POWER,
499 BC_LEX_OP_ASSIGN_MULTIPLY,
500 BC_LEX_OP_ASSIGN_DIVIDE,
501 BC_LEX_OP_ASSIGN_MODULUS,
502 BC_LEX_OP_ASSIGN_PLUS,
503 BC_LEX_OP_ASSIGN_MINUS,
577 typedef BcStatus (*BcLexNext)(struct BcLex *);
579 typedef struct BcLex {
598 #define BC_PARSE_STREND ((char) UCHAR_MAX)
600 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
601 #define bc_parse_updateFunc(p, f) \
602 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
604 #define BC_PARSE_REL (1 << 0)
605 #define BC_PARSE_PRINT (1 << 1)
606 #define BC_PARSE_NOCALL (1 << 2)
607 #define BC_PARSE_NOREAD (1 << 3)
608 #define BC_PARSE_ARRAY (1 << 4)
610 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
611 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
613 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
614 #define BC_PARSE_FUNC_INNER(parse) \
615 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
617 #define BC_PARSE_FLAG_FUNC (1 << 1)
618 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
620 #define BC_PARSE_FLAG_BODY (1 << 2)
621 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
623 #define BC_PARSE_FLAG_LOOP (1 << 3)
624 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
626 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
627 #define BC_PARSE_LOOP_INNER(parse) \
628 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
630 #define BC_PARSE_FLAG_IF (1 << 5)
631 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
633 #define BC_PARSE_FLAG_ELSE (1 << 6)
634 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
636 #define BC_PARSE_FLAG_IF_END (1 << 7)
637 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
639 #define BC_PARSE_CAN_EXEC(parse) \
640 (!(BC_PARSE_TOP_FLAG(parse) & \
641 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
642 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
643 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
645 typedef struct BcOp {
650 typedef struct BcParseNext {
655 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
656 #define BC_PARSE_NEXT(a, ...) \
658 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
665 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
666 typedef BcStatus (*BcParseParse)(struct BcParse *);
667 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
669 typedef struct BcParse {
682 struct BcProgram *prog;
693 typedef struct BcLexKeyword {
699 #define BC_LEX_KW_ENTRY(a, b, c) \
701 .name = a, .len = (b), .posix = (c) \
704 static BcStatus bc_lex_token(BcLex *l);
706 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
707 #define BC_PARSE_LEAF(p, rparen) \
708 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
709 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
711 // We can calculate the conversion between tokens and exprs by subtracting the
712 // position of the first operator in the lex enum and adding the position of the
713 // first in the expr enum. Note: This only works for binary operators.
714 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
716 static BcStatus bc_parse_parse(BcParse *p);
717 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
723 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
725 static BcStatus dc_lex_token(BcLex *l);
727 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
728 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
732 typedef struct BcProgram {
771 BcParseInit parse_init;
772 BcParseExpr parse_expr;
776 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
778 #define BC_PROG_MAIN (0)
779 #define BC_PROG_READ (1)
782 #define BC_PROG_REQ_FUNCS (2)
785 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
786 #define BC_PROG_NUM(r, n) \
787 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
789 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
791 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
792 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
794 #define BC_FLAG_X (1 << 0)
795 #define BC_FLAG_W (1 << 1)
796 #define BC_FLAG_V (1 << 2)
797 #define BC_FLAG_S (1 << 3)
798 #define BC_FLAG_Q (1 << 4)
799 #define BC_FLAG_L (1 << 5)
800 #define BC_FLAG_I (1 << 6)
802 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
803 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
805 #define BC_MAX_OBASE ((unsigned long) 999)
806 #define BC_MAX_DIM ((unsigned long) INT_MAX)
807 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
808 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
809 #define BC_MAX_NAME BC_MAX_STRING
810 #define BC_MAX_NUM BC_MAX_STRING
811 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
812 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
829 #define G (*ptr_to_globals)
830 #define INIT_G() do { \
831 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
833 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
834 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
835 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
836 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
839 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
842 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
846 static void bc_vm_info(void);
848 static const char* const bc_args_env_name = "BC_ENV_ARGS";
850 static const char bc_err_fmt[] = "\n%s error: %s\n";
851 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
852 static const char bc_err_line[] = ":%zu\n\n";
854 static const char *bc_errs[] = {
866 static const uint8_t bc_err_ids[] = {
867 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
868 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
872 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
873 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
874 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
879 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
880 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
881 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
882 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
884 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
886 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
887 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
888 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
890 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
893 static const char *bc_err_msgs[] = {
896 "memory allocation error",
899 "path is a directory:",
902 "string end could not be found",
903 "comment end could not be found",
912 "bad print statement",
913 "bad function definition",
914 "bad assignment: left side must be scale, ibase, "
915 "obase, last, var, or array element",
916 "no auto variable found",
917 "function parameter or auto var has the same name as another",
918 "block end could not be found",
921 "non integer number",
926 "could not open file:",
927 "mismatched parameters",
928 "undefined function",
929 "file is not executable:",
930 "number too long: must be [1, BC_NUM_MAX]",
931 "name too long: must be [1, BC_NAME_MAX]",
932 "string too long: must be [1, BC_STRING_MAX]",
933 "array too long; must be [1, BC_DIM_MAX]",
934 "bad ibase; must be [2, 16]",
935 "bad scale; must be [0, BC_SCALE_MAX]",
936 "bad read() expression",
937 "read() call inside of a read() call",
938 "variable is wrong type",
939 "bad obase; must be [2, BC_BASE_MAX]",
940 "signal caught and not handled",
941 "stack has too few elements",
943 "index is out of bounds",
944 "item already exists",
947 "POSIX only allows one character names; the following is bad:",
948 "POSIX does not allow '#' script comments",
949 "POSIX does not allow the following keyword:",
950 "POSIX does not allow a period ('.') as a shortcut for the last result",
951 "POSIX requires parentheses around return expressions",
952 "POSIX does not allow boolean operators; the following is bad:",
953 "POSIX does not allow comparison operators outside if or loops",
954 "POSIX requires exactly one comparison operator per condition",
955 "POSIX does not allow an empty init expression in a for loop",
956 "POSIX does not allow an empty condition expression in a for loop",
957 "POSIX does not allow an empty update expression in a for loop",
958 "POSIX requires the left brace be on the same line as the function header",
963 static const char bc_func_main[] = "(main)";
964 static const char bc_func_read[] = "(read)";
967 static const BcLexKeyword bc_lex_kws[20] = {
968 BC_LEX_KW_ENTRY("auto", 4, true),
969 BC_LEX_KW_ENTRY("break", 5, true),
970 BC_LEX_KW_ENTRY("continue", 8, false),
971 BC_LEX_KW_ENTRY("define", 6, true),
972 BC_LEX_KW_ENTRY("else", 4, false),
973 BC_LEX_KW_ENTRY("for", 3, true),
974 BC_LEX_KW_ENTRY("halt", 4, false),
975 BC_LEX_KW_ENTRY("ibase", 5, true),
976 BC_LEX_KW_ENTRY("if", 2, true),
977 BC_LEX_KW_ENTRY("last", 4, false),
978 BC_LEX_KW_ENTRY("length", 6, true),
979 BC_LEX_KW_ENTRY("limits", 6, false),
980 BC_LEX_KW_ENTRY("obase", 5, true),
981 BC_LEX_KW_ENTRY("print", 5, false),
982 BC_LEX_KW_ENTRY("quit", 4, true),
983 BC_LEX_KW_ENTRY("read", 4, false),
984 BC_LEX_KW_ENTRY("return", 6, true),
985 BC_LEX_KW_ENTRY("scale", 5, true),
986 BC_LEX_KW_ENTRY("sqrt", 4, true),
987 BC_LEX_KW_ENTRY("while", 5, true),
990 // This is an array that corresponds to token types. An entry is
991 // true if the token is valid in an expression, false otherwise.
992 static const bool bc_parse_exprs[] = {
993 false, false, true, true, true, true, true, true, true, true, true, true,
994 true, true, true, true, true, true, true, true, true, true, true, true,
995 true, true, true, false, false, true, true, false, false, false, false,
996 false, false, false, true, true, false, false, false, false, false, false,
997 false, true, false, true, true, true, true, false, false, true, false, true,
1001 // This is an array of data for operators that correspond to token types.
1002 static const BcOp bc_parse_ops[] = {
1003 { 0, false }, { 0, false },
1006 { 3, true }, { 3, true }, { 3, true },
1007 { 4, true }, { 4, true },
1008 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1010 { 7, true }, { 7, true },
1011 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1012 { 5, false }, { 5, false },
1015 // These identify what tokens can come after expressions in certain cases.
1016 static const BcParseNext bc_parse_next_expr =
1017 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1018 static const BcParseNext bc_parse_next_param =
1019 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1020 static const BcParseNext bc_parse_next_print =
1021 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1022 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1023 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1024 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1025 static const BcParseNext bc_parse_next_read =
1026 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1030 static const BcLexType dc_lex_regs[] = {
1031 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1032 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1033 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1037 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1039 static const BcLexType dc_lex_tokens[] = {
1040 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1041 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1042 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1043 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1044 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1045 BC_LEX_INVALID, BC_LEX_INVALID,
1046 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1047 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1048 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1049 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1050 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1051 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1052 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1053 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1054 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1055 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1056 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1057 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1058 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1059 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1060 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1061 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1062 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1063 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1067 static const BcInst dc_parse_insts[] = {
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1069 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1070 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1071 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1072 BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1075 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1076 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1078 BC_INST_INVALID, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1080 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1081 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1083 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1085 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1086 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1087 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1088 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1094 static const BcNumBinaryOp bc_program_ops[] = {
1095 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1098 static const char bc_program_stdin_name[] = "<stdin>";
1099 static const char bc_program_ready_msg[] = "ready for more input\n";
1102 static const char *bc_lib_name = "gen/lib.bc";
1104 static const char bc_lib[] = {
1105 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1106 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1107 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1108 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,
1109 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1110 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1111 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,
1112 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1113 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1114 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,
1115 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1116 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1117 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1118 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1119 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1120 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1121 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1122 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1123 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1124 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1125 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1126 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1127 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1128 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,
1129 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1130 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,
1131 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1132 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1133 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1134 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1135 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1136 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,
1137 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1138 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1139 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1140 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1141 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,
1142 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1143 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1144 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1145 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1146 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1147 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1148 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1149 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1150 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1151 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1152 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,
1153 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,
1154 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1155 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,
1156 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,
1157 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,
1158 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1159 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1160 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,
1161 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,
1162 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,
1163 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1164 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,
1165 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1166 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1167 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1168 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,
1169 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1170 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1171 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1172 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1173 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1174 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1175 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1176 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1177 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1178 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1179 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1180 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1181 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1182 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1183 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1184 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1188 static void bc_vec_grow(BcVec *v, size_t n)
1190 size_t cap = v->cap * 2;
1191 while (cap < v->len + n) cap *= 2;
1192 v->v = xrealloc(v->v, v->size * cap);
1196 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1199 v->cap = BC_VEC_START_CAP;
1202 v->v = xmalloc(esize * BC_VEC_START_CAP);
1205 static void bc_vec_expand(BcVec *v, size_t req)
1208 v->v = xrealloc(v->v, v->size * req);
1213 static void bc_vec_npop(BcVec *v, size_t n)
1218 size_t len = v->len - n;
1219 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1223 static void bc_vec_push(BcVec *v, const void *data)
1225 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1226 memmove(v->v + (v->size * v->len), data, v->size);
1230 static void bc_vec_pushByte(BcVec *v, char data)
1232 bc_vec_push(v, &data);
1235 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1238 bc_vec_push(v, data);
1243 if (v->len == v->cap) bc_vec_grow(v, 1);
1245 ptr = v->v + v->size * idx;
1247 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1248 memmove(ptr, data, v->size);
1252 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1254 bc_vec_npop(v, v->len);
1255 bc_vec_expand(v, len + 1);
1256 memcpy(v->v, str, len);
1259 bc_vec_pushByte(v, '\0');
1262 static void bc_vec_concat(BcVec *v, const char *str)
1266 if (v->len == 0) bc_vec_pushByte(v, '\0');
1268 len = v->len + strlen(str);
1270 if (v->cap < len) bc_vec_grow(v, len - v->len);
1276 static void *bc_vec_item(const BcVec *v, size_t idx)
1278 return v->v + v->size * idx;
1281 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1283 return v->v + v->size * (v->len - idx - 1);
1286 static void bc_vec_free(void *vec)
1288 BcVec *v = (BcVec *) vec;
1289 bc_vec_npop(v, v->len);
1293 static size_t bc_map_find(const BcVec *v, const void *ptr)
1295 size_t low = 0, high = v->len;
1297 while (low < high) {
1299 size_t mid = (low + high) / 2;
1300 BcId *id = bc_vec_item(v, mid);
1301 int result = bc_id_cmp(ptr, id);
1305 else if (result < 0)
1314 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1316 BcStatus s = BC_STATUS_SUCCESS;
1318 *i = bc_map_find(v, ptr);
1321 bc_vec_push(v, ptr);
1322 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1323 s = BC_STATUS_VEC_ITEM_EXISTS;
1325 bc_vec_pushAt(v, ptr, *i);
1330 static size_t bc_map_index(const BcVec *v, const void *ptr)
1332 size_t i = bc_map_find(v, ptr);
1333 if (i >= v->len) return BC_VEC_INVALID_IDX;
1334 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1337 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1342 bc_vec_npop(vec, vec->len);
1345 #if ENABLE_FEATURE_BC_SIGNALS
1346 if (bb_got_signal) { /* ^C was pressed */
1349 ? "\ninterrupt (type \"quit\" to exit)\n"
1350 : "\ninterrupt (type \"q\" to exit)\n"
1353 bb_got_signal = 0; /* resets G_interrupt to zero */
1355 if (G.ttyin && !G_posix)
1356 fputs(prompt, stderr);
1359 #if ENABLE_FEATURE_BC_SIGNALS
1364 if (ferror(stdout) || ferror(stderr))
1365 bb_perror_msg_and_die("output error");
1369 #if ENABLE_FEATURE_BC_SIGNALS
1370 if (bb_got_signal) /* ^C was pressed */
1375 #if ENABLE_FEATURE_BC_SIGNALS
1376 if (errno == EINTR) {
1382 bb_perror_msg_and_die("input error");
1383 return BC_STATUS_INPUT_EOF;
1386 c = (signed char) i;
1387 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1388 bc_vec_push(vec, &c);
1389 } while (c != '\n');
1391 bc_vec_pushByte(vec, '\0');
1393 return BC_STATUS_SUCCESS;
1396 static BcStatus bc_read_file(const char *path, char **buf)
1398 BcStatus s = BC_STATUS_BIN_FILE;
1399 size_t size = ((size_t) -1);
1402 *buf = xmalloc_open_read_close(path, &size);
1404 for (i = 0; i < size; ++i) {
1405 if (BC_READ_BIN_CHAR((*buf)[i]))
1409 return BC_STATUS_SUCCESS;
1416 static void bc_args(int argc, char **argv)
1421 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1422 G.flags = getopt32long(argv, "xwvsqli",
1423 "extended-register\0" No_argument "x"
1424 "warn\0" No_argument "w"
1425 "version\0" No_argument "v"
1426 "standard\0" No_argument "s"
1427 "quiet\0" No_argument "q"
1428 "mathlib\0" No_argument "l"
1429 "interactive\0" No_argument "i"
1432 G.flags = getopt32(argv, "xwvsqli");
1435 if (G.flags & BC_FLAG_V) bc_vm_info();
1436 // should not be necessary, getopt32() handles this??
1437 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1439 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1442 static void bc_num_setToZero(BcNum *n, size_t scale)
1449 static void bc_num_zero(BcNum *n)
1451 bc_num_setToZero(n, 0);
1454 static void bc_num_one(BcNum *n)
1456 bc_num_setToZero(n, 0);
1461 static void bc_num_ten(BcNum *n)
1463 bc_num_setToZero(n, 0);
1469 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1473 for (i = 0; !G_interrupt && i < len; ++i) {
1474 for (a[i] -= b[i], j = 0; !G_interrupt && a[i + j] < 0;) {
1479 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1482 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1486 for (i = len - 1; !G_interrupt && i < len && !(c = a[i] - b[i]); --i);
1487 return BC_NUM_NEG(i + 1, c < 0);
1490 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1492 size_t i, min, a_int, b_int, diff;
1493 BcDig *max_num, *min_num;
1494 bool a_max, neg = false;
1497 if (a == b) return 0;
1498 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1499 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1509 a_int = BC_NUM_INT(a);
1510 b_int = BC_NUM_INT(b);
1512 a_max = (a->rdx > b->rdx);
1514 if (a_int != 0) return (ssize_t) a_int;
1518 diff = a->rdx - b->rdx;
1519 max_num = a->num + diff;
1524 diff = b->rdx - a->rdx;
1525 max_num = b->num + diff;
1529 cmp = bc_num_compare(max_num, min_num, b_int + min);
1530 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1532 for (max_num -= diff, i = diff - 1; !G_interrupt && i < diff; --i) {
1533 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1539 static void bc_num_truncate(BcNum *n, size_t places)
1541 if (places == 0) return;
1547 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1551 static void bc_num_extend(BcNum *n, size_t places)
1553 size_t len = n->len + places;
1557 if (n->cap < len) bc_num_expand(n, len);
1559 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1560 memset(n->num, 0, sizeof(BcDig) * places);
1567 static void bc_num_clean(BcNum *n)
1569 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1572 else if (n->len < n->rdx)
1576 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1579 bc_num_extend(n, scale - n->rdx);
1581 bc_num_truncate(n, n->rdx - scale);
1584 if (n->len != 0) n->neg = !neg1 != !neg2;
1587 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1592 b->len = n->len - idx;
1594 a->rdx = b->rdx = 0;
1596 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1597 memcpy(a->num, n->num, idx * sizeof(BcDig));
1608 static BcStatus bc_num_shift(BcNum *n, size_t places)
1610 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1611 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1613 if (n->rdx >= places)
1616 bc_num_extend(n, places - n->rdx);
1622 return BC_STATUS_SUCCESS;
1625 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1634 return bc_num_div(&one, a, b, scale);
1637 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1639 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1640 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1643 // Because this function doesn't need to use scale (per the bc spec),
1644 // I am hijacking it to say whether it's doing an add or a subtract.
1648 if (sub && c->len) c->neg = !c->neg;
1649 return BC_STATUS_SUCCESS;
1651 else if (b->len == 0) {
1653 return BC_STATUS_SUCCESS;
1657 c->rdx = BC_MAX(a->rdx, b->rdx);
1658 min_rdx = BC_MIN(a->rdx, b->rdx);
1661 if (a->rdx > b->rdx) {
1662 diff = a->rdx - b->rdx;
1664 ptr_a = a->num + diff;
1668 diff = b->rdx - a->rdx;
1671 ptr_b = b->num + diff;
1674 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1677 a_int = BC_NUM_INT(a);
1678 b_int = BC_NUM_INT(b);
1680 if (a_int > b_int) {
1691 for (carry = 0, i = 0; !G_interrupt && i < min_rdx + min_int; ++i, ++c->len) {
1692 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1694 ptr_c[i] = (BcDig)(in % 10);
1697 for (; !G_interrupt && i < max + min_rdx; ++i, ++c->len) {
1698 in = ((int) ptr[i]) + carry;
1700 ptr_c[i] = (BcDig)(in % 10);
1703 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1705 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1708 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1712 BcNum *minuend, *subtrahend;
1714 bool aneg, bneg, neg;
1716 // Because this function doesn't need to use scale (per the bc spec),
1717 // I am hijacking it to say whether it's doing an add or a subtract.
1721 if (sub && c->len) c->neg = !c->neg;
1722 return BC_STATUS_SUCCESS;
1724 else if (b->len == 0) {
1726 return BC_STATUS_SUCCESS;
1731 a->neg = b->neg = false;
1733 cmp = bc_num_cmp(a, b);
1739 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1740 return BC_STATUS_SUCCESS;
1749 if (sub) neg = !neg;
1754 bc_num_copy(c, minuend);
1757 if (c->rdx < subtrahend->rdx) {
1758 bc_num_extend(c, subtrahend->rdx - c->rdx);
1762 start = c->rdx - subtrahend->rdx;
1764 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1771 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1776 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1777 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1778 bool aone = BC_NUM_ONE(a);
1780 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
1781 if (a->len == 0 || b->len == 0) {
1783 return BC_STATUS_SUCCESS;
1785 else if (aone || BC_NUM_ONE(b)) {
1786 bc_num_copy(c, aone ? b : a);
1787 return BC_STATUS_SUCCESS;
1790 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1791 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1793 bc_num_expand(c, a->len + b->len + 1);
1795 memset(c->num, 0, sizeof(BcDig) * c->cap);
1796 c->len = carry = len = 0;
1798 for (i = 0; !G_interrupt && i < b->len; ++i) {
1800 for (j = 0; !G_interrupt && j < a->len; ++j) {
1801 int in = (int) c->num[i + j];
1802 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1804 c->num[i + j] = (BcDig)(in % 10);
1807 c->num[i + j] += (BcDig) carry;
1808 len = BC_MAX(len, i + j + !!carry);
1814 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1817 bc_num_init(&l1, max);
1818 bc_num_init(&h1, max);
1819 bc_num_init(&l2, max);
1820 bc_num_init(&h2, max);
1821 bc_num_init(&m1, max);
1822 bc_num_init(&m2, max);
1823 bc_num_init(&z0, max);
1824 bc_num_init(&z1, max);
1825 bc_num_init(&z2, max);
1826 bc_num_init(&temp, max + max);
1828 bc_num_split(a, max2, &l1, &h1);
1829 bc_num_split(b, max2, &l2, &h2);
1831 s = bc_num_add(&h1, &l1, &m1, 0);
1833 s = bc_num_add(&h2, &l2, &m2, 0);
1836 s = bc_num_k(&h1, &h2, &z0);
1838 s = bc_num_k(&m1, &m2, &z1);
1840 s = bc_num_k(&l1, &l2, &z2);
1843 s = bc_num_sub(&z1, &z0, &temp, 0);
1845 s = bc_num_sub(&temp, &z2, &z1, 0);
1848 s = bc_num_shift(&z0, max2 * 2);
1850 s = bc_num_shift(&z1, max2);
1852 s = bc_num_add(&z0, &z1, &temp, 0);
1854 s = bc_num_add(&temp, &z2, c, 0);
1870 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1874 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1876 scale = BC_MAX(scale, a->rdx);
1877 scale = BC_MAX(scale, b->rdx);
1878 scale = BC_MIN(a->rdx + b->rdx, scale);
1879 maxrdx = BC_MAX(maxrdx, scale);
1881 bc_num_init(&cpa, a->len);
1882 bc_num_init(&cpb, b->len);
1884 bc_num_copy(&cpa, a);
1885 bc_num_copy(&cpb, b);
1886 cpa.neg = cpb.neg = false;
1888 s = bc_num_shift(&cpa, maxrdx);
1890 s = bc_num_shift(&cpb, maxrdx);
1892 s = bc_num_k(&cpa, &cpb, c);
1896 bc_num_expand(c, c->len + maxrdx);
1898 if (c->len < maxrdx) {
1899 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1904 bc_num_retireMul(c, scale, a->neg, b->neg);
1912 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1914 BcStatus s = BC_STATUS_SUCCESS;
1921 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1922 else if (a->len == 0) {
1923 bc_num_setToZero(c, scale);
1924 return BC_STATUS_SUCCESS;
1926 else if (BC_NUM_ONE(b)) {
1928 bc_num_retireMul(c, scale, a->neg, b->neg);
1929 return BC_STATUS_SUCCESS;
1932 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1933 bc_num_copy(&cp, a);
1937 bc_num_expand(&cp, len + 2);
1938 bc_num_extend(&cp, len - cp.len);
1941 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1943 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1945 if (b->rdx == b->len) {
1946 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1950 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1952 // We want an extra zero in front to make things simpler.
1953 cp.num[cp.len++] = 0;
1956 bc_num_expand(c, cp.len);
1959 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1964 for (i = end - 1; !G_interrupt && !s && i < end; --i) {
1966 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1967 s = bc_num_subArrays(n, p, len);
1971 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1977 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1978 BcNum *restrict d, size_t scale, size_t ts)
1984 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1987 bc_num_setToZero(d, ts);
1988 return BC_STATUS_SUCCESS;
1991 bc_num_init(&temp, d->cap);
1992 bc_num_d(a, b, c, scale);
1994 if (scale != 0) scale = ts;
1996 s = bc_num_m(c, b, &temp, scale);
1998 s = bc_num_sub(a, &temp, d, scale);
2001 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2004 bc_num_retireMul(d, ts, a->neg, b->neg);
2012 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2016 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2018 bc_num_init(&c1, len);
2019 s = bc_num_r(a, b, &c1, c, scale, ts);
2025 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2027 BcStatus s = BC_STATUS_SUCCESS;
2030 size_t i, powrdx, resrdx;
2033 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2037 return BC_STATUS_SUCCESS;
2039 else if (a->len == 0) {
2040 bc_num_setToZero(c, scale);
2041 return BC_STATUS_SUCCESS;
2043 else if (BC_NUM_ONE(b)) {
2047 s = bc_num_inv(a, c, scale);
2054 s = bc_num_ulong(b, &pow);
2057 bc_num_init(©, a->len);
2058 bc_num_copy(©, a);
2060 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2064 for (powrdx = a->rdx; !G_interrupt && !(pow & 1); pow >>= 1) {
2066 s = bc_num_mul(©, ©, ©, powrdx);
2071 s = BC_STATUS_EXEC_SIGNAL;
2075 bc_num_copy(c, ©);
2077 for (resrdx = powrdx, pow >>= 1; !G_interrupt && pow != 0; pow >>= 1) {
2080 s = bc_num_mul(©, ©, ©, powrdx);
2085 s = bc_num_mul(c, ©, c, resrdx);
2091 s = bc_num_inv(c, c, scale);
2096 s = BC_STATUS_EXEC_SIGNAL;
2100 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2102 // We can't use bc_num_clean() here.
2103 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2104 if (zero) bc_num_setToZero(c, scale);
2111 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2112 BcNumBinaryOp op, size_t req)
2115 BcNum num2, *ptr_a, *ptr_b;
2120 memcpy(ptr_a, c, sizeof(BcNum));
2129 memcpy(ptr_b, c, sizeof(BcNum));
2137 bc_num_init(c, req);
2139 bc_num_expand(c, req);
2141 s = op(ptr_a, ptr_b, c, scale);
2143 if (init) bc_num_free(&num2);
2148 static bool bc_num_strValid(const char *val, size_t base)
2151 bool small, radix = false;
2152 size_t i, len = strlen(val);
2154 if (!len) return true;
2157 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2159 for (i = 0; i < len; ++i) {
2165 if (radix) return false;
2171 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2178 static void bc_num_parseDecimal(BcNum *n, const char *val)
2184 for (i = 0; val[i] == '0'; ++i);
2191 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2192 bc_num_expand(n, len);
2195 ptr = strchr(val, '.');
2197 // Explicitly test for NULL here to produce either a 0 or 1.
2198 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2201 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2202 n->num[n->len] = val[i] - '0';
2206 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2209 BcNum temp, mult, result;
2213 size_t i, digits, len = strlen(val);
2217 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2220 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2221 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2223 for (i = 0; i < len; ++i) {
2226 if (c == '.') break;
2228 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2230 s = bc_num_mul(n, base, &mult, 0);
2231 if (s) goto int_err;
2232 s = bc_num_ulong2num(&temp, v);
2233 if (s) goto int_err;
2234 s = bc_num_add(&mult, &temp, n, 0);
2235 if (s) goto int_err;
2240 if (c == 0) goto int_err;
2243 bc_num_init(&result, base->len);
2244 bc_num_zero(&result);
2247 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2252 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2254 s = bc_num_mul(&result, base, &result, 0);
2256 s = bc_num_ulong2num(&temp, v);
2258 s = bc_num_add(&result, &temp, &result, 0);
2260 s = bc_num_mul(&mult, base, &mult, 0);
2264 s = bc_num_div(&result, &mult, &result, digits);
2266 s = bc_num_add(n, &result, n, digits);
2270 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2276 bc_num_free(&result);
2282 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2284 if (*nchars == line_len - 1) {
2292 static void bc_num_printChar(size_t num, size_t width, bool radix,
2293 size_t *nchars, size_t line_len)
2295 (void) radix, (void) line_len;
2296 bb_putchar((char) num);
2297 *nchars = *nchars + width;
2301 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2302 size_t *nchars, size_t line_len)
2306 bc_num_printNewline(nchars, line_len);
2307 bb_putchar(radix ? '.' : ' ');
2310 bc_num_printNewline(nchars, line_len);
2311 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2314 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2316 bc_num_printNewline(nchars, line_len);
2319 bb_putchar(((char) dig) + '0');
2323 static void bc_num_printHex(size_t num, size_t width, bool radix,
2324 size_t *nchars, size_t line_len)
2327 bc_num_printNewline(nchars, line_len);
2332 bc_num_printNewline(nchars, line_len);
2333 bb_putchar(bb_hexdigits_upcase[num]);
2334 *nchars = *nchars + width;
2337 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2339 size_t i, rdx = n->rdx - 1;
2341 if (n->neg) bb_putchar('-');
2342 (*nchars) += n->neg;
2344 for (i = n->len - 1; i < n->len; --i)
2345 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2348 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2349 size_t *nchars, size_t len, BcNumDigitOp print)
2353 BcNum intp, fracp, digit, frac_len;
2354 unsigned long dig, *ptr;
2359 print(0, width, false, nchars, len);
2360 return BC_STATUS_SUCCESS;
2363 bc_vec_init(&stack, sizeof(long), NULL);
2364 bc_num_init(&intp, n->len);
2365 bc_num_init(&fracp, n->rdx);
2366 bc_num_init(&digit, width);
2367 bc_num_init(&frac_len, BC_NUM_INT(n));
2368 bc_num_copy(&intp, n);
2369 bc_num_one(&frac_len);
2371 bc_num_truncate(&intp, intp.rdx);
2372 s = bc_num_sub(n, &intp, &fracp, 0);
2375 while (intp.len != 0) {
2376 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2378 s = bc_num_ulong(&digit, &dig);
2380 bc_vec_push(&stack, &dig);
2383 for (i = 0; i < stack.len; ++i) {
2384 ptr = bc_vec_item_rev(&stack, i);
2385 print(*ptr, width, false, nchars, len);
2388 if (!n->rdx) goto err;
2390 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2391 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2393 s = bc_num_ulong(&fracp, &dig);
2395 s = bc_num_ulong2num(&intp, dig);
2397 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2399 print(dig, width, radix, nchars, len);
2400 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2405 bc_num_free(&frac_len);
2406 bc_num_free(&digit);
2407 bc_num_free(&fracp);
2409 bc_vec_free(&stack);
2413 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2414 size_t *nchars, size_t line_len)
2421 if (neg) bb_putchar('-');
2426 if (base_t <= BC_NUM_MAX_IBASE) {
2428 print = bc_num_printHex;
2431 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2432 print = bc_num_printDigits;
2435 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2442 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2444 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2448 static void bc_num_init(BcNum *n, size_t req)
2450 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2451 memset(n, 0, sizeof(BcNum));
2452 n->num = xmalloc(req);
2456 static void bc_num_expand(BcNum *n, size_t req)
2458 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2460 n->num = xrealloc(n->num, req);
2465 static void bc_num_free(void *num)
2467 free(((BcNum *) num)->num);
2470 static void bc_num_copy(BcNum *d, BcNum *s)
2473 bc_num_expand(d, s->cap);
2477 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2481 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2484 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2487 bc_num_parseDecimal(n, val);
2489 bc_num_parseBase(n, val, base);
2491 return BC_STATUS_SUCCESS;
2494 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2495 size_t *nchars, size_t line_len)
2497 BcStatus s = BC_STATUS_SUCCESS;
2499 bc_num_printNewline(nchars, line_len);
2505 else if (base_t == 10)
2506 bc_num_printDecimal(n, nchars, line_len);
2508 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2518 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2523 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2525 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2527 unsigned long prev = *result, powprev = pow;
2529 *result += ((unsigned long) n->num[i]) * pow;
2532 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2535 return BC_STATUS_SUCCESS;
2538 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2546 if (val == 0) return BC_STATUS_SUCCESS;
2548 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2549 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2551 return BC_STATUS_SUCCESS;
2554 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2556 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2558 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2561 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2563 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2565 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2568 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2570 size_t req = BC_NUM_MREQ(a, b, scale);
2571 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2574 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2576 size_t req = BC_NUM_MREQ(a, b, scale);
2577 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2580 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2582 size_t req = BC_NUM_MREQ(a, b, scale);
2583 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2586 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2588 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2591 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2594 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2595 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2596 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2598 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2599 bc_num_expand(b, req);
2602 bc_num_setToZero(b, scale);
2603 return BC_STATUS_SUCCESS;
2606 return BC_STATUS_MATH_NEGATIVE;
2607 else if (BC_NUM_ONE(a)) {
2609 bc_num_extend(b, scale);
2610 return BC_STATUS_SUCCESS;
2613 scale = BC_MAX(scale, a->rdx) + 1;
2614 len = a->len + scale;
2616 bc_num_init(&num1, len);
2617 bc_num_init(&num2, len);
2618 bc_num_init(&half, BC_NUM_DEF_SIZE);
2624 bc_num_init(&f, len);
2625 bc_num_init(&fprime, len);
2631 pow = BC_NUM_INT(a);
2640 pow -= 2 - (pow & 1);
2642 bc_num_extend(x0, pow);
2644 // Make sure to move the radix back.
2648 x0->rdx = digs = digs1 = 0;
2650 len = BC_NUM_INT(x0) + resrdx - 1;
2652 while (!G_interrupt && (cmp != 0 || digs < len)) {
2654 s = bc_num_div(a, x0, &f, resrdx);
2656 s = bc_num_add(x0, &f, &fprime, resrdx);
2658 s = bc_num_mul(&fprime, &half, x1, resrdx);
2661 cmp = bc_num_cmp(x1, x0);
2662 digs = x1->len - (unsigned long long) llabs(cmp);
2664 if (cmp == cmp2 && digs == digs1)
2669 resrdx += times > 4;
2681 s = BC_STATUS_EXEC_SIGNAL;
2687 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2690 bc_num_free(&fprime);
2698 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2704 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2707 memcpy(&num2, c, sizeof(BcNum));
2709 bc_num_init(c, len);
2714 bc_num_expand(c, len);
2717 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2719 if (init) bc_num_free(&num2);
2725 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2728 BcNum base, exp, two, temp;
2730 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2731 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2732 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2734 bc_num_expand(d, c->len);
2735 bc_num_init(&base, c->len);
2736 bc_num_init(&exp, b->len);
2737 bc_num_init(&two, BC_NUM_DEF_SIZE);
2738 bc_num_init(&temp, b->len);
2744 s = bc_num_rem(a, c, &base, 0);
2746 bc_num_copy(&exp, b);
2748 while (exp.len != 0) {
2750 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2753 if (BC_NUM_ONE(&temp)) {
2754 s = bc_num_mul(d, &base, &temp, 0);
2756 s = bc_num_rem(&temp, c, d, 0);
2760 s = bc_num_mul(&base, &base, &temp, 0);
2762 s = bc_num_rem(&temp, c, &base, 0);
2775 static int bc_id_cmp(const void *e1, const void *e2)
2777 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2780 static void bc_id_free(void *id)
2782 free(((BcId *) id)->name);
2785 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2790 for (i = 0; i < f->autos.len; ++i) {
2791 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2792 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2798 bc_vec_push(&f->autos, &a);
2800 return BC_STATUS_SUCCESS;
2803 static void bc_func_init(BcFunc *f)
2805 bc_vec_init(&f->code, sizeof(char), NULL);
2806 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2807 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2811 static void bc_func_free(void *func)
2813 BcFunc *f = (BcFunc *) func;
2814 bc_vec_free(&f->code);
2815 bc_vec_free(&f->autos);
2816 bc_vec_free(&f->labels);
2819 static void bc_array_init(BcVec *a, bool nums)
2822 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2824 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2825 bc_array_expand(a, 1);
2828 static void bc_array_copy(BcVec *d, const BcVec *s)
2832 bc_vec_npop(d, d->len);
2833 bc_vec_expand(d, s->cap);
2836 for (i = 0; i < s->len; ++i) {
2837 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2838 bc_num_init(dnum, snum->len);
2839 bc_num_copy(dnum, snum);
2843 static void bc_array_expand(BcVec *a, size_t len)
2847 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2848 while (len > a->len) {
2849 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2850 bc_vec_push(a, &data.n);
2854 while (len > a->len) {
2855 bc_array_init(&data.v, true);
2856 bc_vec_push(a, &data.v);
2861 static void bc_string_free(void *string)
2863 free(*((char **) string));
2867 static void bc_result_copy(BcResult *d, BcResult *src)
2873 case BC_RESULT_TEMP:
2874 case BC_RESULT_IBASE:
2875 case BC_RESULT_SCALE:
2876 case BC_RESULT_OBASE:
2878 bc_num_init(&d->d.n, src->d.n.len);
2879 bc_num_copy(&d->d.n, &src->d.n);
2884 case BC_RESULT_ARRAY:
2885 case BC_RESULT_ARRAY_ELEM:
2887 d->d.id.name = xstrdup(src->d.id.name);
2891 case BC_RESULT_CONSTANT:
2892 case BC_RESULT_LAST:
2896 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2903 static void bc_result_free(void *result)
2905 BcResult *r = (BcResult *) result;
2909 case BC_RESULT_TEMP:
2910 case BC_RESULT_IBASE:
2911 case BC_RESULT_SCALE:
2912 case BC_RESULT_OBASE:
2914 bc_num_free(&r->d.n);
2919 case BC_RESULT_ARRAY:
2920 case BC_RESULT_ARRAY_ELEM:
2934 static void bc_lex_lineComment(BcLex *l)
2936 l->t.t = BC_LEX_WHITESPACE;
2937 while (l->i < l->len && l->buf[l->i++] != '\n');
2941 static void bc_lex_whitespace(BcLex *l)
2944 l->t.t = BC_LEX_WHITESPACE;
2945 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2948 static BcStatus bc_lex_number(BcLex *l, char start)
2950 const char *buf = l->buf + l->i;
2951 size_t len, hits = 0, bslashes = 0, i = 0, j;
2953 bool last_pt, pt = start == '.';
2956 l->t.t = BC_LEX_NUMBER;
2958 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2959 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2973 len = i + 1 * !last_pt - bslashes * 2;
2974 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2976 bc_vec_npop(&l->t.v, l->t.v.len);
2977 bc_vec_expand(&l->t.v, len + 1);
2978 bc_vec_push(&l->t.v, &start);
2980 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2984 // If we have hit a backslash, skip it. We don't have
2985 // to check for a newline because it's guaranteed.
2986 if (hits < bslashes && c == '\\') {
2992 bc_vec_push(&l->t.v, &c);
2995 bc_vec_pushByte(&l->t.v, '\0');
2998 return BC_STATUS_SUCCESS;
3001 static BcStatus bc_lex_name(BcLex *l)
3004 const char *buf = l->buf + l->i - 1;
3007 l->t.t = BC_LEX_NAME;
3009 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3011 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3012 bc_vec_string(&l->t.v, i, buf);
3014 // Increment the index. We minus 1 because it has already been incremented.
3017 return BC_STATUS_SUCCESS;
3020 static void bc_lex_init(BcLex *l, BcLexNext next)
3023 bc_vec_init(&l->t.v, sizeof(char), NULL);
3026 static void bc_lex_free(BcLex *l)
3028 bc_vec_free(&l->t.v);
3031 static void bc_lex_file(BcLex *l, const char *file)
3038 static BcStatus bc_lex_next(BcLex *l)
3043 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3045 l->line += l->newline;
3046 l->t.t = BC_LEX_EOF;
3048 l->newline = (l->i == l->len);
3049 if (l->newline) return BC_STATUS_SUCCESS;
3051 // Loop until failure or we don't have whitespace. This
3052 // is so the parser doesn't get inundated with whitespace.
3055 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3060 static BcStatus bc_lex_text(BcLex *l, const char *text)
3064 l->len = strlen(text);
3065 l->t.t = l->t.last = BC_LEX_INVALID;
3066 return bc_lex_next(l);
3070 static BcStatus bc_lex_identifier(BcLex *l)
3074 const char *buf = l->buf + l->i - 1;
3076 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3078 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3080 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3082 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3084 if (!bc_lex_kws[i].posix) {
3085 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3086 bc_lex_kws[i].name);
3090 // We minus 1 because the index has already been incremented.
3092 return BC_STATUS_SUCCESS;
3099 if (l->t.v.len - 1 > 1)
3100 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3105 static BcStatus bc_lex_string(BcLex *l)
3107 size_t len, nls = 0, i = l->i;
3110 l->t.t = BC_LEX_STR;
3112 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3116 return BC_STATUS_LEX_NO_STRING_END;
3120 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3121 bc_vec_string(&l->t.v, len, l->buf + l->i);
3126 return BC_STATUS_SUCCESS;
3129 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3131 if (l->buf[l->i] == '=') {
3139 static BcStatus bc_lex_comment(BcLex *l)
3142 const char *buf = l->buf;
3146 l->t.t = BC_LEX_WHITESPACE;
3148 for (i = ++l->i; !end; i += !end) {
3150 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3152 if (c == 0 || buf[i + 1] == '\0') {
3154 return BC_STATUS_LEX_NO_COMMENT_END;
3157 end = buf[i + 1] == '/';
3163 return BC_STATUS_SUCCESS;
3166 static BcStatus bc_lex_token(BcLex *l)
3168 BcStatus s = BC_STATUS_SUCCESS;
3169 char c = l->buf[l->i++], c2;
3171 // This is the workhorse of the lexer.
3178 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3188 bc_lex_whitespace(l);
3194 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3196 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3197 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3206 s = bc_lex_string(l);
3212 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3215 bc_lex_lineComment(l);
3222 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3231 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3235 l->t.t = BC_LEX_OP_BOOL_AND;
3238 l->t.t = BC_LEX_INVALID;
3239 s = BC_STATUS_LEX_BAD_CHAR;
3248 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3254 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3263 l->t.t = BC_LEX_OP_INC;
3266 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3272 l->t.t = BC_LEX_COMMA;
3281 l->t.t = BC_LEX_OP_DEC;
3284 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3290 if (isdigit(l->buf[l->i]))
3291 s = bc_lex_number(l, c);
3293 l->t.t = BC_LEX_KEY_LAST;
3294 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3303 s = bc_lex_comment(l);
3305 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3326 s = bc_lex_number(l, c);
3332 l->t.t = BC_LEX_SCOLON;
3338 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3344 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3350 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3357 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3363 if (l->buf[l->i] == '\n') {
3364 l->t.t = BC_LEX_WHITESPACE;
3368 s = BC_STATUS_LEX_BAD_CHAR;
3374 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3405 s = bc_lex_identifier(l);
3412 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3422 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3426 l->t.t = BC_LEX_OP_BOOL_OR;
3429 l->t.t = BC_LEX_INVALID;
3430 s = BC_STATUS_LEX_BAD_CHAR;
3438 l->t.t = BC_LEX_INVALID;
3439 s = BC_STATUS_LEX_BAD_CHAR;
3449 static BcStatus dc_lex_register(BcLex *l)
3451 BcStatus s = BC_STATUS_SUCCESS;
3453 if (isspace(l->buf[l->i - 1])) {
3454 bc_lex_whitespace(l);
3457 s = BC_STATUS_LEX_EXTENDED_REG;
3462 bc_vec_npop(&l->t.v, l->t.v.len);
3463 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3464 bc_vec_pushByte(&l->t.v, '\0');
3465 l->t.t = BC_LEX_NAME;
3471 static BcStatus dc_lex_string(BcLex *l)
3473 size_t depth = 1, nls = 0, i = l->i;
3476 l->t.t = BC_LEX_STR;
3477 bc_vec_npop(&l->t.v, l->t.v.len);
3479 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3481 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3482 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3485 if (depth) bc_vec_push(&l->t.v, &c);
3490 return BC_STATUS_LEX_NO_STRING_END;
3493 bc_vec_pushByte(&l->t.v, '\0');
3494 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3499 return BC_STATUS_SUCCESS;
3502 static BcStatus dc_lex_token(BcLex *l)
3504 BcStatus s = BC_STATUS_SUCCESS;
3505 char c = l->buf[l->i++], c2;
3508 for (i = 0; i < dc_lex_regs_len; ++i) {
3509 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3512 if (c >= '%' && c <= '~' &&
3513 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3518 // This is the workhorse of the lexer.
3523 l->t.t = BC_LEX_EOF;
3534 l->newline = (c == '\n');
3535 bc_lex_whitespace(l);
3544 l->t.t = BC_LEX_OP_REL_NE;
3546 l->t.t = BC_LEX_OP_REL_LE;
3548 l->t.t = BC_LEX_OP_REL_GE;
3550 return BC_STATUS_LEX_BAD_CHAR;
3558 bc_lex_lineComment(l);
3564 if (isdigit(l->buf[l->i]))
3565 s = bc_lex_number(l, c);
3567 s = BC_STATUS_LEX_BAD_CHAR;
3588 s = bc_lex_number(l, c);
3594 s = dc_lex_string(l);
3600 l->t.t = BC_LEX_INVALID;
3601 s = BC_STATUS_LEX_BAD_CHAR;
3610 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3612 bc_program_addFunc(p->prog, name, idx);
3613 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3616 static void bc_parse_pushName(BcParse *p, char *name)
3618 size_t i = 0, len = strlen(name);
3620 for (; i < len; ++i) bc_parse_push(p, name[i]);
3621 bc_parse_push(p, BC_PARSE_STREND);
3626 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3628 unsigned char amt, i, nums[sizeof(size_t)];
3630 for (amt = 0; idx; ++amt) {
3631 nums[amt] = (char) idx;
3632 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3635 bc_parse_push(p, amt);
3636 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3639 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3641 char *num = xstrdup(p->l.t.v.v);
3642 size_t idx = p->prog->consts.len;
3644 bc_vec_push(&p->prog->consts, &num);
3646 bc_parse_push(p, BC_INST_NUM);
3647 bc_parse_pushIndex(p, idx);
3650 (*prev) = BC_INST_NUM;
3653 static BcStatus bc_parse_text(BcParse *p, const char *text)
3657 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3659 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3660 p->l.t.t = BC_LEX_INVALID;
3663 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3666 return bc_lex_text(&p->l, text);
3669 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3671 if (p->fidx != BC_PROG_MAIN) {
3673 p->func->nparams = 0;
3674 bc_vec_npop(&p->func->code, p->func->code.len);
3675 bc_vec_npop(&p->func->autos, p->func->autos.len);
3676 bc_vec_npop(&p->func->labels, p->func->labels.len);
3678 bc_parse_updateFunc(p, BC_PROG_MAIN);
3682 p->l.t.t = BC_LEX_EOF;
3683 p->auto_part = (p->nbraces = 0);
3685 bc_vec_npop(&p->flags, p->flags.len - 1);
3686 bc_vec_npop(&p->exits, p->exits.len);
3687 bc_vec_npop(&p->conds, p->conds.len);
3688 bc_vec_npop(&p->ops, p->ops.len);
3690 return bc_program_reset(p->prog, s);
3693 static void bc_parse_free(BcParse *p)
3695 bc_vec_free(&p->flags);
3696 bc_vec_free(&p->exits);
3697 bc_vec_free(&p->conds);
3698 bc_vec_free(&p->ops);
3702 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3703 BcParseParse parse, BcLexNext next)
3705 memset(p, 0, sizeof(BcParse));
3707 bc_lex_init(&p->l, next);
3708 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3709 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3710 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3711 bc_vec_pushByte(&p->flags, 0);
3712 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3716 p->auto_part = (p->nbraces = 0);
3717 bc_parse_updateFunc(p, func);
3721 static BcStatus bc_parse_else(BcParse *p);
3722 static BcStatus bc_parse_stmt(BcParse *p);
3724 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3725 size_t *nexprs, bool next)
3727 BcStatus s = BC_STATUS_SUCCESS;
3729 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3730 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3732 while (p->ops.len > start) {
3734 t = BC_PARSE_TOP_OP(p);
3735 if (t == BC_LEX_LPAREN) break;
3737 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3738 if (l >= r && (l != r || !left)) break;
3740 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3741 bc_vec_pop(&p->ops);
3742 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3745 bc_vec_push(&p->ops, &type);
3746 if (next) s = bc_lex_next(&p->l);
3751 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3755 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3756 top = BC_PARSE_TOP_OP(p);
3758 while (top != BC_LEX_LPAREN) {
3760 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3762 bc_vec_pop(&p->ops);
3763 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3765 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3766 top = BC_PARSE_TOP_OP(p);
3769 bc_vec_pop(&p->ops);
3771 return bc_lex_next(&p->l);
3774 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3780 s = bc_lex_next(&p->l);
3783 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3785 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3786 s = bc_parse_expr(p, flags, bc_parse_next_param);
3789 comma = p->l.t.t == BC_LEX_COMMA;
3791 s = bc_lex_next(&p->l);
3796 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3797 bc_parse_push(p, BC_INST_CALL);
3798 bc_parse_pushIndex(p, nparams);
3800 return BC_STATUS_SUCCESS;
3803 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3806 BcId entry, *entry_ptr;
3811 s = bc_parse_params(p, flags);
3814 if (p->l.t.t != BC_LEX_RPAREN) {
3815 s = BC_STATUS_PARSE_BAD_TOKEN;
3819 idx = bc_map_index(&p->prog->fn_map, &entry);
3821 if (idx == BC_VEC_INVALID_IDX) {
3822 name = xstrdup(entry.name);
3823 bc_parse_addFunc(p, name, &idx);
3824 idx = bc_map_index(&p->prog->fn_map, &entry);
3830 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3831 bc_parse_pushIndex(p, entry_ptr->idx);
3833 return bc_lex_next(&p->l);
3840 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3845 name = xstrdup(p->l.t.v.v);
3846 s = bc_lex_next(&p->l);
3849 if (p->l.t.t == BC_LEX_LBRACKET) {
3851 s = bc_lex_next(&p->l);
3854 if (p->l.t.t == BC_LEX_RBRACKET) {
3856 if (!(flags & BC_PARSE_ARRAY)) {
3857 s = BC_STATUS_PARSE_BAD_EXP;
3861 *type = BC_INST_ARRAY;
3865 *type = BC_INST_ARRAY_ELEM;
3867 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3868 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3872 s = bc_lex_next(&p->l);
3874 bc_parse_push(p, *type);
3875 bc_parse_pushName(p, name);
3877 else if (p->l.t.t == BC_LEX_LPAREN) {
3879 if (flags & BC_PARSE_NOCALL) {
3880 s = BC_STATUS_PARSE_BAD_TOKEN;
3884 *type = BC_INST_CALL;
3885 s = bc_parse_call(p, name, flags);
3888 *type = BC_INST_VAR;
3889 bc_parse_push(p, BC_INST_VAR);
3890 bc_parse_pushName(p, name);
3900 static BcStatus bc_parse_read(BcParse *p)
3904 s = bc_lex_next(&p->l);
3906 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3908 s = bc_lex_next(&p->l);
3910 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3912 bc_parse_push(p, BC_INST_READ);
3914 return bc_lex_next(&p->l);
3917 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3922 s = bc_lex_next(&p->l);
3924 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3926 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3928 s = bc_lex_next(&p->l);
3931 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3934 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3936 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3937 bc_parse_push(p, *prev);
3939 return bc_lex_next(&p->l);
3942 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3946 s = bc_lex_next(&p->l);
3949 if (p->l.t.t != BC_LEX_LPAREN) {
3950 *type = BC_INST_SCALE;
3951 bc_parse_push(p, BC_INST_SCALE);
3952 return BC_STATUS_SUCCESS;
3955 *type = BC_INST_SCALE_FUNC;
3956 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3958 s = bc_lex_next(&p->l);
3961 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3963 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3964 bc_parse_push(p, BC_INST_SCALE_FUNC);
3966 return bc_lex_next(&p->l);
3969 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3970 size_t *nexprs, uint8_t flags)
3975 BcInst etype = *prev;
3977 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3978 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3979 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3981 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3982 bc_parse_push(p, inst);
3983 s = bc_lex_next(&p->l);
3987 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3990 s = bc_lex_next(&p->l);
3994 // Because we parse the next part of the expression
3995 // right here, we need to increment this.
3996 *nexprs = *nexprs + 1;
4002 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4006 case BC_LEX_KEY_IBASE:
4007 case BC_LEX_KEY_LAST:
4008 case BC_LEX_KEY_OBASE:
4010 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4011 s = bc_lex_next(&p->l);
4015 case BC_LEX_KEY_SCALE:
4017 s = bc_lex_next(&p->l);
4019 if (p->l.t.t == BC_LEX_LPAREN)
4020 s = BC_STATUS_PARSE_BAD_TOKEN;
4022 bc_parse_push(p, BC_INST_SCALE);
4028 s = BC_STATUS_PARSE_BAD_TOKEN;
4033 if (!s) bc_parse_push(p, inst);
4039 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4040 bool rparen, size_t *nexprs)
4044 BcInst etype = *prev;
4046 s = bc_lex_next(&p->l);
4049 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4050 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4053 *prev = BC_PARSE_TOKEN_INST(type);
4055 // We can just push onto the op stack because this is the largest
4056 // precedence operator that gets pushed. Inc/dec does not.
4057 if (type != BC_LEX_OP_MINUS)
4058 bc_vec_push(&p->ops, &type);
4060 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4065 static BcStatus bc_parse_string(BcParse *p, char inst)
4067 char *str = xstrdup(p->l.t.v.v);
4069 bc_parse_push(p, BC_INST_STR);
4070 bc_parse_pushIndex(p, p->prog->strs.len);
4071 bc_vec_push(&p->prog->strs, &str);
4072 bc_parse_push(p, inst);
4074 return bc_lex_next(&p->l);
4077 static BcStatus bc_parse_print(BcParse *p)
4083 s = bc_lex_next(&p->l);
4088 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4089 return BC_STATUS_PARSE_BAD_PRINT;
4091 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4093 if (type == BC_LEX_STR)
4094 s = bc_parse_string(p, BC_INST_PRINT_POP);
4096 s = bc_parse_expr(p, 0, bc_parse_next_print);
4098 bc_parse_push(p, BC_INST_PRINT_POP);
4103 comma = p->l.t.t == BC_LEX_COMMA;
4104 if (comma) s = bc_lex_next(&p->l);
4109 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4111 return bc_lex_next(&p->l);
4114 static BcStatus bc_parse_return(BcParse *p)
4120 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4122 s = bc_lex_next(&p->l);
4126 paren = t == BC_LEX_LPAREN;
4128 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4129 bc_parse_push(p, BC_INST_RET0);
4132 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4133 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4135 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4136 bc_parse_push(p, BC_INST_RET0);
4137 s = bc_lex_next(&p->l);
4141 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4142 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4146 bc_parse_push(p, BC_INST_RET);
4152 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4154 BcStatus s = BC_STATUS_SUCCESS;
4156 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4157 return BC_STATUS_PARSE_BAD_TOKEN;
4161 if (p->l.t.t == BC_LEX_RBRACE) {
4162 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4164 s = bc_lex_next(&p->l);
4168 return BC_STATUS_PARSE_BAD_TOKEN;
4171 if (BC_PARSE_IF(p)) {
4175 while (p->l.t.t == BC_LEX_NLINE) {
4176 s = bc_lex_next(&p->l);
4180 bc_vec_pop(&p->flags);
4182 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4183 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4185 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4187 else if (BC_PARSE_ELSE(p)) {
4192 bc_vec_pop(&p->flags);
4194 ip = bc_vec_top(&p->exits);
4195 label = bc_vec_item(&p->func->labels, ip->idx);
4196 *label = p->func->code.len;
4198 bc_vec_pop(&p->exits);
4200 else if (BC_PARSE_FUNC_INNER(p)) {
4201 bc_parse_push(p, BC_INST_RET0);
4202 bc_parse_updateFunc(p, BC_PROG_MAIN);
4203 bc_vec_pop(&p->flags);
4207 BcInstPtr *ip = bc_vec_top(&p->exits);
4208 size_t *label = bc_vec_top(&p->conds);
4210 bc_parse_push(p, BC_INST_JUMP);
4211 bc_parse_pushIndex(p, *label);
4213 label = bc_vec_item(&p->func->labels, ip->idx);
4214 *label = p->func->code.len;
4216 bc_vec_pop(&p->flags);
4217 bc_vec_pop(&p->exits);
4218 bc_vec_pop(&p->conds);
4224 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4226 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4227 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4228 flags |= BC_PARSE_FLAG_BODY;
4229 bc_vec_push(&p->flags, &flags);
4232 static void bc_parse_noElse(BcParse *p)
4236 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4238 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4240 ip = bc_vec_top(&p->exits);
4241 label = bc_vec_item(&p->func->labels, ip->idx);
4242 *label = p->func->code.len;
4244 bc_vec_pop(&p->exits);
4247 static BcStatus bc_parse_if(BcParse *p)
4252 s = bc_lex_next(&p->l);
4254 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4256 s = bc_lex_next(&p->l);
4258 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4260 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4262 s = bc_lex_next(&p->l);
4264 bc_parse_push(p, BC_INST_JUMP_ZERO);
4266 ip.idx = p->func->labels.len;
4267 ip.func = ip.len = 0;
4269 bc_parse_pushIndex(p, ip.idx);
4270 bc_vec_push(&p->exits, &ip);
4271 bc_vec_push(&p->func->labels, &ip.idx);
4272 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4274 return BC_STATUS_SUCCESS;
4277 static BcStatus bc_parse_else(BcParse *p)
4281 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4283 ip.idx = p->func->labels.len;
4284 ip.func = ip.len = 0;
4286 bc_parse_push(p, BC_INST_JUMP);
4287 bc_parse_pushIndex(p, ip.idx);
4291 bc_vec_push(&p->exits, &ip);
4292 bc_vec_push(&p->func->labels, &ip.idx);
4293 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4295 return bc_lex_next(&p->l);
4298 static BcStatus bc_parse_while(BcParse *p)
4303 s = bc_lex_next(&p->l);
4305 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4306 s = bc_lex_next(&p->l);
4309 ip.idx = p->func->labels.len;
4311 bc_vec_push(&p->func->labels, &p->func->code.len);
4312 bc_vec_push(&p->conds, &ip.idx);
4314 ip.idx = p->func->labels.len;
4318 bc_vec_push(&p->exits, &ip);
4319 bc_vec_push(&p->func->labels, &ip.idx);
4321 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4323 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4324 s = bc_lex_next(&p->l);
4327 bc_parse_push(p, BC_INST_JUMP_ZERO);
4328 bc_parse_pushIndex(p, ip.idx);
4329 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4331 return BC_STATUS_SUCCESS;
4334 static BcStatus bc_parse_for(BcParse *p)
4338 size_t cond_idx, exit_idx, body_idx, update_idx;
4340 s = bc_lex_next(&p->l);
4342 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4343 s = bc_lex_next(&p->l);
4346 if (p->l.t.t != BC_LEX_SCOLON)
4347 s = bc_parse_expr(p, 0, bc_parse_next_for);
4349 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4352 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4353 s = bc_lex_next(&p->l);
4356 cond_idx = p->func->labels.len;
4357 update_idx = cond_idx + 1;
4358 body_idx = update_idx + 1;
4359 exit_idx = body_idx + 1;
4361 bc_vec_push(&p->func->labels, &p->func->code.len);
4363 if (p->l.t.t != BC_LEX_SCOLON)
4364 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4366 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4369 if (p->l.t.t != BC_LEX_SCOLON) 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, exit_idx);
4376 bc_parse_push(p, BC_INST_JUMP);
4377 bc_parse_pushIndex(p, body_idx);
4379 ip.idx = p->func->labels.len;
4381 bc_vec_push(&p->conds, &update_idx);
4382 bc_vec_push(&p->func->labels, &p->func->code.len);
4384 if (p->l.t.t != BC_LEX_RPAREN)
4385 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4387 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4391 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4392 bc_parse_push(p, BC_INST_JUMP);
4393 bc_parse_pushIndex(p, cond_idx);
4394 bc_vec_push(&p->func->labels, &p->func->code.len);
4400 bc_vec_push(&p->exits, &ip);
4401 bc_vec_push(&p->func->labels, &ip.idx);
4403 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4405 return BC_STATUS_SUCCESS;
4408 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4414 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4416 if (type == BC_LEX_KEY_BREAK) {
4418 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4420 i = p->exits.len - 1;
4421 ip = bc_vec_item(&p->exits, i);
4423 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4424 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4429 i = *((size_t *) bc_vec_top(&p->conds));
4431 bc_parse_push(p, BC_INST_JUMP);
4432 bc_parse_pushIndex(p, i);
4434 s = bc_lex_next(&p->l);
4437 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4438 return BC_STATUS_PARSE_BAD_TOKEN;
4440 return bc_lex_next(&p->l);
4443 static BcStatus bc_parse_func(BcParse *p)
4446 bool var, comma = false;
4450 s = bc_lex_next(&p->l);
4452 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4454 name = xstrdup(p->l.t.v.v);
4455 bc_parse_addFunc(p, name, &p->fidx);
4457 s = bc_lex_next(&p->l);
4459 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4460 s = bc_lex_next(&p->l);
4463 while (p->l.t.t != BC_LEX_RPAREN) {
4465 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4469 name = xstrdup(p->l.t.v.v);
4470 s = bc_lex_next(&p->l);
4473 var = p->l.t.t != BC_LEX_LBRACKET;
4477 s = bc_lex_next(&p->l);
4480 if (p->l.t.t != BC_LEX_RBRACKET) {
4481 s = BC_STATUS_PARSE_BAD_FUNC;
4485 s = bc_lex_next(&p->l);
4489 comma = p->l.t.t == BC_LEX_COMMA;
4491 s = bc_lex_next(&p->l);
4495 s = bc_func_insert(p->func, name, var);
4499 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4501 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4502 bc_parse_startBody(p, flags);
4504 s = bc_lex_next(&p->l);
4507 if (p->l.t.t != BC_LEX_LBRACE)
4508 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4517 static BcStatus bc_parse_auto(BcParse *p)
4520 bool comma, var, one;
4523 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4524 s = bc_lex_next(&p->l);
4527 p->auto_part = comma = false;
4528 one = p->l.t.t == BC_LEX_NAME;
4530 while (p->l.t.t == BC_LEX_NAME) {
4532 name = xstrdup(p->l.t.v.v);
4533 s = bc_lex_next(&p->l);
4536 var = p->l.t.t != BC_LEX_LBRACKET;
4539 s = bc_lex_next(&p->l);
4542 if (p->l.t.t != BC_LEX_RBRACKET) {
4543 s = BC_STATUS_PARSE_BAD_FUNC;
4547 s = bc_lex_next(&p->l);
4551 comma = p->l.t.t == BC_LEX_COMMA;
4553 s = bc_lex_next(&p->l);
4557 s = bc_func_insert(p->func, name, var);
4561 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4562 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4564 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4565 return BC_STATUS_PARSE_BAD_TOKEN;
4567 return bc_lex_next(&p->l);
4574 static BcStatus bc_parse_body(BcParse *p, bool brace)
4576 BcStatus s = BC_STATUS_SUCCESS;
4577 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4579 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4581 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4583 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4584 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4586 if (!p->auto_part) {
4587 s = bc_parse_auto(p);
4591 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4594 s = bc_parse_stmt(p);
4595 if (!s && !brace) s = bc_parse_endBody(p, false);
4601 static BcStatus bc_parse_stmt(BcParse *p)
4603 BcStatus s = BC_STATUS_SUCCESS;
4609 return bc_lex_next(&p->l);
4612 case BC_LEX_KEY_ELSE:
4614 p->auto_part = false;
4620 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4623 s = bc_lex_next(&p->l);
4626 return bc_parse_body(p, true);
4629 case BC_LEX_KEY_AUTO:
4631 return bc_parse_auto(p);
4636 p->auto_part = false;
4638 if (BC_PARSE_IF_END(p)) {
4640 return BC_STATUS_SUCCESS;
4642 else if (BC_PARSE_BODY(p))
4643 return bc_parse_body(p, false);
4653 case BC_LEX_OP_MINUS:
4654 case BC_LEX_OP_BOOL_NOT:
4658 case BC_LEX_KEY_IBASE:
4659 case BC_LEX_KEY_LAST:
4660 case BC_LEX_KEY_LENGTH:
4661 case BC_LEX_KEY_OBASE:
4662 case BC_LEX_KEY_READ:
4663 case BC_LEX_KEY_SCALE:
4664 case BC_LEX_KEY_SQRT:
4666 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4670 case BC_LEX_KEY_ELSE:
4672 s = bc_parse_else(p);
4678 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4684 s = bc_parse_endBody(p, true);
4690 s = bc_parse_string(p, BC_INST_PRINT_STR);
4694 case BC_LEX_KEY_BREAK:
4695 case BC_LEX_KEY_CONTINUE:
4697 s = bc_parse_loopExit(p, p->l.t.t);
4701 case BC_LEX_KEY_FOR:
4703 s = bc_parse_for(p);
4707 case BC_LEX_KEY_HALT:
4709 bc_parse_push(p, BC_INST_HALT);
4710 s = bc_lex_next(&p->l);
4720 case BC_LEX_KEY_LIMITS:
4722 s = bc_lex_next(&p->l);
4724 s = BC_STATUS_LIMITS;
4728 case BC_LEX_KEY_PRINT:
4730 s = bc_parse_print(p);
4734 case BC_LEX_KEY_QUIT:
4736 // Quit is a compile-time command. We don't exit directly,
4737 // so the vm can clean up. Limits do the same thing.
4742 case BC_LEX_KEY_RETURN:
4744 s = bc_parse_return(p);
4748 case BC_LEX_KEY_WHILE:
4750 s = bc_parse_while(p);
4756 s = BC_STATUS_PARSE_BAD_TOKEN;
4764 static BcStatus bc_parse_parse(BcParse *p)
4768 if (p->l.t.t == BC_LEX_EOF)
4769 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4770 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4771 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4772 s = bc_parse_func(p);
4775 s = bc_parse_stmt(p);
4777 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4778 s = bc_parse_reset(p, s);
4783 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4785 BcStatus s = BC_STATUS_SUCCESS;
4786 BcInst prev = BC_INST_PRINT;
4787 BcLexType top, t = p->l.t.t;
4788 size_t nexprs = 0, ops_bgn = p->ops.len;
4789 uint32_t i, nparens, nrelops;
4790 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4792 paren_first = p->l.t.t == BC_LEX_LPAREN;
4793 nparens = nrelops = 0;
4794 paren_expr = rprn = done = get_token = assign = false;
4797 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4803 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4804 rprn = get_token = bin_last = false;
4808 case BC_LEX_OP_MINUS:
4810 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4811 rprn = get_token = false;
4812 bin_last = prev == BC_INST_MINUS;
4816 case BC_LEX_OP_ASSIGN_POWER:
4817 case BC_LEX_OP_ASSIGN_MULTIPLY:
4818 case BC_LEX_OP_ASSIGN_DIVIDE:
4819 case BC_LEX_OP_ASSIGN_MODULUS:
4820 case BC_LEX_OP_ASSIGN_PLUS:
4821 case BC_LEX_OP_ASSIGN_MINUS:
4822 case BC_LEX_OP_ASSIGN:
4824 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4825 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4826 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4828 s = BC_STATUS_PARSE_BAD_ASSIGN;
4833 case BC_LEX_OP_POWER:
4834 case BC_LEX_OP_MULTIPLY:
4835 case BC_LEX_OP_DIVIDE:
4836 case BC_LEX_OP_MODULUS:
4837 case BC_LEX_OP_PLUS:
4838 case BC_LEX_OP_REL_EQ:
4839 case BC_LEX_OP_REL_LE:
4840 case BC_LEX_OP_REL_GE:
4841 case BC_LEX_OP_REL_NE:
4842 case BC_LEX_OP_REL_LT:
4843 case BC_LEX_OP_REL_GT:
4844 case BC_LEX_OP_BOOL_NOT:
4845 case BC_LEX_OP_BOOL_OR:
4846 case BC_LEX_OP_BOOL_AND:
4848 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4849 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4851 return BC_STATUS_PARSE_BAD_EXP;
4854 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4855 prev = BC_PARSE_TOKEN_INST(t);
4856 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4857 rprn = get_token = false;
4858 bin_last = t != BC_LEX_OP_BOOL_NOT;
4865 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4868 paren_expr = rprn = bin_last = false;
4870 bc_vec_push(&p->ops, &t);
4877 if (bin_last || prev == BC_INST_BOOL_NOT)
4878 return BC_STATUS_PARSE_BAD_EXP;
4881 s = BC_STATUS_SUCCESS;
4886 else if (!paren_expr)
4887 return BC_STATUS_PARSE_EMPTY_EXP;
4890 paren_expr = rprn = true;
4891 get_token = bin_last = false;
4893 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4900 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4903 rprn = get_token = bin_last = false;
4904 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4912 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4914 bc_parse_number(p, &prev, &nexprs);
4915 paren_expr = get_token = true;
4916 rprn = bin_last = false;
4921 case BC_LEX_KEY_IBASE:
4922 case BC_LEX_KEY_LAST:
4923 case BC_LEX_KEY_OBASE:
4925 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4927 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4928 bc_parse_push(p, (char) prev);
4930 paren_expr = get_token = true;
4931 rprn = bin_last = false;
4937 case BC_LEX_KEY_LENGTH:
4938 case BC_LEX_KEY_SQRT:
4940 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4942 s = bc_parse_builtin(p, t, flags, &prev);
4944 rprn = get_token = bin_last = false;
4950 case BC_LEX_KEY_READ:
4952 if (BC_PARSE_LEAF(prev, rprn))
4953 return BC_STATUS_PARSE_BAD_EXP;
4954 else if (flags & BC_PARSE_NOREAD)
4955 s = BC_STATUS_EXEC_REC_READ;
4957 s = bc_parse_read(p);
4960 rprn = get_token = bin_last = false;
4962 prev = BC_INST_READ;
4967 case BC_LEX_KEY_SCALE:
4969 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4971 s = bc_parse_scale(p, &prev, flags);
4973 rprn = get_token = bin_last = false;
4975 prev = BC_INST_SCALE;
4982 s = BC_STATUS_PARSE_BAD_TOKEN;
4987 if (!s && get_token) s = bc_lex_next(&p->l);
4991 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4993 while (p->ops.len > ops_bgn) {
4995 top = BC_PARSE_TOP_OP(p);
4996 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4998 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4999 return BC_STATUS_PARSE_BAD_EXP;
5001 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5003 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5004 bc_vec_pop(&p->ops);
5007 s = BC_STATUS_PARSE_BAD_EXP;
5008 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5010 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5013 if (!(flags & BC_PARSE_REL) && nrelops) {
5014 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5017 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5018 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5022 if (flags & BC_PARSE_PRINT) {
5023 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5024 bc_parse_push(p, BC_INST_POP);
5030 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5032 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5035 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5037 return bc_parse_expr(p, flags, bc_parse_next_read);
5042 static BcStatus dc_parse_register(BcParse *p)
5047 s = bc_lex_next(&p->l);
5049 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5051 name = xstrdup(p->l.t.v.v);
5052 bc_parse_pushName(p, name);
5057 static BcStatus dc_parse_string(BcParse *p)
5059 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5060 size_t idx, len = p->prog->strs.len;
5062 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5065 str = xstrdup(p->l.t.v.v);
5066 bc_parse_push(p, BC_INST_STR);
5067 bc_parse_pushIndex(p, len);
5068 bc_vec_push(&p->prog->strs, &str);
5069 bc_parse_addFunc(p, name, &idx);
5071 return bc_lex_next(&p->l);
5074 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5078 bc_parse_push(p, inst);
5080 s = dc_parse_register(p);
5085 bc_parse_push(p, BC_INST_SWAP);
5086 bc_parse_push(p, BC_INST_ASSIGN);
5087 bc_parse_push(p, BC_INST_POP);
5090 return bc_lex_next(&p->l);
5093 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5097 bc_parse_push(p, inst);
5098 bc_parse_push(p, BC_INST_EXEC_COND);
5100 s = dc_parse_register(p);
5103 s = bc_lex_next(&p->l);
5106 if (p->l.t.t == BC_LEX_ELSE) {
5107 s = dc_parse_register(p);
5109 s = bc_lex_next(&p->l);
5112 bc_parse_push(p, BC_PARSE_STREND);
5117 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5119 BcStatus s = BC_STATUS_SUCCESS;
5122 bool assign, get_token = false;
5126 case BC_LEX_OP_REL_EQ:
5127 case BC_LEX_OP_REL_LE:
5128 case BC_LEX_OP_REL_GE:
5129 case BC_LEX_OP_REL_NE:
5130 case BC_LEX_OP_REL_LT:
5131 case BC_LEX_OP_REL_GT:
5133 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5140 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5146 s = dc_parse_string(p);
5153 if (t == BC_LEX_NEG) {
5154 s = bc_lex_next(&p->l);
5156 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5159 bc_parse_number(p, &prev, &p->nbraces);
5161 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5167 case BC_LEX_KEY_READ:
5169 if (flags & BC_PARSE_NOREAD)
5170 s = BC_STATUS_EXEC_REC_READ;
5172 bc_parse_push(p, BC_INST_READ);
5177 case BC_LEX_OP_ASSIGN:
5178 case BC_LEX_STORE_PUSH:
5180 assign = t == BC_LEX_OP_ASSIGN;
5181 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5182 s = dc_parse_mem(p, inst, true, assign);
5187 case BC_LEX_LOAD_POP:
5189 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5190 s = dc_parse_mem(p, inst, true, false);
5194 case BC_LEX_STORE_IBASE:
5195 case BC_LEX_STORE_SCALE:
5196 case BC_LEX_STORE_OBASE:
5198 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5199 s = dc_parse_mem(p, inst, false, true);
5205 s = BC_STATUS_PARSE_BAD_TOKEN;
5211 if (!s && get_token) s = bc_lex_next(&p->l);
5216 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5218 BcStatus s = BC_STATUS_SUCCESS;
5222 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5224 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5226 inst = dc_parse_insts[t];
5228 if (inst != BC_INST_INVALID) {
5229 bc_parse_push(p, inst);
5230 s = bc_lex_next(&p->l);
5233 s = dc_parse_token(p, t, flags);
5236 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5237 bc_parse_push(p, BC_INST_POP_EXEC);
5242 static BcStatus dc_parse_parse(BcParse *p)
5246 if (p->l.t.t == BC_LEX_EOF)
5247 s = BC_STATUS_LEX_EOF;
5249 s = dc_parse_expr(p, 0);
5251 if (s || G_interrupt) s = bc_parse_reset(p, s);
5256 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5258 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5262 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5271 v = var ? &p->vars : &p->arrs;
5272 map = var ? &p->var_map : &p->arr_map;
5276 s = bc_map_insert(map, &e, &i);
5277 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5280 bc_array_init(&data.v, var);
5281 bc_vec_push(v, &data.v);
5284 ptr = bc_vec_item(map, i);
5285 if (new) ptr->name = xstrdup(e.name);
5286 *ret = bc_vec_item(v, ptr->idx);
5289 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5291 BcStatus s = BC_STATUS_SUCCESS;
5296 case BC_RESULT_TEMP:
5297 case BC_RESULT_IBASE:
5298 case BC_RESULT_SCALE:
5299 case BC_RESULT_OBASE:
5305 case BC_RESULT_CONSTANT:
5307 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5308 size_t base_t, len = strlen(*str);
5311 bc_num_init(&r->d.n, len);
5313 hex = hex && len == 1;
5314 base = hex ? &p->hexb : &p->ib;
5315 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5316 s = bc_num_parse(&r->d.n, *str, base, base_t);
5319 bc_num_free(&r->d.n);
5324 r->t = BC_RESULT_TEMP;
5330 case BC_RESULT_ARRAY:
5331 case BC_RESULT_ARRAY_ELEM:
5335 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5337 if (r->t == BC_RESULT_ARRAY_ELEM) {
5339 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5340 *num = bc_vec_item(v, r->d.id.idx);
5343 *num = bc_vec_top(v);
5348 case BC_RESULT_LAST:
5364 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5365 BcResult **r, BcNum **rn, bool assign)
5369 BcResultType lt, rt;
5371 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5373 *r = bc_vec_item_rev(&p->results, 0);
5374 *l = bc_vec_item_rev(&p->results, 1);
5378 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5380 s = bc_program_num(p, *l, ln, false);
5382 s = bc_program_num(p, *r, rn, hex);
5385 // We run this again under these conditions in case any vector has been
5386 // reallocated out from under the BcNums or arrays we had.
5387 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5388 s = bc_program_num(p, *l, ln, false);
5392 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5393 return BC_STATUS_EXEC_BAD_TYPE;
5394 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5399 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5401 r->t = BC_RESULT_TEMP;
5402 bc_vec_pop(&p->results);
5403 bc_vec_pop(&p->results);
5404 bc_vec_push(&p->results, r);
5407 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5411 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5412 *r = bc_vec_top(&p->results);
5414 s = bc_program_num(p, *r, n, false);
5417 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5422 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5425 bc_vec_pop(&p->results);
5426 bc_vec_push(&p->results, r);
5429 static BcStatus bc_program_op(BcProgram *p, char inst)
5432 BcResult *opd1, *opd2, res;
5433 BcNum *n1, *n2 = NULL;
5435 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5437 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5439 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5441 bc_program_binOpRetire(p, &res);
5446 bc_num_free(&res.d.n);
5450 static BcStatus bc_program_read(void)
5452 BcProgram *p = &G.prog;
5459 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5461 for (i = 0; i < p->stack.len; ++i) {
5462 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5463 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5466 bc_vec_npop(&f->code, f->code.len);
5467 bc_vec_init(&buf, sizeof(char), NULL);
5469 s = bc_read_line(&buf, "read> ");
5472 p->parse_init(&parse, p, BC_PROG_READ);
5473 bc_lex_file(&parse.l, bc_program_stdin_name);
5475 s = bc_parse_text(&parse, buf.v);
5476 if (s) goto exec_err;
5477 /// replace by IS_BC selection
5478 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5479 if (s) goto exec_err;
5481 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5482 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5486 ip.func = BC_PROG_READ;
5488 ip.len = p->results.len;
5490 // Update this pointer, just in case.
5491 f = bc_vec_item(&p->fns, BC_PROG_READ);
5493 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5494 bc_vec_push(&p->stack, &ip);
5497 bc_parse_free(&parse);
5503 static size_t bc_program_index(char *code, size_t *bgn)
5505 char amt = code[(*bgn)++], i = 0;
5508 for (; i < amt; ++i, ++(*bgn))
5509 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5514 static char *bc_program_name(char *code, size_t *bgn)
5517 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5519 s = xmalloc(ptr - str + 1);
5522 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5530 static void bc_program_printString(const char *str, size_t *nchars)
5532 size_t i, len = strlen(str);
5541 for (i = 0; i < len; ++i, ++(*nchars)) {
5545 if (c != '\\' || i == len - 1)
5605 // Just print the backslash and following character.
5616 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5618 BcStatus s = BC_STATUS_SUCCESS;
5623 bool pop = inst != BC_INST_PRINT;
5625 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5627 r = bc_vec_item_rev(&p->results, idx);
5628 s = bc_program_num(p, r, &num, false);
5631 if (BC_PROG_NUM(r, num)) {
5632 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5633 if (!s) bc_num_copy(&p->last, num);
5637 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5638 str = *((char **) bc_vec_item(&p->strs, idx));
5640 if (inst == BC_INST_PRINT_STR) {
5641 for (i = 0, len = strlen(str); i < len; ++i) {
5644 if (c == '\n') p->nchars = SIZE_MAX;
5649 bc_program_printString(str, &p->nchars);
5650 if (inst == BC_INST_PRINT) bb_putchar('\n');
5654 if (!s && pop) bc_vec_pop(&p->results);
5659 static BcStatus bc_program_negate(BcProgram *p)
5665 s = bc_program_prep(p, &ptr, &num);
5668 bc_num_init(&res.d.n, num->len);
5669 bc_num_copy(&res.d.n, num);
5670 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5672 bc_program_retire(p, &res, BC_RESULT_TEMP);
5677 static BcStatus bc_program_logical(BcProgram *p, char inst)
5680 BcResult *opd1, *opd2, res;
5685 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5687 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5689 if (inst == BC_INST_BOOL_AND)
5690 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5691 else if (inst == BC_INST_BOOL_OR)
5692 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5695 cmp = bc_num_cmp(n1, n2);
5699 case BC_INST_REL_EQ:
5705 case BC_INST_REL_LE:
5711 case BC_INST_REL_GE:
5717 case BC_INST_REL_NE:
5723 case BC_INST_REL_LT:
5729 case BC_INST_REL_GT:
5737 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5739 bc_program_binOpRetire(p, &res);
5745 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5751 memset(&n2, 0, sizeof(BcNum));
5752 n2.rdx = res.d.id.idx = r->d.id.idx;
5753 res.t = BC_RESULT_STR;
5756 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5758 bc_vec_pop(&p->results);
5761 bc_vec_pop(&p->results);
5763 bc_vec_push(&p->results, &res);
5764 bc_vec_push(v, &n2);
5766 return BC_STATUS_SUCCESS;
5770 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5777 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5779 ptr = bc_vec_top(&p->results);
5780 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5781 bc_program_search(p, name, &v, var);
5784 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5785 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5788 s = bc_program_num(p, ptr, &n, false);
5791 // Do this once more to make sure that pointers were not invalidated.
5792 bc_program_search(p, name, &v, var);
5795 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5796 bc_num_copy(&r.d.n, n);
5799 bc_array_init(&r.d.v, true);
5800 bc_array_copy(&r.d.v, (BcVec *) n);
5803 bc_vec_push(v, &r.d);
5804 bc_vec_pop(&p->results);
5809 static BcStatus bc_program_assign(BcProgram *p, char inst)
5812 BcResult *left, *right, res;
5813 BcNum *l = NULL, *r = NULL;
5814 unsigned long val, max;
5815 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5817 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5820 ib = left->t == BC_RESULT_IBASE;
5821 sc = left->t == BC_RESULT_SCALE;
5825 if (right->t == BC_RESULT_STR) {
5829 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5830 bc_program_search(p, left->d.id.name, &v, true);
5832 return bc_program_assignStr(p, right, v, false);
5836 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5837 return BC_STATUS_PARSE_BAD_ASSIGN;
5840 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5841 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5846 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5853 if (ib || sc || left->t == BC_RESULT_OBASE) {
5857 s = bc_num_ulong(l, &val);
5859 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5866 if (val < BC_NUM_MIN_BASE) return s;
5867 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5868 ptr = ib ? &p->ib_t : &p->ob_t;
5871 if (val > max) return s;
5872 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5874 *ptr = (size_t) val;
5875 s = BC_STATUS_SUCCESS;
5878 bc_num_init(&res.d.n, l->len);
5879 bc_num_copy(&res.d.n, l);
5880 bc_program_binOpRetire(p, &res);
5885 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5886 bool pop, bool copy)
5888 BcStatus s = BC_STATUS_SUCCESS;
5890 char *name = bc_program_name(code, bgn);
5891 #if ENABLE_DC // Exclude
5895 (void) pop, (void) copy;
5898 r.t = BC_RESULT_VAR;
5902 bc_program_search(p, name, &v, true);
5903 num = bc_vec_top(v);
5907 if (!BC_PROG_STACK(v, 2 - copy)) {
5909 return BC_STATUS_EXEC_STACK;
5915 if (!BC_PROG_STR(num)) {
5917 r.t = BC_RESULT_TEMP;
5919 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5920 bc_num_copy(&r.d.n, num);
5923 r.t = BC_RESULT_STR;
5924 r.d.id.idx = num->rdx;
5927 if (!copy) bc_vec_pop(v);
5931 bc_vec_push(&p->results, &r);
5936 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5939 BcStatus s = BC_STATUS_SUCCESS;
5943 r.d.id.name = bc_program_name(code, bgn);
5945 if (inst == BC_INST_ARRAY) {
5946 r.t = BC_RESULT_ARRAY;
5947 bc_vec_push(&p->results, &r);
5954 s = bc_program_prep(p, &operand, &num);
5956 s = bc_num_ulong(num, &temp);
5959 if (temp > BC_MAX_DIM) {
5960 s = BC_STATUS_EXEC_ARRAY_LEN;
5964 r.d.id.idx = (size_t) temp;
5965 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5969 if (s) free(r.d.id.name);
5974 static BcStatus bc_program_incdec(BcProgram *p, char inst)
5977 BcResult *ptr, res, copy;
5981 s = bc_program_prep(p, &ptr, &num);
5984 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5985 copy.t = BC_RESULT_TEMP;
5986 bc_num_init(©.d.n, num->len);
5987 bc_num_copy(©.d.n, num);
5990 res.t = BC_RESULT_ONE;
5991 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5992 BC_INST_ASSIGN_PLUS :
5993 BC_INST_ASSIGN_MINUS;
5995 bc_vec_push(&p->results, &res);
5996 bc_program_assign(p, inst);
5998 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5999 bc_vec_pop(&p->results);
6000 bc_vec_push(&p->results, ©);
6006 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6008 BcStatus s = BC_STATUS_SUCCESS;
6010 size_t i, nparams = bc_program_index(code, idx);
6018 ip.func = bc_program_index(code, idx);
6019 func = bc_vec_item(&p->fns, ip.func);
6021 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6022 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6023 ip.len = p->results.len - nparams;
6025 for (i = 0; i < nparams; ++i) {
6027 a = bc_vec_item(&func->autos, nparams - 1 - i);
6028 arg = bc_vec_top(&p->results);
6030 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6031 return BC_STATUS_EXEC_BAD_TYPE;
6033 s = bc_program_copyToVar(p, a->name, a->idx);
6037 for (; i < func->autos.len; ++i) {
6039 a = bc_vec_item(&func->autos, i);
6040 bc_program_search(p, a->name, &v, a->idx);
6043 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6044 bc_vec_push(v, ¶m.n);
6047 bc_array_init(¶m.v, true);
6048 bc_vec_push(v, ¶m.v);
6052 bc_vec_push(&p->stack, &ip);
6054 return BC_STATUS_SUCCESS;
6057 static BcStatus bc_program_return(BcProgram *p, char inst)
6063 BcInstPtr *ip = bc_vec_top(&p->stack);
6065 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6066 return BC_STATUS_EXEC_STACK;
6068 f = bc_vec_item(&p->fns, ip->func);
6069 res.t = BC_RESULT_TEMP;
6071 if (inst == BC_INST_RET) {
6074 BcResult *operand = bc_vec_top(&p->results);
6076 s = bc_program_num(p, operand, &num, false);
6078 bc_num_init(&res.d.n, num->len);
6079 bc_num_copy(&res.d.n, num);
6082 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6083 bc_num_zero(&res.d.n);
6086 // We need to pop arguments as well, so this takes that into account.
6087 for (i = 0; i < f->autos.len; ++i) {
6090 BcId *a = bc_vec_item(&f->autos, i);
6092 bc_program_search(p, a->name, &v, a->idx);
6096 bc_vec_npop(&p->results, p->results.len - ip->len);
6097 bc_vec_push(&p->results, &res);
6098 bc_vec_pop(&p->stack);
6100 return BC_STATUS_SUCCESS;
6104 static unsigned long bc_program_scale(BcNum *n)
6106 return (unsigned long) n->rdx;
6109 static unsigned long bc_program_len(BcNum *n)
6111 unsigned long len = n->len;
6114 if (n->rdx != n->len) return len;
6115 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6120 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6126 bool len = inst == BC_INST_LENGTH;
6128 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6129 opnd = bc_vec_top(&p->results);
6131 s = bc_program_num(p, opnd, &num, false);
6135 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6138 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6140 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6142 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6143 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6147 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6150 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6152 str = bc_vec_item(&p->strs, idx);
6153 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6158 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6159 s = bc_num_ulong2num(&res.d.n, f(num));
6163 bc_program_retire(p, &res, BC_RESULT_TEMP);
6168 bc_num_free(&res.d.n);
6173 static BcStatus bc_program_divmod(BcProgram *p)
6176 BcResult *opd1, *opd2, res, res2;
6177 BcNum *n1, *n2 = NULL;
6179 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6182 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6183 bc_num_init(&res2.d.n, n2->len);
6185 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6188 bc_program_binOpRetire(p, &res2);
6189 res.t = BC_RESULT_TEMP;
6190 bc_vec_push(&p->results, &res);
6195 bc_num_free(&res2.d.n);
6196 bc_num_free(&res.d.n);
6200 static BcStatus bc_program_modexp(BcProgram *p)
6203 BcResult *r1, *r2, *r3, res;
6204 BcNum *n1, *n2, *n3;
6206 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6207 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6210 r1 = bc_vec_item_rev(&p->results, 2);
6211 s = bc_program_num(p, r1, &n1, false);
6213 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6215 // Make sure that the values have their pointers updated, if necessary.
6216 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6218 if (r1->t == r2->t) {
6219 s = bc_program_num(p, r2, &n2, false);
6223 if (r1->t == r3->t) {
6224 s = bc_program_num(p, r3, &n3, false);
6229 bc_num_init(&res.d.n, n3->len);
6230 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6233 bc_vec_pop(&p->results);
6234 bc_program_binOpRetire(p, &res);
6239 bc_num_free(&res.d.n);
6243 static BcStatus bc_program_stackLen(BcProgram *p)
6247 size_t len = p->results.len;
6249 res.t = BC_RESULT_TEMP;
6251 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6252 s = bc_num_ulong2num(&res.d.n, len);
6254 bc_vec_push(&p->results, &res);
6259 bc_num_free(&res.d.n);
6263 static BcStatus bc_program_asciify(BcProgram *p)
6267 BcNum *num = NULL, n;
6268 char *str, *str2, c;
6269 size_t len = p->strs.len, idx;
6272 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6273 r = bc_vec_top(&p->results);
6275 s = bc_program_num(p, r, &num, false);
6278 if (BC_PROG_NUM(r, num)) {
6280 bc_num_init(&n, BC_NUM_DEF_SIZE);
6281 bc_num_copy(&n, num);
6282 bc_num_truncate(&n, n.rdx);
6284 s = bc_num_mod(&n, &p->strmb, &n, 0);
6285 if (s) goto num_err;
6286 s = bc_num_ulong(&n, &val);
6287 if (s) goto num_err;
6294 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6295 str2 = *((char **) bc_vec_item(&p->strs, idx));
6303 str2 = xstrdup(str);
6304 bc_program_addFunc(p, str2, &idx);
6306 if (idx != len + BC_PROG_REQ_FUNCS) {
6308 for (idx = 0; idx < p->strs.len; ++idx) {
6309 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6318 bc_vec_push(&p->strs, &str);
6320 res.t = BC_RESULT_STR;
6322 bc_vec_pop(&p->results);
6323 bc_vec_push(&p->results, &res);
6325 return BC_STATUS_SUCCESS;
6332 static BcStatus bc_program_printStream(BcProgram *p)
6340 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6341 r = bc_vec_top(&p->results);
6343 s = bc_program_num(p, r, &n, false);
6346 if (BC_PROG_NUM(r, n))
6347 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6349 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6350 str = *((char **) bc_vec_item(&p->strs, idx));
6357 static BcStatus bc_program_nquit(void)
6359 BcProgram *p = &G.prog;
6366 s = bc_program_prep(p, &opnd, &num);
6368 s = bc_num_ulong(num, &val);
6371 bc_vec_pop(&p->results);
6373 if (p->stack.len < val)
6374 return BC_STATUS_EXEC_STACK;
6375 else if (p->stack.len == val)
6376 return BC_STATUS_QUIT;
6378 bc_vec_npop(&p->stack, val);
6383 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6386 BcProgram *p = &G.prog;
6388 BcStatus s = BC_STATUS_SUCCESS;
6398 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6400 r = bc_vec_top(&p->results);
6405 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6407 if (code[*bgn] == BC_PARSE_STREND)
6410 else_name = bc_program_name(code, bgn);
6412 exec = r->d.n.len != 0;
6416 else if (else_name != NULL) {
6422 bc_program_search(p, name, &v, true);
6429 if (!exec) goto exit;
6430 if (!BC_PROG_STR(n)) {
6431 s = BC_STATUS_EXEC_BAD_TYPE;
6439 if (r->t == BC_RESULT_STR)
6441 else if (r->t == BC_RESULT_VAR) {
6442 s = bc_program_num(p, r, &n, false);
6443 if (s || !BC_PROG_STR(n)) goto exit;
6450 fidx = sidx + BC_PROG_REQ_FUNCS;
6452 str = bc_vec_item(&p->strs, sidx);
6453 f = bc_vec_item(&p->fns, fidx);
6455 if (f->code.len == 0) {
6456 /// replace by IS_BC selection
6457 p->parse_init(&prs, p, fidx);
6458 s = bc_parse_text(&prs, *str);
6460 /// replace by IS_BC selection
6461 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6464 if (prs.l.t.t != BC_LEX_EOF) {
6465 s = BC_STATUS_PARSE_BAD_EXP;
6469 bc_parse_free(&prs);
6473 ip.len = p->results.len;
6476 bc_vec_pop(&p->results);
6477 bc_vec_push(&p->stack, &ip);
6479 return BC_STATUS_SUCCESS;
6482 bc_parse_free(&prs);
6483 f = bc_vec_item(&p->fns, fidx);
6484 bc_vec_npop(&f->code, f->code.len);
6486 bc_vec_pop(&p->results);
6491 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6497 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6498 if (inst == BC_INST_IBASE)
6499 val = (unsigned long) p->ib_t;
6500 else if (inst == BC_INST_SCALE)
6501 val = (unsigned long) p->scale;
6503 val = (unsigned long) p->ob_t;
6505 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6506 s = bc_num_ulong2num(&res.d.n, val);
6508 bc_vec_push(&p->results, &res);
6513 bc_num_free(&res.d.n);
6517 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6520 BcId entry, *entry_ptr;
6524 entry.idx = p->fns.len;
6526 s = bc_map_insert(&p->fn_map, &entry, idx);
6529 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6530 *idx = entry_ptr->idx;
6532 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6534 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6536 // We need to reset these, so the function can be repopulated.
6538 bc_vec_npop(&func->autos, func->autos.len);
6539 bc_vec_npop(&func->code, func->code.len);
6540 bc_vec_npop(&func->labels, func->labels.len);
6544 bc_vec_push(&p->fns, &f);
6548 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6553 bc_vec_npop(&p->stack, p->stack.len - 1);
6554 bc_vec_npop(&p->results, p->results.len);
6556 f = bc_vec_item(&p->fns, 0);
6557 ip = bc_vec_top(&p->stack);
6558 ip->idx = f->code.len;
6560 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6562 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6565 fputs(bc_program_ready_msg, stderr);
6567 s = BC_STATUS_SUCCESS;
6576 static BcStatus bc_program_exec(void)
6578 BcProgram *p = &G.prog;
6580 BcStatus s = BC_STATUS_SUCCESS;
6584 BcInstPtr *ip = bc_vec_top(&p->stack);
6585 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6586 char *code = func->code.v;
6589 while (!s && ip->idx < func->code.len) {
6591 char inst = code[(ip->idx)++];
6596 case BC_INST_JUMP_ZERO:
6598 s = bc_program_prep(p, &ptr, &num);
6600 cond = !bc_num_cmp(num, &p->zero);
6601 bc_vec_pop(&p->results);
6607 idx = bc_program_index(code, &ip->idx);
6608 addr = bc_vec_item(&func->labels, idx);
6609 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6615 s = bc_program_call(p, code, &ip->idx);
6619 case BC_INST_INC_PRE:
6620 case BC_INST_DEC_PRE:
6621 case BC_INST_INC_POST:
6622 case BC_INST_DEC_POST:
6624 s = bc_program_incdec(p, inst);
6637 s = bc_program_return(p, inst);
6641 case BC_INST_BOOL_OR:
6642 case BC_INST_BOOL_AND:
6644 case BC_INST_REL_EQ:
6645 case BC_INST_REL_LE:
6646 case BC_INST_REL_GE:
6647 case BC_INST_REL_NE:
6648 case BC_INST_REL_LT:
6649 case BC_INST_REL_GT:
6651 s = bc_program_logical(p, inst);
6657 s = bc_program_read();
6663 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6667 case BC_INST_ARRAY_ELEM:
6670 s = bc_program_pushArray(p, code, &ip->idx, inst);
6676 r.t = BC_RESULT_LAST;
6677 bc_vec_push(&p->results, &r);
6685 s = bc_program_pushGlobal(p, inst);
6689 case BC_INST_SCALE_FUNC:
6690 case BC_INST_LENGTH:
6693 s = bc_program_builtin(p, inst);
6699 r.t = BC_RESULT_CONSTANT;
6700 r.d.id.idx = bc_program_index(code, &ip->idx);
6701 bc_vec_push(&p->results, &r);
6707 if (!BC_PROG_STACK(&p->results, 1))
6708 s = BC_STATUS_EXEC_STACK;
6710 bc_vec_pop(&p->results);
6714 case BC_INST_POP_EXEC:
6716 bc_vec_pop(&p->stack);
6721 case BC_INST_PRINT_POP:
6722 case BC_INST_PRINT_STR:
6724 s = bc_program_print(p, inst, 0);
6730 r.t = BC_RESULT_STR;
6731 r.d.id.idx = bc_program_index(code, &ip->idx);
6732 bc_vec_push(&p->results, &r);
6737 case BC_INST_MULTIPLY:
6738 case BC_INST_DIVIDE:
6739 case BC_INST_MODULUS:
6743 s = bc_program_op(p, inst);
6747 case BC_INST_BOOL_NOT:
6749 s = bc_program_prep(p, &ptr, &num);
6752 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6753 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6754 bc_program_retire(p, &r, BC_RESULT_TEMP);
6761 s = bc_program_negate(p);
6766 case BC_INST_ASSIGN_POWER:
6767 case BC_INST_ASSIGN_MULTIPLY:
6768 case BC_INST_ASSIGN_DIVIDE:
6769 case BC_INST_ASSIGN_MODULUS:
6770 case BC_INST_ASSIGN_PLUS:
6771 case BC_INST_ASSIGN_MINUS:
6773 case BC_INST_ASSIGN:
6775 s = bc_program_assign(p, inst);
6779 case BC_INST_MODEXP:
6781 s = bc_program_modexp(p);
6785 case BC_INST_DIVMOD:
6787 s = bc_program_divmod(p);
6791 case BC_INST_EXECUTE:
6792 case BC_INST_EXEC_COND:
6794 cond = inst == BC_INST_EXEC_COND;
6795 s = bc_program_execStr(code, &ip->idx, cond);
6799 case BC_INST_PRINT_STACK:
6801 for (idx = 0; !s && idx < p->results.len; ++idx)
6802 s = bc_program_print(p, BC_INST_PRINT, idx);
6806 case BC_INST_CLEAR_STACK:
6808 bc_vec_npop(&p->results, p->results.len);
6812 case BC_INST_STACK_LEN:
6814 s = bc_program_stackLen(p);
6818 case BC_INST_DUPLICATE:
6820 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6821 ptr = bc_vec_top(&p->results);
6822 bc_result_copy(&r, ptr);
6823 bc_vec_push(&p->results, &r);
6831 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6833 ptr = bc_vec_item_rev(&p->results, 0);
6834 ptr2 = bc_vec_item_rev(&p->results, 1);
6835 memcpy(&r, ptr, sizeof(BcResult));
6836 memcpy(ptr, ptr2, sizeof(BcResult));
6837 memcpy(ptr2, &r, sizeof(BcResult));
6842 case BC_INST_ASCIIFY:
6844 s = bc_program_asciify(p);
6848 case BC_INST_PRINT_STREAM:
6850 s = bc_program_printStream(p);
6855 case BC_INST_PUSH_VAR:
6857 bool copy = inst == BC_INST_LOAD;
6858 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6862 case BC_INST_PUSH_TO_VAR:
6864 char *name = bc_program_name(code, &ip->idx);
6865 s = bc_program_copyToVar(p, name, true);
6872 if (p->stack.len <= 2)
6875 bc_vec_npop(&p->stack, 2);
6881 s = bc_program_nquit();
6887 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(p, s);
6889 // If the stack has changed, pointers may be invalid.
6890 ip = bc_vec_top(&p->stack);
6891 func = bc_vec_item(&p->fns, ip->func);
6892 code = func->code.v;
6898 static void bc_vm_info(void)
6900 printf("%s "BB_VER"\n"
6901 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6902 "Report bugs at: https://github.com/gavinhoward/bc\n"
6903 "This is free software with ABSOLUTELY NO WARRANTY\n"
6907 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6909 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6911 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6912 fprintf(stderr, " %s", file);
6913 fprintf(stderr, bc_err_line + 4 * !line, line);
6915 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6919 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6922 int p = (int) G_posix, w = (int) G_warn;
6923 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6925 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6927 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6928 if (msg) fprintf(stderr, " %s\n", msg);
6929 fprintf(stderr, " %s", file);
6930 fprintf(stderr, bc_err_line + 4 * !line, line);
6932 return s * (!G.ttyin && !!p);
6935 static void bc_vm_envArgs(void)
6938 char *env_args = getenv(bc_args_env_name), *buf;
6940 if (!env_args) return;
6942 G.env_args = xstrdup(env_args);
6945 bc_vec_init(&v, sizeof(char *), NULL);
6946 bc_vec_push(&v, &bc_args_env_name);
6949 if (!isspace(*buf)) {
6950 bc_vec_push(&v, &buf);
6951 while (*buf != 0 && !isspace(*buf)) ++buf;
6952 if (*buf != 0) (*(buf++)) = '\0';
6958 bc_args((int) v.len, (char **) v.v);
6964 static size_t bc_vm_envLen(const char *var)
6966 char *lenv = getenv(var);
6967 size_t i, len = BC_NUM_PRINT_WIDTH;
6970 if (!lenv) return len;
6974 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6976 len = (size_t) atoi(lenv) - 1;
6977 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6980 len = BC_NUM_PRINT_WIDTH;
6985 static BcStatus bc_vm_process(const char *text)
6987 BcStatus s = bc_parse_text(&G.prs, text);
6989 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6992 while (G.prs.l.t.t != BC_LEX_EOF) {
6994 s = G.prs.parse(&G.prs);
6996 if (s == BC_STATUS_LIMITS) {
6999 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7000 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7001 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7002 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7003 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7004 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7005 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7006 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7009 s = BC_STATUS_SUCCESS;
7012 if (s == BC_STATUS_QUIT) return s;
7013 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7018 if (BC_PARSE_CAN_EXEC(&G.prs)) {
7019 s = bc_program_exec();
7020 if (!s && G.tty) fflush(stdout);
7021 if (s && s != BC_STATUS_QUIT)
7022 s = bc_vm_error(bc_program_reset(&G.prog, s), G.prs.l.f, 0);
7028 static BcStatus bc_vm_file(const char *file)
7036 s = bc_read_file(file, &data);
7037 if (s) return bc_vm_error(s, file, 0);
7039 bc_lex_file(&G.prs.l, file);
7040 s = bc_vm_process(data);
7043 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7044 ip = bc_vec_item(&G.prog.stack, 0);
7046 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7053 static BcStatus bc_vm_stdin(void)
7055 BcStatus s = BC_STATUS_SUCCESS;
7058 size_t len, i, str = 0;
7059 bool comment = false, notend;
7061 G.prog.file = bc_program_stdin_name;
7062 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7064 bc_vec_init(&buffer, sizeof(char), NULL);
7065 bc_vec_init(&buf, sizeof(char), NULL);
7066 bc_vec_pushByte(&buffer, '\0');
7068 // This loop is complex because the vm tries not to send any lines that end
7069 // with a backslash to the parser. The reason for that is because the parser
7070 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7071 // case, and for strings and comments, the parser will expect more stuff.
7072 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7074 char *string = buf.v;
7079 if (str && buf.v[0] == G.send)
7081 else if (buf.v[0] == G.sbgn)
7084 else if (len > 1 || comment) {
7086 for (i = 0; i < len; ++i) {
7088 notend = len > i + 1;
7091 if (i - 1 > len || string[i - 1] != '\\') {
7092 if (G.sbgn == G.send)
7094 else if (c == G.send)
7096 else if (c == G.sbgn)
7100 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7104 else if (c == '*' && notend && comment && string[i + 1] == '/')
7108 if (str || comment || string[len - 2] == '\\') {
7109 bc_vec_concat(&buffer, buf.v);
7114 bc_vec_concat(&buffer, buf.v);
7115 s = bc_vm_process(buffer.v);
7118 bc_vec_npop(&buffer, buffer.len);
7121 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7123 // INPUT_EOF will always happen when stdin is
7124 // closed. It's not a problem in that case.
7125 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7126 s = BC_STATUS_SUCCESS;
7129 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7132 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7137 bc_vec_free(&buffer);
7141 static BcStatus bc_vm_exec(void)
7143 BcStatus s = BC_STATUS_SUCCESS;
7147 if (G.flags & BC_FLAG_L) {
7149 bc_lex_file(&G.prs.l, bc_lib_name);
7150 s = bc_parse_text(&G.prs, bc_lib);
7152 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7155 s = bc_program_exec();
7160 for (i = 0; !s && i < G.files.len; ++i)
7161 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7162 if (s && s != BC_STATUS_QUIT) return s;
7164 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7165 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7167 if (s == BC_STATUS_QUIT)
7168 s = BC_STATUS_SUCCESS;
7172 #if ENABLE_FEATURE_CLEAN_UP
7173 static void bc_program_free(BcProgram *p)
7175 bc_num_free(&p->ib);
7176 bc_num_free(&p->ob);
7177 bc_num_free(&p->hexb);
7179 bc_num_free(&p->strmb);
7181 bc_vec_free(&p->fns);
7182 bc_vec_free(&p->fn_map);
7183 bc_vec_free(&p->vars);
7184 bc_vec_free(&p->var_map);
7185 bc_vec_free(&p->arrs);
7186 bc_vec_free(&p->arr_map);
7187 bc_vec_free(&p->strs);
7188 bc_vec_free(&p->consts);
7189 bc_vec_free(&p->results);
7190 bc_vec_free(&p->stack);
7191 bc_num_free(&p->last);
7192 bc_num_free(&p->zero);
7193 bc_num_free(&p->one);
7196 static void bc_vm_free(void)
7198 bc_vec_free(&G.files);
7199 bc_program_free(&G.prog);
7200 bc_parse_free(&G.prs);
7205 static void bc_program_init(size_t line_len)
7210 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7211 memset(&ip, 0, sizeof(BcInstPtr));
7213 /* G.prog.nchars = G.prog.scale = 0; - already is */
7214 G.prog.len = line_len;
7216 G.prog.parse_init = bc_parse_init;
7217 G.prog.parse_expr = bc_parse_expression;
7219 G.prog.parse_init = dc_parse_init;
7220 G.prog.parse_expr = dc_parse_expr;
7223 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7224 bc_num_ten(&G.prog.ib);
7227 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7228 bc_num_ten(&G.prog.ob);
7231 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7232 bc_num_ten(&G.prog.hexb);
7233 G.prog.hexb.num[0] = 6;
7236 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7237 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7240 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7241 bc_num_zero(&G.prog.last);
7243 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7244 bc_num_zero(&G.prog.zero);
7246 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7247 bc_num_one(&G.prog.one);
7249 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7250 bc_map_init(&G.prog.fn_map);
7252 bc_program_addFunc(&G.prog, xstrdup(bc_func_main), &idx);
7253 bc_program_addFunc(&G.prog, xstrdup(bc_func_read), &idx);
7255 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7256 bc_map_init(&G.prog.var_map);
7258 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7259 bc_map_init(&G.prog.arr_map);
7261 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7262 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7263 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7264 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7265 bc_vec_push(&G.prog.stack, &ip);
7268 static void bc_vm_init(const char *env_len)
7271 size_t len = bc_vm_envLen(env_len);
7273 #if ENABLE_FEATURE_BC_SIGNALS
7274 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7277 bc_vec_init(&G.files, sizeof(char *), NULL);
7280 if (getenv("POSIXLY_CORRECT"))
7281 G.flags |= BC_FLAG_S;
7283 init = bc_parse_init;
7285 init = dc_parse_init;
7288 bc_program_init(len);
7289 init(&G.prs, &G.prog, BC_PROG_MAIN);
7292 static BcStatus bc_vm_run(int argc, char *argv[],
7293 const char *env_len)
7297 bc_vm_init(env_len);
7298 bc_args(argc, argv);
7300 G.ttyin = isatty(0);
7301 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7303 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7306 #if ENABLE_FEATURE_CLEAN_UP
7313 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7314 int bc_main(int argc, char **argv)
7317 G.sbgn = G.send = '"';
7319 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7324 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7325 int dc_main(int argc, char **argv)
7331 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");