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 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
177 BC_STATUS_PATH_IS_DIR,
179 BC_STATUS_LEX_BAD_CHAR,
180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
184 BC_STATUS_LEX_EXTENDED_REG,
187 BC_STATUS_PARSE_BAD_TOKEN,
188 BC_STATUS_PARSE_BAD_EXP,
189 BC_STATUS_PARSE_EMPTY_EXP,
190 BC_STATUS_PARSE_BAD_PRINT,
191 BC_STATUS_PARSE_BAD_FUNC,
192 BC_STATUS_PARSE_BAD_ASSIGN,
193 BC_STATUS_PARSE_NO_AUTO,
194 BC_STATUS_PARSE_DUPLICATE_LOCAL,
195 BC_STATUS_PARSE_NO_BLOCK_END,
197 BC_STATUS_MATH_NEGATIVE,
198 BC_STATUS_MATH_NON_INTEGER,
199 BC_STATUS_MATH_OVERFLOW,
200 BC_STATUS_MATH_DIVIDE_BY_ZERO,
201 BC_STATUS_MATH_BAD_STRING,
203 BC_STATUS_EXEC_FILE_ERR,
204 BC_STATUS_EXEC_MISMATCHED_PARAMS,
205 BC_STATUS_EXEC_UNDEFINED_FUNC,
206 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
207 BC_STATUS_EXEC_NUM_LEN,
208 BC_STATUS_EXEC_NAME_LEN,
209 BC_STATUS_EXEC_STRING_LEN,
210 BC_STATUS_EXEC_ARRAY_LEN,
211 BC_STATUS_EXEC_BAD_IBASE,
212 BC_STATUS_EXEC_BAD_SCALE,
213 BC_STATUS_EXEC_BAD_READ_EXPR,
214 BC_STATUS_EXEC_REC_READ,
215 BC_STATUS_EXEC_BAD_TYPE,
216 BC_STATUS_EXEC_BAD_OBASE,
217 BC_STATUS_EXEC_SIGNAL,
218 BC_STATUS_EXEC_STACK,
220 BC_STATUS_VEC_OUT_OF_BOUNDS,
221 BC_STATUS_VEC_ITEM_EXISTS,
224 BC_STATUS_POSIX_NAME_LEN,
225 BC_STATUS_POSIX_COMMENT,
226 BC_STATUS_POSIX_BAD_KW,
229 BC_STATUS_POSIX_BOOL,
230 BC_STATUS_POSIX_REL_POS,
231 BC_STATUS_POSIX_MULTIREL,
232 BC_STATUS_POSIX_FOR1,
233 BC_STATUS_POSIX_FOR2,
234 BC_STATUS_POSIX_FOR3,
235 BC_STATUS_POSIX_BRACE,
241 BC_STATUS_INVALID_OPTION,
245 #define BC_VEC_INVALID_IDX ((size_t) -1)
246 #define BC_VEC_START_CAP (1 << 5)
248 typedef void (*BcVecFree)(void *);
250 typedef struct BcVec {
258 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
259 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
261 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
263 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
265 typedef signed char BcDig;
267 typedef struct BcNum {
275 #define BC_NUM_MIN_BASE ((unsigned long) 2)
276 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
277 #define BC_NUM_DEF_SIZE (16)
278 #define BC_NUM_PRINT_WIDTH (69)
280 #define BC_NUM_KARATSUBA_LEN (32)
282 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
283 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
284 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
285 #define BC_NUM_AREQ(a, b) \
286 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
287 #define BC_NUM_MREQ(a, b, scale) \
288 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
290 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
291 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
293 static void bc_num_init(BcNum *n, size_t req);
294 static void bc_num_expand(BcNum *n, size_t req);
295 static void bc_num_copy(BcNum *d, BcNum *s);
296 static void bc_num_free(void *num);
298 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
299 static void bc_num_ulong2num(BcNum *n, unsigned long val);
301 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
302 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
303 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
304 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
308 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
311 typedef enum BcInst {
341 BC_INST_ASSIGN_POWER,
342 BC_INST_ASSIGN_MULTIPLY,
343 BC_INST_ASSIGN_DIVIDE,
344 BC_INST_ASSIGN_MODULUS,
346 BC_INST_ASSIGN_MINUS,
392 BC_INST_PRINT_STREAM,
407 BC_INST_INVALID = -1,
412 typedef struct BcId {
417 typedef struct BcFunc {
424 typedef enum BcResultType {
429 BC_RESULT_ARRAY_ELEM,
438 // These are between to calculate ibase, obase, and last from instructions.
446 typedef union BcResultData {
452 typedef struct BcResult {
457 typedef struct BcInstPtr {
463 static void bc_array_expand(BcVec *a, size_t len);
464 static int bc_id_cmp(const void *e1, const void *e2);
466 // BC_LEX_NEG is not used in lexing; it is only for parsing.
467 typedef enum BcLexType {
495 BC_LEX_OP_ASSIGN_POWER,
496 BC_LEX_OP_ASSIGN_MULTIPLY,
497 BC_LEX_OP_ASSIGN_DIVIDE,
498 BC_LEX_OP_ASSIGN_MODULUS,
499 BC_LEX_OP_ASSIGN_PLUS,
500 BC_LEX_OP_ASSIGN_MINUS,
574 typedef BcStatus (*BcLexNext)(struct BcLex *);
576 typedef struct BcLex {
595 #define BC_PARSE_STREND ((char) UCHAR_MAX)
597 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
598 #define bc_parse_updateFunc(p, f) \
599 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
601 #define BC_PARSE_REL (1 << 0)
602 #define BC_PARSE_PRINT (1 << 1)
603 #define BC_PARSE_NOCALL (1 << 2)
604 #define BC_PARSE_NOREAD (1 << 3)
605 #define BC_PARSE_ARRAY (1 << 4)
607 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
608 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
610 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
611 #define BC_PARSE_FUNC_INNER(parse) \
612 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
614 #define BC_PARSE_FLAG_FUNC (1 << 1)
615 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
617 #define BC_PARSE_FLAG_BODY (1 << 2)
618 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
620 #define BC_PARSE_FLAG_LOOP (1 << 3)
621 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
623 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
624 #define BC_PARSE_LOOP_INNER(parse) \
625 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
627 #define BC_PARSE_FLAG_IF (1 << 5)
628 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
630 #define BC_PARSE_FLAG_ELSE (1 << 6)
631 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
633 #define BC_PARSE_FLAG_IF_END (1 << 7)
634 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
636 #define BC_PARSE_CAN_EXEC(parse) \
637 (!(BC_PARSE_TOP_FLAG(parse) & \
638 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
639 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
640 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
642 typedef struct BcOp {
647 typedef struct BcParseNext {
652 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
653 #define BC_PARSE_NEXT(a, ...) \
655 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
662 typedef BcStatus (*BcParseParse)(struct BcParse *);
664 typedef struct BcParse {
687 typedef struct BcLexKeyword {
693 #define BC_LEX_KW_ENTRY(a, b, c) \
695 .name = a, .len = (b), .posix = (c) \
698 static BcStatus bc_lex_token(BcLex *l);
700 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
701 #define BC_PARSE_LEAF(p, rparen) \
702 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
703 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
705 // We can calculate the conversion between tokens and exprs by subtracting the
706 // position of the first operator in the lex enum and adding the position of the
707 // first in the expr enum. Note: This only works for binary operators.
708 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
710 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
716 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
718 static BcStatus dc_lex_token(BcLex *l);
720 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
724 typedef struct BcProgram {
765 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
767 #define BC_PROG_MAIN (0)
768 #define BC_PROG_READ (1)
771 #define BC_PROG_REQ_FUNCS (2)
774 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
775 #define BC_PROG_NUM(r, n) \
776 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
778 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
780 static void bc_program_addFunc(char *name, size_t *idx);
781 static BcStatus bc_program_reset(BcStatus s);
783 #define BC_FLAG_X (1 << 0)
784 #define BC_FLAG_W (1 << 1)
785 #define BC_FLAG_V (1 << 2)
786 #define BC_FLAG_S (1 << 3)
787 #define BC_FLAG_Q (1 << 4)
788 #define BC_FLAG_L (1 << 5)
789 #define BC_FLAG_I (1 << 6)
791 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
792 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
794 #define BC_MAX_OBASE ((unsigned) 999)
795 #define BC_MAX_DIM ((unsigned) INT_MAX)
796 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
797 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
798 #define BC_MAX_NAME BC_MAX_STRING
799 #define BC_MAX_NUM BC_MAX_STRING
800 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
801 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
818 #define G (*ptr_to_globals)
819 #define INIT_G() do { \
820 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
822 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
823 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
824 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
825 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
828 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
831 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
835 static void bc_vm_info(void);
837 static const char bc_err_fmt[] = "\nerror: %s\n";
838 static const char bc_warn_fmt[] = "\nwarning: %s\n";
839 static const char bc_err_line[] = ":%zu\n\n";
841 static const char *bc_err_msgs[] = {
844 "memory allocation error",
847 "path is a directory:",
850 "string end could not be found",
851 "comment end could not be found",
860 "bad print statement",
861 "bad function definition",
862 "bad assignment: left side must be scale, ibase, "
863 "obase, last, var, or array element",
864 "no auto variable found",
865 "function parameter or auto var has the same name as another",
866 "block end could not be found",
869 "non integer number",
874 "could not open file:",
875 "mismatched parameters",
876 "undefined function",
877 "file is not executable:",
878 "number too long: must be [1, BC_NUM_MAX]",
879 "name too long: must be [1, BC_NAME_MAX]",
880 "string too long: must be [1, BC_STRING_MAX]",
881 "array too long; must be [1, BC_DIM_MAX]",
882 "bad ibase; must be [2, 16]",
883 "bad scale; must be [0, BC_SCALE_MAX]",
884 "bad read() expression",
885 "read() call inside of a read() call",
886 "variable is wrong type",
887 "bad obase; must be [2, BC_BASE_MAX]",
888 "signal caught and not handled",
889 "stack has too few elements",
891 "index is out of bounds",
892 "item already exists",
895 "POSIX only allows one character names; the following is bad:",
896 "POSIX does not allow '#' script comments",
897 "POSIX does not allow the following keyword:",
898 "POSIX does not allow a period ('.') as a shortcut for the last result",
899 "POSIX requires parentheses around return expressions",
900 "POSIX does not allow boolean operators; the following is bad:",
901 "POSIX does not allow comparison operators outside if or loops",
902 "POSIX requires exactly one comparison operator per condition",
903 "POSIX does not allow an empty init expression in a for loop",
904 "POSIX does not allow an empty condition expression in a for loop",
905 "POSIX does not allow an empty update expression in a for loop",
906 "POSIX requires the left brace be on the same line as the function header",
912 static const BcLexKeyword bc_lex_kws[20] = {
913 BC_LEX_KW_ENTRY("auto", 4, true),
914 BC_LEX_KW_ENTRY("break", 5, true),
915 BC_LEX_KW_ENTRY("continue", 8, false),
916 BC_LEX_KW_ENTRY("define", 6, true),
917 BC_LEX_KW_ENTRY("else", 4, false),
918 BC_LEX_KW_ENTRY("for", 3, true),
919 BC_LEX_KW_ENTRY("halt", 4, false),
920 BC_LEX_KW_ENTRY("ibase", 5, true),
921 BC_LEX_KW_ENTRY("if", 2, true),
922 BC_LEX_KW_ENTRY("last", 4, false),
923 BC_LEX_KW_ENTRY("length", 6, true),
924 BC_LEX_KW_ENTRY("limits", 6, false),
925 BC_LEX_KW_ENTRY("obase", 5, true),
926 BC_LEX_KW_ENTRY("print", 5, false),
927 BC_LEX_KW_ENTRY("quit", 4, true),
928 BC_LEX_KW_ENTRY("read", 4, false),
929 BC_LEX_KW_ENTRY("return", 6, true),
930 BC_LEX_KW_ENTRY("scale", 5, true),
931 BC_LEX_KW_ENTRY("sqrt", 4, true),
932 BC_LEX_KW_ENTRY("while", 5, true),
935 // This is an array that corresponds to token types. An entry is
936 // true if the token is valid in an expression, false otherwise.
937 static const bool bc_parse_exprs[] = {
938 false, false, true, true, true, true, true, true, true, true, true, true,
939 true, true, true, true, true, true, true, true, true, true, true, true,
940 true, true, true, false, false, true, true, false, false, false, false,
941 false, false, false, true, true, false, false, false, false, false, false,
942 false, true, false, true, true, true, true, false, false, true, false, true,
946 // This is an array of data for operators that correspond to token types.
947 static const BcOp bc_parse_ops[] = {
948 { 0, false }, { 0, false },
951 { 3, true }, { 3, true }, { 3, true },
952 { 4, true }, { 4, true },
953 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
955 { 7, true }, { 7, true },
956 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
957 { 5, false }, { 5, false },
960 // These identify what tokens can come after expressions in certain cases.
961 static const BcParseNext bc_parse_next_expr =
962 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
963 static const BcParseNext bc_parse_next_param =
964 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
965 static const BcParseNext bc_parse_next_print =
966 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
967 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
968 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
969 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
970 static const BcParseNext bc_parse_next_read =
971 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
975 static const BcLexType dc_lex_regs[] = {
976 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
977 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
978 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
982 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
984 static const BcLexType dc_lex_tokens[] = {
985 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
986 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
987 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
988 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
989 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
990 BC_LEX_INVALID, BC_LEX_INVALID,
991 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
992 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
993 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
994 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
995 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
996 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
997 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
998 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
999 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1000 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1001 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1002 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1003 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1004 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1005 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1006 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1007 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1008 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1012 static const BcInst dc_parse_insts[] = {
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1014 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1015 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1016 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1020 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1021 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1022 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1023 BC_INST_INVALID, BC_INST_INVALID,
1024 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1025 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1026 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1027 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1028 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1029 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1030 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1031 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1032 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1033 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1034 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1035 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1039 static const BcNumBinaryOp bc_program_ops[] = {
1040 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1043 static const char bc_program_stdin_name[] = "<stdin>";
1044 static const char bc_program_ready_msg[] = "ready for more input\n";
1047 static const char *bc_lib_name = "gen/lib.bc";
1049 static const char bc_lib[] = {
1050 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1051 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1052 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1053 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,
1054 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1055 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1056 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,
1057 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1058 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1059 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,
1060 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1061 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1062 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1063 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1064 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1065 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1066 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1067 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1068 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1069 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1070 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1071 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1072 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1073 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,
1074 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1075 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,
1076 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1077 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1078 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1079 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1080 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1081 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,
1082 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1083 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1084 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1085 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1086 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,
1087 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1088 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1089 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1090 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1091 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1092 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1093 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1094 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1095 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1096 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1097 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,
1098 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,
1099 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1100 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,
1101 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,
1102 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,
1103 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1104 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1105 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,
1106 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,
1107 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,
1108 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1109 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,
1110 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1111 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1112 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1113 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,
1114 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1115 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1116 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1117 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1118 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1119 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1120 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1121 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1122 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1123 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1124 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1125 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1126 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1127 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1128 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1129 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1133 static void bc_vec_grow(BcVec *v, size_t n)
1135 size_t cap = v->cap * 2;
1136 while (cap < v->len + n) cap *= 2;
1137 v->v = xrealloc(v->v, v->size * cap);
1141 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1144 v->cap = BC_VEC_START_CAP;
1147 v->v = xmalloc(esize * BC_VEC_START_CAP);
1150 static void bc_vec_expand(BcVec *v, size_t req)
1153 v->v = xrealloc(v->v, v->size * req);
1158 static void bc_vec_npop(BcVec *v, size_t n)
1163 size_t len = v->len - n;
1164 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1168 static void bc_vec_push(BcVec *v, const void *data)
1170 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1171 memmove(v->v + (v->size * v->len), data, v->size);
1175 static void bc_vec_pushByte(BcVec *v, char data)
1177 bc_vec_push(v, &data);
1180 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1183 bc_vec_push(v, data);
1188 if (v->len == v->cap) bc_vec_grow(v, 1);
1190 ptr = v->v + v->size * idx;
1192 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1193 memmove(ptr, data, v->size);
1197 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1199 bc_vec_npop(v, v->len);
1200 bc_vec_expand(v, len + 1);
1201 memcpy(v->v, str, len);
1204 bc_vec_pushByte(v, '\0');
1207 static void bc_vec_concat(BcVec *v, const char *str)
1211 if (v->len == 0) bc_vec_pushByte(v, '\0');
1213 len = v->len + strlen(str);
1215 if (v->cap < len) bc_vec_grow(v, len - v->len);
1221 static void *bc_vec_item(const BcVec *v, size_t idx)
1223 return v->v + v->size * idx;
1226 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1228 return v->v + v->size * (v->len - idx - 1);
1231 static void bc_vec_free(void *vec)
1233 BcVec *v = (BcVec *) vec;
1234 bc_vec_npop(v, v->len);
1238 static size_t bc_map_find(const BcVec *v, const void *ptr)
1240 size_t low = 0, high = v->len;
1242 while (low < high) {
1244 size_t mid = (low + high) / 2;
1245 BcId *id = bc_vec_item(v, mid);
1246 int result = bc_id_cmp(ptr, id);
1250 else if (result < 0)
1259 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1261 BcStatus s = BC_STATUS_SUCCESS;
1263 *i = bc_map_find(v, ptr);
1266 bc_vec_push(v, ptr);
1267 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1268 s = BC_STATUS_VEC_ITEM_EXISTS;
1270 bc_vec_pushAt(v, ptr, *i);
1275 static size_t bc_map_index(const BcVec *v, const void *ptr)
1277 size_t i = bc_map_find(v, ptr);
1278 if (i >= v->len) return BC_VEC_INVALID_IDX;
1279 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1282 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1287 bc_vec_npop(vec, vec->len);
1290 #if ENABLE_FEATURE_BC_SIGNALS
1291 if (bb_got_signal) { /* ^C was pressed */
1293 bb_got_signal = 0; /* resets G_interrupt to zero */
1295 ? "\ninterrupt (type \"quit\" to exit)\n"
1296 : "\ninterrupt (type \"q\" to exit)\n"
1300 if (G.ttyin && !G_posix)
1301 fputs(prompt, stderr);
1304 #if ENABLE_FEATURE_BC_SIGNALS
1309 if (ferror(stdout) || ferror(stderr))
1310 bb_perror_msg_and_die("output error");
1314 #if ENABLE_FEATURE_BC_SIGNALS
1315 if (bb_got_signal) /* ^C was pressed */
1320 #if ENABLE_FEATURE_BC_SIGNALS
1321 if (errno == EINTR) {
1327 bb_perror_msg_and_die("input error");
1328 return BC_STATUS_INPUT_EOF;
1331 c = (signed char) i;
1332 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1333 bc_vec_push(vec, &c);
1334 } while (c != '\n');
1336 bc_vec_pushByte(vec, '\0');
1338 return BC_STATUS_SUCCESS;
1341 static char* bc_read_file(const char *path)
1344 size_t size = ((size_t) -1);
1347 buf = xmalloc_open_read_close(path, &size);
1349 for (i = 0; i < size; ++i) {
1350 if (BC_READ_BIN_CHAR(buf[i])) {
1360 static void bc_args(int argc, char **argv)
1365 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1366 G.flags = getopt32long(argv, "xwvsqli",
1367 "extended-register\0" No_argument "x"
1368 "warn\0" No_argument "w"
1369 "version\0" No_argument "v"
1370 "standard\0" No_argument "s"
1371 "quiet\0" No_argument "q"
1372 "mathlib\0" No_argument "l"
1373 "interactive\0" No_argument "i"
1376 G.flags = getopt32(argv, "xwvsqli");
1379 if (G.flags & BC_FLAG_V) bc_vm_info();
1380 // should not be necessary, getopt32() handles this??
1381 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1383 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1386 static void bc_num_setToZero(BcNum *n, size_t scale)
1393 static void bc_num_zero(BcNum *n)
1395 bc_num_setToZero(n, 0);
1398 static void bc_num_one(BcNum *n)
1400 bc_num_setToZero(n, 0);
1405 static void bc_num_ten(BcNum *n)
1407 bc_num_setToZero(n, 0);
1413 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1417 for (i = 0; i < len; ++i) {
1418 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1425 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1429 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1430 return BC_NUM_NEG(i + 1, c < 0);
1433 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1435 size_t i, min, a_int, b_int, diff;
1436 BcDig *max_num, *min_num;
1437 bool a_max, neg = false;
1440 if (a == b) return 0;
1441 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1442 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1452 a_int = BC_NUM_INT(a);
1453 b_int = BC_NUM_INT(b);
1455 a_max = (a->rdx > b->rdx);
1457 if (a_int != 0) return (ssize_t) a_int;
1461 diff = a->rdx - b->rdx;
1462 max_num = a->num + diff;
1467 diff = b->rdx - a->rdx;
1468 max_num = b->num + diff;
1472 cmp = bc_num_compare(max_num, min_num, b_int + min);
1473 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1475 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1476 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1482 static void bc_num_truncate(BcNum *n, size_t places)
1484 if (places == 0) return;
1490 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1494 static void bc_num_extend(BcNum *n, size_t places)
1496 size_t len = n->len + places;
1500 if (n->cap < len) bc_num_expand(n, len);
1502 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1503 memset(n->num, 0, sizeof(BcDig) * places);
1510 static void bc_num_clean(BcNum *n)
1512 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1515 else if (n->len < n->rdx)
1519 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1522 bc_num_extend(n, scale - n->rdx);
1524 bc_num_truncate(n, n->rdx - scale);
1527 if (n->len != 0) n->neg = !neg1 != !neg2;
1530 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1535 b->len = n->len - idx;
1537 a->rdx = b->rdx = 0;
1539 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1540 memcpy(a->num, n->num, idx * sizeof(BcDig));
1551 static BcStatus bc_num_shift(BcNum *n, size_t places)
1553 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1554 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1556 if (n->rdx >= places)
1559 bc_num_extend(n, places - n->rdx);
1565 return BC_STATUS_SUCCESS;
1568 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1577 return bc_num_div(&one, a, b, scale);
1580 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1582 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1583 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1586 // Because this function doesn't need to use scale (per the bc spec),
1587 // I am hijacking it to say whether it's doing an add or a subtract.
1591 if (sub && c->len) c->neg = !c->neg;
1592 return BC_STATUS_SUCCESS;
1594 else if (b->len == 0) {
1596 return BC_STATUS_SUCCESS;
1600 c->rdx = BC_MAX(a->rdx, b->rdx);
1601 min_rdx = BC_MIN(a->rdx, b->rdx);
1604 if (a->rdx > b->rdx) {
1605 diff = a->rdx - b->rdx;
1607 ptr_a = a->num + diff;
1611 diff = b->rdx - a->rdx;
1614 ptr_b = b->num + diff;
1617 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1620 a_int = BC_NUM_INT(a);
1621 b_int = BC_NUM_INT(b);
1623 if (a_int > b_int) {
1634 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1635 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1637 ptr_c[i] = (BcDig)(in % 10);
1640 for (; i < max + min_rdx; ++i, ++c->len) {
1641 in = ((int) ptr[i]) + carry;
1643 ptr_c[i] = (BcDig)(in % 10);
1646 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1648 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1651 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1654 BcNum *minuend, *subtrahend;
1656 bool aneg, bneg, neg;
1658 // Because this function doesn't need to use scale (per the bc spec),
1659 // I am hijacking it to say whether it's doing an add or a subtract.
1663 if (sub && c->len) c->neg = !c->neg;
1664 return BC_STATUS_SUCCESS;
1666 else if (b->len == 0) {
1668 return BC_STATUS_SUCCESS;
1673 a->neg = b->neg = false;
1675 cmp = bc_num_cmp(a, b);
1681 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1682 return BC_STATUS_SUCCESS;
1691 if (sub) neg = !neg;
1696 bc_num_copy(c, minuend);
1699 if (c->rdx < subtrahend->rdx) {
1700 bc_num_extend(c, subtrahend->rdx - c->rdx);
1704 start = c->rdx - subtrahend->rdx;
1706 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1710 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1713 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1718 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1719 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1720 bool aone = BC_NUM_ONE(a);
1722 if (a->len == 0 || b->len == 0) {
1724 return BC_STATUS_SUCCESS;
1726 else if (aone || BC_NUM_ONE(b)) {
1727 bc_num_copy(c, aone ? b : a);
1728 return BC_STATUS_SUCCESS;
1731 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1732 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1734 bc_num_expand(c, a->len + b->len + 1);
1736 memset(c->num, 0, sizeof(BcDig) * c->cap);
1737 c->len = carry = len = 0;
1739 for (i = 0; i < b->len; ++i) {
1741 for (j = 0; j < a->len; ++j) {
1742 int in = (int) c->num[i + j];
1743 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1745 c->num[i + j] = (BcDig)(in % 10);
1748 c->num[i + j] += (BcDig) carry;
1749 len = BC_MAX(len, i + j + !!carry);
1755 return BC_STATUS_SUCCESS;
1758 bc_num_init(&l1, max);
1759 bc_num_init(&h1, max);
1760 bc_num_init(&l2, max);
1761 bc_num_init(&h2, max);
1762 bc_num_init(&m1, max);
1763 bc_num_init(&m2, max);
1764 bc_num_init(&z0, max);
1765 bc_num_init(&z1, max);
1766 bc_num_init(&z2, max);
1767 bc_num_init(&temp, max + max);
1769 bc_num_split(a, max2, &l1, &h1);
1770 bc_num_split(b, max2, &l2, &h2);
1772 s = bc_num_add(&h1, &l1, &m1, 0);
1774 s = bc_num_add(&h2, &l2, &m2, 0);
1777 s = bc_num_k(&h1, &h2, &z0);
1779 s = bc_num_k(&m1, &m2, &z1);
1781 s = bc_num_k(&l1, &l2, &z2);
1784 s = bc_num_sub(&z1, &z0, &temp, 0);
1786 s = bc_num_sub(&temp, &z2, &z1, 0);
1789 s = bc_num_shift(&z0, max2 * 2);
1791 s = bc_num_shift(&z1, max2);
1793 s = bc_num_add(&z0, &z1, &temp, 0);
1795 s = bc_num_add(&temp, &z2, c, 0);
1811 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1815 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1817 scale = BC_MAX(scale, a->rdx);
1818 scale = BC_MAX(scale, b->rdx);
1819 scale = BC_MIN(a->rdx + b->rdx, scale);
1820 maxrdx = BC_MAX(maxrdx, scale);
1822 bc_num_init(&cpa, a->len);
1823 bc_num_init(&cpb, b->len);
1825 bc_num_copy(&cpa, a);
1826 bc_num_copy(&cpb, b);
1827 cpa.neg = cpb.neg = false;
1829 s = bc_num_shift(&cpa, maxrdx);
1831 s = bc_num_shift(&cpb, maxrdx);
1833 s = bc_num_k(&cpa, &cpb, c);
1837 bc_num_expand(c, c->len + maxrdx);
1839 if (c->len < maxrdx) {
1840 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1845 bc_num_retireMul(c, scale, a->neg, b->neg);
1853 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1855 BcStatus s = BC_STATUS_SUCCESS;
1862 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1863 else if (a->len == 0) {
1864 bc_num_setToZero(c, scale);
1865 return BC_STATUS_SUCCESS;
1867 else if (BC_NUM_ONE(b)) {
1869 bc_num_retireMul(c, scale, a->neg, b->neg);
1870 return BC_STATUS_SUCCESS;
1873 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1874 bc_num_copy(&cp, a);
1878 bc_num_expand(&cp, len + 2);
1879 bc_num_extend(&cp, len - cp.len);
1882 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1884 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1886 if (b->rdx == b->len) {
1887 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1891 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1893 // We want an extra zero in front to make things simpler.
1894 cp.num[cp.len++] = 0;
1897 bc_num_expand(c, cp.len);
1900 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1905 for (i = end - 1; !s && i < end; --i) {
1907 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1908 bc_num_subArrays(n, p, len);
1912 bc_num_retireMul(c, scale, a->neg, b->neg);
1915 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1918 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1919 BcNum *restrict d, size_t scale, size_t ts)
1925 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1928 bc_num_setToZero(d, ts);
1929 return BC_STATUS_SUCCESS;
1932 bc_num_init(&temp, d->cap);
1933 bc_num_d(a, b, c, scale);
1935 if (scale != 0) scale = ts;
1937 s = bc_num_m(c, b, &temp, scale);
1939 s = bc_num_sub(a, &temp, d, scale);
1942 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1945 bc_num_retireMul(d, ts, a->neg, b->neg);
1953 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1957 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1959 bc_num_init(&c1, len);
1960 s = bc_num_r(a, b, &c1, c, scale, ts);
1966 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1968 BcStatus s = BC_STATUS_SUCCESS;
1971 size_t i, powrdx, resrdx;
1974 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
1978 return BC_STATUS_SUCCESS;
1980 else if (a->len == 0) {
1981 bc_num_setToZero(c, scale);
1982 return BC_STATUS_SUCCESS;
1984 else if (BC_NUM_ONE(b)) {
1988 s = bc_num_inv(a, c, scale);
1995 s = bc_num_ulong(b, &pow);
1998 bc_num_init(©, a->len);
1999 bc_num_copy(©, a);
2001 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2005 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2007 s = bc_num_mul(©, ©, ©, powrdx);
2011 bc_num_copy(c, ©);
2013 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2016 s = bc_num_mul(©, ©, ©, powrdx);
2021 s = bc_num_mul(c, ©, c, resrdx);
2027 s = bc_num_inv(c, c, scale);
2031 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2033 // We can't use bc_num_clean() here.
2034 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2035 if (zero) bc_num_setToZero(c, scale);
2042 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2043 BcNumBinaryOp op, size_t req)
2046 BcNum num2, *ptr_a, *ptr_b;
2051 memcpy(ptr_a, c, sizeof(BcNum));
2060 memcpy(ptr_b, c, sizeof(BcNum));
2068 bc_num_init(c, req);
2070 bc_num_expand(c, req);
2072 s = op(ptr_a, ptr_b, c, scale);
2074 if (init) bc_num_free(&num2);
2079 static bool bc_num_strValid(const char *val, size_t base)
2082 bool small, radix = false;
2083 size_t i, len = strlen(val);
2085 if (!len) return true;
2088 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2090 for (i = 0; i < len; ++i) {
2096 if (radix) return false;
2102 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2109 static void bc_num_parseDecimal(BcNum *n, const char *val)
2115 for (i = 0; val[i] == '0'; ++i);
2122 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2123 bc_num_expand(n, len);
2126 ptr = strchr(val, '.');
2128 // Explicitly test for NULL here to produce either a 0 or 1.
2129 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2132 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2133 n->num[n->len] = val[i] - '0';
2137 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2140 BcNum temp, mult, result;
2144 size_t i, digits, len = strlen(val);
2148 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2151 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2152 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2154 for (i = 0; i < len; ++i) {
2157 if (c == '.') break;
2159 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2161 s = bc_num_mul(n, base, &mult, 0);
2162 if (s) goto int_err;
2163 bc_num_ulong2num(&temp, v);
2164 s = bc_num_add(&mult, &temp, n, 0);
2165 if (s) goto int_err;
2170 if (c == 0) goto int_err;
2173 bc_num_init(&result, base->len);
2174 bc_num_zero(&result);
2177 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2182 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2184 s = bc_num_mul(&result, base, &result, 0);
2186 bc_num_ulong2num(&temp, v);
2187 s = bc_num_add(&result, &temp, &result, 0);
2189 s = bc_num_mul(&mult, base, &mult, 0);
2193 s = bc_num_div(&result, &mult, &result, digits);
2195 s = bc_num_add(n, &result, n, digits);
2199 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2205 bc_num_free(&result);
2211 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2213 if (*nchars == line_len - 1) {
2221 static void bc_num_printChar(size_t num, size_t width, bool radix,
2222 size_t *nchars, size_t line_len)
2224 (void) radix, (void) line_len;
2225 bb_putchar((char) num);
2226 *nchars = *nchars + width;
2230 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2231 size_t *nchars, size_t line_len)
2235 bc_num_printNewline(nchars, line_len);
2236 bb_putchar(radix ? '.' : ' ');
2239 bc_num_printNewline(nchars, line_len);
2240 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2243 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2245 bc_num_printNewline(nchars, line_len);
2248 bb_putchar(((char) dig) + '0');
2252 static void bc_num_printHex(size_t num, size_t width, bool radix,
2253 size_t *nchars, size_t line_len)
2256 bc_num_printNewline(nchars, line_len);
2261 bc_num_printNewline(nchars, line_len);
2262 bb_putchar(bb_hexdigits_upcase[num]);
2263 *nchars = *nchars + width;
2266 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2268 size_t i, rdx = n->rdx - 1;
2270 if (n->neg) bb_putchar('-');
2271 (*nchars) += n->neg;
2273 for (i = n->len - 1; i < n->len; --i)
2274 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2277 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2278 size_t *nchars, size_t len, BcNumDigitOp print)
2282 BcNum intp, fracp, digit, frac_len;
2283 unsigned long dig, *ptr;
2288 print(0, width, false, nchars, len);
2289 return BC_STATUS_SUCCESS;
2292 bc_vec_init(&stack, sizeof(long), NULL);
2293 bc_num_init(&intp, n->len);
2294 bc_num_init(&fracp, n->rdx);
2295 bc_num_init(&digit, width);
2296 bc_num_init(&frac_len, BC_NUM_INT(n));
2297 bc_num_copy(&intp, n);
2298 bc_num_one(&frac_len);
2300 bc_num_truncate(&intp, intp.rdx);
2301 s = bc_num_sub(n, &intp, &fracp, 0);
2304 while (intp.len != 0) {
2305 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2307 s = bc_num_ulong(&digit, &dig);
2309 bc_vec_push(&stack, &dig);
2312 for (i = 0; i < stack.len; ++i) {
2313 ptr = bc_vec_item_rev(&stack, i);
2314 print(*ptr, width, false, nchars, len);
2317 if (!n->rdx) goto err;
2319 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2320 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2322 s = bc_num_ulong(&fracp, &dig);
2324 bc_num_ulong2num(&intp, dig);
2325 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2327 print(dig, width, radix, nchars, len);
2328 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2333 bc_num_free(&frac_len);
2334 bc_num_free(&digit);
2335 bc_num_free(&fracp);
2337 bc_vec_free(&stack);
2341 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2342 size_t *nchars, size_t line_len)
2349 if (neg) bb_putchar('-');
2354 if (base_t <= BC_NUM_MAX_IBASE) {
2356 print = bc_num_printHex;
2359 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2360 print = bc_num_printDigits;
2363 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2370 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2372 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2376 static void bc_num_init(BcNum *n, size_t req)
2378 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2379 memset(n, 0, sizeof(BcNum));
2380 n->num = xmalloc(req);
2384 static void bc_num_expand(BcNum *n, size_t req)
2386 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2388 n->num = xrealloc(n->num, req);
2393 static void bc_num_free(void *num)
2395 free(((BcNum *) num)->num);
2398 static void bc_num_copy(BcNum *d, BcNum *s)
2401 bc_num_expand(d, s->cap);
2405 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2409 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2412 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2415 bc_num_parseDecimal(n, val);
2417 bc_num_parseBase(n, val, base);
2419 return BC_STATUS_SUCCESS;
2422 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2423 size_t *nchars, size_t line_len)
2425 BcStatus s = BC_STATUS_SUCCESS;
2427 bc_num_printNewline(nchars, line_len);
2433 else if (base_t == 10)
2434 bc_num_printDecimal(n, nchars, line_len);
2436 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2446 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2451 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2453 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2455 unsigned long prev = *result, powprev = pow;
2457 *result += ((unsigned long) n->num[i]) * pow;
2460 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2463 return BC_STATUS_SUCCESS;
2466 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2474 if (val == 0) return;
2476 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2477 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2480 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2482 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2484 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2487 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2489 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2491 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2494 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2496 size_t req = BC_NUM_MREQ(a, b, scale);
2497 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2500 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2502 size_t req = BC_NUM_MREQ(a, b, scale);
2503 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2506 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2508 size_t req = BC_NUM_MREQ(a, b, scale);
2509 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2512 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2514 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2517 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2520 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2521 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2522 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2524 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2525 bc_num_expand(b, req);
2528 bc_num_setToZero(b, scale);
2529 return BC_STATUS_SUCCESS;
2532 return BC_STATUS_MATH_NEGATIVE;
2533 else if (BC_NUM_ONE(a)) {
2535 bc_num_extend(b, scale);
2536 return BC_STATUS_SUCCESS;
2539 scale = BC_MAX(scale, a->rdx) + 1;
2540 len = a->len + scale;
2542 bc_num_init(&num1, len);
2543 bc_num_init(&num2, len);
2544 bc_num_init(&half, BC_NUM_DEF_SIZE);
2550 bc_num_init(&f, len);
2551 bc_num_init(&fprime, len);
2557 pow = BC_NUM_INT(a);
2566 pow -= 2 - (pow & 1);
2568 bc_num_extend(x0, pow);
2570 // Make sure to move the radix back.
2574 x0->rdx = digs = digs1 = 0;
2576 len = BC_NUM_INT(x0) + resrdx - 1;
2578 while (cmp != 0 || digs < len) {
2580 s = bc_num_div(a, x0, &f, resrdx);
2582 s = bc_num_add(x0, &f, &fprime, resrdx);
2584 s = bc_num_mul(&fprime, &half, x1, resrdx);
2587 cmp = bc_num_cmp(x1, x0);
2588 digs = x1->len - (unsigned long long) llabs(cmp);
2590 if (cmp == cmp2 && digs == digs1)
2595 resrdx += times > 4;
2608 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2611 bc_num_free(&fprime);
2619 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2625 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2628 memcpy(&num2, c, sizeof(BcNum));
2630 bc_num_init(c, len);
2635 bc_num_expand(c, len);
2638 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2640 if (init) bc_num_free(&num2);
2646 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2649 BcNum base, exp, two, temp;
2651 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2652 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2653 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2655 bc_num_expand(d, c->len);
2656 bc_num_init(&base, c->len);
2657 bc_num_init(&exp, b->len);
2658 bc_num_init(&two, BC_NUM_DEF_SIZE);
2659 bc_num_init(&temp, b->len);
2665 s = bc_num_rem(a, c, &base, 0);
2667 bc_num_copy(&exp, b);
2669 while (exp.len != 0) {
2671 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2674 if (BC_NUM_ONE(&temp)) {
2675 s = bc_num_mul(d, &base, &temp, 0);
2677 s = bc_num_rem(&temp, c, d, 0);
2681 s = bc_num_mul(&base, &base, &temp, 0);
2683 s = bc_num_rem(&temp, c, &base, 0);
2696 static int bc_id_cmp(const void *e1, const void *e2)
2698 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2701 static void bc_id_free(void *id)
2703 free(((BcId *) id)->name);
2706 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2711 for (i = 0; i < f->autos.len; ++i) {
2712 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2713 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2719 bc_vec_push(&f->autos, &a);
2721 return BC_STATUS_SUCCESS;
2724 static void bc_func_init(BcFunc *f)
2726 bc_vec_init(&f->code, sizeof(char), NULL);
2727 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2728 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2732 static void bc_func_free(void *func)
2734 BcFunc *f = (BcFunc *) func;
2735 bc_vec_free(&f->code);
2736 bc_vec_free(&f->autos);
2737 bc_vec_free(&f->labels);
2740 static void bc_array_init(BcVec *a, bool nums)
2743 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2745 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2746 bc_array_expand(a, 1);
2749 static void bc_array_copy(BcVec *d, const BcVec *s)
2753 bc_vec_npop(d, d->len);
2754 bc_vec_expand(d, s->cap);
2757 for (i = 0; i < s->len; ++i) {
2758 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2759 bc_num_init(dnum, snum->len);
2760 bc_num_copy(dnum, snum);
2764 static void bc_array_expand(BcVec *a, size_t len)
2768 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2769 while (len > a->len) {
2770 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2771 bc_vec_push(a, &data.n);
2775 while (len > a->len) {
2776 bc_array_init(&data.v, true);
2777 bc_vec_push(a, &data.v);
2782 static void bc_string_free(void *string)
2784 free(*((char **) string));
2788 static void bc_result_copy(BcResult *d, BcResult *src)
2794 case BC_RESULT_TEMP:
2795 case BC_RESULT_IBASE:
2796 case BC_RESULT_SCALE:
2797 case BC_RESULT_OBASE:
2799 bc_num_init(&d->d.n, src->d.n.len);
2800 bc_num_copy(&d->d.n, &src->d.n);
2805 case BC_RESULT_ARRAY:
2806 case BC_RESULT_ARRAY_ELEM:
2808 d->d.id.name = xstrdup(src->d.id.name);
2812 case BC_RESULT_CONSTANT:
2813 case BC_RESULT_LAST:
2817 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2824 static void bc_result_free(void *result)
2826 BcResult *r = (BcResult *) result;
2830 case BC_RESULT_TEMP:
2831 case BC_RESULT_IBASE:
2832 case BC_RESULT_SCALE:
2833 case BC_RESULT_OBASE:
2835 bc_num_free(&r->d.n);
2840 case BC_RESULT_ARRAY:
2841 case BC_RESULT_ARRAY_ELEM:
2855 static void bc_lex_lineComment(BcLex *l)
2857 l->t.t = BC_LEX_WHITESPACE;
2858 while (l->i < l->len && l->buf[l->i++] != '\n');
2862 static void bc_lex_whitespace(BcLex *l)
2865 l->t.t = BC_LEX_WHITESPACE;
2866 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2869 static BcStatus bc_lex_number(BcLex *l, char start)
2871 const char *buf = l->buf + l->i;
2872 size_t len, hits = 0, bslashes = 0, i = 0, j;
2874 bool last_pt, pt = start == '.';
2877 l->t.t = BC_LEX_NUMBER;
2879 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2880 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2894 len = i + 1 * !last_pt - bslashes * 2;
2895 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2897 bc_vec_npop(&l->t.v, l->t.v.len);
2898 bc_vec_expand(&l->t.v, len + 1);
2899 bc_vec_push(&l->t.v, &start);
2901 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2905 // If we have hit a backslash, skip it. We don't have
2906 // to check for a newline because it's guaranteed.
2907 if (hits < bslashes && c == '\\') {
2913 bc_vec_push(&l->t.v, &c);
2916 bc_vec_pushByte(&l->t.v, '\0');
2919 return BC_STATUS_SUCCESS;
2922 static BcStatus bc_lex_name(BcLex *l)
2925 const char *buf = l->buf + l->i - 1;
2928 l->t.t = BC_LEX_NAME;
2930 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2932 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2933 bc_vec_string(&l->t.v, i, buf);
2935 // Increment the index. We minus 1 because it has already been incremented.
2938 return BC_STATUS_SUCCESS;
2941 static void bc_lex_init(BcLex *l, BcLexNext next)
2944 bc_vec_init(&l->t.v, sizeof(char), NULL);
2947 static void bc_lex_free(BcLex *l)
2949 bc_vec_free(&l->t.v);
2952 static void bc_lex_file(BcLex *l, const char *file)
2959 static BcStatus bc_lex_next(BcLex *l)
2964 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2966 l->line += l->newline;
2967 l->t.t = BC_LEX_EOF;
2969 l->newline = (l->i == l->len);
2970 if (l->newline) return BC_STATUS_SUCCESS;
2972 // Loop until failure or we don't have whitespace. This
2973 // is so the parser doesn't get inundated with whitespace.
2976 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2981 static BcStatus bc_lex_text(BcLex *l, const char *text)
2985 l->len = strlen(text);
2986 l->t.t = l->t.last = BC_LEX_INVALID;
2987 return bc_lex_next(l);
2991 static BcStatus bc_lex_identifier(BcLex *l)
2995 const char *buf = l->buf + l->i - 1;
2997 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2999 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3001 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3003 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3005 if (!bc_lex_kws[i].posix) {
3006 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3007 bc_lex_kws[i].name);
3011 // We minus 1 because the index has already been incremented.
3013 return BC_STATUS_SUCCESS;
3020 if (l->t.v.len - 1 > 1)
3021 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3026 static BcStatus bc_lex_string(BcLex *l)
3028 size_t len, nls = 0, i = l->i;
3031 l->t.t = BC_LEX_STR;
3033 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3037 return BC_STATUS_LEX_NO_STRING_END;
3041 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3042 bc_vec_string(&l->t.v, len, l->buf + l->i);
3047 return BC_STATUS_SUCCESS;
3050 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3052 if (l->buf[l->i] == '=') {
3060 static BcStatus bc_lex_comment(BcLex *l)
3063 const char *buf = l->buf;
3067 l->t.t = BC_LEX_WHITESPACE;
3069 for (i = ++l->i; !end; i += !end) {
3071 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3073 if (c == 0 || buf[i + 1] == '\0') {
3075 return BC_STATUS_LEX_NO_COMMENT_END;
3078 end = buf[i + 1] == '/';
3084 return BC_STATUS_SUCCESS;
3087 static BcStatus bc_lex_token(BcLex *l)
3089 BcStatus s = BC_STATUS_SUCCESS;
3090 char c = l->buf[l->i++], c2;
3092 // This is the workhorse of the lexer.
3099 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3109 bc_lex_whitespace(l);
3115 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3117 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3118 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3127 s = bc_lex_string(l);
3133 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3136 bc_lex_lineComment(l);
3143 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3152 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3156 l->t.t = BC_LEX_OP_BOOL_AND;
3159 l->t.t = BC_LEX_INVALID;
3160 s = BC_STATUS_LEX_BAD_CHAR;
3169 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3175 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3184 l->t.t = BC_LEX_OP_INC;
3187 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3193 l->t.t = BC_LEX_COMMA;
3202 l->t.t = BC_LEX_OP_DEC;
3205 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3211 if (isdigit(l->buf[l->i]))
3212 s = bc_lex_number(l, c);
3214 l->t.t = BC_LEX_KEY_LAST;
3215 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3224 s = bc_lex_comment(l);
3226 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3247 s = bc_lex_number(l, c);
3253 l->t.t = BC_LEX_SCOLON;
3259 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3265 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3271 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3278 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3284 if (l->buf[l->i] == '\n') {
3285 l->t.t = BC_LEX_WHITESPACE;
3289 s = BC_STATUS_LEX_BAD_CHAR;
3295 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3326 s = bc_lex_identifier(l);
3333 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3343 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3347 l->t.t = BC_LEX_OP_BOOL_OR;
3350 l->t.t = BC_LEX_INVALID;
3351 s = BC_STATUS_LEX_BAD_CHAR;
3359 l->t.t = BC_LEX_INVALID;
3360 s = BC_STATUS_LEX_BAD_CHAR;
3370 static BcStatus dc_lex_register(BcLex *l)
3372 BcStatus s = BC_STATUS_SUCCESS;
3374 if (isspace(l->buf[l->i - 1])) {
3375 bc_lex_whitespace(l);
3378 s = BC_STATUS_LEX_EXTENDED_REG;
3383 bc_vec_npop(&l->t.v, l->t.v.len);
3384 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3385 bc_vec_pushByte(&l->t.v, '\0');
3386 l->t.t = BC_LEX_NAME;
3392 static BcStatus dc_lex_string(BcLex *l)
3394 size_t depth = 1, nls = 0, i = l->i;
3397 l->t.t = BC_LEX_STR;
3398 bc_vec_npop(&l->t.v, l->t.v.len);
3400 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3402 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3403 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3406 if (depth) bc_vec_push(&l->t.v, &c);
3411 return BC_STATUS_LEX_NO_STRING_END;
3414 bc_vec_pushByte(&l->t.v, '\0');
3415 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3420 return BC_STATUS_SUCCESS;
3423 static BcStatus dc_lex_token(BcLex *l)
3425 BcStatus s = BC_STATUS_SUCCESS;
3426 char c = l->buf[l->i++], c2;
3429 for (i = 0; i < dc_lex_regs_len; ++i) {
3430 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3433 if (c >= '%' && c <= '~' &&
3434 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3439 // This is the workhorse of the lexer.
3444 l->t.t = BC_LEX_EOF;
3455 l->newline = (c == '\n');
3456 bc_lex_whitespace(l);
3465 l->t.t = BC_LEX_OP_REL_NE;
3467 l->t.t = BC_LEX_OP_REL_LE;
3469 l->t.t = BC_LEX_OP_REL_GE;
3471 return BC_STATUS_LEX_BAD_CHAR;
3479 bc_lex_lineComment(l);
3485 if (isdigit(l->buf[l->i]))
3486 s = bc_lex_number(l, c);
3488 s = BC_STATUS_LEX_BAD_CHAR;
3509 s = bc_lex_number(l, c);
3515 s = dc_lex_string(l);
3521 l->t.t = BC_LEX_INVALID;
3522 s = BC_STATUS_LEX_BAD_CHAR;
3531 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3533 bc_program_addFunc(name, idx);
3534 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3537 static void bc_parse_pushName(BcParse *p, char *name)
3539 size_t i = 0, len = strlen(name);
3541 for (; i < len; ++i) bc_parse_push(p, name[i]);
3542 bc_parse_push(p, BC_PARSE_STREND);
3547 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3549 unsigned char amt, i, nums[sizeof(size_t)];
3551 for (amt = 0; idx; ++amt) {
3552 nums[amt] = (char) idx;
3553 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3556 bc_parse_push(p, amt);
3557 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3560 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3562 char *num = xstrdup(p->l.t.v.v);
3563 size_t idx = G.prog.consts.len;
3565 bc_vec_push(&G.prog.consts, &num);
3567 bc_parse_push(p, BC_INST_NUM);
3568 bc_parse_pushIndex(p, idx);
3571 (*prev) = BC_INST_NUM;
3574 static BcStatus bc_parse_text(BcParse *p, const char *text)
3578 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3580 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3581 p->l.t.t = BC_LEX_INVALID;
3584 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3587 return bc_lex_text(&p->l, text);
3590 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3592 if (p->fidx != BC_PROG_MAIN) {
3594 p->func->nparams = 0;
3595 bc_vec_npop(&p->func->code, p->func->code.len);
3596 bc_vec_npop(&p->func->autos, p->func->autos.len);
3597 bc_vec_npop(&p->func->labels, p->func->labels.len);
3599 bc_parse_updateFunc(p, BC_PROG_MAIN);
3603 p->l.t.t = BC_LEX_EOF;
3604 p->auto_part = (p->nbraces = 0);
3606 bc_vec_npop(&p->flags, p->flags.len - 1);
3607 bc_vec_npop(&p->exits, p->exits.len);
3608 bc_vec_npop(&p->conds, p->conds.len);
3609 bc_vec_npop(&p->ops, p->ops.len);
3611 return bc_program_reset(s);
3614 static void bc_parse_free(BcParse *p)
3616 bc_vec_free(&p->flags);
3617 bc_vec_free(&p->exits);
3618 bc_vec_free(&p->conds);
3619 bc_vec_free(&p->ops);
3623 static void bc_parse_create(BcParse *p, size_t func,
3624 BcParseParse parse, BcLexNext next)
3626 memset(p, 0, sizeof(BcParse));
3628 bc_lex_init(&p->l, next);
3629 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3630 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3631 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3632 bc_vec_pushByte(&p->flags, 0);
3633 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3636 p->auto_part = (p->nbraces = 0);
3637 bc_parse_updateFunc(p, func);
3641 static BcStatus bc_parse_else(BcParse *p);
3642 static BcStatus bc_parse_stmt(BcParse *p);
3644 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3645 size_t *nexprs, bool next)
3647 BcStatus s = BC_STATUS_SUCCESS;
3649 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3650 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3652 while (p->ops.len > start) {
3654 t = BC_PARSE_TOP_OP(p);
3655 if (t == BC_LEX_LPAREN) break;
3657 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3658 if (l >= r && (l != r || !left)) break;
3660 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3661 bc_vec_pop(&p->ops);
3662 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3665 bc_vec_push(&p->ops, &type);
3666 if (next) s = bc_lex_next(&p->l);
3671 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3675 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3676 top = BC_PARSE_TOP_OP(p);
3678 while (top != BC_LEX_LPAREN) {
3680 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3682 bc_vec_pop(&p->ops);
3683 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3685 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3686 top = BC_PARSE_TOP_OP(p);
3689 bc_vec_pop(&p->ops);
3691 return bc_lex_next(&p->l);
3694 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3700 s = bc_lex_next(&p->l);
3703 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3705 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3706 s = bc_parse_expr(p, flags, bc_parse_next_param);
3709 comma = p->l.t.t == BC_LEX_COMMA;
3711 s = bc_lex_next(&p->l);
3716 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3717 bc_parse_push(p, BC_INST_CALL);
3718 bc_parse_pushIndex(p, nparams);
3720 return BC_STATUS_SUCCESS;
3723 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3726 BcId entry, *entry_ptr;
3731 s = bc_parse_params(p, flags);
3734 if (p->l.t.t != BC_LEX_RPAREN) {
3735 s = BC_STATUS_PARSE_BAD_TOKEN;
3739 idx = bc_map_index(&G.prog.fn_map, &entry);
3741 if (idx == BC_VEC_INVALID_IDX) {
3742 name = xstrdup(entry.name);
3743 bc_parse_addFunc(p, name, &idx);
3744 idx = bc_map_index(&G.prog.fn_map, &entry);
3750 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3751 bc_parse_pushIndex(p, entry_ptr->idx);
3753 return bc_lex_next(&p->l);
3760 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3765 name = xstrdup(p->l.t.v.v);
3766 s = bc_lex_next(&p->l);
3769 if (p->l.t.t == BC_LEX_LBRACKET) {
3771 s = bc_lex_next(&p->l);
3774 if (p->l.t.t == BC_LEX_RBRACKET) {
3776 if (!(flags & BC_PARSE_ARRAY)) {
3777 s = BC_STATUS_PARSE_BAD_EXP;
3781 *type = BC_INST_ARRAY;
3785 *type = BC_INST_ARRAY_ELEM;
3787 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3788 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3792 s = bc_lex_next(&p->l);
3794 bc_parse_push(p, *type);
3795 bc_parse_pushName(p, name);
3797 else if (p->l.t.t == BC_LEX_LPAREN) {
3799 if (flags & BC_PARSE_NOCALL) {
3800 s = BC_STATUS_PARSE_BAD_TOKEN;
3804 *type = BC_INST_CALL;
3805 s = bc_parse_call(p, name, flags);
3808 *type = BC_INST_VAR;
3809 bc_parse_push(p, BC_INST_VAR);
3810 bc_parse_pushName(p, name);
3820 static BcStatus bc_parse_read(BcParse *p)
3824 s = bc_lex_next(&p->l);
3826 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3828 s = bc_lex_next(&p->l);
3830 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3832 bc_parse_push(p, BC_INST_READ);
3834 return bc_lex_next(&p->l);
3837 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3842 s = bc_lex_next(&p->l);
3844 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3846 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3848 s = bc_lex_next(&p->l);
3851 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3854 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3856 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3857 bc_parse_push(p, *prev);
3859 return bc_lex_next(&p->l);
3862 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3866 s = bc_lex_next(&p->l);
3869 if (p->l.t.t != BC_LEX_LPAREN) {
3870 *type = BC_INST_SCALE;
3871 bc_parse_push(p, BC_INST_SCALE);
3872 return BC_STATUS_SUCCESS;
3875 *type = BC_INST_SCALE_FUNC;
3876 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3878 s = bc_lex_next(&p->l);
3881 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3883 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3884 bc_parse_push(p, BC_INST_SCALE_FUNC);
3886 return bc_lex_next(&p->l);
3889 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3890 size_t *nexprs, uint8_t flags)
3895 BcInst etype = *prev;
3897 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3898 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3899 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3901 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3902 bc_parse_push(p, inst);
3903 s = bc_lex_next(&p->l);
3907 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3910 s = bc_lex_next(&p->l);
3914 // Because we parse the next part of the expression
3915 // right here, we need to increment this.
3916 *nexprs = *nexprs + 1;
3922 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3926 case BC_LEX_KEY_IBASE:
3927 case BC_LEX_KEY_LAST:
3928 case BC_LEX_KEY_OBASE:
3930 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3931 s = bc_lex_next(&p->l);
3935 case BC_LEX_KEY_SCALE:
3937 s = bc_lex_next(&p->l);
3939 if (p->l.t.t == BC_LEX_LPAREN)
3940 s = BC_STATUS_PARSE_BAD_TOKEN;
3942 bc_parse_push(p, BC_INST_SCALE);
3948 s = BC_STATUS_PARSE_BAD_TOKEN;
3953 if (!s) bc_parse_push(p, inst);
3959 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3960 bool rparen, size_t *nexprs)
3964 BcInst etype = *prev;
3966 s = bc_lex_next(&p->l);
3969 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3970 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3973 *prev = BC_PARSE_TOKEN_INST(type);
3975 // We can just push onto the op stack because this is the largest
3976 // precedence operator that gets pushed. Inc/dec does not.
3977 if (type != BC_LEX_OP_MINUS)
3978 bc_vec_push(&p->ops, &type);
3980 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3985 static BcStatus bc_parse_string(BcParse *p, char inst)
3987 char *str = xstrdup(p->l.t.v.v);
3989 bc_parse_push(p, BC_INST_STR);
3990 bc_parse_pushIndex(p, G.prog.strs.len);
3991 bc_vec_push(&G.prog.strs, &str);
3992 bc_parse_push(p, inst);
3994 return bc_lex_next(&p->l);
3997 static BcStatus bc_parse_print(BcParse *p)
4003 s = bc_lex_next(&p->l);
4008 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4009 return BC_STATUS_PARSE_BAD_PRINT;
4011 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4013 if (type == BC_LEX_STR)
4014 s = bc_parse_string(p, BC_INST_PRINT_POP);
4016 s = bc_parse_expr(p, 0, bc_parse_next_print);
4018 bc_parse_push(p, BC_INST_PRINT_POP);
4023 comma = p->l.t.t == BC_LEX_COMMA;
4024 if (comma) s = bc_lex_next(&p->l);
4029 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4031 return bc_lex_next(&p->l);
4034 static BcStatus bc_parse_return(BcParse *p)
4040 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4042 s = bc_lex_next(&p->l);
4046 paren = t == BC_LEX_LPAREN;
4048 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4049 bc_parse_push(p, BC_INST_RET0);
4052 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4053 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4055 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4056 bc_parse_push(p, BC_INST_RET0);
4057 s = bc_lex_next(&p->l);
4061 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4062 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4066 bc_parse_push(p, BC_INST_RET);
4072 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4074 BcStatus s = BC_STATUS_SUCCESS;
4076 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4077 return BC_STATUS_PARSE_BAD_TOKEN;
4081 if (p->l.t.t == BC_LEX_RBRACE) {
4082 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4084 s = bc_lex_next(&p->l);
4088 return BC_STATUS_PARSE_BAD_TOKEN;
4091 if (BC_PARSE_IF(p)) {
4095 while (p->l.t.t == BC_LEX_NLINE) {
4096 s = bc_lex_next(&p->l);
4100 bc_vec_pop(&p->flags);
4102 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4103 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4105 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4107 else if (BC_PARSE_ELSE(p)) {
4112 bc_vec_pop(&p->flags);
4114 ip = bc_vec_top(&p->exits);
4115 label = bc_vec_item(&p->func->labels, ip->idx);
4116 *label = p->func->code.len;
4118 bc_vec_pop(&p->exits);
4120 else if (BC_PARSE_FUNC_INNER(p)) {
4121 bc_parse_push(p, BC_INST_RET0);
4122 bc_parse_updateFunc(p, BC_PROG_MAIN);
4123 bc_vec_pop(&p->flags);
4127 BcInstPtr *ip = bc_vec_top(&p->exits);
4128 size_t *label = bc_vec_top(&p->conds);
4130 bc_parse_push(p, BC_INST_JUMP);
4131 bc_parse_pushIndex(p, *label);
4133 label = bc_vec_item(&p->func->labels, ip->idx);
4134 *label = p->func->code.len;
4136 bc_vec_pop(&p->flags);
4137 bc_vec_pop(&p->exits);
4138 bc_vec_pop(&p->conds);
4144 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4146 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4147 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4148 flags |= BC_PARSE_FLAG_BODY;
4149 bc_vec_push(&p->flags, &flags);
4152 static void bc_parse_noElse(BcParse *p)
4156 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4158 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4160 ip = bc_vec_top(&p->exits);
4161 label = bc_vec_item(&p->func->labels, ip->idx);
4162 *label = p->func->code.len;
4164 bc_vec_pop(&p->exits);
4167 static BcStatus bc_parse_if(BcParse *p)
4172 s = bc_lex_next(&p->l);
4174 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4176 s = bc_lex_next(&p->l);
4178 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4180 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4182 s = bc_lex_next(&p->l);
4184 bc_parse_push(p, BC_INST_JUMP_ZERO);
4186 ip.idx = p->func->labels.len;
4187 ip.func = ip.len = 0;
4189 bc_parse_pushIndex(p, ip.idx);
4190 bc_vec_push(&p->exits, &ip);
4191 bc_vec_push(&p->func->labels, &ip.idx);
4192 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4194 return BC_STATUS_SUCCESS;
4197 static BcStatus bc_parse_else(BcParse *p)
4201 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4203 ip.idx = p->func->labels.len;
4204 ip.func = ip.len = 0;
4206 bc_parse_push(p, BC_INST_JUMP);
4207 bc_parse_pushIndex(p, ip.idx);
4211 bc_vec_push(&p->exits, &ip);
4212 bc_vec_push(&p->func->labels, &ip.idx);
4213 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4215 return bc_lex_next(&p->l);
4218 static BcStatus bc_parse_while(BcParse *p)
4223 s = bc_lex_next(&p->l);
4225 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4226 s = bc_lex_next(&p->l);
4229 ip.idx = p->func->labels.len;
4231 bc_vec_push(&p->func->labels, &p->func->code.len);
4232 bc_vec_push(&p->conds, &ip.idx);
4234 ip.idx = p->func->labels.len;
4238 bc_vec_push(&p->exits, &ip);
4239 bc_vec_push(&p->func->labels, &ip.idx);
4241 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4243 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4244 s = bc_lex_next(&p->l);
4247 bc_parse_push(p, BC_INST_JUMP_ZERO);
4248 bc_parse_pushIndex(p, ip.idx);
4249 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4251 return BC_STATUS_SUCCESS;
4254 static BcStatus bc_parse_for(BcParse *p)
4258 size_t cond_idx, exit_idx, body_idx, update_idx;
4260 s = bc_lex_next(&p->l);
4262 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4263 s = bc_lex_next(&p->l);
4266 if (p->l.t.t != BC_LEX_SCOLON)
4267 s = bc_parse_expr(p, 0, bc_parse_next_for);
4269 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4272 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4273 s = bc_lex_next(&p->l);
4276 cond_idx = p->func->labels.len;
4277 update_idx = cond_idx + 1;
4278 body_idx = update_idx + 1;
4279 exit_idx = body_idx + 1;
4281 bc_vec_push(&p->func->labels, &p->func->code.len);
4283 if (p->l.t.t != BC_LEX_SCOLON)
4284 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4286 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4289 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4291 s = bc_lex_next(&p->l);
4294 bc_parse_push(p, BC_INST_JUMP_ZERO);
4295 bc_parse_pushIndex(p, exit_idx);
4296 bc_parse_push(p, BC_INST_JUMP);
4297 bc_parse_pushIndex(p, body_idx);
4299 ip.idx = p->func->labels.len;
4301 bc_vec_push(&p->conds, &update_idx);
4302 bc_vec_push(&p->func->labels, &p->func->code.len);
4304 if (p->l.t.t != BC_LEX_RPAREN)
4305 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4307 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4311 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4312 bc_parse_push(p, BC_INST_JUMP);
4313 bc_parse_pushIndex(p, cond_idx);
4314 bc_vec_push(&p->func->labels, &p->func->code.len);
4320 bc_vec_push(&p->exits, &ip);
4321 bc_vec_push(&p->func->labels, &ip.idx);
4323 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4325 return BC_STATUS_SUCCESS;
4328 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4334 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4336 if (type == BC_LEX_KEY_BREAK) {
4338 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4340 i = p->exits.len - 1;
4341 ip = bc_vec_item(&p->exits, i);
4343 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4344 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4349 i = *((size_t *) bc_vec_top(&p->conds));
4351 bc_parse_push(p, BC_INST_JUMP);
4352 bc_parse_pushIndex(p, i);
4354 s = bc_lex_next(&p->l);
4357 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4358 return BC_STATUS_PARSE_BAD_TOKEN;
4360 return bc_lex_next(&p->l);
4363 static BcStatus bc_parse_func(BcParse *p)
4366 bool var, comma = false;
4370 s = bc_lex_next(&p->l);
4372 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4374 name = xstrdup(p->l.t.v.v);
4375 bc_parse_addFunc(p, name, &p->fidx);
4377 s = bc_lex_next(&p->l);
4379 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4380 s = bc_lex_next(&p->l);
4383 while (p->l.t.t != BC_LEX_RPAREN) {
4385 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4389 name = xstrdup(p->l.t.v.v);
4390 s = bc_lex_next(&p->l);
4393 var = p->l.t.t != BC_LEX_LBRACKET;
4397 s = bc_lex_next(&p->l);
4400 if (p->l.t.t != BC_LEX_RBRACKET) {
4401 s = BC_STATUS_PARSE_BAD_FUNC;
4405 s = bc_lex_next(&p->l);
4409 comma = p->l.t.t == BC_LEX_COMMA;
4411 s = bc_lex_next(&p->l);
4415 s = bc_func_insert(p->func, name, var);
4419 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4421 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4422 bc_parse_startBody(p, flags);
4424 s = bc_lex_next(&p->l);
4427 if (p->l.t.t != BC_LEX_LBRACE)
4428 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4437 static BcStatus bc_parse_auto(BcParse *p)
4440 bool comma, var, one;
4443 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4444 s = bc_lex_next(&p->l);
4447 p->auto_part = comma = false;
4448 one = p->l.t.t == BC_LEX_NAME;
4450 while (p->l.t.t == BC_LEX_NAME) {
4452 name = xstrdup(p->l.t.v.v);
4453 s = bc_lex_next(&p->l);
4456 var = p->l.t.t != BC_LEX_LBRACKET;
4459 s = bc_lex_next(&p->l);
4462 if (p->l.t.t != BC_LEX_RBRACKET) {
4463 s = BC_STATUS_PARSE_BAD_FUNC;
4467 s = bc_lex_next(&p->l);
4471 comma = p->l.t.t == BC_LEX_COMMA;
4473 s = bc_lex_next(&p->l);
4477 s = bc_func_insert(p->func, name, var);
4481 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4482 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4484 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4485 return BC_STATUS_PARSE_BAD_TOKEN;
4487 return bc_lex_next(&p->l);
4494 static BcStatus bc_parse_body(BcParse *p, bool brace)
4496 BcStatus s = BC_STATUS_SUCCESS;
4497 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4499 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4501 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4503 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4504 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4506 if (!p->auto_part) {
4507 s = bc_parse_auto(p);
4511 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4514 s = bc_parse_stmt(p);
4515 if (!s && !brace) s = bc_parse_endBody(p, false);
4521 static BcStatus bc_parse_stmt(BcParse *p)
4523 BcStatus s = BC_STATUS_SUCCESS;
4529 return bc_lex_next(&p->l);
4532 case BC_LEX_KEY_ELSE:
4534 p->auto_part = false;
4540 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4543 s = bc_lex_next(&p->l);
4546 return bc_parse_body(p, true);
4549 case BC_LEX_KEY_AUTO:
4551 return bc_parse_auto(p);
4556 p->auto_part = false;
4558 if (BC_PARSE_IF_END(p)) {
4560 return BC_STATUS_SUCCESS;
4562 else if (BC_PARSE_BODY(p))
4563 return bc_parse_body(p, false);
4573 case BC_LEX_OP_MINUS:
4574 case BC_LEX_OP_BOOL_NOT:
4578 case BC_LEX_KEY_IBASE:
4579 case BC_LEX_KEY_LAST:
4580 case BC_LEX_KEY_LENGTH:
4581 case BC_LEX_KEY_OBASE:
4582 case BC_LEX_KEY_READ:
4583 case BC_LEX_KEY_SCALE:
4584 case BC_LEX_KEY_SQRT:
4586 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4590 case BC_LEX_KEY_ELSE:
4592 s = bc_parse_else(p);
4598 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4604 s = bc_parse_endBody(p, true);
4610 s = bc_parse_string(p, BC_INST_PRINT_STR);
4614 case BC_LEX_KEY_BREAK:
4615 case BC_LEX_KEY_CONTINUE:
4617 s = bc_parse_loopExit(p, p->l.t.t);
4621 case BC_LEX_KEY_FOR:
4623 s = bc_parse_for(p);
4627 case BC_LEX_KEY_HALT:
4629 bc_parse_push(p, BC_INST_HALT);
4630 s = bc_lex_next(&p->l);
4640 case BC_LEX_KEY_LIMITS:
4642 s = bc_lex_next(&p->l);
4644 s = BC_STATUS_LIMITS;
4648 case BC_LEX_KEY_PRINT:
4650 s = bc_parse_print(p);
4654 case BC_LEX_KEY_QUIT:
4656 // Quit is a compile-time command. We don't exit directly,
4657 // so the vm can clean up. Limits do the same thing.
4662 case BC_LEX_KEY_RETURN:
4664 s = bc_parse_return(p);
4668 case BC_LEX_KEY_WHILE:
4670 s = bc_parse_while(p);
4676 s = BC_STATUS_PARSE_BAD_TOKEN;
4684 static BcStatus bc_parse_parse(BcParse *p)
4688 if (p->l.t.t == BC_LEX_EOF)
4689 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4690 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4691 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4692 s = bc_parse_func(p);
4695 s = bc_parse_stmt(p);
4697 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4698 s = bc_parse_reset(p, s);
4703 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4705 BcStatus s = BC_STATUS_SUCCESS;
4706 BcInst prev = BC_INST_PRINT;
4707 BcLexType top, t = p->l.t.t;
4708 size_t nexprs = 0, ops_bgn = p->ops.len;
4709 uint32_t i, nparens, nrelops;
4710 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4712 paren_first = p->l.t.t == BC_LEX_LPAREN;
4713 nparens = nrelops = 0;
4714 paren_expr = rprn = done = get_token = assign = false;
4717 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4723 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4724 rprn = get_token = bin_last = false;
4728 case BC_LEX_OP_MINUS:
4730 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4731 rprn = get_token = false;
4732 bin_last = prev == BC_INST_MINUS;
4736 case BC_LEX_OP_ASSIGN_POWER:
4737 case BC_LEX_OP_ASSIGN_MULTIPLY:
4738 case BC_LEX_OP_ASSIGN_DIVIDE:
4739 case BC_LEX_OP_ASSIGN_MODULUS:
4740 case BC_LEX_OP_ASSIGN_PLUS:
4741 case BC_LEX_OP_ASSIGN_MINUS:
4742 case BC_LEX_OP_ASSIGN:
4744 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4745 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4746 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4748 s = BC_STATUS_PARSE_BAD_ASSIGN;
4753 case BC_LEX_OP_POWER:
4754 case BC_LEX_OP_MULTIPLY:
4755 case BC_LEX_OP_DIVIDE:
4756 case BC_LEX_OP_MODULUS:
4757 case BC_LEX_OP_PLUS:
4758 case BC_LEX_OP_REL_EQ:
4759 case BC_LEX_OP_REL_LE:
4760 case BC_LEX_OP_REL_GE:
4761 case BC_LEX_OP_REL_NE:
4762 case BC_LEX_OP_REL_LT:
4763 case BC_LEX_OP_REL_GT:
4764 case BC_LEX_OP_BOOL_NOT:
4765 case BC_LEX_OP_BOOL_OR:
4766 case BC_LEX_OP_BOOL_AND:
4768 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4769 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4771 return BC_STATUS_PARSE_BAD_EXP;
4774 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4775 prev = BC_PARSE_TOKEN_INST(t);
4776 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4777 rprn = get_token = false;
4778 bin_last = t != BC_LEX_OP_BOOL_NOT;
4785 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4788 paren_expr = rprn = bin_last = false;
4790 bc_vec_push(&p->ops, &t);
4797 if (bin_last || prev == BC_INST_BOOL_NOT)
4798 return BC_STATUS_PARSE_BAD_EXP;
4801 s = BC_STATUS_SUCCESS;
4806 else if (!paren_expr)
4807 return BC_STATUS_PARSE_EMPTY_EXP;
4810 paren_expr = rprn = true;
4811 get_token = bin_last = false;
4813 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4820 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4823 rprn = get_token = bin_last = false;
4824 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4832 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4834 bc_parse_number(p, &prev, &nexprs);
4835 paren_expr = get_token = true;
4836 rprn = bin_last = false;
4841 case BC_LEX_KEY_IBASE:
4842 case BC_LEX_KEY_LAST:
4843 case BC_LEX_KEY_OBASE:
4845 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4847 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4848 bc_parse_push(p, (char) prev);
4850 paren_expr = get_token = true;
4851 rprn = bin_last = false;
4857 case BC_LEX_KEY_LENGTH:
4858 case BC_LEX_KEY_SQRT:
4860 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4862 s = bc_parse_builtin(p, t, flags, &prev);
4864 rprn = get_token = bin_last = false;
4870 case BC_LEX_KEY_READ:
4872 if (BC_PARSE_LEAF(prev, rprn))
4873 return BC_STATUS_PARSE_BAD_EXP;
4874 else if (flags & BC_PARSE_NOREAD)
4875 s = BC_STATUS_EXEC_REC_READ;
4877 s = bc_parse_read(p);
4880 rprn = get_token = bin_last = false;
4882 prev = BC_INST_READ;
4887 case BC_LEX_KEY_SCALE:
4889 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4891 s = bc_parse_scale(p, &prev, flags);
4893 rprn = get_token = bin_last = false;
4895 prev = BC_INST_SCALE;
4902 s = BC_STATUS_PARSE_BAD_TOKEN;
4907 if (!s && get_token) s = bc_lex_next(&p->l);
4911 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4913 while (p->ops.len > ops_bgn) {
4915 top = BC_PARSE_TOP_OP(p);
4916 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4918 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4919 return BC_STATUS_PARSE_BAD_EXP;
4921 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4923 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4924 bc_vec_pop(&p->ops);
4927 s = BC_STATUS_PARSE_BAD_EXP;
4928 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4930 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4933 if (!(flags & BC_PARSE_REL) && nrelops) {
4934 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4937 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4938 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4942 if (flags & BC_PARSE_PRINT) {
4943 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4944 bc_parse_push(p, BC_INST_POP);
4950 static void bc_parse_init(BcParse *p, size_t func)
4952 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4955 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4957 return bc_parse_expr(p, flags, bc_parse_next_read);
4962 static BcStatus dc_parse_register(BcParse *p)
4967 s = bc_lex_next(&p->l);
4969 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
4971 name = xstrdup(p->l.t.v.v);
4972 bc_parse_pushName(p, name);
4977 static BcStatus dc_parse_string(BcParse *p)
4979 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4980 size_t idx, len = G.prog.strs.len;
4982 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4985 str = xstrdup(p->l.t.v.v);
4986 bc_parse_push(p, BC_INST_STR);
4987 bc_parse_pushIndex(p, len);
4988 bc_vec_push(&G.prog.strs, &str);
4989 bc_parse_addFunc(p, name, &idx);
4991 return bc_lex_next(&p->l);
4994 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4998 bc_parse_push(p, inst);
5000 s = dc_parse_register(p);
5005 bc_parse_push(p, BC_INST_SWAP);
5006 bc_parse_push(p, BC_INST_ASSIGN);
5007 bc_parse_push(p, BC_INST_POP);
5010 return bc_lex_next(&p->l);
5013 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5017 bc_parse_push(p, inst);
5018 bc_parse_push(p, BC_INST_EXEC_COND);
5020 s = dc_parse_register(p);
5023 s = bc_lex_next(&p->l);
5026 if (p->l.t.t == BC_LEX_ELSE) {
5027 s = dc_parse_register(p);
5029 s = bc_lex_next(&p->l);
5032 bc_parse_push(p, BC_PARSE_STREND);
5037 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5039 BcStatus s = BC_STATUS_SUCCESS;
5042 bool assign, get_token = false;
5046 case BC_LEX_OP_REL_EQ:
5047 case BC_LEX_OP_REL_LE:
5048 case BC_LEX_OP_REL_GE:
5049 case BC_LEX_OP_REL_NE:
5050 case BC_LEX_OP_REL_LT:
5051 case BC_LEX_OP_REL_GT:
5053 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5060 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5066 s = dc_parse_string(p);
5073 if (t == BC_LEX_NEG) {
5074 s = bc_lex_next(&p->l);
5076 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5079 bc_parse_number(p, &prev, &p->nbraces);
5081 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5087 case BC_LEX_KEY_READ:
5089 if (flags & BC_PARSE_NOREAD)
5090 s = BC_STATUS_EXEC_REC_READ;
5092 bc_parse_push(p, BC_INST_READ);
5097 case BC_LEX_OP_ASSIGN:
5098 case BC_LEX_STORE_PUSH:
5100 assign = t == BC_LEX_OP_ASSIGN;
5101 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5102 s = dc_parse_mem(p, inst, true, assign);
5107 case BC_LEX_LOAD_POP:
5109 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5110 s = dc_parse_mem(p, inst, true, false);
5114 case BC_LEX_STORE_IBASE:
5115 case BC_LEX_STORE_SCALE:
5116 case BC_LEX_STORE_OBASE:
5118 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5119 s = dc_parse_mem(p, inst, false, true);
5125 s = BC_STATUS_PARSE_BAD_TOKEN;
5131 if (!s && get_token) s = bc_lex_next(&p->l);
5136 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5138 BcStatus s = BC_STATUS_SUCCESS;
5142 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5144 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5146 inst = dc_parse_insts[t];
5148 if (inst != BC_INST_INVALID) {
5149 bc_parse_push(p, inst);
5150 s = bc_lex_next(&p->l);
5153 s = dc_parse_token(p, t, flags);
5156 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5157 bc_parse_push(p, BC_INST_POP_EXEC);
5162 static BcStatus dc_parse_parse(BcParse *p)
5166 if (p->l.t.t == BC_LEX_EOF)
5167 s = BC_STATUS_LEX_EOF;
5169 s = dc_parse_expr(p, 0);
5171 if (s || G_interrupt) s = bc_parse_reset(p, s);
5176 static void dc_parse_init(BcParse *p, size_t func)
5178 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5182 static void common_parse_init(BcParse *p, size_t func)
5185 bc_parse_init(p, func);
5187 dc_parse_init(p, func);
5191 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5194 return bc_parse_expression(p, flags);
5196 return dc_parse_expr(p, flags);
5200 static BcVec* bc_program_search(char *id, bool var)
5209 v = var ? &G.prog.vars : &G.prog.arrs;
5210 map = var ? &G.prog.var_map : &G.prog.arr_map;
5214 s = bc_map_insert(map, &e, &i);
5215 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5218 bc_array_init(&data.v, var);
5219 bc_vec_push(v, &data.v);
5222 ptr = bc_vec_item(map, i);
5223 if (new) ptr->name = xstrdup(e.name);
5224 return bc_vec_item(v, ptr->idx);
5227 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5229 BcStatus s = BC_STATUS_SUCCESS;
5234 case BC_RESULT_TEMP:
5235 case BC_RESULT_IBASE:
5236 case BC_RESULT_SCALE:
5237 case BC_RESULT_OBASE:
5243 case BC_RESULT_CONSTANT:
5245 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5246 size_t base_t, len = strlen(*str);
5249 bc_num_init(&r->d.n, len);
5251 hex = hex && len == 1;
5252 base = hex ? &G.prog.hexb : &G.prog.ib;
5253 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5254 s = bc_num_parse(&r->d.n, *str, base, base_t);
5257 bc_num_free(&r->d.n);
5262 r->t = BC_RESULT_TEMP;
5268 case BC_RESULT_ARRAY:
5269 case BC_RESULT_ARRAY_ELEM:
5273 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5275 if (r->t == BC_RESULT_ARRAY_ELEM) {
5277 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5278 *num = bc_vec_item(v, r->d.id.idx);
5281 *num = bc_vec_top(v);
5286 case BC_RESULT_LAST:
5288 *num = &G.prog.last;
5302 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5303 BcResult **r, BcNum **rn, bool assign)
5307 BcResultType lt, rt;
5309 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5311 *r = bc_vec_item_rev(&G.prog.results, 0);
5312 *l = bc_vec_item_rev(&G.prog.results, 1);
5316 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5318 s = bc_program_num(*l, ln, false);
5320 s = bc_program_num(*r, rn, hex);
5323 // We run this again under these conditions in case any vector has been
5324 // reallocated out from under the BcNums or arrays we had.
5325 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5326 s = bc_program_num(*l, ln, false);
5330 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5331 return BC_STATUS_EXEC_BAD_TYPE;
5332 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5337 static void bc_program_binOpRetire(BcResult *r)
5339 r->t = BC_RESULT_TEMP;
5340 bc_vec_pop(&G.prog.results);
5341 bc_vec_pop(&G.prog.results);
5342 bc_vec_push(&G.prog.results, r);
5345 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5349 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5350 *r = bc_vec_top(&G.prog.results);
5352 s = bc_program_num(*r, n, false);
5355 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5360 static void bc_program_retire(BcResult *r, BcResultType t)
5363 bc_vec_pop(&G.prog.results);
5364 bc_vec_push(&G.prog.results, r);
5367 static BcStatus bc_program_op(char inst)
5370 BcResult *opd1, *opd2, res;
5371 BcNum *n1, *n2 = NULL;
5373 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5375 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5377 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5379 bc_program_binOpRetire(&res);
5384 bc_num_free(&res.d.n);
5388 static BcStatus bc_program_read(void)
5395 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5397 for (i = 0; i < G.prog.stack.len; ++i) {
5398 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5399 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5402 bc_vec_npop(&f->code, f->code.len);
5403 bc_vec_init(&buf, sizeof(char), NULL);
5405 s = bc_read_line(&buf, "read> ");
5408 common_parse_init(&parse, BC_PROG_READ);
5409 bc_lex_file(&parse.l, bc_program_stdin_name);
5411 s = bc_parse_text(&parse, buf.v);
5412 if (s) goto exec_err;
5413 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5414 if (s) goto exec_err;
5416 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5417 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5421 ip.func = BC_PROG_READ;
5423 ip.len = G.prog.results.len;
5425 // Update this pointer, just in case.
5426 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5428 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5429 bc_vec_push(&G.prog.stack, &ip);
5432 bc_parse_free(&parse);
5438 static size_t bc_program_index(char *code, size_t *bgn)
5440 char amt = code[(*bgn)++], i = 0;
5443 for (; i < amt; ++i, ++(*bgn))
5444 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5449 static char *bc_program_name(char *code, size_t *bgn)
5452 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5454 s = xmalloc(ptr - str + 1);
5457 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5465 static void bc_program_printString(const char *str, size_t *nchars)
5467 size_t i, len = strlen(str);
5476 for (i = 0; i < len; ++i, ++(*nchars)) {
5480 if (c != '\\' || i == len - 1)
5540 // Just print the backslash and following character.
5551 static BcStatus bc_program_print(char inst, size_t idx)
5553 BcStatus s = BC_STATUS_SUCCESS;
5558 bool pop = inst != BC_INST_PRINT;
5560 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5562 r = bc_vec_item_rev(&G.prog.results, idx);
5563 s = bc_program_num(r, &num, false);
5566 if (BC_PROG_NUM(r, num)) {
5567 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5568 if (!s) bc_num_copy(&G.prog.last, num);
5572 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5573 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5575 if (inst == BC_INST_PRINT_STR) {
5576 for (i = 0, len = strlen(str); i < len; ++i) {
5579 if (c == '\n') G.prog.nchars = SIZE_MAX;
5584 bc_program_printString(str, &G.prog.nchars);
5585 if (inst == BC_INST_PRINT) bb_putchar('\n');
5589 if (!s && pop) bc_vec_pop(&G.prog.results);
5594 static BcStatus bc_program_negate(void)
5600 s = bc_program_prep(&ptr, &num);
5603 bc_num_init(&res.d.n, num->len);
5604 bc_num_copy(&res.d.n, num);
5605 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5607 bc_program_retire(&res, BC_RESULT_TEMP);
5612 static BcStatus bc_program_logical(char inst)
5615 BcResult *opd1, *opd2, res;
5620 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5622 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5624 if (inst == BC_INST_BOOL_AND)
5625 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5626 else if (inst == BC_INST_BOOL_OR)
5627 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5630 cmp = bc_num_cmp(n1, n2);
5634 case BC_INST_REL_EQ:
5640 case BC_INST_REL_LE:
5646 case BC_INST_REL_GE:
5652 case BC_INST_REL_NE:
5658 case BC_INST_REL_LT:
5664 case BC_INST_REL_GT:
5672 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5674 bc_program_binOpRetire(&res);
5680 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5686 memset(&n2, 0, sizeof(BcNum));
5687 n2.rdx = res.d.id.idx = r->d.id.idx;
5688 res.t = BC_RESULT_STR;
5691 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5693 bc_vec_pop(&G.prog.results);
5696 bc_vec_pop(&G.prog.results);
5698 bc_vec_push(&G.prog.results, &res);
5699 bc_vec_push(v, &n2);
5701 return BC_STATUS_SUCCESS;
5705 static BcStatus bc_program_copyToVar(char *name, bool var)
5712 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5714 ptr = bc_vec_top(&G.prog.results);
5715 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5716 v = bc_program_search(name, var);
5719 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5720 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5723 s = bc_program_num(ptr, &n, false);
5726 // Do this once more to make sure that pointers were not invalidated.
5727 v = bc_program_search(name, var);
5730 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5731 bc_num_copy(&r.d.n, n);
5734 bc_array_init(&r.d.v, true);
5735 bc_array_copy(&r.d.v, (BcVec *) n);
5738 bc_vec_push(v, &r.d);
5739 bc_vec_pop(&G.prog.results);
5744 static BcStatus bc_program_assign(char inst)
5747 BcResult *left, *right, res;
5748 BcNum *l = NULL, *r = NULL;
5749 unsigned long val, max;
5750 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5752 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5755 ib = left->t == BC_RESULT_IBASE;
5756 sc = left->t == BC_RESULT_SCALE;
5760 if (right->t == BC_RESULT_STR) {
5764 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5765 v = bc_program_search(left->d.id.name, true);
5767 return bc_program_assignStr(right, v, false);
5771 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5772 return BC_STATUS_PARSE_BAD_ASSIGN;
5775 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5776 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5781 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5788 if (ib || sc || left->t == BC_RESULT_OBASE) {
5792 s = bc_num_ulong(l, &val);
5794 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5798 ptr = &G.prog.scale;
5801 if (val < BC_NUM_MIN_BASE) return s;
5802 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5803 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5806 if (val > max) return s;
5807 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5809 *ptr = (size_t) val;
5810 s = BC_STATUS_SUCCESS;
5813 bc_num_init(&res.d.n, l->len);
5814 bc_num_copy(&res.d.n, l);
5815 bc_program_binOpRetire(&res);
5821 #define bc_program_pushVar(code, bgn, pop, copy) \
5822 bc_program_pushVar(code, bgn)
5823 // for bc, 'pop' and 'copy' are always false
5825 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5826 bool pop, bool copy)
5828 BcStatus s = BC_STATUS_SUCCESS;
5830 char *name = bc_program_name(code, bgn);
5832 r.t = BC_RESULT_VAR;
5837 BcVec *v = bc_program_search(name, true);
5838 BcNum *num = bc_vec_top(v);
5842 if (!BC_PROG_STACK(v, 2 - copy)) {
5844 return BC_STATUS_EXEC_STACK;
5850 if (!BC_PROG_STR(num)) {
5852 r.t = BC_RESULT_TEMP;
5854 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5855 bc_num_copy(&r.d.n, num);
5858 r.t = BC_RESULT_STR;
5859 r.d.id.idx = num->rdx;
5862 if (!copy) bc_vec_pop(v);
5867 bc_vec_push(&G.prog.results, &r);
5872 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5875 BcStatus s = BC_STATUS_SUCCESS;
5879 r.d.id.name = bc_program_name(code, bgn);
5881 if (inst == BC_INST_ARRAY) {
5882 r.t = BC_RESULT_ARRAY;
5883 bc_vec_push(&G.prog.results, &r);
5890 s = bc_program_prep(&operand, &num);
5892 s = bc_num_ulong(num, &temp);
5895 if (temp > BC_MAX_DIM) {
5896 s = BC_STATUS_EXEC_ARRAY_LEN;
5900 r.d.id.idx = (size_t) temp;
5901 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5905 if (s) free(r.d.id.name);
5910 static BcStatus bc_program_incdec(char inst)
5913 BcResult *ptr, res, copy;
5917 s = bc_program_prep(&ptr, &num);
5920 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5921 copy.t = BC_RESULT_TEMP;
5922 bc_num_init(©.d.n, num->len);
5923 bc_num_copy(©.d.n, num);
5926 res.t = BC_RESULT_ONE;
5927 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5928 BC_INST_ASSIGN_PLUS :
5929 BC_INST_ASSIGN_MINUS;
5931 bc_vec_push(&G.prog.results, &res);
5932 bc_program_assign(inst);
5934 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5935 bc_vec_pop(&G.prog.results);
5936 bc_vec_push(&G.prog.results, ©);
5942 static BcStatus bc_program_call(char *code, size_t *idx)
5944 BcStatus s = BC_STATUS_SUCCESS;
5946 size_t i, nparams = bc_program_index(code, idx);
5953 ip.func = bc_program_index(code, idx);
5954 func = bc_vec_item(&G.prog.fns, ip.func);
5956 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
5957 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
5958 ip.len = G.prog.results.len - nparams;
5960 for (i = 0; i < nparams; ++i) {
5962 a = bc_vec_item(&func->autos, nparams - 1 - i);
5963 arg = bc_vec_top(&G.prog.results);
5965 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5966 return BC_STATUS_EXEC_BAD_TYPE;
5968 s = bc_program_copyToVar(a->name, a->idx);
5972 for (; i < func->autos.len; ++i) {
5975 a = bc_vec_item(&func->autos, i);
5976 v = bc_program_search(a->name, a->idx);
5979 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5980 bc_vec_push(v, ¶m.n);
5983 bc_array_init(¶m.v, true);
5984 bc_vec_push(v, ¶m.v);
5988 bc_vec_push(&G.prog.stack, &ip);
5990 return BC_STATUS_SUCCESS;
5993 static BcStatus bc_program_return(char inst)
5999 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6001 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6002 return BC_STATUS_EXEC_STACK;
6004 f = bc_vec_item(&G.prog.fns, ip->func);
6005 res.t = BC_RESULT_TEMP;
6007 if (inst == BC_INST_RET) {
6010 BcResult *operand = bc_vec_top(&G.prog.results);
6012 s = bc_program_num(operand, &num, false);
6014 bc_num_init(&res.d.n, num->len);
6015 bc_num_copy(&res.d.n, num);
6018 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6019 bc_num_zero(&res.d.n);
6022 // We need to pop arguments as well, so this takes that into account.
6023 for (i = 0; i < f->autos.len; ++i) {
6026 BcId *a = bc_vec_item(&f->autos, i);
6028 v = bc_program_search(a->name, a->idx);
6032 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6033 bc_vec_push(&G.prog.results, &res);
6034 bc_vec_pop(&G.prog.stack);
6036 return BC_STATUS_SUCCESS;
6040 static unsigned long bc_program_scale(BcNum *n)
6042 return (unsigned long) n->rdx;
6045 static unsigned long bc_program_len(BcNum *n)
6047 unsigned long len = n->len;
6050 if (n->rdx != n->len) return len;
6051 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6056 static BcStatus bc_program_builtin(char inst)
6062 bool len = inst == BC_INST_LENGTH;
6064 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6065 opnd = bc_vec_top(&G.prog.results);
6067 s = bc_program_num(opnd, &num, false);
6071 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6074 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6076 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6078 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6079 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6083 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6086 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6088 str = bc_vec_item(&G.prog.strs, idx);
6089 bc_num_ulong2num(&res.d.n, strlen(*str));
6093 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6094 bc_num_ulong2num(&res.d.n, f(num));
6097 bc_program_retire(&res, BC_RESULT_TEMP);
6103 static BcStatus bc_program_divmod(void)
6106 BcResult *opd1, *opd2, res, res2;
6107 BcNum *n1, *n2 = NULL;
6109 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6112 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6113 bc_num_init(&res2.d.n, n2->len);
6115 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6118 bc_program_binOpRetire(&res2);
6119 res.t = BC_RESULT_TEMP;
6120 bc_vec_push(&G.prog.results, &res);
6125 bc_num_free(&res2.d.n);
6126 bc_num_free(&res.d.n);
6130 static BcStatus bc_program_modexp(void)
6133 BcResult *r1, *r2, *r3, res;
6134 BcNum *n1, *n2, *n3;
6136 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6137 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6140 r1 = bc_vec_item_rev(&G.prog.results, 2);
6141 s = bc_program_num(r1, &n1, false);
6143 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6145 // Make sure that the values have their pointers updated, if necessary.
6146 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6148 if (r1->t == r2->t) {
6149 s = bc_program_num(r2, &n2, false);
6153 if (r1->t == r3->t) {
6154 s = bc_program_num(r3, &n3, false);
6159 bc_num_init(&res.d.n, n3->len);
6160 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6163 bc_vec_pop(&G.prog.results);
6164 bc_program_binOpRetire(&res);
6169 bc_num_free(&res.d.n);
6173 static void bc_program_stackLen(void)
6176 size_t len = G.prog.results.len;
6178 res.t = BC_RESULT_TEMP;
6180 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6181 bc_num_ulong2num(&res.d.n, len);
6182 bc_vec_push(&G.prog.results, &res);
6185 static BcStatus bc_program_asciify(void)
6189 BcNum *num = NULL, n;
6190 char *str, *str2, c;
6191 size_t len = G.prog.strs.len, idx;
6194 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6195 r = bc_vec_top(&G.prog.results);
6197 s = bc_program_num(r, &num, false);
6200 if (BC_PROG_NUM(r, num)) {
6202 bc_num_init(&n, BC_NUM_DEF_SIZE);
6203 bc_num_copy(&n, num);
6204 bc_num_truncate(&n, n.rdx);
6206 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6207 if (s) goto num_err;
6208 s = bc_num_ulong(&n, &val);
6209 if (s) goto num_err;
6216 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6217 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6225 str2 = xstrdup(str);
6226 bc_program_addFunc(str2, &idx);
6228 if (idx != len + BC_PROG_REQ_FUNCS) {
6230 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6231 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6240 bc_vec_push(&G.prog.strs, &str);
6242 res.t = BC_RESULT_STR;
6244 bc_vec_pop(&G.prog.results);
6245 bc_vec_push(&G.prog.results, &res);
6247 return BC_STATUS_SUCCESS;
6254 static BcStatus bc_program_printStream(void)
6262 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6263 r = bc_vec_top(&G.prog.results);
6265 s = bc_program_num(r, &n, false);
6268 if (BC_PROG_NUM(r, n))
6269 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6271 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6272 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6279 static BcStatus bc_program_nquit(void)
6286 s = bc_program_prep(&opnd, &num);
6288 s = bc_num_ulong(num, &val);
6291 bc_vec_pop(&G.prog.results);
6293 if (G.prog.stack.len < val)
6294 return BC_STATUS_EXEC_STACK;
6295 else if (G.prog.stack.len == val)
6296 return BC_STATUS_QUIT;
6298 bc_vec_npop(&G.prog.stack, val);
6303 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6306 BcStatus s = BC_STATUS_SUCCESS;
6316 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6318 r = bc_vec_top(&G.prog.results);
6322 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6324 if (code[*bgn] == BC_PARSE_STREND)
6327 else_name = bc_program_name(code, bgn);
6329 exec = r->d.n.len != 0;
6333 else if (else_name != NULL) {
6340 v = bc_program_search(name, true);
6347 if (!exec) goto exit;
6348 if (!BC_PROG_STR(n)) {
6349 s = BC_STATUS_EXEC_BAD_TYPE;
6357 if (r->t == BC_RESULT_STR)
6359 else if (r->t == BC_RESULT_VAR) {
6360 s = bc_program_num(r, &n, false);
6361 if (s || !BC_PROG_STR(n)) goto exit;
6368 fidx = sidx + BC_PROG_REQ_FUNCS;
6370 str = bc_vec_item(&G.prog.strs, sidx);
6371 f = bc_vec_item(&G.prog.fns, fidx);
6373 if (f->code.len == 0) {
6374 common_parse_init(&prs, fidx);
6375 s = bc_parse_text(&prs, *str);
6377 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6380 if (prs.l.t.t != BC_LEX_EOF) {
6381 s = BC_STATUS_PARSE_BAD_EXP;
6385 bc_parse_free(&prs);
6389 ip.len = G.prog.results.len;
6392 bc_vec_pop(&G.prog.results);
6393 bc_vec_push(&G.prog.stack, &ip);
6395 return BC_STATUS_SUCCESS;
6398 bc_parse_free(&prs);
6399 f = bc_vec_item(&G.prog.fns, fidx);
6400 bc_vec_npop(&f->code, f->code.len);
6402 bc_vec_pop(&G.prog.results);
6407 static void bc_program_pushGlobal(char inst)
6412 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6413 if (inst == BC_INST_IBASE)
6414 val = (unsigned long) G.prog.ib_t;
6415 else if (inst == BC_INST_SCALE)
6416 val = (unsigned long) G.prog.scale;
6418 val = (unsigned long) G.prog.ob_t;
6420 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6421 bc_num_ulong2num(&res.d.n, val);
6422 bc_vec_push(&G.prog.results, &res);
6425 static void bc_program_addFunc(char *name, size_t *idx)
6428 BcId entry, *entry_ptr;
6432 entry.idx = G.prog.fns.len;
6434 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6437 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6438 *idx = entry_ptr->idx;
6440 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6442 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6444 // We need to reset these, so the function can be repopulated.
6446 bc_vec_npop(&func->autos, func->autos.len);
6447 bc_vec_npop(&func->code, func->code.len);
6448 bc_vec_npop(&func->labels, func->labels.len);
6452 bc_vec_push(&G.prog.fns, &f);
6456 static BcStatus bc_program_reset(BcStatus s)
6461 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6462 bc_vec_npop(&G.prog.results, G.prog.results.len);
6464 f = bc_vec_item(&G.prog.fns, 0);
6465 ip = bc_vec_top(&G.prog.stack);
6466 ip->idx = f->code.len;
6468 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6470 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6473 fputs(bc_program_ready_msg, stderr);
6475 s = BC_STATUS_SUCCESS;
6484 static BcStatus bc_program_exec(void)
6486 BcStatus s = BC_STATUS_SUCCESS;
6490 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6491 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6492 char *code = func->code.v;
6495 while (!s && ip->idx < func->code.len) {
6497 char inst = code[(ip->idx)++];
6502 case BC_INST_JUMP_ZERO:
6504 s = bc_program_prep(&ptr, &num);
6506 cond = !bc_num_cmp(num, &G.prog.zero);
6507 bc_vec_pop(&G.prog.results);
6513 idx = bc_program_index(code, &ip->idx);
6514 addr = bc_vec_item(&func->labels, idx);
6515 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6521 s = bc_program_call(code, &ip->idx);
6525 case BC_INST_INC_PRE:
6526 case BC_INST_DEC_PRE:
6527 case BC_INST_INC_POST:
6528 case BC_INST_DEC_POST:
6530 s = bc_program_incdec(inst);
6543 s = bc_program_return(inst);
6547 case BC_INST_BOOL_OR:
6548 case BC_INST_BOOL_AND:
6550 case BC_INST_REL_EQ:
6551 case BC_INST_REL_LE:
6552 case BC_INST_REL_GE:
6553 case BC_INST_REL_NE:
6554 case BC_INST_REL_LT:
6555 case BC_INST_REL_GT:
6557 s = bc_program_logical(inst);
6563 s = bc_program_read();
6569 s = bc_program_pushVar(code, &ip->idx, false, false);
6573 case BC_INST_ARRAY_ELEM:
6576 s = bc_program_pushArray(code, &ip->idx, inst);
6582 r.t = BC_RESULT_LAST;
6583 bc_vec_push(&G.prog.results, &r);
6591 bc_program_pushGlobal(inst);
6595 case BC_INST_SCALE_FUNC:
6596 case BC_INST_LENGTH:
6599 s = bc_program_builtin(inst);
6605 r.t = BC_RESULT_CONSTANT;
6606 r.d.id.idx = bc_program_index(code, &ip->idx);
6607 bc_vec_push(&G.prog.results, &r);
6613 if (!BC_PROG_STACK(&G.prog.results, 1))
6614 s = BC_STATUS_EXEC_STACK;
6616 bc_vec_pop(&G.prog.results);
6620 case BC_INST_POP_EXEC:
6622 bc_vec_pop(&G.prog.stack);
6627 case BC_INST_PRINT_POP:
6628 case BC_INST_PRINT_STR:
6630 s = bc_program_print(inst, 0);
6636 r.t = BC_RESULT_STR;
6637 r.d.id.idx = bc_program_index(code, &ip->idx);
6638 bc_vec_push(&G.prog.results, &r);
6643 case BC_INST_MULTIPLY:
6644 case BC_INST_DIVIDE:
6645 case BC_INST_MODULUS:
6649 s = bc_program_op(inst);
6653 case BC_INST_BOOL_NOT:
6655 s = bc_program_prep(&ptr, &num);
6658 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6659 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6660 bc_program_retire(&r, BC_RESULT_TEMP);
6667 s = bc_program_negate();
6672 case BC_INST_ASSIGN_POWER:
6673 case BC_INST_ASSIGN_MULTIPLY:
6674 case BC_INST_ASSIGN_DIVIDE:
6675 case BC_INST_ASSIGN_MODULUS:
6676 case BC_INST_ASSIGN_PLUS:
6677 case BC_INST_ASSIGN_MINUS:
6679 case BC_INST_ASSIGN:
6681 s = bc_program_assign(inst);
6685 case BC_INST_MODEXP:
6687 s = bc_program_modexp();
6691 case BC_INST_DIVMOD:
6693 s = bc_program_divmod();
6697 case BC_INST_EXECUTE:
6698 case BC_INST_EXEC_COND:
6700 cond = inst == BC_INST_EXEC_COND;
6701 s = bc_program_execStr(code, &ip->idx, cond);
6705 case BC_INST_PRINT_STACK:
6707 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6708 s = bc_program_print(BC_INST_PRINT, idx);
6712 case BC_INST_CLEAR_STACK:
6714 bc_vec_npop(&G.prog.results, G.prog.results.len);
6718 case BC_INST_STACK_LEN:
6720 bc_program_stackLen();
6724 case BC_INST_DUPLICATE:
6726 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6727 ptr = bc_vec_top(&G.prog.results);
6728 bc_result_copy(&r, ptr);
6729 bc_vec_push(&G.prog.results, &r);
6737 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6739 ptr = bc_vec_item_rev(&G.prog.results, 0);
6740 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6741 memcpy(&r, ptr, sizeof(BcResult));
6742 memcpy(ptr, ptr2, sizeof(BcResult));
6743 memcpy(ptr2, &r, sizeof(BcResult));
6748 case BC_INST_ASCIIFY:
6750 s = bc_program_asciify();
6754 case BC_INST_PRINT_STREAM:
6756 s = bc_program_printStream();
6761 case BC_INST_PUSH_VAR:
6763 bool copy = inst == BC_INST_LOAD;
6764 s = bc_program_pushVar(code, &ip->idx, true, copy);
6768 case BC_INST_PUSH_TO_VAR:
6770 char *name = bc_program_name(code, &ip->idx);
6771 s = bc_program_copyToVar(name, true);
6778 if (G.prog.stack.len <= 2)
6781 bc_vec_npop(&G.prog.stack, 2);
6787 s = bc_program_nquit();
6793 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
6795 // If the stack has changed, pointers may be invalid.
6796 ip = bc_vec_top(&G.prog.stack);
6797 func = bc_vec_item(&G.prog.fns, ip->func);
6798 code = func->code.v;
6804 static void bc_vm_info(void)
6806 printf("%s "BB_VER"\n"
6807 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6808 "Report bugs at: https://github.com/gavinhoward/bc\n"
6809 "This is free software with ABSOLUTELY NO WARRANTY\n"
6813 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6815 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6817 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6818 fprintf(stderr, " %s", file);
6819 fprintf(stderr, bc_err_line + 4 * !line, line);
6821 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6825 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6830 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6831 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6833 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6834 fprintf(stderr, fmt, bc_err_msgs[s]);
6835 if (msg) fprintf(stderr, " %s\n", msg);
6836 fprintf(stderr, " %s", file);
6837 fprintf(stderr, bc_err_line + 4 * !line, line);
6839 if (G.ttyin || !G_posix)
6840 s = BC_STATUS_SUCCESS;
6844 static void bc_vm_envArgs(void)
6846 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6849 char *env_args = getenv(bc_args_env_name), *buf;
6851 if (!env_args) return;
6853 G.env_args = xstrdup(env_args);
6856 bc_vec_init(&v, sizeof(char *), NULL);
6857 bc_vec_push(&v, &bc_args_env_name);
6860 if (!isspace(*buf)) {
6861 bc_vec_push(&v, &buf);
6862 while (*buf != 0 && !isspace(*buf)) ++buf;
6863 if (*buf != 0) (*(buf++)) = '\0';
6869 bc_args((int) v.len, (char **) v.v);
6875 static size_t bc_vm_envLen(const char *var)
6877 char *lenv = getenv(var);
6878 size_t i, len = BC_NUM_PRINT_WIDTH;
6881 if (!lenv) return len;
6885 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6887 len = (size_t) atoi(lenv) - 1;
6888 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6891 len = BC_NUM_PRINT_WIDTH;
6896 static BcStatus bc_vm_process(const char *text)
6898 BcStatus s = bc_parse_text(&G.prs, text);
6900 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6903 while (G.prs.l.t.t != BC_LEX_EOF) {
6905 s = G.prs.parse(&G.prs);
6907 if (s == BC_STATUS_LIMITS) {
6909 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
6910 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
6911 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
6912 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
6913 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
6914 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
6915 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
6916 printf("Number of vars = %lu\n", BC_MAX_VARS);
6918 s = BC_STATUS_SUCCESS;
6921 if (s == BC_STATUS_QUIT) return s;
6922 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6927 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6928 s = bc_program_exec();
6929 if (!s && G.tty) fflush(stdout);
6930 if (s && s != BC_STATUS_QUIT)
6931 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6937 static BcStatus bc_vm_file(const char *file)
6945 data = bc_read_file(file);
6946 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
6948 bc_lex_file(&G.prs.l, file);
6949 s = bc_vm_process(data);
6952 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6953 ip = bc_vec_item(&G.prog.stack, 0);
6955 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6962 static BcStatus bc_vm_stdin(void)
6966 size_t len, i, str = 0;
6967 bool comment = false;
6969 G.prog.file = bc_program_stdin_name;
6970 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6972 bc_vec_init(&buffer, sizeof(char), NULL);
6973 bc_vec_init(&buf, sizeof(char), NULL);
6974 bc_vec_pushByte(&buffer, '\0');
6976 // This loop is complex because the vm tries not to send any lines that end
6977 // with a backslash to the parser. The reason for that is because the parser
6978 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6979 // case, and for strings and comments, the parser will expect more stuff.
6980 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6982 char *string = buf.v;
6987 if (str && buf.v[0] == G.send)
6989 else if (buf.v[0] == G.sbgn)
6992 else if (len > 1 || comment) {
6994 for (i = 0; i < len; ++i) {
6996 bool notend = len > i + 1;
6999 if (i - 1 > len || string[i - 1] != '\\') {
7000 if (G.sbgn == G.send)
7002 else if (c == G.send)
7004 else if (c == G.sbgn)
7008 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7012 else if (c == '*' && notend && comment && string[i + 1] == '/')
7016 if (str || comment || string[len - 2] == '\\') {
7017 bc_vec_concat(&buffer, buf.v);
7022 bc_vec_concat(&buffer, buf.v);
7023 s = bc_vm_process(buffer.v);
7026 bc_vec_npop(&buffer, buffer.len);
7029 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7031 // INPUT_EOF will always happen when stdin is
7032 // closed. It's not a problem in that case.
7033 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7034 s = BC_STATUS_SUCCESS;
7037 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7040 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7045 bc_vec_free(&buffer);
7049 static BcStatus bc_vm_exec(void)
7051 BcStatus s = BC_STATUS_SUCCESS;
7055 if (G.flags & BC_FLAG_L) {
7057 bc_lex_file(&G.prs.l, bc_lib_name);
7058 s = bc_parse_text(&G.prs, bc_lib);
7060 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7063 s = bc_program_exec();
7068 for (i = 0; !s && i < G.files.len; ++i)
7069 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7070 if (s && s != BC_STATUS_QUIT) return s;
7072 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7073 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7075 if (s == BC_STATUS_QUIT)
7076 s = BC_STATUS_SUCCESS;
7080 #if ENABLE_FEATURE_CLEAN_UP
7081 static void bc_program_free()
7083 bc_num_free(&G.prog.ib);
7084 bc_num_free(&G.prog.ob);
7085 bc_num_free(&G.prog.hexb);
7087 bc_num_free(&G.prog.strmb);
7089 bc_vec_free(&G.prog.fns);
7090 bc_vec_free(&G.prog.fn_map);
7091 bc_vec_free(&G.prog.vars);
7092 bc_vec_free(&G.prog.var_map);
7093 bc_vec_free(&G.prog.arrs);
7094 bc_vec_free(&G.prog.arr_map);
7095 bc_vec_free(&G.prog.strs);
7096 bc_vec_free(&G.prog.consts);
7097 bc_vec_free(&G.prog.results);
7098 bc_vec_free(&G.prog.stack);
7099 bc_num_free(&G.prog.last);
7100 bc_num_free(&G.prog.zero);
7101 bc_num_free(&G.prog.one);
7104 static void bc_vm_free(void)
7106 bc_vec_free(&G.files);
7108 bc_parse_free(&G.prs);
7113 static void bc_program_init(size_t line_len)
7118 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7119 memset(&ip, 0, sizeof(BcInstPtr));
7121 /* G.prog.nchars = G.prog.scale = 0; - already is */
7122 G.prog.len = line_len;
7124 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7125 bc_num_ten(&G.prog.ib);
7128 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7129 bc_num_ten(&G.prog.ob);
7132 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7133 bc_num_ten(&G.prog.hexb);
7134 G.prog.hexb.num[0] = 6;
7137 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7138 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7141 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7142 bc_num_zero(&G.prog.last);
7144 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7145 bc_num_zero(&G.prog.zero);
7147 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7148 bc_num_one(&G.prog.one);
7150 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7151 bc_map_init(&G.prog.fn_map);
7153 bc_program_addFunc(xstrdup("(main)"), &idx);
7154 bc_program_addFunc(xstrdup("(read)"), &idx);
7156 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7157 bc_map_init(&G.prog.var_map);
7159 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7160 bc_map_init(&G.prog.arr_map);
7162 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7163 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7164 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7165 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7166 bc_vec_push(&G.prog.stack, &ip);
7169 static void bc_vm_init(const char *env_len)
7171 size_t len = bc_vm_envLen(env_len);
7173 #if ENABLE_FEATURE_BC_SIGNALS
7174 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7177 bc_vec_init(&G.files, sizeof(char *), NULL);
7180 if (getenv("POSIXLY_CORRECT"))
7181 G.flags |= BC_FLAG_S;
7185 bc_program_init(len);
7187 bc_parse_init(&G.prs, BC_PROG_MAIN);
7189 dc_parse_init(&G.prs, BC_PROG_MAIN);
7193 static BcStatus bc_vm_run(int argc, char *argv[],
7194 const char *env_len)
7198 bc_vm_init(env_len);
7199 bc_args(argc, argv);
7201 G.ttyin = isatty(0);
7202 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7204 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7207 #if ENABLE_FEATURE_CLEAN_UP
7214 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7215 int bc_main(int argc, char **argv)
7218 G.sbgn = G.send = '"';
7220 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7225 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7226 int dc_main(int argc, char **argv)
7232 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");