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);
793 static BcStatus bc_program_exec(BcProgram *p);
795 #define BC_FLAG_X (1 << 0)
796 #define BC_FLAG_W (1 << 1)
797 #define BC_FLAG_V (1 << 2)
798 #define BC_FLAG_S (1 << 3)
799 #define BC_FLAG_Q (1 << 4)
800 #define BC_FLAG_L (1 << 5)
801 #define BC_FLAG_I (1 << 6)
803 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
804 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
806 #define BC_MAX_OBASE ((unsigned long) 999)
807 #define BC_MAX_DIM ((unsigned long) INT_MAX)
808 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
809 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
810 #define BC_MAX_NAME BC_MAX_STRING
811 #define BC_MAX_NUM BC_MAX_STRING
812 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
813 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
832 #define G (*ptr_to_globals)
833 #define INIT_G() do { \
834 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
836 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
837 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
838 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
839 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
842 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
845 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
849 static void bc_vm_info(void);
851 static const char* const bc_args_env_name = "BC_ENV_ARGS";
853 static const char bc_err_fmt[] = "\n%s error: %s\n";
854 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
855 static const char bc_err_line[] = ":%zu\n\n";
857 static const char *bc_errs[] = {
869 static const uint8_t bc_err_ids[] = {
870 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
871 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
875 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
876 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
877 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
882 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
883 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
884 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
885 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
887 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
889 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
890 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
891 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
893 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
896 static const char *bc_err_msgs[] = {
899 "memory allocation error",
902 "path is a directory:",
905 "string end could not be found",
906 "comment end could not be found",
915 "bad print statement",
916 "bad function definition",
917 "bad assignment: left side must be scale, ibase, "
918 "obase, last, var, or array element",
919 "no auto variable found",
920 "function parameter or auto var has the same name as another",
921 "block end could not be found",
924 "non integer number",
929 "could not open file:",
930 "mismatched parameters",
931 "undefined function",
932 "file is not executable:",
933 "number too long: must be [1, BC_NUM_MAX]",
934 "name too long: must be [1, BC_NAME_MAX]",
935 "string too long: must be [1, BC_STRING_MAX]",
936 "array too long; must be [1, BC_DIM_MAX]",
937 "bad ibase; must be [2, 16]",
938 "bad scale; must be [0, BC_SCALE_MAX]",
939 "bad read() expression",
940 "read() call inside of a read() call",
941 "variable is wrong type",
942 "bad obase; must be [2, BC_BASE_MAX]",
943 "signal caught and not handled",
944 "stack has too few elements",
946 "index is out of bounds",
947 "item already exists",
950 "POSIX only allows one character names; the following is bad:",
951 "POSIX does not allow '#' script comments",
952 "POSIX does not allow the following keyword:",
953 "POSIX does not allow a period ('.') as a shortcut for the last result",
954 "POSIX requires parentheses around return expressions",
955 "POSIX does not allow boolean operators; the following is bad:",
956 "POSIX does not allow comparison operators outside if or loops",
957 "POSIX requires exactly one comparison operator per condition",
958 "POSIX does not allow an empty init expression in a for loop",
959 "POSIX does not allow an empty condition expression in a for loop",
960 "POSIX does not allow an empty update expression in a for loop",
961 "POSIX requires the left brace be on the same line as the function header",
966 static const char bc_func_main[] = "(main)";
967 static const char bc_func_read[] = "(read)";
970 static const BcLexKeyword bc_lex_kws[20] = {
971 BC_LEX_KW_ENTRY("auto", 4, true),
972 BC_LEX_KW_ENTRY("break", 5, true),
973 BC_LEX_KW_ENTRY("continue", 8, false),
974 BC_LEX_KW_ENTRY("define", 6, true),
975 BC_LEX_KW_ENTRY("else", 4, false),
976 BC_LEX_KW_ENTRY("for", 3, true),
977 BC_LEX_KW_ENTRY("halt", 4, false),
978 BC_LEX_KW_ENTRY("ibase", 5, true),
979 BC_LEX_KW_ENTRY("if", 2, true),
980 BC_LEX_KW_ENTRY("last", 4, false),
981 BC_LEX_KW_ENTRY("length", 6, true),
982 BC_LEX_KW_ENTRY("limits", 6, false),
983 BC_LEX_KW_ENTRY("obase", 5, true),
984 BC_LEX_KW_ENTRY("print", 5, false),
985 BC_LEX_KW_ENTRY("quit", 4, true),
986 BC_LEX_KW_ENTRY("read", 4, false),
987 BC_LEX_KW_ENTRY("return", 6, true),
988 BC_LEX_KW_ENTRY("scale", 5, true),
989 BC_LEX_KW_ENTRY("sqrt", 4, true),
990 BC_LEX_KW_ENTRY("while", 5, true),
993 // This is an array that corresponds to token types. An entry is
994 // true if the token is valid in an expression, false otherwise.
995 static const bool bc_parse_exprs[] = {
996 false, false, true, true, true, true, true, true, true, true, true, true,
997 true, true, true, true, true, true, true, true, true, true, true, true,
998 true, true, true, false, false, true, true, false, false, false, false,
999 false, false, false, true, true, false, false, false, false, false, false,
1000 false, true, false, true, true, true, true, false, false, true, false, true,
1004 // This is an array of data for operators that correspond to token types.
1005 static const BcOp bc_parse_ops[] = {
1006 { 0, false }, { 0, false },
1009 { 3, true }, { 3, true }, { 3, true },
1010 { 4, true }, { 4, true },
1011 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1013 { 7, true }, { 7, true },
1014 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1015 { 5, false }, { 5, false },
1018 // These identify what tokens can come after expressions in certain cases.
1019 static const BcParseNext bc_parse_next_expr =
1020 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1021 static const BcParseNext bc_parse_next_param =
1022 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1023 static const BcParseNext bc_parse_next_print =
1024 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1025 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1026 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1027 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1028 static const BcParseNext bc_parse_next_read =
1029 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1033 static const BcLexType dc_lex_regs[] = {
1034 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1035 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1036 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1040 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1042 static const BcLexType dc_lex_tokens[] = {
1043 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1044 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1045 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1046 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1047 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1048 BC_LEX_INVALID, BC_LEX_INVALID,
1049 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1050 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1051 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1052 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1053 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1054 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1055 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1056 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1057 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1058 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1059 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1060 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1061 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1062 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1063 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1064 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1065 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1066 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1070 static const BcInst dc_parse_insts[] = {
1071 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1072 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1073 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1075 BC_INST_INVALID, BC_INST_INVALID,
1076 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1078 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1080 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1081 BC_INST_INVALID, BC_INST_INVALID,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1085 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1086 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1087 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1088 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1090 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1091 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1092 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1093 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1097 static const BcNumBinaryOp bc_program_ops[] = {
1098 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1101 static const char bc_program_stdin_name[] = "<stdin>";
1102 static const char bc_program_ready_msg[] = "ready for more input\n";
1105 static const char *bc_lib_name = "gen/lib.bc";
1107 static const char bc_lib[] = {
1108 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1109 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1110 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1111 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,
1112 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1113 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1114 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,
1115 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1116 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1117 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,
1118 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1119 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1120 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1121 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1122 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1123 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1124 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1125 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1126 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1127 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1128 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1129 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1130 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1131 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,
1132 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1133 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,
1134 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1135 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1136 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1137 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1138 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1139 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,
1140 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1141 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1142 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1143 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1144 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,
1145 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1146 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1147 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1148 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1149 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1150 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1151 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1152 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1153 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1154 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1155 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,
1156 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,
1157 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1158 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,
1159 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,
1160 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,
1161 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1162 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1163 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,
1164 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,
1165 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,
1166 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1167 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,
1168 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1169 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1170 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1171 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,
1172 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1173 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1174 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1175 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1176 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1177 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1178 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1179 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1180 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1181 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1182 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1183 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1184 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1185 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1186 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1187 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1191 static void bc_vec_grow(BcVec *v, size_t n)
1193 size_t cap = v->cap * 2;
1194 while (cap < v->len + n) cap *= 2;
1195 v->v = xrealloc(v->v, v->size * cap);
1199 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1202 v->cap = BC_VEC_START_CAP;
1205 v->v = xmalloc(esize * BC_VEC_START_CAP);
1208 static void bc_vec_expand(BcVec *v, size_t req)
1211 v->v = xrealloc(v->v, v->size * req);
1216 static void bc_vec_npop(BcVec *v, size_t n)
1221 size_t len = v->len - n;
1222 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1226 static void bc_vec_push(BcVec *v, const void *data)
1228 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1229 memmove(v->v + (v->size * v->len), data, v->size);
1233 static void bc_vec_pushByte(BcVec *v, char data)
1235 bc_vec_push(v, &data);
1238 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1241 bc_vec_push(v, data);
1246 if (v->len == v->cap) bc_vec_grow(v, 1);
1248 ptr = v->v + v->size * idx;
1250 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1251 memmove(ptr, data, v->size);
1255 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1257 bc_vec_npop(v, v->len);
1258 bc_vec_expand(v, len + 1);
1259 memcpy(v->v, str, len);
1262 bc_vec_pushByte(v, '\0');
1265 static void bc_vec_concat(BcVec *v, const char *str)
1269 if (v->len == 0) bc_vec_pushByte(v, '\0');
1271 len = v->len + strlen(str);
1273 if (v->cap < len) bc_vec_grow(v, len - v->len);
1279 static void *bc_vec_item(const BcVec *v, size_t idx)
1281 return v->v + v->size * idx;
1284 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1286 return v->v + v->size * (v->len - idx - 1);
1289 static void bc_vec_free(void *vec)
1291 BcVec *v = (BcVec *) vec;
1292 bc_vec_npop(v, v->len);
1296 static size_t bc_map_find(const BcVec *v, const void *ptr)
1298 size_t low = 0, high = v->len;
1300 while (low < high) {
1302 size_t mid = (low + high) / 2;
1303 BcId *id = bc_vec_item(v, mid);
1304 int result = bc_id_cmp(ptr, id);
1308 else if (result < 0)
1317 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1319 BcStatus s = BC_STATUS_SUCCESS;
1321 *i = bc_map_find(v, ptr);
1324 bc_vec_push(v, ptr);
1325 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1326 s = BC_STATUS_VEC_ITEM_EXISTS;
1328 bc_vec_pushAt(v, ptr, *i);
1333 static size_t bc_map_index(const BcVec *v, const void *ptr)
1335 size_t i = bc_map_find(v, ptr);
1336 if (i >= v->len) return BC_VEC_INVALID_IDX;
1337 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1340 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1345 bc_vec_npop(vec, vec->len);
1348 #if ENABLE_FEATURE_BC_SIGNALS
1349 if (bb_got_signal) { /* ^C was pressed */
1352 ? "\ninterrupt (type \"quit\" to exit)\n"
1353 : "\ninterrupt (type \"q\" to exit)\n"
1356 bb_got_signal = 0; /* resets G_interrupt to zero */
1358 if (G.ttyin && !G_posix)
1359 fputs(prompt, stderr);
1362 #if ENABLE_FEATURE_BC_SIGNALS
1367 if (ferror(stdout) || ferror(stderr))
1368 bb_perror_msg_and_die("output error");
1372 #if ENABLE_FEATURE_BC_SIGNALS
1373 if (bb_got_signal) /* ^C was pressed */
1378 #if ENABLE_FEATURE_BC_SIGNALS
1379 if (errno == EINTR) {
1385 bb_perror_msg_and_die("input error");
1386 return BC_STATUS_INPUT_EOF;
1389 c = (signed char) i;
1390 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1391 bc_vec_push(vec, &c);
1392 } while (c != '\n');
1394 bc_vec_pushByte(vec, '\0');
1396 return BC_STATUS_SUCCESS;
1399 static BcStatus bc_read_file(const char *path, char **buf)
1401 BcStatus s = BC_STATUS_BIN_FILE;
1402 size_t size = ((size_t) -1);
1405 *buf = xmalloc_open_read_close(path, &size);
1407 for (i = 0; i < size; ++i) {
1408 if (BC_READ_BIN_CHAR((*buf)[i]))
1412 return BC_STATUS_SUCCESS;
1419 static void bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1422 bool do_exit = false;
1425 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1426 *flags = getopt32long(argv, "xwvsqli",
1427 "extended-register\0" No_argument "x"
1428 "warn\0" No_argument "w"
1429 "version\0" No_argument "v"
1430 "standard\0" No_argument "s"
1431 "quiet\0" No_argument "q"
1432 "mathlib\0" No_argument "l"
1433 "interactive\0" No_argument "i"
1436 *flags = getopt32(argv, "xwvsqli");
1439 if ((*flags) & BC_FLAG_V) bc_vm_info();
1440 if (do_exit) exit(0);
1441 // should not be necessary, getopt32() handles this??
1442 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1444 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1447 static void bc_num_setToZero(BcNum *n, size_t scale)
1454 static void bc_num_zero(BcNum *n)
1456 bc_num_setToZero(n, 0);
1459 static void bc_num_one(BcNum *n)
1461 bc_num_setToZero(n, 0);
1466 static void bc_num_ten(BcNum *n)
1468 bc_num_setToZero(n, 0);
1474 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1478 for (i = 0; !G_interrupt && i < len; ++i) {
1479 for (a[i] -= b[i], j = 0; !G_interrupt && a[i + j] < 0;) {
1484 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1487 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1491 for (i = len - 1; !G_interrupt && i < len && !(c = a[i] - b[i]); --i);
1492 return BC_NUM_NEG(i + 1, c < 0);
1495 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1497 size_t i, min, a_int, b_int, diff;
1498 BcDig *max_num, *min_num;
1499 bool a_max, neg = false;
1502 if (a == b) return 0;
1503 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1504 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1514 a_int = BC_NUM_INT(a);
1515 b_int = BC_NUM_INT(b);
1517 a_max = (a->rdx > b->rdx);
1519 if (a_int != 0) return (ssize_t) a_int;
1523 diff = a->rdx - b->rdx;
1524 max_num = a->num + diff;
1529 diff = b->rdx - a->rdx;
1530 max_num = b->num + diff;
1534 cmp = bc_num_compare(max_num, min_num, b_int + min);
1535 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1537 for (max_num -= diff, i = diff - 1; !G_interrupt && i < diff; --i) {
1538 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1544 static void bc_num_truncate(BcNum *n, size_t places)
1546 if (places == 0) return;
1552 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1556 static void bc_num_extend(BcNum *n, size_t places)
1558 size_t len = n->len + places;
1562 if (n->cap < len) bc_num_expand(n, len);
1564 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1565 memset(n->num, 0, sizeof(BcDig) * places);
1572 static void bc_num_clean(BcNum *n)
1574 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1577 else if (n->len < n->rdx)
1581 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1584 bc_num_extend(n, scale - n->rdx);
1586 bc_num_truncate(n, n->rdx - scale);
1589 if (n->len != 0) n->neg = !neg1 != !neg2;
1592 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1597 b->len = n->len - idx;
1599 a->rdx = b->rdx = 0;
1601 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1602 memcpy(a->num, n->num, idx * sizeof(BcDig));
1613 static BcStatus bc_num_shift(BcNum *n, size_t places)
1615 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1616 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1618 if (n->rdx >= places)
1621 bc_num_extend(n, places - n->rdx);
1627 return BC_STATUS_SUCCESS;
1630 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1639 return bc_num_div(&one, a, b, scale);
1642 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1644 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1645 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1648 // Because this function doesn't need to use scale (per the bc spec),
1649 // I am hijacking it to say whether it's doing an add or a subtract.
1653 if (sub && c->len) c->neg = !c->neg;
1654 return BC_STATUS_SUCCESS;
1656 else if (b->len == 0) {
1658 return BC_STATUS_SUCCESS;
1662 c->rdx = BC_MAX(a->rdx, b->rdx);
1663 min_rdx = BC_MIN(a->rdx, b->rdx);
1666 if (a->rdx > b->rdx) {
1667 diff = a->rdx - b->rdx;
1669 ptr_a = a->num + diff;
1673 diff = b->rdx - a->rdx;
1676 ptr_b = b->num + diff;
1679 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1682 a_int = BC_NUM_INT(a);
1683 b_int = BC_NUM_INT(b);
1685 if (a_int > b_int) {
1696 for (carry = 0, i = 0; !G_interrupt && i < min_rdx + min_int; ++i, ++c->len) {
1697 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1699 ptr_c[i] = (BcDig)(in % 10);
1702 for (; !G_interrupt && i < max + min_rdx; ++i, ++c->len) {
1703 in = ((int) ptr[i]) + carry;
1705 ptr_c[i] = (BcDig)(in % 10);
1708 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1710 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1713 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1717 BcNum *minuend, *subtrahend;
1719 bool aneg, bneg, neg;
1721 // Because this function doesn't need to use scale (per the bc spec),
1722 // I am hijacking it to say whether it's doing an add or a subtract.
1726 if (sub && c->len) c->neg = !c->neg;
1727 return BC_STATUS_SUCCESS;
1729 else if (b->len == 0) {
1731 return BC_STATUS_SUCCESS;
1736 a->neg = b->neg = false;
1738 cmp = bc_num_cmp(a, b);
1744 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1745 return BC_STATUS_SUCCESS;
1754 if (sub) neg = !neg;
1759 bc_num_copy(c, minuend);
1762 if (c->rdx < subtrahend->rdx) {
1763 bc_num_extend(c, subtrahend->rdx - c->rdx);
1767 start = c->rdx - subtrahend->rdx;
1769 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1776 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1781 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1782 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1783 bool aone = BC_NUM_ONE(a);
1785 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
1786 if (a->len == 0 || b->len == 0) {
1788 return BC_STATUS_SUCCESS;
1790 else if (aone || BC_NUM_ONE(b)) {
1791 bc_num_copy(c, aone ? b : a);
1792 return BC_STATUS_SUCCESS;
1795 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1796 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1798 bc_num_expand(c, a->len + b->len + 1);
1800 memset(c->num, 0, sizeof(BcDig) * c->cap);
1801 c->len = carry = len = 0;
1803 for (i = 0; !G_interrupt && i < b->len; ++i) {
1805 for (j = 0; !G_interrupt && j < a->len; ++j) {
1806 int in = (int) c->num[i + j];
1807 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1809 c->num[i + j] = (BcDig)(in % 10);
1812 c->num[i + j] += (BcDig) carry;
1813 len = BC_MAX(len, i + j + !!carry);
1819 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1822 bc_num_init(&l1, max);
1823 bc_num_init(&h1, max);
1824 bc_num_init(&l2, max);
1825 bc_num_init(&h2, max);
1826 bc_num_init(&m1, max);
1827 bc_num_init(&m2, max);
1828 bc_num_init(&z0, max);
1829 bc_num_init(&z1, max);
1830 bc_num_init(&z2, max);
1831 bc_num_init(&temp, max + max);
1833 bc_num_split(a, max2, &l1, &h1);
1834 bc_num_split(b, max2, &l2, &h2);
1836 s = bc_num_add(&h1, &l1, &m1, 0);
1838 s = bc_num_add(&h2, &l2, &m2, 0);
1841 s = bc_num_k(&h1, &h2, &z0);
1843 s = bc_num_k(&m1, &m2, &z1);
1845 s = bc_num_k(&l1, &l2, &z2);
1848 s = bc_num_sub(&z1, &z0, &temp, 0);
1850 s = bc_num_sub(&temp, &z2, &z1, 0);
1853 s = bc_num_shift(&z0, max2 * 2);
1855 s = bc_num_shift(&z1, max2);
1857 s = bc_num_add(&z0, &z1, &temp, 0);
1859 s = bc_num_add(&temp, &z2, c, 0);
1875 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1879 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1881 scale = BC_MAX(scale, a->rdx);
1882 scale = BC_MAX(scale, b->rdx);
1883 scale = BC_MIN(a->rdx + b->rdx, scale);
1884 maxrdx = BC_MAX(maxrdx, scale);
1886 bc_num_init(&cpa, a->len);
1887 bc_num_init(&cpb, b->len);
1889 bc_num_copy(&cpa, a);
1890 bc_num_copy(&cpb, b);
1891 cpa.neg = cpb.neg = false;
1893 s = bc_num_shift(&cpa, maxrdx);
1895 s = bc_num_shift(&cpb, maxrdx);
1897 s = bc_num_k(&cpa, &cpb, c);
1901 bc_num_expand(c, c->len + maxrdx);
1903 if (c->len < maxrdx) {
1904 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1909 bc_num_retireMul(c, scale, a->neg, b->neg);
1917 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1919 BcStatus s = BC_STATUS_SUCCESS;
1926 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1927 else if (a->len == 0) {
1928 bc_num_setToZero(c, scale);
1929 return BC_STATUS_SUCCESS;
1931 else if (BC_NUM_ONE(b)) {
1933 bc_num_retireMul(c, scale, a->neg, b->neg);
1934 return BC_STATUS_SUCCESS;
1937 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1938 bc_num_copy(&cp, a);
1942 bc_num_expand(&cp, len + 2);
1943 bc_num_extend(&cp, len - cp.len);
1946 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1948 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1950 if (b->rdx == b->len) {
1951 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1955 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1957 // We want an extra zero in front to make things simpler.
1958 cp.num[cp.len++] = 0;
1961 bc_num_expand(c, cp.len);
1964 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1969 for (i = end - 1; !G_interrupt && !s && i < end; --i) {
1971 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1972 s = bc_num_subArrays(n, p, len);
1976 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1982 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1983 BcNum *restrict d, size_t scale, size_t ts)
1989 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1992 bc_num_setToZero(d, ts);
1993 return BC_STATUS_SUCCESS;
1996 bc_num_init(&temp, d->cap);
1997 bc_num_d(a, b, c, scale);
1999 if (scale != 0) scale = ts;
2001 s = bc_num_m(c, b, &temp, scale);
2003 s = bc_num_sub(a, &temp, d, scale);
2006 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2009 bc_num_retireMul(d, ts, a->neg, b->neg);
2017 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2021 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2023 bc_num_init(&c1, len);
2024 s = bc_num_r(a, b, &c1, c, scale, ts);
2030 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2032 BcStatus s = BC_STATUS_SUCCESS;
2035 size_t i, powrdx, resrdx;
2038 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2042 return BC_STATUS_SUCCESS;
2044 else if (a->len == 0) {
2045 bc_num_setToZero(c, scale);
2046 return BC_STATUS_SUCCESS;
2048 else if (BC_NUM_ONE(b)) {
2052 s = bc_num_inv(a, c, scale);
2059 s = bc_num_ulong(b, &pow);
2062 bc_num_init(©, a->len);
2063 bc_num_copy(©, a);
2065 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2069 for (powrdx = a->rdx; !G_interrupt && !(pow & 1); pow >>= 1) {
2071 s = bc_num_mul(©, ©, ©, powrdx);
2076 s = BC_STATUS_EXEC_SIGNAL;
2080 bc_num_copy(c, ©);
2082 for (resrdx = powrdx, pow >>= 1; !G_interrupt && pow != 0; pow >>= 1) {
2085 s = bc_num_mul(©, ©, ©, powrdx);
2090 s = bc_num_mul(c, ©, c, resrdx);
2096 s = bc_num_inv(c, c, scale);
2101 s = BC_STATUS_EXEC_SIGNAL;
2105 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2107 // We can't use bc_num_clean() here.
2108 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2109 if (zero) bc_num_setToZero(c, scale);
2116 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2117 BcNumBinaryOp op, size_t req)
2120 BcNum num2, *ptr_a, *ptr_b;
2125 memcpy(ptr_a, c, sizeof(BcNum));
2134 memcpy(ptr_b, c, sizeof(BcNum));
2142 bc_num_init(c, req);
2144 bc_num_expand(c, req);
2146 s = op(ptr_a, ptr_b, c, scale);
2148 if (init) bc_num_free(&num2);
2153 static bool bc_num_strValid(const char *val, size_t base)
2156 bool small, radix = false;
2157 size_t i, len = strlen(val);
2159 if (!len) return true;
2162 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2164 for (i = 0; i < len; ++i) {
2170 if (radix) return false;
2176 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2183 static void bc_num_parseDecimal(BcNum *n, const char *val)
2189 for (i = 0; val[i] == '0'; ++i);
2196 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2197 bc_num_expand(n, len);
2200 ptr = strchr(val, '.');
2202 // Explicitly test for NULL here to produce either a 0 or 1.
2203 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2206 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2207 n->num[n->len] = val[i] - '0';
2211 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2214 BcNum temp, mult, result;
2218 size_t i, digits, len = strlen(val);
2222 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2225 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2226 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2228 for (i = 0; i < len; ++i) {
2231 if (c == '.') break;
2233 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2235 s = bc_num_mul(n, base, &mult, 0);
2236 if (s) goto int_err;
2237 s = bc_num_ulong2num(&temp, v);
2238 if (s) goto int_err;
2239 s = bc_num_add(&mult, &temp, n, 0);
2240 if (s) goto int_err;
2245 if (c == 0) goto int_err;
2248 bc_num_init(&result, base->len);
2249 bc_num_zero(&result);
2252 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2257 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2259 s = bc_num_mul(&result, base, &result, 0);
2261 s = bc_num_ulong2num(&temp, v);
2263 s = bc_num_add(&result, &temp, &result, 0);
2265 s = bc_num_mul(&mult, base, &mult, 0);
2269 s = bc_num_div(&result, &mult, &result, digits);
2271 s = bc_num_add(n, &result, n, digits);
2275 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2281 bc_num_free(&result);
2287 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2289 if (*nchars == line_len - 1) {
2297 static void bc_num_printChar(size_t num, size_t width, bool radix,
2298 size_t *nchars, size_t line_len)
2300 (void) radix, (void) line_len;
2301 bb_putchar((char) num);
2302 *nchars = *nchars + width;
2306 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2307 size_t *nchars, size_t line_len)
2311 bc_num_printNewline(nchars, line_len);
2312 bb_putchar(radix ? '.' : ' ');
2315 bc_num_printNewline(nchars, line_len);
2316 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2319 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2321 bc_num_printNewline(nchars, line_len);
2324 bb_putchar(((char) dig) + '0');
2328 static void bc_num_printHex(size_t num, size_t width, bool radix,
2329 size_t *nchars, size_t line_len)
2332 bc_num_printNewline(nchars, line_len);
2337 bc_num_printNewline(nchars, line_len);
2338 bb_putchar(bb_hexdigits_upcase[num]);
2339 *nchars = *nchars + width;
2342 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2344 size_t i, rdx = n->rdx - 1;
2346 if (n->neg) bb_putchar('-');
2347 (*nchars) += n->neg;
2349 for (i = n->len - 1; i < n->len; --i)
2350 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2353 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2354 size_t *nchars, size_t len, BcNumDigitOp print)
2358 BcNum intp, fracp, digit, frac_len;
2359 unsigned long dig, *ptr;
2364 print(0, width, false, nchars, len);
2365 return BC_STATUS_SUCCESS;
2368 bc_vec_init(&stack, sizeof(long), NULL);
2369 bc_num_init(&intp, n->len);
2370 bc_num_init(&fracp, n->rdx);
2371 bc_num_init(&digit, width);
2372 bc_num_init(&frac_len, BC_NUM_INT(n));
2373 bc_num_copy(&intp, n);
2374 bc_num_one(&frac_len);
2376 bc_num_truncate(&intp, intp.rdx);
2377 s = bc_num_sub(n, &intp, &fracp, 0);
2380 while (intp.len != 0) {
2381 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2383 s = bc_num_ulong(&digit, &dig);
2385 bc_vec_push(&stack, &dig);
2388 for (i = 0; i < stack.len; ++i) {
2389 ptr = bc_vec_item_rev(&stack, i);
2390 print(*ptr, width, false, nchars, len);
2393 if (!n->rdx) goto err;
2395 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2396 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2398 s = bc_num_ulong(&fracp, &dig);
2400 s = bc_num_ulong2num(&intp, dig);
2402 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2404 print(dig, width, radix, nchars, len);
2405 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2410 bc_num_free(&frac_len);
2411 bc_num_free(&digit);
2412 bc_num_free(&fracp);
2414 bc_vec_free(&stack);
2418 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2419 size_t *nchars, size_t line_len)
2426 if (neg) bb_putchar('-');
2431 if (base_t <= BC_NUM_MAX_IBASE) {
2433 print = bc_num_printHex;
2436 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2437 print = bc_num_printDigits;
2440 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2447 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2449 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2453 static void bc_num_init(BcNum *n, size_t req)
2455 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2456 memset(n, 0, sizeof(BcNum));
2457 n->num = xmalloc(req);
2461 static void bc_num_expand(BcNum *n, size_t req)
2463 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2465 n->num = xrealloc(n->num, req);
2470 static void bc_num_free(void *num)
2472 free(((BcNum *) num)->num);
2475 static void bc_num_copy(BcNum *d, BcNum *s)
2478 bc_num_expand(d, s->cap);
2482 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2486 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2489 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2492 bc_num_parseDecimal(n, val);
2494 bc_num_parseBase(n, val, base);
2496 return BC_STATUS_SUCCESS;
2499 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2500 size_t *nchars, size_t line_len)
2502 BcStatus s = BC_STATUS_SUCCESS;
2504 bc_num_printNewline(nchars, line_len);
2510 else if (base_t == 10)
2511 bc_num_printDecimal(n, nchars, line_len);
2513 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2523 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2528 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2530 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2532 unsigned long prev = *result, powprev = pow;
2534 *result += ((unsigned long) n->num[i]) * pow;
2537 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2540 return BC_STATUS_SUCCESS;
2543 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2551 if (val == 0) return BC_STATUS_SUCCESS;
2553 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2554 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2556 return BC_STATUS_SUCCESS;
2559 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2561 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2563 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2566 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2568 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2570 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2573 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2575 size_t req = BC_NUM_MREQ(a, b, scale);
2576 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2579 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2581 size_t req = BC_NUM_MREQ(a, b, scale);
2582 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2585 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2587 size_t req = BC_NUM_MREQ(a, b, scale);
2588 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2591 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2593 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2596 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2599 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2600 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2601 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2603 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2604 bc_num_expand(b, req);
2607 bc_num_setToZero(b, scale);
2608 return BC_STATUS_SUCCESS;
2611 return BC_STATUS_MATH_NEGATIVE;
2612 else if (BC_NUM_ONE(a)) {
2614 bc_num_extend(b, scale);
2615 return BC_STATUS_SUCCESS;
2618 scale = BC_MAX(scale, a->rdx) + 1;
2619 len = a->len + scale;
2621 bc_num_init(&num1, len);
2622 bc_num_init(&num2, len);
2623 bc_num_init(&half, BC_NUM_DEF_SIZE);
2629 bc_num_init(&f, len);
2630 bc_num_init(&fprime, len);
2636 pow = BC_NUM_INT(a);
2645 pow -= 2 - (pow & 1);
2647 bc_num_extend(x0, pow);
2649 // Make sure to move the radix back.
2653 x0->rdx = digs = digs1 = 0;
2655 len = BC_NUM_INT(x0) + resrdx - 1;
2657 while (!G_interrupt && (cmp != 0 || digs < len)) {
2659 s = bc_num_div(a, x0, &f, resrdx);
2661 s = bc_num_add(x0, &f, &fprime, resrdx);
2663 s = bc_num_mul(&fprime, &half, x1, resrdx);
2666 cmp = bc_num_cmp(x1, x0);
2667 digs = x1->len - (unsigned long long) llabs(cmp);
2669 if (cmp == cmp2 && digs == digs1)
2674 resrdx += times > 4;
2686 s = BC_STATUS_EXEC_SIGNAL;
2692 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2695 bc_num_free(&fprime);
2703 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2709 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2712 memcpy(&num2, c, sizeof(BcNum));
2714 bc_num_init(c, len);
2719 bc_num_expand(c, len);
2722 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2724 if (init) bc_num_free(&num2);
2730 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2733 BcNum base, exp, two, temp;
2735 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2736 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2737 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2739 bc_num_expand(d, c->len);
2740 bc_num_init(&base, c->len);
2741 bc_num_init(&exp, b->len);
2742 bc_num_init(&two, BC_NUM_DEF_SIZE);
2743 bc_num_init(&temp, b->len);
2749 s = bc_num_rem(a, c, &base, 0);
2751 bc_num_copy(&exp, b);
2753 while (exp.len != 0) {
2755 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2758 if (BC_NUM_ONE(&temp)) {
2759 s = bc_num_mul(d, &base, &temp, 0);
2761 s = bc_num_rem(&temp, c, d, 0);
2765 s = bc_num_mul(&base, &base, &temp, 0);
2767 s = bc_num_rem(&temp, c, &base, 0);
2780 static int bc_id_cmp(const void *e1, const void *e2)
2782 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2785 static void bc_id_free(void *id)
2787 free(((BcId *) id)->name);
2790 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2795 for (i = 0; i < f->autos.len; ++i) {
2796 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2797 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2803 bc_vec_push(&f->autos, &a);
2805 return BC_STATUS_SUCCESS;
2808 static void bc_func_init(BcFunc *f)
2810 bc_vec_init(&f->code, sizeof(char), NULL);
2811 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2812 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2816 static void bc_func_free(void *func)
2818 BcFunc *f = (BcFunc *) func;
2819 bc_vec_free(&f->code);
2820 bc_vec_free(&f->autos);
2821 bc_vec_free(&f->labels);
2824 static void bc_array_init(BcVec *a, bool nums)
2827 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2829 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2830 bc_array_expand(a, 1);
2833 static void bc_array_copy(BcVec *d, const BcVec *s)
2837 bc_vec_npop(d, d->len);
2838 bc_vec_expand(d, s->cap);
2841 for (i = 0; i < s->len; ++i) {
2842 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2843 bc_num_init(dnum, snum->len);
2844 bc_num_copy(dnum, snum);
2848 static void bc_array_expand(BcVec *a, size_t len)
2852 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2853 while (len > a->len) {
2854 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2855 bc_vec_push(a, &data.n);
2859 while (len > a->len) {
2860 bc_array_init(&data.v, true);
2861 bc_vec_push(a, &data.v);
2866 static void bc_string_free(void *string)
2868 free(*((char **) string));
2872 static void bc_result_copy(BcResult *d, BcResult *src)
2878 case BC_RESULT_TEMP:
2879 case BC_RESULT_IBASE:
2880 case BC_RESULT_SCALE:
2881 case BC_RESULT_OBASE:
2883 bc_num_init(&d->d.n, src->d.n.len);
2884 bc_num_copy(&d->d.n, &src->d.n);
2889 case BC_RESULT_ARRAY:
2890 case BC_RESULT_ARRAY_ELEM:
2892 d->d.id.name = xstrdup(src->d.id.name);
2896 case BC_RESULT_CONSTANT:
2897 case BC_RESULT_LAST:
2901 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2908 static void bc_result_free(void *result)
2910 BcResult *r = (BcResult *) result;
2914 case BC_RESULT_TEMP:
2915 case BC_RESULT_IBASE:
2916 case BC_RESULT_SCALE:
2917 case BC_RESULT_OBASE:
2919 bc_num_free(&r->d.n);
2924 case BC_RESULT_ARRAY:
2925 case BC_RESULT_ARRAY_ELEM:
2939 static void bc_lex_lineComment(BcLex *l)
2941 l->t.t = BC_LEX_WHITESPACE;
2942 while (l->i < l->len && l->buf[l->i++] != '\n');
2946 static void bc_lex_whitespace(BcLex *l)
2949 l->t.t = BC_LEX_WHITESPACE;
2950 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2953 static BcStatus bc_lex_number(BcLex *l, char start)
2955 const char *buf = l->buf + l->i;
2956 size_t len, hits = 0, bslashes = 0, i = 0, j;
2958 bool last_pt, pt = start == '.';
2961 l->t.t = BC_LEX_NUMBER;
2963 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2964 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2978 len = i + 1 * !last_pt - bslashes * 2;
2979 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2981 bc_vec_npop(&l->t.v, l->t.v.len);
2982 bc_vec_expand(&l->t.v, len + 1);
2983 bc_vec_push(&l->t.v, &start);
2985 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2989 // If we have hit a backslash, skip it. We don't have
2990 // to check for a newline because it's guaranteed.
2991 if (hits < bslashes && c == '\\') {
2997 bc_vec_push(&l->t.v, &c);
3000 bc_vec_pushByte(&l->t.v, '\0');
3003 return BC_STATUS_SUCCESS;
3006 static BcStatus bc_lex_name(BcLex *l)
3009 const char *buf = l->buf + l->i - 1;
3012 l->t.t = BC_LEX_NAME;
3014 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3016 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3017 bc_vec_string(&l->t.v, i, buf);
3019 // Increment the index. We minus 1 because it has already been incremented.
3022 return BC_STATUS_SUCCESS;
3025 static void bc_lex_init(BcLex *l, BcLexNext next)
3028 bc_vec_init(&l->t.v, sizeof(char), NULL);
3031 static void bc_lex_free(BcLex *l)
3033 bc_vec_free(&l->t.v);
3036 static void bc_lex_file(BcLex *l, const char *file)
3043 static BcStatus bc_lex_next(BcLex *l)
3048 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3050 l->line += l->newline;
3051 l->t.t = BC_LEX_EOF;
3053 l->newline = (l->i == l->len);
3054 if (l->newline) return BC_STATUS_SUCCESS;
3056 // Loop until failure or we don't have whitespace. This
3057 // is so the parser doesn't get inundated with whitespace.
3060 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3065 static BcStatus bc_lex_text(BcLex *l, const char *text)
3069 l->len = strlen(text);
3070 l->t.t = l->t.last = BC_LEX_INVALID;
3071 return bc_lex_next(l);
3075 static BcStatus bc_lex_identifier(BcLex *l)
3079 const char *buf = l->buf + l->i - 1;
3081 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3083 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3085 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3087 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3089 if (!bc_lex_kws[i].posix) {
3090 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3091 bc_lex_kws[i].name);
3095 // We minus 1 because the index has already been incremented.
3097 return BC_STATUS_SUCCESS;
3104 if (l->t.v.len - 1 > 1)
3105 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3110 static BcStatus bc_lex_string(BcLex *l)
3112 size_t len, nls = 0, i = l->i;
3115 l->t.t = BC_LEX_STR;
3117 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3121 return BC_STATUS_LEX_NO_STRING_END;
3125 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3126 bc_vec_string(&l->t.v, len, l->buf + l->i);
3131 return BC_STATUS_SUCCESS;
3134 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3136 if (l->buf[l->i] == '=') {
3144 static BcStatus bc_lex_comment(BcLex *l)
3147 const char *buf = l->buf;
3151 l->t.t = BC_LEX_WHITESPACE;
3153 for (i = ++l->i; !end; i += !end) {
3155 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3157 if (c == 0 || buf[i + 1] == '\0') {
3159 return BC_STATUS_LEX_NO_COMMENT_END;
3162 end = buf[i + 1] == '/';
3168 return BC_STATUS_SUCCESS;
3171 static BcStatus bc_lex_token(BcLex *l)
3173 BcStatus s = BC_STATUS_SUCCESS;
3174 char c = l->buf[l->i++], c2;
3176 // This is the workhorse of the lexer.
3183 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3193 bc_lex_whitespace(l);
3199 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3201 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3202 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3211 s = bc_lex_string(l);
3217 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3220 bc_lex_lineComment(l);
3227 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3236 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3240 l->t.t = BC_LEX_OP_BOOL_AND;
3243 l->t.t = BC_LEX_INVALID;
3244 s = BC_STATUS_LEX_BAD_CHAR;
3253 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3259 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3268 l->t.t = BC_LEX_OP_INC;
3271 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3277 l->t.t = BC_LEX_COMMA;
3286 l->t.t = BC_LEX_OP_DEC;
3289 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3295 if (isdigit(l->buf[l->i]))
3296 s = bc_lex_number(l, c);
3298 l->t.t = BC_LEX_KEY_LAST;
3299 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3308 s = bc_lex_comment(l);
3310 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3331 s = bc_lex_number(l, c);
3337 l->t.t = BC_LEX_SCOLON;
3343 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3349 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3355 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3362 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3368 if (l->buf[l->i] == '\n') {
3369 l->t.t = BC_LEX_WHITESPACE;
3373 s = BC_STATUS_LEX_BAD_CHAR;
3379 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3410 s = bc_lex_identifier(l);
3417 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3427 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3431 l->t.t = BC_LEX_OP_BOOL_OR;
3434 l->t.t = BC_LEX_INVALID;
3435 s = BC_STATUS_LEX_BAD_CHAR;
3443 l->t.t = BC_LEX_INVALID;
3444 s = BC_STATUS_LEX_BAD_CHAR;
3454 static BcStatus dc_lex_register(BcLex *l)
3456 BcStatus s = BC_STATUS_SUCCESS;
3458 if (isspace(l->buf[l->i - 1])) {
3459 bc_lex_whitespace(l);
3462 s = BC_STATUS_LEX_EXTENDED_REG;
3467 bc_vec_npop(&l->t.v, l->t.v.len);
3468 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3469 bc_vec_pushByte(&l->t.v, '\0');
3470 l->t.t = BC_LEX_NAME;
3476 static BcStatus dc_lex_string(BcLex *l)
3478 size_t depth = 1, nls = 0, i = l->i;
3481 l->t.t = BC_LEX_STR;
3482 bc_vec_npop(&l->t.v, l->t.v.len);
3484 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3486 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3487 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3490 if (depth) bc_vec_push(&l->t.v, &c);
3495 return BC_STATUS_LEX_NO_STRING_END;
3498 bc_vec_pushByte(&l->t.v, '\0');
3499 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3504 return BC_STATUS_SUCCESS;
3507 static BcStatus dc_lex_token(BcLex *l)
3509 BcStatus s = BC_STATUS_SUCCESS;
3510 char c = l->buf[l->i++], c2;
3513 for (i = 0; i < dc_lex_regs_len; ++i) {
3514 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3517 if (c >= '%' && c <= '~' &&
3518 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3523 // This is the workhorse of the lexer.
3528 l->t.t = BC_LEX_EOF;
3539 l->newline = (c == '\n');
3540 bc_lex_whitespace(l);
3549 l->t.t = BC_LEX_OP_REL_NE;
3551 l->t.t = BC_LEX_OP_REL_LE;
3553 l->t.t = BC_LEX_OP_REL_GE;
3555 return BC_STATUS_LEX_BAD_CHAR;
3563 bc_lex_lineComment(l);
3569 if (isdigit(l->buf[l->i]))
3570 s = bc_lex_number(l, c);
3572 s = BC_STATUS_LEX_BAD_CHAR;
3593 s = bc_lex_number(l, c);
3599 s = dc_lex_string(l);
3605 l->t.t = BC_LEX_INVALID;
3606 s = BC_STATUS_LEX_BAD_CHAR;
3615 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3617 bc_program_addFunc(p->prog, name, idx);
3618 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3621 static void bc_parse_pushName(BcParse *p, char *name)
3623 size_t i = 0, len = strlen(name);
3625 for (; i < len; ++i) bc_parse_push(p, name[i]);
3626 bc_parse_push(p, BC_PARSE_STREND);
3631 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3633 unsigned char amt, i, nums[sizeof(size_t)];
3635 for (amt = 0; idx; ++amt) {
3636 nums[amt] = (char) idx;
3637 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3640 bc_parse_push(p, amt);
3641 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3644 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3646 char *num = xstrdup(p->l.t.v.v);
3647 size_t idx = p->prog->consts.len;
3649 bc_vec_push(&p->prog->consts, &num);
3651 bc_parse_push(p, BC_INST_NUM);
3652 bc_parse_pushIndex(p, idx);
3655 (*prev) = BC_INST_NUM;
3658 static BcStatus bc_parse_text(BcParse *p, const char *text)
3662 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3664 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3665 p->l.t.t = BC_LEX_INVALID;
3668 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3671 return bc_lex_text(&p->l, text);
3674 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3676 if (p->fidx != BC_PROG_MAIN) {
3678 p->func->nparams = 0;
3679 bc_vec_npop(&p->func->code, p->func->code.len);
3680 bc_vec_npop(&p->func->autos, p->func->autos.len);
3681 bc_vec_npop(&p->func->labels, p->func->labels.len);
3683 bc_parse_updateFunc(p, BC_PROG_MAIN);
3687 p->l.t.t = BC_LEX_EOF;
3688 p->auto_part = (p->nbraces = 0);
3690 bc_vec_npop(&p->flags, p->flags.len - 1);
3691 bc_vec_npop(&p->exits, p->exits.len);
3692 bc_vec_npop(&p->conds, p->conds.len);
3693 bc_vec_npop(&p->ops, p->ops.len);
3695 return bc_program_reset(p->prog, s);
3698 static void bc_parse_free(BcParse *p)
3700 bc_vec_free(&p->flags);
3701 bc_vec_free(&p->exits);
3702 bc_vec_free(&p->conds);
3703 bc_vec_free(&p->ops);
3707 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3708 BcParseParse parse, BcLexNext next)
3710 memset(p, 0, sizeof(BcParse));
3712 bc_lex_init(&p->l, next);
3713 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3714 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3715 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3716 bc_vec_pushByte(&p->flags, 0);
3717 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3721 p->auto_part = (p->nbraces = 0);
3722 bc_parse_updateFunc(p, func);
3726 static BcStatus bc_parse_else(BcParse *p);
3727 static BcStatus bc_parse_stmt(BcParse *p);
3729 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3730 size_t *nexprs, bool next)
3732 BcStatus s = BC_STATUS_SUCCESS;
3734 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3735 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3737 while (p->ops.len > start) {
3739 t = BC_PARSE_TOP_OP(p);
3740 if (t == BC_LEX_LPAREN) break;
3742 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3743 if (l >= r && (l != r || !left)) break;
3745 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3746 bc_vec_pop(&p->ops);
3747 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3750 bc_vec_push(&p->ops, &type);
3751 if (next) s = bc_lex_next(&p->l);
3756 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3760 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3761 top = BC_PARSE_TOP_OP(p);
3763 while (top != BC_LEX_LPAREN) {
3765 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3767 bc_vec_pop(&p->ops);
3768 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3770 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3771 top = BC_PARSE_TOP_OP(p);
3774 bc_vec_pop(&p->ops);
3776 return bc_lex_next(&p->l);
3779 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3785 s = bc_lex_next(&p->l);
3788 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3790 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3791 s = bc_parse_expr(p, flags, bc_parse_next_param);
3794 comma = p->l.t.t == BC_LEX_COMMA;
3796 s = bc_lex_next(&p->l);
3801 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3802 bc_parse_push(p, BC_INST_CALL);
3803 bc_parse_pushIndex(p, nparams);
3805 return BC_STATUS_SUCCESS;
3808 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3811 BcId entry, *entry_ptr;
3816 s = bc_parse_params(p, flags);
3819 if (p->l.t.t != BC_LEX_RPAREN) {
3820 s = BC_STATUS_PARSE_BAD_TOKEN;
3824 idx = bc_map_index(&p->prog->fn_map, &entry);
3826 if (idx == BC_VEC_INVALID_IDX) {
3827 name = xstrdup(entry.name);
3828 bc_parse_addFunc(p, name, &idx);
3829 idx = bc_map_index(&p->prog->fn_map, &entry);
3835 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3836 bc_parse_pushIndex(p, entry_ptr->idx);
3838 return bc_lex_next(&p->l);
3845 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3850 name = xstrdup(p->l.t.v.v);
3851 s = bc_lex_next(&p->l);
3854 if (p->l.t.t == BC_LEX_LBRACKET) {
3856 s = bc_lex_next(&p->l);
3859 if (p->l.t.t == BC_LEX_RBRACKET) {
3861 if (!(flags & BC_PARSE_ARRAY)) {
3862 s = BC_STATUS_PARSE_BAD_EXP;
3866 *type = BC_INST_ARRAY;
3870 *type = BC_INST_ARRAY_ELEM;
3872 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3873 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3877 s = bc_lex_next(&p->l);
3879 bc_parse_push(p, *type);
3880 bc_parse_pushName(p, name);
3882 else if (p->l.t.t == BC_LEX_LPAREN) {
3884 if (flags & BC_PARSE_NOCALL) {
3885 s = BC_STATUS_PARSE_BAD_TOKEN;
3889 *type = BC_INST_CALL;
3890 s = bc_parse_call(p, name, flags);
3893 *type = BC_INST_VAR;
3894 bc_parse_push(p, BC_INST_VAR);
3895 bc_parse_pushName(p, name);
3905 static BcStatus bc_parse_read(BcParse *p)
3909 s = bc_lex_next(&p->l);
3911 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3913 s = bc_lex_next(&p->l);
3915 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3917 bc_parse_push(p, BC_INST_READ);
3919 return bc_lex_next(&p->l);
3922 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3927 s = bc_lex_next(&p->l);
3929 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3931 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3933 s = bc_lex_next(&p->l);
3936 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3939 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3941 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3942 bc_parse_push(p, *prev);
3944 return bc_lex_next(&p->l);
3947 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3951 s = bc_lex_next(&p->l);
3954 if (p->l.t.t != BC_LEX_LPAREN) {
3955 *type = BC_INST_SCALE;
3956 bc_parse_push(p, BC_INST_SCALE);
3957 return BC_STATUS_SUCCESS;
3960 *type = BC_INST_SCALE_FUNC;
3961 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3963 s = bc_lex_next(&p->l);
3966 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3968 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3969 bc_parse_push(p, BC_INST_SCALE_FUNC);
3971 return bc_lex_next(&p->l);
3974 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3975 size_t *nexprs, uint8_t flags)
3980 BcInst etype = *prev;
3982 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3983 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3984 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3986 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3987 bc_parse_push(p, inst);
3988 s = bc_lex_next(&p->l);
3992 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3995 s = bc_lex_next(&p->l);
3999 // Because we parse the next part of the expression
4000 // right here, we need to increment this.
4001 *nexprs = *nexprs + 1;
4007 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4011 case BC_LEX_KEY_IBASE:
4012 case BC_LEX_KEY_LAST:
4013 case BC_LEX_KEY_OBASE:
4015 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4016 s = bc_lex_next(&p->l);
4020 case BC_LEX_KEY_SCALE:
4022 s = bc_lex_next(&p->l);
4024 if (p->l.t.t == BC_LEX_LPAREN)
4025 s = BC_STATUS_PARSE_BAD_TOKEN;
4027 bc_parse_push(p, BC_INST_SCALE);
4033 s = BC_STATUS_PARSE_BAD_TOKEN;
4038 if (!s) bc_parse_push(p, inst);
4044 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4045 bool rparen, size_t *nexprs)
4049 BcInst etype = *prev;
4051 s = bc_lex_next(&p->l);
4054 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4055 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4058 *prev = BC_PARSE_TOKEN_INST(type);
4060 // We can just push onto the op stack because this is the largest
4061 // precedence operator that gets pushed. Inc/dec does not.
4062 if (type != BC_LEX_OP_MINUS)
4063 bc_vec_push(&p->ops, &type);
4065 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4070 static BcStatus bc_parse_string(BcParse *p, char inst)
4072 char *str = xstrdup(p->l.t.v.v);
4074 bc_parse_push(p, BC_INST_STR);
4075 bc_parse_pushIndex(p, p->prog->strs.len);
4076 bc_vec_push(&p->prog->strs, &str);
4077 bc_parse_push(p, inst);
4079 return bc_lex_next(&p->l);
4082 static BcStatus bc_parse_print(BcParse *p)
4088 s = bc_lex_next(&p->l);
4093 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4094 return BC_STATUS_PARSE_BAD_PRINT;
4096 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4098 if (type == BC_LEX_STR)
4099 s = bc_parse_string(p, BC_INST_PRINT_POP);
4101 s = bc_parse_expr(p, 0, bc_parse_next_print);
4103 bc_parse_push(p, BC_INST_PRINT_POP);
4108 comma = p->l.t.t == BC_LEX_COMMA;
4109 if (comma) s = bc_lex_next(&p->l);
4114 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4116 return bc_lex_next(&p->l);
4119 static BcStatus bc_parse_return(BcParse *p)
4125 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4127 s = bc_lex_next(&p->l);
4131 paren = t == BC_LEX_LPAREN;
4133 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4134 bc_parse_push(p, BC_INST_RET0);
4137 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4138 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4140 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4141 bc_parse_push(p, BC_INST_RET0);
4142 s = bc_lex_next(&p->l);
4146 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4147 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4151 bc_parse_push(p, BC_INST_RET);
4157 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4159 BcStatus s = BC_STATUS_SUCCESS;
4161 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4162 return BC_STATUS_PARSE_BAD_TOKEN;
4166 if (p->l.t.t == BC_LEX_RBRACE) {
4167 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4169 s = bc_lex_next(&p->l);
4173 return BC_STATUS_PARSE_BAD_TOKEN;
4176 if (BC_PARSE_IF(p)) {
4180 while (p->l.t.t == BC_LEX_NLINE) {
4181 s = bc_lex_next(&p->l);
4185 bc_vec_pop(&p->flags);
4187 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4188 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4190 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4192 else if (BC_PARSE_ELSE(p)) {
4197 bc_vec_pop(&p->flags);
4199 ip = bc_vec_top(&p->exits);
4200 label = bc_vec_item(&p->func->labels, ip->idx);
4201 *label = p->func->code.len;
4203 bc_vec_pop(&p->exits);
4205 else if (BC_PARSE_FUNC_INNER(p)) {
4206 bc_parse_push(p, BC_INST_RET0);
4207 bc_parse_updateFunc(p, BC_PROG_MAIN);
4208 bc_vec_pop(&p->flags);
4212 BcInstPtr *ip = bc_vec_top(&p->exits);
4213 size_t *label = bc_vec_top(&p->conds);
4215 bc_parse_push(p, BC_INST_JUMP);
4216 bc_parse_pushIndex(p, *label);
4218 label = bc_vec_item(&p->func->labels, ip->idx);
4219 *label = p->func->code.len;
4221 bc_vec_pop(&p->flags);
4222 bc_vec_pop(&p->exits);
4223 bc_vec_pop(&p->conds);
4229 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4231 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4232 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4233 flags |= BC_PARSE_FLAG_BODY;
4234 bc_vec_push(&p->flags, &flags);
4237 static void bc_parse_noElse(BcParse *p)
4241 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4243 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4245 ip = bc_vec_top(&p->exits);
4246 label = bc_vec_item(&p->func->labels, ip->idx);
4247 *label = p->func->code.len;
4249 bc_vec_pop(&p->exits);
4252 static BcStatus bc_parse_if(BcParse *p)
4257 s = bc_lex_next(&p->l);
4259 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4261 s = bc_lex_next(&p->l);
4263 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4265 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4267 s = bc_lex_next(&p->l);
4269 bc_parse_push(p, BC_INST_JUMP_ZERO);
4271 ip.idx = p->func->labels.len;
4272 ip.func = ip.len = 0;
4274 bc_parse_pushIndex(p, ip.idx);
4275 bc_vec_push(&p->exits, &ip);
4276 bc_vec_push(&p->func->labels, &ip.idx);
4277 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4279 return BC_STATUS_SUCCESS;
4282 static BcStatus bc_parse_else(BcParse *p)
4286 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4288 ip.idx = p->func->labels.len;
4289 ip.func = ip.len = 0;
4291 bc_parse_push(p, BC_INST_JUMP);
4292 bc_parse_pushIndex(p, ip.idx);
4296 bc_vec_push(&p->exits, &ip);
4297 bc_vec_push(&p->func->labels, &ip.idx);
4298 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4300 return bc_lex_next(&p->l);
4303 static BcStatus bc_parse_while(BcParse *p)
4308 s = bc_lex_next(&p->l);
4310 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4311 s = bc_lex_next(&p->l);
4314 ip.idx = p->func->labels.len;
4316 bc_vec_push(&p->func->labels, &p->func->code.len);
4317 bc_vec_push(&p->conds, &ip.idx);
4319 ip.idx = p->func->labels.len;
4323 bc_vec_push(&p->exits, &ip);
4324 bc_vec_push(&p->func->labels, &ip.idx);
4326 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4328 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4329 s = bc_lex_next(&p->l);
4332 bc_parse_push(p, BC_INST_JUMP_ZERO);
4333 bc_parse_pushIndex(p, ip.idx);
4334 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4336 return BC_STATUS_SUCCESS;
4339 static BcStatus bc_parse_for(BcParse *p)
4343 size_t cond_idx, exit_idx, body_idx, update_idx;
4345 s = bc_lex_next(&p->l);
4347 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4348 s = bc_lex_next(&p->l);
4351 if (p->l.t.t != BC_LEX_SCOLON)
4352 s = bc_parse_expr(p, 0, bc_parse_next_for);
4354 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4357 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4358 s = bc_lex_next(&p->l);
4361 cond_idx = p->func->labels.len;
4362 update_idx = cond_idx + 1;
4363 body_idx = update_idx + 1;
4364 exit_idx = body_idx + 1;
4366 bc_vec_push(&p->func->labels, &p->func->code.len);
4368 if (p->l.t.t != BC_LEX_SCOLON)
4369 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4371 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4374 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4376 s = bc_lex_next(&p->l);
4379 bc_parse_push(p, BC_INST_JUMP_ZERO);
4380 bc_parse_pushIndex(p, exit_idx);
4381 bc_parse_push(p, BC_INST_JUMP);
4382 bc_parse_pushIndex(p, body_idx);
4384 ip.idx = p->func->labels.len;
4386 bc_vec_push(&p->conds, &update_idx);
4387 bc_vec_push(&p->func->labels, &p->func->code.len);
4389 if (p->l.t.t != BC_LEX_RPAREN)
4390 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4392 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4396 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4397 bc_parse_push(p, BC_INST_JUMP);
4398 bc_parse_pushIndex(p, cond_idx);
4399 bc_vec_push(&p->func->labels, &p->func->code.len);
4405 bc_vec_push(&p->exits, &ip);
4406 bc_vec_push(&p->func->labels, &ip.idx);
4408 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4410 return BC_STATUS_SUCCESS;
4413 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4419 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4421 if (type == BC_LEX_KEY_BREAK) {
4423 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4425 i = p->exits.len - 1;
4426 ip = bc_vec_item(&p->exits, i);
4428 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4429 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4434 i = *((size_t *) bc_vec_top(&p->conds));
4436 bc_parse_push(p, BC_INST_JUMP);
4437 bc_parse_pushIndex(p, i);
4439 s = bc_lex_next(&p->l);
4442 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4443 return BC_STATUS_PARSE_BAD_TOKEN;
4445 return bc_lex_next(&p->l);
4448 static BcStatus bc_parse_func(BcParse *p)
4451 bool var, comma = false;
4455 s = bc_lex_next(&p->l);
4457 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4459 name = xstrdup(p->l.t.v.v);
4460 bc_parse_addFunc(p, name, &p->fidx);
4462 s = bc_lex_next(&p->l);
4464 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4465 s = bc_lex_next(&p->l);
4468 while (p->l.t.t != BC_LEX_RPAREN) {
4470 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4474 name = xstrdup(p->l.t.v.v);
4475 s = bc_lex_next(&p->l);
4478 var = p->l.t.t != BC_LEX_LBRACKET;
4482 s = bc_lex_next(&p->l);
4485 if (p->l.t.t != BC_LEX_RBRACKET) {
4486 s = BC_STATUS_PARSE_BAD_FUNC;
4490 s = bc_lex_next(&p->l);
4494 comma = p->l.t.t == BC_LEX_COMMA;
4496 s = bc_lex_next(&p->l);
4500 s = bc_func_insert(p->func, name, var);
4504 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4506 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4507 bc_parse_startBody(p, flags);
4509 s = bc_lex_next(&p->l);
4512 if (p->l.t.t != BC_LEX_LBRACE)
4513 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4522 static BcStatus bc_parse_auto(BcParse *p)
4525 bool comma, var, one;
4528 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4529 s = bc_lex_next(&p->l);
4532 p->auto_part = comma = false;
4533 one = p->l.t.t == BC_LEX_NAME;
4535 while (p->l.t.t == BC_LEX_NAME) {
4537 name = xstrdup(p->l.t.v.v);
4538 s = bc_lex_next(&p->l);
4541 var = p->l.t.t != BC_LEX_LBRACKET;
4544 s = bc_lex_next(&p->l);
4547 if (p->l.t.t != BC_LEX_RBRACKET) {
4548 s = BC_STATUS_PARSE_BAD_FUNC;
4552 s = bc_lex_next(&p->l);
4556 comma = p->l.t.t == BC_LEX_COMMA;
4558 s = bc_lex_next(&p->l);
4562 s = bc_func_insert(p->func, name, var);
4566 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4567 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4569 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4570 return BC_STATUS_PARSE_BAD_TOKEN;
4572 return bc_lex_next(&p->l);
4579 static BcStatus bc_parse_body(BcParse *p, bool brace)
4581 BcStatus s = BC_STATUS_SUCCESS;
4582 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4584 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4586 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4588 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4589 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4591 if (!p->auto_part) {
4592 s = bc_parse_auto(p);
4596 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4599 s = bc_parse_stmt(p);
4600 if (!s && !brace) s = bc_parse_endBody(p, false);
4606 static BcStatus bc_parse_stmt(BcParse *p)
4608 BcStatus s = BC_STATUS_SUCCESS;
4614 return bc_lex_next(&p->l);
4617 case BC_LEX_KEY_ELSE:
4619 p->auto_part = false;
4625 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4628 s = bc_lex_next(&p->l);
4631 return bc_parse_body(p, true);
4634 case BC_LEX_KEY_AUTO:
4636 return bc_parse_auto(p);
4641 p->auto_part = false;
4643 if (BC_PARSE_IF_END(p)) {
4645 return BC_STATUS_SUCCESS;
4647 else if (BC_PARSE_BODY(p))
4648 return bc_parse_body(p, false);
4658 case BC_LEX_OP_MINUS:
4659 case BC_LEX_OP_BOOL_NOT:
4663 case BC_LEX_KEY_IBASE:
4664 case BC_LEX_KEY_LAST:
4665 case BC_LEX_KEY_LENGTH:
4666 case BC_LEX_KEY_OBASE:
4667 case BC_LEX_KEY_READ:
4668 case BC_LEX_KEY_SCALE:
4669 case BC_LEX_KEY_SQRT:
4671 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4675 case BC_LEX_KEY_ELSE:
4677 s = bc_parse_else(p);
4683 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4689 s = bc_parse_endBody(p, true);
4695 s = bc_parse_string(p, BC_INST_PRINT_STR);
4699 case BC_LEX_KEY_BREAK:
4700 case BC_LEX_KEY_CONTINUE:
4702 s = bc_parse_loopExit(p, p->l.t.t);
4706 case BC_LEX_KEY_FOR:
4708 s = bc_parse_for(p);
4712 case BC_LEX_KEY_HALT:
4714 bc_parse_push(p, BC_INST_HALT);
4715 s = bc_lex_next(&p->l);
4725 case BC_LEX_KEY_LIMITS:
4727 s = bc_lex_next(&p->l);
4729 s = BC_STATUS_LIMITS;
4733 case BC_LEX_KEY_PRINT:
4735 s = bc_parse_print(p);
4739 case BC_LEX_KEY_QUIT:
4741 // Quit is a compile-time command. We don't exit directly,
4742 // so the vm can clean up. Limits do the same thing.
4747 case BC_LEX_KEY_RETURN:
4749 s = bc_parse_return(p);
4753 case BC_LEX_KEY_WHILE:
4755 s = bc_parse_while(p);
4761 s = BC_STATUS_PARSE_BAD_TOKEN;
4769 static BcStatus bc_parse_parse(BcParse *p)
4773 if (p->l.t.t == BC_LEX_EOF)
4774 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4775 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4776 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4777 s = bc_parse_func(p);
4780 s = bc_parse_stmt(p);
4782 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4783 s = bc_parse_reset(p, s);
4788 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4790 BcStatus s = BC_STATUS_SUCCESS;
4791 BcInst prev = BC_INST_PRINT;
4792 BcLexType top, t = p->l.t.t;
4793 size_t nexprs = 0, ops_bgn = p->ops.len;
4794 uint32_t i, nparens, nrelops;
4795 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4797 paren_first = p->l.t.t == BC_LEX_LPAREN;
4798 nparens = nrelops = 0;
4799 paren_expr = rprn = done = get_token = assign = false;
4802 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4808 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4809 rprn = get_token = bin_last = false;
4813 case BC_LEX_OP_MINUS:
4815 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4816 rprn = get_token = false;
4817 bin_last = prev == BC_INST_MINUS;
4821 case BC_LEX_OP_ASSIGN_POWER:
4822 case BC_LEX_OP_ASSIGN_MULTIPLY:
4823 case BC_LEX_OP_ASSIGN_DIVIDE:
4824 case BC_LEX_OP_ASSIGN_MODULUS:
4825 case BC_LEX_OP_ASSIGN_PLUS:
4826 case BC_LEX_OP_ASSIGN_MINUS:
4827 case BC_LEX_OP_ASSIGN:
4829 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4830 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4831 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4833 s = BC_STATUS_PARSE_BAD_ASSIGN;
4838 case BC_LEX_OP_POWER:
4839 case BC_LEX_OP_MULTIPLY:
4840 case BC_LEX_OP_DIVIDE:
4841 case BC_LEX_OP_MODULUS:
4842 case BC_LEX_OP_PLUS:
4843 case BC_LEX_OP_REL_EQ:
4844 case BC_LEX_OP_REL_LE:
4845 case BC_LEX_OP_REL_GE:
4846 case BC_LEX_OP_REL_NE:
4847 case BC_LEX_OP_REL_LT:
4848 case BC_LEX_OP_REL_GT:
4849 case BC_LEX_OP_BOOL_NOT:
4850 case BC_LEX_OP_BOOL_OR:
4851 case BC_LEX_OP_BOOL_AND:
4853 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4854 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4856 return BC_STATUS_PARSE_BAD_EXP;
4859 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4860 prev = BC_PARSE_TOKEN_INST(t);
4861 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4862 rprn = get_token = false;
4863 bin_last = t != BC_LEX_OP_BOOL_NOT;
4870 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4873 paren_expr = rprn = bin_last = false;
4875 bc_vec_push(&p->ops, &t);
4882 if (bin_last || prev == BC_INST_BOOL_NOT)
4883 return BC_STATUS_PARSE_BAD_EXP;
4886 s = BC_STATUS_SUCCESS;
4891 else if (!paren_expr)
4892 return BC_STATUS_PARSE_EMPTY_EXP;
4895 paren_expr = rprn = true;
4896 get_token = bin_last = false;
4898 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4905 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4908 rprn = get_token = bin_last = false;
4909 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4917 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4919 bc_parse_number(p, &prev, &nexprs);
4920 paren_expr = get_token = true;
4921 rprn = bin_last = false;
4926 case BC_LEX_KEY_IBASE:
4927 case BC_LEX_KEY_LAST:
4928 case BC_LEX_KEY_OBASE:
4930 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4932 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4933 bc_parse_push(p, (char) prev);
4935 paren_expr = get_token = true;
4936 rprn = bin_last = false;
4942 case BC_LEX_KEY_LENGTH:
4943 case BC_LEX_KEY_SQRT:
4945 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4947 s = bc_parse_builtin(p, t, flags, &prev);
4949 rprn = get_token = bin_last = false;
4955 case BC_LEX_KEY_READ:
4957 if (BC_PARSE_LEAF(prev, rprn))
4958 return BC_STATUS_PARSE_BAD_EXP;
4959 else if (flags & BC_PARSE_NOREAD)
4960 s = BC_STATUS_EXEC_REC_READ;
4962 s = bc_parse_read(p);
4965 rprn = get_token = bin_last = false;
4967 prev = BC_INST_READ;
4972 case BC_LEX_KEY_SCALE:
4974 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4976 s = bc_parse_scale(p, &prev, flags);
4978 rprn = get_token = bin_last = false;
4980 prev = BC_INST_SCALE;
4987 s = BC_STATUS_PARSE_BAD_TOKEN;
4992 if (!s && get_token) s = bc_lex_next(&p->l);
4996 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4998 while (p->ops.len > ops_bgn) {
5000 top = BC_PARSE_TOP_OP(p);
5001 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5003 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5004 return BC_STATUS_PARSE_BAD_EXP;
5006 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5008 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5009 bc_vec_pop(&p->ops);
5012 s = BC_STATUS_PARSE_BAD_EXP;
5013 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5015 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5018 if (!(flags & BC_PARSE_REL) && nrelops) {
5019 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5022 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5023 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5027 if (flags & BC_PARSE_PRINT) {
5028 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5029 bc_parse_push(p, BC_INST_POP);
5035 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5037 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5040 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5042 return bc_parse_expr(p, flags, bc_parse_next_read);
5047 static BcStatus dc_parse_register(BcParse *p)
5052 s = bc_lex_next(&p->l);
5054 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5056 name = xstrdup(p->l.t.v.v);
5057 bc_parse_pushName(p, name);
5062 static BcStatus dc_parse_string(BcParse *p)
5064 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5065 size_t idx, len = p->prog->strs.len;
5067 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5070 str = xstrdup(p->l.t.v.v);
5071 bc_parse_push(p, BC_INST_STR);
5072 bc_parse_pushIndex(p, len);
5073 bc_vec_push(&p->prog->strs, &str);
5074 bc_parse_addFunc(p, name, &idx);
5076 return bc_lex_next(&p->l);
5079 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5083 bc_parse_push(p, inst);
5085 s = dc_parse_register(p);
5090 bc_parse_push(p, BC_INST_SWAP);
5091 bc_parse_push(p, BC_INST_ASSIGN);
5092 bc_parse_push(p, BC_INST_POP);
5095 return bc_lex_next(&p->l);
5098 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5102 bc_parse_push(p, inst);
5103 bc_parse_push(p, BC_INST_EXEC_COND);
5105 s = dc_parse_register(p);
5108 s = bc_lex_next(&p->l);
5111 if (p->l.t.t == BC_LEX_ELSE) {
5112 s = dc_parse_register(p);
5114 s = bc_lex_next(&p->l);
5117 bc_parse_push(p, BC_PARSE_STREND);
5122 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5124 BcStatus s = BC_STATUS_SUCCESS;
5127 bool assign, get_token = false;
5131 case BC_LEX_OP_REL_EQ:
5132 case BC_LEX_OP_REL_LE:
5133 case BC_LEX_OP_REL_GE:
5134 case BC_LEX_OP_REL_NE:
5135 case BC_LEX_OP_REL_LT:
5136 case BC_LEX_OP_REL_GT:
5138 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5145 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5151 s = dc_parse_string(p);
5158 if (t == BC_LEX_NEG) {
5159 s = bc_lex_next(&p->l);
5161 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5164 bc_parse_number(p, &prev, &p->nbraces);
5166 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5172 case BC_LEX_KEY_READ:
5174 if (flags & BC_PARSE_NOREAD)
5175 s = BC_STATUS_EXEC_REC_READ;
5177 bc_parse_push(p, BC_INST_READ);
5182 case BC_LEX_OP_ASSIGN:
5183 case BC_LEX_STORE_PUSH:
5185 assign = t == BC_LEX_OP_ASSIGN;
5186 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5187 s = dc_parse_mem(p, inst, true, assign);
5192 case BC_LEX_LOAD_POP:
5194 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5195 s = dc_parse_mem(p, inst, true, false);
5199 case BC_LEX_STORE_IBASE:
5200 case BC_LEX_STORE_SCALE:
5201 case BC_LEX_STORE_OBASE:
5203 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5204 s = dc_parse_mem(p, inst, false, true);
5210 s = BC_STATUS_PARSE_BAD_TOKEN;
5216 if (!s && get_token) s = bc_lex_next(&p->l);
5221 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5223 BcStatus s = BC_STATUS_SUCCESS;
5227 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5229 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5231 inst = dc_parse_insts[t];
5233 if (inst != BC_INST_INVALID) {
5234 bc_parse_push(p, inst);
5235 s = bc_lex_next(&p->l);
5238 s = dc_parse_token(p, t, flags);
5241 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5242 bc_parse_push(p, BC_INST_POP_EXEC);
5247 static BcStatus dc_parse_parse(BcParse *p)
5251 if (p->l.t.t == BC_LEX_EOF)
5252 s = BC_STATUS_LEX_EOF;
5254 s = dc_parse_expr(p, 0);
5256 if (s || G_interrupt) s = bc_parse_reset(p, s);
5261 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5263 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5267 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5276 v = var ? &p->vars : &p->arrs;
5277 map = var ? &p->var_map : &p->arr_map;
5281 s = bc_map_insert(map, &e, &i);
5282 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5285 bc_array_init(&data.v, var);
5286 bc_vec_push(v, &data.v);
5289 ptr = bc_vec_item(map, i);
5290 if (new) ptr->name = xstrdup(e.name);
5291 *ret = bc_vec_item(v, ptr->idx);
5294 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5296 BcStatus s = BC_STATUS_SUCCESS;
5301 case BC_RESULT_TEMP:
5302 case BC_RESULT_IBASE:
5303 case BC_RESULT_SCALE:
5304 case BC_RESULT_OBASE:
5310 case BC_RESULT_CONSTANT:
5312 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5313 size_t base_t, len = strlen(*str);
5316 bc_num_init(&r->d.n, len);
5318 hex = hex && len == 1;
5319 base = hex ? &p->hexb : &p->ib;
5320 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5321 s = bc_num_parse(&r->d.n, *str, base, base_t);
5324 bc_num_free(&r->d.n);
5329 r->t = BC_RESULT_TEMP;
5335 case BC_RESULT_ARRAY:
5336 case BC_RESULT_ARRAY_ELEM:
5340 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5342 if (r->t == BC_RESULT_ARRAY_ELEM) {
5344 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5345 *num = bc_vec_item(v, r->d.id.idx);
5348 *num = bc_vec_top(v);
5353 case BC_RESULT_LAST:
5369 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5370 BcResult **r, BcNum **rn, bool assign)
5374 BcResultType lt, rt;
5376 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5378 *r = bc_vec_item_rev(&p->results, 0);
5379 *l = bc_vec_item_rev(&p->results, 1);
5383 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5385 s = bc_program_num(p, *l, ln, false);
5387 s = bc_program_num(p, *r, rn, hex);
5390 // We run this again under these conditions in case any vector has been
5391 // reallocated out from under the BcNums or arrays we had.
5392 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5393 s = bc_program_num(p, *l, ln, false);
5397 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5398 return BC_STATUS_EXEC_BAD_TYPE;
5399 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5404 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5406 r->t = BC_RESULT_TEMP;
5407 bc_vec_pop(&p->results);
5408 bc_vec_pop(&p->results);
5409 bc_vec_push(&p->results, r);
5412 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5416 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5417 *r = bc_vec_top(&p->results);
5419 s = bc_program_num(p, *r, n, false);
5422 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5427 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5430 bc_vec_pop(&p->results);
5431 bc_vec_push(&p->results, r);
5434 static BcStatus bc_program_op(BcProgram *p, char inst)
5437 BcResult *opd1, *opd2, res;
5438 BcNum *n1, *n2 = NULL;
5440 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5442 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5444 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5446 bc_program_binOpRetire(p, &res);
5451 bc_num_free(&res.d.n);
5455 static BcStatus bc_program_read(BcProgram *p)
5462 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5464 for (i = 0; i < p->stack.len; ++i) {
5465 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5466 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5469 bc_vec_npop(&f->code, f->code.len);
5470 bc_vec_init(&buf, sizeof(char), NULL);
5472 s = bc_read_line(&buf, "read> ");
5475 p->parse_init(&parse, p, BC_PROG_READ);
5476 bc_lex_file(&parse.l, bc_program_stdin_name);
5478 s = bc_parse_text(&parse, buf.v);
5479 if (s) goto exec_err;
5480 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5481 if (s) goto exec_err;
5483 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5484 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5488 ip.func = BC_PROG_READ;
5490 ip.len = p->results.len;
5492 // Update this pointer, just in case.
5493 f = bc_vec_item(&p->fns, BC_PROG_READ);
5495 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5496 bc_vec_push(&p->stack, &ip);
5499 bc_parse_free(&parse);
5505 static size_t bc_program_index(char *code, size_t *bgn)
5507 char amt = code[(*bgn)++], i = 0;
5510 for (; i < amt; ++i, ++(*bgn))
5511 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5516 static char *bc_program_name(char *code, size_t *bgn)
5519 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5521 s = xmalloc(ptr - str + 1);
5524 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5532 static void bc_program_printString(const char *str, size_t *nchars)
5534 size_t i, len = strlen(str);
5543 for (i = 0; i < len; ++i, ++(*nchars)) {
5547 if (c != '\\' || i == len - 1)
5607 // Just print the backslash and following character.
5618 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5620 BcStatus s = BC_STATUS_SUCCESS;
5625 bool pop = inst != BC_INST_PRINT;
5627 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5629 r = bc_vec_item_rev(&p->results, idx);
5630 s = bc_program_num(p, r, &num, false);
5633 if (BC_PROG_NUM(r, num)) {
5634 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5635 if (!s) bc_num_copy(&p->last, num);
5639 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5640 str = *((char **) bc_vec_item(&p->strs, idx));
5642 if (inst == BC_INST_PRINT_STR) {
5643 for (i = 0, len = strlen(str); i < len; ++i) {
5646 if (c == '\n') p->nchars = SIZE_MAX;
5651 bc_program_printString(str, &p->nchars);
5652 if (inst == BC_INST_PRINT) bb_putchar('\n');
5656 if (!s && pop) bc_vec_pop(&p->results);
5661 static BcStatus bc_program_negate(BcProgram *p)
5667 s = bc_program_prep(p, &ptr, &num);
5670 bc_num_init(&res.d.n, num->len);
5671 bc_num_copy(&res.d.n, num);
5672 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5674 bc_program_retire(p, &res, BC_RESULT_TEMP);
5679 static BcStatus bc_program_logical(BcProgram *p, char inst)
5682 BcResult *opd1, *opd2, res;
5687 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5689 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5691 if (inst == BC_INST_BOOL_AND)
5692 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5693 else if (inst == BC_INST_BOOL_OR)
5694 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5697 cmp = bc_num_cmp(n1, n2);
5701 case BC_INST_REL_EQ:
5707 case BC_INST_REL_LE:
5713 case BC_INST_REL_GE:
5719 case BC_INST_REL_NE:
5725 case BC_INST_REL_LT:
5731 case BC_INST_REL_GT:
5739 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5741 bc_program_binOpRetire(p, &res);
5747 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5753 memset(&n2, 0, sizeof(BcNum));
5754 n2.rdx = res.d.id.idx = r->d.id.idx;
5755 res.t = BC_RESULT_STR;
5758 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5760 bc_vec_pop(&p->results);
5763 bc_vec_pop(&p->results);
5765 bc_vec_push(&p->results, &res);
5766 bc_vec_push(v, &n2);
5768 return BC_STATUS_SUCCESS;
5772 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5779 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5781 ptr = bc_vec_top(&p->results);
5782 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5783 bc_program_search(p, name, &v, var);
5786 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5787 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5790 s = bc_program_num(p, ptr, &n, false);
5793 // Do this once more to make sure that pointers were not invalidated.
5794 bc_program_search(p, name, &v, var);
5797 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5798 bc_num_copy(&r.d.n, n);
5801 bc_array_init(&r.d.v, true);
5802 bc_array_copy(&r.d.v, (BcVec *) n);
5805 bc_vec_push(v, &r.d);
5806 bc_vec_pop(&p->results);
5811 static BcStatus bc_program_assign(BcProgram *p, char inst)
5814 BcResult *left, *right, res;
5815 BcNum *l = NULL, *r = NULL;
5816 unsigned long val, max;
5817 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5819 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5822 ib = left->t == BC_RESULT_IBASE;
5823 sc = left->t == BC_RESULT_SCALE;
5827 if (right->t == BC_RESULT_STR) {
5831 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5832 bc_program_search(p, left->d.id.name, &v, true);
5834 return bc_program_assignStr(p, right, v, false);
5838 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5839 return BC_STATUS_PARSE_BAD_ASSIGN;
5842 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5843 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5848 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5855 if (ib || sc || left->t == BC_RESULT_OBASE) {
5859 s = bc_num_ulong(l, &val);
5861 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5868 if (val < BC_NUM_MIN_BASE) return s;
5869 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5870 ptr = ib ? &p->ib_t : &p->ob_t;
5873 if (val > max) return s;
5874 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5876 *ptr = (size_t) val;
5877 s = BC_STATUS_SUCCESS;
5880 bc_num_init(&res.d.n, l->len);
5881 bc_num_copy(&res.d.n, l);
5882 bc_program_binOpRetire(p, &res);
5887 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5888 bool pop, bool copy)
5890 BcStatus s = BC_STATUS_SUCCESS;
5892 char *name = bc_program_name(code, bgn);
5893 #if ENABLE_DC // Exclude
5897 (void) pop, (void) copy;
5900 r.t = BC_RESULT_VAR;
5904 bc_program_search(p, name, &v, true);
5905 num = bc_vec_top(v);
5909 if (!BC_PROG_STACK(v, 2 - copy)) {
5911 return BC_STATUS_EXEC_STACK;
5917 if (!BC_PROG_STR(num)) {
5919 r.t = BC_RESULT_TEMP;
5921 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5922 bc_num_copy(&r.d.n, num);
5925 r.t = BC_RESULT_STR;
5926 r.d.id.idx = num->rdx;
5929 if (!copy) bc_vec_pop(v);
5933 bc_vec_push(&p->results, &r);
5938 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5941 BcStatus s = BC_STATUS_SUCCESS;
5945 r.d.id.name = bc_program_name(code, bgn);
5947 if (inst == BC_INST_ARRAY) {
5948 r.t = BC_RESULT_ARRAY;
5949 bc_vec_push(&p->results, &r);
5956 s = bc_program_prep(p, &operand, &num);
5958 s = bc_num_ulong(num, &temp);
5961 if (temp > BC_MAX_DIM) {
5962 s = BC_STATUS_EXEC_ARRAY_LEN;
5966 r.d.id.idx = (size_t) temp;
5967 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5971 if (s) free(r.d.id.name);
5976 static BcStatus bc_program_incdec(BcProgram *p, char inst)
5979 BcResult *ptr, res, copy;
5983 s = bc_program_prep(p, &ptr, &num);
5986 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5987 copy.t = BC_RESULT_TEMP;
5988 bc_num_init(©.d.n, num->len);
5989 bc_num_copy(©.d.n, num);
5992 res.t = BC_RESULT_ONE;
5993 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5994 BC_INST_ASSIGN_PLUS :
5995 BC_INST_ASSIGN_MINUS;
5997 bc_vec_push(&p->results, &res);
5998 bc_program_assign(p, inst);
6000 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6001 bc_vec_pop(&p->results);
6002 bc_vec_push(&p->results, ©);
6008 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6010 BcStatus s = BC_STATUS_SUCCESS;
6012 size_t i, nparams = bc_program_index(code, idx);
6020 ip.func = bc_program_index(code, idx);
6021 func = bc_vec_item(&p->fns, ip.func);
6023 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6024 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6025 ip.len = p->results.len - nparams;
6027 for (i = 0; i < nparams; ++i) {
6029 a = bc_vec_item(&func->autos, nparams - 1 - i);
6030 arg = bc_vec_top(&p->results);
6032 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6033 return BC_STATUS_EXEC_BAD_TYPE;
6035 s = bc_program_copyToVar(p, a->name, a->idx);
6039 for (; i < func->autos.len; ++i) {
6041 a = bc_vec_item(&func->autos, i);
6042 bc_program_search(p, a->name, &v, a->idx);
6045 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6046 bc_vec_push(v, ¶m.n);
6049 bc_array_init(¶m.v, true);
6050 bc_vec_push(v, ¶m.v);
6054 bc_vec_push(&p->stack, &ip);
6056 return BC_STATUS_SUCCESS;
6059 static BcStatus bc_program_return(BcProgram *p, char inst)
6065 BcInstPtr *ip = bc_vec_top(&p->stack);
6067 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6068 return BC_STATUS_EXEC_STACK;
6070 f = bc_vec_item(&p->fns, ip->func);
6071 res.t = BC_RESULT_TEMP;
6073 if (inst == BC_INST_RET) {
6076 BcResult *operand = bc_vec_top(&p->results);
6078 s = bc_program_num(p, operand, &num, false);
6080 bc_num_init(&res.d.n, num->len);
6081 bc_num_copy(&res.d.n, num);
6084 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6085 bc_num_zero(&res.d.n);
6088 // We need to pop arguments as well, so this takes that into account.
6089 for (i = 0; i < f->autos.len; ++i) {
6092 BcId *a = bc_vec_item(&f->autos, i);
6094 bc_program_search(p, a->name, &v, a->idx);
6098 bc_vec_npop(&p->results, p->results.len - ip->len);
6099 bc_vec_push(&p->results, &res);
6100 bc_vec_pop(&p->stack);
6102 return BC_STATUS_SUCCESS;
6106 static unsigned long bc_program_scale(BcNum *n)
6108 return (unsigned long) n->rdx;
6111 static unsigned long bc_program_len(BcNum *n)
6113 unsigned long len = n->len;
6116 if (n->rdx != n->len) return len;
6117 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6122 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6128 bool len = inst == BC_INST_LENGTH;
6130 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6131 opnd = bc_vec_top(&p->results);
6133 s = bc_program_num(p, opnd, &num, false);
6137 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6140 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6142 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6144 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6145 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6149 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6152 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6154 str = bc_vec_item(&p->strs, idx);
6155 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6160 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6161 s = bc_num_ulong2num(&res.d.n, f(num));
6165 bc_program_retire(p, &res, BC_RESULT_TEMP);
6170 bc_num_free(&res.d.n);
6175 static BcStatus bc_program_divmod(BcProgram *p)
6178 BcResult *opd1, *opd2, res, res2;
6179 BcNum *n1, *n2 = NULL;
6181 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6184 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6185 bc_num_init(&res2.d.n, n2->len);
6187 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6190 bc_program_binOpRetire(p, &res2);
6191 res.t = BC_RESULT_TEMP;
6192 bc_vec_push(&p->results, &res);
6197 bc_num_free(&res2.d.n);
6198 bc_num_free(&res.d.n);
6202 static BcStatus bc_program_modexp(BcProgram *p)
6205 BcResult *r1, *r2, *r3, res;
6206 BcNum *n1, *n2, *n3;
6208 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6209 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6212 r1 = bc_vec_item_rev(&p->results, 2);
6213 s = bc_program_num(p, r1, &n1, false);
6215 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6217 // Make sure that the values have their pointers updated, if necessary.
6218 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6220 if (r1->t == r2->t) {
6221 s = bc_program_num(p, r2, &n2, false);
6225 if (r1->t == r3->t) {
6226 s = bc_program_num(p, r3, &n3, false);
6231 bc_num_init(&res.d.n, n3->len);
6232 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6235 bc_vec_pop(&p->results);
6236 bc_program_binOpRetire(p, &res);
6241 bc_num_free(&res.d.n);
6245 static BcStatus bc_program_stackLen(BcProgram *p)
6249 size_t len = p->results.len;
6251 res.t = BC_RESULT_TEMP;
6253 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6254 s = bc_num_ulong2num(&res.d.n, len);
6256 bc_vec_push(&p->results, &res);
6261 bc_num_free(&res.d.n);
6265 static BcStatus bc_program_asciify(BcProgram *p)
6269 BcNum *num = NULL, n;
6270 char *str, *str2, c;
6271 size_t len = p->strs.len, idx;
6274 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6275 r = bc_vec_top(&p->results);
6277 s = bc_program_num(p, r, &num, false);
6280 if (BC_PROG_NUM(r, num)) {
6282 bc_num_init(&n, BC_NUM_DEF_SIZE);
6283 bc_num_copy(&n, num);
6284 bc_num_truncate(&n, n.rdx);
6286 s = bc_num_mod(&n, &p->strmb, &n, 0);
6287 if (s) goto num_err;
6288 s = bc_num_ulong(&n, &val);
6289 if (s) goto num_err;
6296 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6297 str2 = *((char **) bc_vec_item(&p->strs, idx));
6305 str2 = xstrdup(str);
6306 bc_program_addFunc(p, str2, &idx);
6308 if (idx != len + BC_PROG_REQ_FUNCS) {
6310 for (idx = 0; idx < p->strs.len; ++idx) {
6311 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6320 bc_vec_push(&p->strs, &str);
6322 res.t = BC_RESULT_STR;
6324 bc_vec_pop(&p->results);
6325 bc_vec_push(&p->results, &res);
6327 return BC_STATUS_SUCCESS;
6334 static BcStatus bc_program_printStream(BcProgram *p)
6342 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6343 r = bc_vec_top(&p->results);
6345 s = bc_program_num(p, r, &n, false);
6348 if (BC_PROG_NUM(r, n))
6349 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6351 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6352 str = *((char **) bc_vec_item(&p->strs, idx));
6359 static BcStatus bc_program_nquit(BcProgram *p)
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(BcProgram *p, char *code, size_t *bgn,
6386 BcStatus s = BC_STATUS_SUCCESS;
6396 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6398 r = bc_vec_top(&p->results);
6403 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6405 if (code[*bgn] == BC_PARSE_STREND)
6408 else_name = bc_program_name(code, bgn);
6410 exec = r->d.n.len != 0;
6414 else if (else_name != NULL) {
6420 bc_program_search(p, name, &v, true);
6427 if (!exec) goto exit;
6428 if (!BC_PROG_STR(n)) {
6429 s = BC_STATUS_EXEC_BAD_TYPE;
6437 if (r->t == BC_RESULT_STR)
6439 else if (r->t == BC_RESULT_VAR) {
6440 s = bc_program_num(p, r, &n, false);
6441 if (s || !BC_PROG_STR(n)) goto exit;
6448 fidx = sidx + BC_PROG_REQ_FUNCS;
6450 str = bc_vec_item(&p->strs, sidx);
6451 f = bc_vec_item(&p->fns, fidx);
6453 if (f->code.len == 0) {
6455 p->parse_init(&prs, p, fidx);
6456 s = bc_parse_text(&prs, *str);
6458 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6461 if (prs.l.t.t != BC_LEX_EOF) {
6462 s = BC_STATUS_PARSE_BAD_EXP;
6466 bc_parse_free(&prs);
6470 ip.len = p->results.len;
6473 bc_vec_pop(&p->results);
6474 bc_vec_push(&p->stack, &ip);
6476 return BC_STATUS_SUCCESS;
6479 bc_parse_free(&prs);
6480 f = bc_vec_item(&p->fns, fidx);
6481 bc_vec_npop(&f->code, f->code.len);
6483 bc_vec_pop(&p->results);
6488 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6494 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6495 if (inst == BC_INST_IBASE)
6496 val = (unsigned long) p->ib_t;
6497 else if (inst == BC_INST_SCALE)
6498 val = (unsigned long) p->scale;
6500 val = (unsigned long) p->ob_t;
6502 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6503 s = bc_num_ulong2num(&res.d.n, val);
6505 bc_vec_push(&p->results, &res);
6510 bc_num_free(&res.d.n);
6514 static void bc_program_free(BcProgram *p)
6516 bc_num_free(&p->ib);
6517 bc_num_free(&p->ob);
6518 bc_num_free(&p->hexb);
6520 bc_num_free(&p->strmb);
6522 bc_vec_free(&p->fns);
6523 bc_vec_free(&p->fn_map);
6524 bc_vec_free(&p->vars);
6525 bc_vec_free(&p->var_map);
6526 bc_vec_free(&p->arrs);
6527 bc_vec_free(&p->arr_map);
6528 bc_vec_free(&p->strs);
6529 bc_vec_free(&p->consts);
6530 bc_vec_free(&p->results);
6531 bc_vec_free(&p->stack);
6532 bc_num_free(&p->last);
6533 bc_num_free(&p->zero);
6534 bc_num_free(&p->one);
6537 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6543 memset(p, 0, sizeof(BcProgram));
6544 memset(&ip, 0, sizeof(BcInstPtr));
6546 p->nchars = p->scale = 0;
6548 p->parse_init = init;
6549 p->parse_expr = expr;
6551 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6555 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6559 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6560 bc_num_ten(&p->hexb);
6564 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6565 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6568 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6569 bc_num_zero(&p->last);
6571 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6572 bc_num_zero(&p->zero);
6574 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6575 bc_num_one(&p->one);
6577 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6578 bc_map_init(&p->fn_map);
6580 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6581 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6583 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6584 bc_map_init(&p->var_map);
6586 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6587 bc_map_init(&p->arr_map);
6589 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6590 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6591 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6592 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6593 bc_vec_push(&p->stack, &ip);
6596 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6599 BcId entry, *entry_ptr;
6603 entry.idx = p->fns.len;
6605 s = bc_map_insert(&p->fn_map, &entry, idx);
6608 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6609 *idx = entry_ptr->idx;
6611 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6613 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6615 // We need to reset these, so the function can be repopulated.
6617 bc_vec_npop(&func->autos, func->autos.len);
6618 bc_vec_npop(&func->code, func->code.len);
6619 bc_vec_npop(&func->labels, func->labels.len);
6623 bc_vec_push(&p->fns, &f);
6627 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6632 bc_vec_npop(&p->stack, p->stack.len - 1);
6633 bc_vec_npop(&p->results, p->results.len);
6635 f = bc_vec_item(&p->fns, 0);
6636 ip = bc_vec_top(&p->stack);
6637 ip->idx = f->code.len;
6639 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6641 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6644 fputs(bc_program_ready_msg, stderr);
6646 s = BC_STATUS_SUCCESS;
6655 static BcStatus bc_program_exec(BcProgram *p)
6657 BcStatus s = BC_STATUS_SUCCESS;
6661 BcInstPtr *ip = bc_vec_top(&p->stack);
6662 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6663 char *code = func->code.v;
6666 while (!s && ip->idx < func->code.len) {
6668 char inst = code[(ip->idx)++];
6673 case BC_INST_JUMP_ZERO:
6675 s = bc_program_prep(p, &ptr, &num);
6677 cond = !bc_num_cmp(num, &p->zero);
6678 bc_vec_pop(&p->results);
6684 idx = bc_program_index(code, &ip->idx);
6685 addr = bc_vec_item(&func->labels, idx);
6686 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6692 s = bc_program_call(p, code, &ip->idx);
6696 case BC_INST_INC_PRE:
6697 case BC_INST_DEC_PRE:
6698 case BC_INST_INC_POST:
6699 case BC_INST_DEC_POST:
6701 s = bc_program_incdec(p, inst);
6714 s = bc_program_return(p, inst);
6718 case BC_INST_BOOL_OR:
6719 case BC_INST_BOOL_AND:
6721 case BC_INST_REL_EQ:
6722 case BC_INST_REL_LE:
6723 case BC_INST_REL_GE:
6724 case BC_INST_REL_NE:
6725 case BC_INST_REL_LT:
6726 case BC_INST_REL_GT:
6728 s = bc_program_logical(p, inst);
6734 s = bc_program_read(p);
6740 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6744 case BC_INST_ARRAY_ELEM:
6747 s = bc_program_pushArray(p, code, &ip->idx, inst);
6753 r.t = BC_RESULT_LAST;
6754 bc_vec_push(&p->results, &r);
6762 s = bc_program_pushGlobal(p, inst);
6766 case BC_INST_SCALE_FUNC:
6767 case BC_INST_LENGTH:
6770 s = bc_program_builtin(p, inst);
6776 r.t = BC_RESULT_CONSTANT;
6777 r.d.id.idx = bc_program_index(code, &ip->idx);
6778 bc_vec_push(&p->results, &r);
6784 if (!BC_PROG_STACK(&p->results, 1))
6785 s = BC_STATUS_EXEC_STACK;
6787 bc_vec_pop(&p->results);
6791 case BC_INST_POP_EXEC:
6793 bc_vec_pop(&p->stack);
6798 case BC_INST_PRINT_POP:
6799 case BC_INST_PRINT_STR:
6801 s = bc_program_print(p, inst, 0);
6807 r.t = BC_RESULT_STR;
6808 r.d.id.idx = bc_program_index(code, &ip->idx);
6809 bc_vec_push(&p->results, &r);
6814 case BC_INST_MULTIPLY:
6815 case BC_INST_DIVIDE:
6816 case BC_INST_MODULUS:
6820 s = bc_program_op(p, inst);
6824 case BC_INST_BOOL_NOT:
6826 s = bc_program_prep(p, &ptr, &num);
6829 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6830 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6831 bc_program_retire(p, &r, BC_RESULT_TEMP);
6838 s = bc_program_negate(p);
6843 case BC_INST_ASSIGN_POWER:
6844 case BC_INST_ASSIGN_MULTIPLY:
6845 case BC_INST_ASSIGN_DIVIDE:
6846 case BC_INST_ASSIGN_MODULUS:
6847 case BC_INST_ASSIGN_PLUS:
6848 case BC_INST_ASSIGN_MINUS:
6850 case BC_INST_ASSIGN:
6852 s = bc_program_assign(p, inst);
6856 case BC_INST_MODEXP:
6858 s = bc_program_modexp(p);
6862 case BC_INST_DIVMOD:
6864 s = bc_program_divmod(p);
6868 case BC_INST_EXECUTE:
6869 case BC_INST_EXEC_COND:
6871 cond = inst == BC_INST_EXEC_COND;
6872 s = bc_program_execStr(p, code, &ip->idx, cond);
6876 case BC_INST_PRINT_STACK:
6878 for (idx = 0; !s && idx < p->results.len; ++idx)
6879 s = bc_program_print(p, BC_INST_PRINT, idx);
6883 case BC_INST_CLEAR_STACK:
6885 bc_vec_npop(&p->results, p->results.len);
6889 case BC_INST_STACK_LEN:
6891 s = bc_program_stackLen(p);
6895 case BC_INST_DUPLICATE:
6897 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6898 ptr = bc_vec_top(&p->results);
6899 bc_result_copy(&r, ptr);
6900 bc_vec_push(&p->results, &r);
6908 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6910 ptr = bc_vec_item_rev(&p->results, 0);
6911 ptr2 = bc_vec_item_rev(&p->results, 1);
6912 memcpy(&r, ptr, sizeof(BcResult));
6913 memcpy(ptr, ptr2, sizeof(BcResult));
6914 memcpy(ptr2, &r, sizeof(BcResult));
6919 case BC_INST_ASCIIFY:
6921 s = bc_program_asciify(p);
6925 case BC_INST_PRINT_STREAM:
6927 s = bc_program_printStream(p);
6932 case BC_INST_PUSH_VAR:
6934 bool copy = inst == BC_INST_LOAD;
6935 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6939 case BC_INST_PUSH_TO_VAR:
6941 char *name = bc_program_name(code, &ip->idx);
6942 s = bc_program_copyToVar(p, name, true);
6949 if (p->stack.len <= 2)
6952 bc_vec_npop(&p->stack, 2);
6958 s = bc_program_nquit(p);
6964 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(p, s);
6966 // If the stack has changed, pointers may be invalid.
6967 ip = bc_vec_top(&p->stack);
6968 func = bc_vec_item(&p->fns, ip->func);
6969 code = func->code.v;
6975 static void bc_vm_info(void)
6977 printf("%s "BB_VER"\n"
6978 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6979 "Report bugs at: https://github.com/gavinhoward/bc\n"
6980 "This is free software with ABSOLUTELY NO WARRANTY\n"
6984 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6986 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6988 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6989 fprintf(stderr, " %s", file);
6990 fprintf(stderr, bc_err_line + 4 * !line, line);
6992 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6996 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6999 int p = (int) G_posix, w = (int) G_warn;
7000 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7002 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7004 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7005 if (msg) fprintf(stderr, " %s\n", msg);
7006 fprintf(stderr, " %s", file);
7007 fprintf(stderr, bc_err_line + 4 * !line, line);
7009 return s * (!G.ttyin && !!p);
7012 static void bc_vm_envArgs(void)
7015 char *env_args = getenv(bc_args_env_name), *buf;
7017 if (!env_args) return;
7019 G.env_args = xstrdup(env_args);
7022 bc_vec_init(&v, sizeof(char *), NULL);
7023 bc_vec_push(&v, &bc_args_env_name);
7026 if (!isspace(*buf)) {
7027 bc_vec_push(&v, &buf);
7028 while (*buf != 0 && !isspace(*buf)) ++buf;
7029 if (*buf != 0) (*(buf++)) = '\0';
7035 bc_args((int) v.len, (char **) v.v, &G.flags, &G.files);
7041 static size_t bc_vm_envLen(const char *var)
7043 char *lenv = getenv(var);
7044 size_t i, len = BC_NUM_PRINT_WIDTH;
7047 if (!lenv) return len;
7051 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7053 len = (size_t) atoi(lenv) - 1;
7054 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7057 len = BC_NUM_PRINT_WIDTH;
7062 static BcStatus bc_vm_process(const char *text)
7064 BcStatus s = bc_parse_text(&G.prs, text);
7066 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7069 while (G.prs.l.t.t != BC_LEX_EOF) {
7071 s = G.prs.parse(&G.prs);
7073 if (s == BC_STATUS_LIMITS) {
7076 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7077 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7078 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7079 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7080 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7081 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7082 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7083 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7086 s = BC_STATUS_SUCCESS;
7089 if (s == BC_STATUS_QUIT) return s;
7090 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7095 if (BC_PARSE_CAN_EXEC(&G.prs)) {
7096 s = bc_program_exec(&G.prog);
7097 if (!s && G.tty) fflush(stdout);
7098 if (s && s != BC_STATUS_QUIT)
7099 s = bc_vm_error(bc_program_reset(&G.prog, s), G.prs.l.f, 0);
7105 static BcStatus bc_vm_file(const char *file)
7113 s = bc_read_file(file, &data);
7114 if (s) return bc_vm_error(s, file, 0);
7116 bc_lex_file(&G.prs.l, file);
7117 s = bc_vm_process(data);
7120 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7121 ip = bc_vec_item(&G.prog.stack, 0);
7123 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7130 static BcStatus bc_vm_stdin(void)
7132 BcStatus s = BC_STATUS_SUCCESS;
7135 size_t len, i, str = 0;
7136 bool comment = false, notend;
7138 G.prog.file = bc_program_stdin_name;
7139 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7141 bc_vec_init(&buffer, sizeof(char), NULL);
7142 bc_vec_init(&buf, sizeof(char), NULL);
7143 bc_vec_pushByte(&buffer, '\0');
7145 // This loop is complex because the vm tries not to send any lines that end
7146 // with a backslash to the parser. The reason for that is because the parser
7147 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7148 // case, and for strings and comments, the parser will expect more stuff.
7149 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7151 char *string = buf.v;
7156 if (str && buf.v[0] == G.send)
7158 else if (buf.v[0] == G.sbgn)
7161 else if (len > 1 || comment) {
7163 for (i = 0; i < len; ++i) {
7165 notend = len > i + 1;
7168 if (i - 1 > len || string[i - 1] != '\\') {
7169 if (G.sbgn == G.send)
7171 else if (c == G.send)
7173 else if (c == G.sbgn)
7177 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7181 else if (c == '*' && notend && comment && string[i + 1] == '/')
7185 if (str || comment || string[len - 2] == '\\') {
7186 bc_vec_concat(&buffer, buf.v);
7191 bc_vec_concat(&buffer, buf.v);
7192 s = bc_vm_process(buffer.v);
7195 bc_vec_npop(&buffer, buffer.len);
7198 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7200 // INPUT_EOF will always happen when stdin is
7201 // closed. It's not a problem in that case.
7202 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7203 s = BC_STATUS_SUCCESS;
7206 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7209 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7214 bc_vec_free(&buffer);
7218 static BcStatus bc_vm_exec(void)
7220 BcStatus s = BC_STATUS_SUCCESS;
7224 if (G.flags & BC_FLAG_L) {
7226 bc_lex_file(&G.prs.l, bc_lib_name);
7227 s = bc_parse_text(&G.prs, bc_lib);
7229 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7232 s = bc_program_exec(&G.prog);
7237 for (i = 0; !s && i < G.files.len; ++i)
7238 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7239 if (s && s != BC_STATUS_QUIT) return s;
7241 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7242 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7244 if (s == BC_STATUS_QUIT)
7245 s = BC_STATUS_SUCCESS;
7249 static void bc_vm_free(void)
7251 bc_vec_free(&G.files);
7252 bc_program_free(&G.prog);
7253 bc_parse_free(&G.prs);
7257 static void bc_vm_init(const char *env_len)
7259 size_t len = bc_vm_envLen(env_len);
7261 #if ENABLE_FEATURE_BC_SIGNALS
7262 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7265 bc_vec_init(&G.files, sizeof(char *), NULL);
7268 G.flags |= BC_FLAG_S * (getenv("POSIXLY_CORRECT") != NULL);
7272 bc_program_init(&G.prog, len, G.init, G.exp);
7273 G.init(&G.prs, &G.prog, BC_PROG_MAIN);
7276 static BcStatus bc_vm_run(int argc, char *argv[],
7277 const char *env_len)
7281 bc_vm_init(env_len);
7282 bc_args(argc, argv, &G.flags, &G.files);
7284 G.ttyin = isatty(0);
7285 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7287 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7295 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7296 int bc_main(int argc, char **argv)
7299 G.init = bc_parse_init;
7300 G.exp = bc_parse_expression;
7301 G.sbgn = G.send = '"';
7303 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7308 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7309 int dc_main(int argc, char **argv)
7312 G.init = dc_parse_init;
7313 G.exp = dc_parse_expr;
7317 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");