1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //usage:#define bc_trivial_usage
118 //usage: "EXPRESSION...\n"
119 //usage: "function_definition\n"
121 //usage:#define bc_full_usage "\n\n"
122 //usage: "See www.gnu.org/software/bc/manual/bc.html\n"
124 //usage:#define bc_example_usage
125 //usage: "3 + 4.129\n"
126 //usage: "1903 - 2893\n"
127 //usage: "-129 * 213.28935\n"
128 //usage: "12 / -1932\n"
130 //usage: "34 ^ 189\n"
131 //usage: "scale = 13\n"
132 //usage: "ibase = 2\n"
133 //usage: "obase = A\n"
135 //usage:#define dc_trivial_usage
136 //usage: "EXPRESSION..."
138 //usage:#define dc_full_usage "\n\n"
139 //usage: "Tiny RPN calculator. Operations:\n"
140 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141 //usage: "modular exponentiation,\n"
142 //usage: "p - print top of the stack (without popping),\n"
143 //usage: "f - print entire stack,\n"
144 //usage: "k - pop the value and set the precision.\n"
145 //usage: "i - pop the value and set input radix.\n"
146 //usage: "o - pop the value and set output radix.\n"
147 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
149 //usage:#define dc_example_usage
150 //usage: "$ dc 2 2 + p\n"
152 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
154 //usage: "$ dc 0 1 and p\n"
156 //usage: "$ dc 0 1 or p\n"
158 //usage: "$ echo 72 9 div 8 mul p | dc\n"
163 typedef enum BcStatus {
170 BC_STATUS_PATH_IS_DIR,
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
177 BC_STATUS_LEX_EXTENDED_REG,
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
234 BC_STATUS_INVALID_OPTION,
238 #define BC_ERR_IDX_VM (0)
239 #define BC_ERR_IDX_LEX (1)
240 #define BC_ERR_IDX_PARSE (2)
241 #define BC_ERR_IDX_MATH (3)
242 #define BC_ERR_IDX_EXEC (4)
243 #define BC_ERR_IDX_VEC (5)
245 #define BC_ERR_IDX_POSIX (6)
248 #define BC_VEC_INVALID_IDX ((size_t) -1)
249 #define BC_VEC_START_CAP (1 << 5)
251 typedef void (*BcVecFree)(void *);
253 typedef struct BcVec {
261 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
262 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
264 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
266 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
268 typedef signed char BcDig;
270 typedef struct BcNum {
278 #define BC_NUM_MIN_BASE ((unsigned long) 2)
279 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
280 #define BC_NUM_DEF_SIZE (16)
281 #define BC_NUM_PRINT_WIDTH (69)
283 #define BC_NUM_KARATSUBA_LEN (32)
285 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
286 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
287 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
288 #define BC_NUM_AREQ(a, b) \
289 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
290 #define BC_NUM_MREQ(a, b, scale) \
291 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
293 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
294 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
296 static void bc_num_init(BcNum *n, size_t req);
297 static void bc_num_expand(BcNum *n, size_t req);
298 static void bc_num_copy(BcNum *d, BcNum *s);
299 static void bc_num_free(void *num);
301 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
302 static void bc_num_ulong2num(BcNum *n, unsigned long val);
304 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
311 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
314 typedef enum BcInst {
344 BC_INST_ASSIGN_POWER,
345 BC_INST_ASSIGN_MULTIPLY,
346 BC_INST_ASSIGN_DIVIDE,
347 BC_INST_ASSIGN_MODULUS,
349 BC_INST_ASSIGN_MINUS,
395 BC_INST_PRINT_STREAM,
410 BC_INST_INVALID = -1,
415 typedef struct BcId {
420 typedef struct BcFunc {
427 typedef enum BcResultType {
432 BC_RESULT_ARRAY_ELEM,
441 // These are between to calculate ibase, obase, and last from instructions.
449 typedef union BcResultData {
455 typedef struct BcResult {
460 typedef struct BcInstPtr {
466 static void bc_array_expand(BcVec *a, size_t len);
467 static int bc_id_cmp(const void *e1, const void *e2);
469 // BC_LEX_NEG is not used in lexing; it is only for parsing.
470 typedef enum BcLexType {
498 BC_LEX_OP_ASSIGN_POWER,
499 BC_LEX_OP_ASSIGN_MULTIPLY,
500 BC_LEX_OP_ASSIGN_DIVIDE,
501 BC_LEX_OP_ASSIGN_MODULUS,
502 BC_LEX_OP_ASSIGN_PLUS,
503 BC_LEX_OP_ASSIGN_MINUS,
577 typedef BcStatus (*BcLexNext)(struct BcLex *);
579 typedef struct BcLex {
598 #define BC_PARSE_STREND ((char) UCHAR_MAX)
600 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
601 #define bc_parse_updateFunc(p, f) \
602 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
604 #define BC_PARSE_REL (1 << 0)
605 #define BC_PARSE_PRINT (1 << 1)
606 #define BC_PARSE_NOCALL (1 << 2)
607 #define BC_PARSE_NOREAD (1 << 3)
608 #define BC_PARSE_ARRAY (1 << 4)
610 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
611 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
613 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
614 #define BC_PARSE_FUNC_INNER(parse) \
615 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
617 #define BC_PARSE_FLAG_FUNC (1 << 1)
618 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
620 #define BC_PARSE_FLAG_BODY (1 << 2)
621 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
623 #define BC_PARSE_FLAG_LOOP (1 << 3)
624 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
626 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
627 #define BC_PARSE_LOOP_INNER(parse) \
628 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
630 #define BC_PARSE_FLAG_IF (1 << 5)
631 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
633 #define BC_PARSE_FLAG_ELSE (1 << 6)
634 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
636 #define BC_PARSE_FLAG_IF_END (1 << 7)
637 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
639 #define BC_PARSE_CAN_EXEC(parse) \
640 (!(BC_PARSE_TOP_FLAG(parse) & \
641 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
642 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
643 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
645 typedef struct BcOp {
650 typedef struct BcParseNext {
655 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
656 #define BC_PARSE_NEXT(a, ...) \
658 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
665 typedef BcStatus (*BcParseParse)(struct BcParse *);
667 typedef struct BcParse {
690 typedef struct BcLexKeyword {
696 #define BC_LEX_KW_ENTRY(a, b, c) \
698 .name = a, .len = (b), .posix = (c) \
701 static BcStatus bc_lex_token(BcLex *l);
703 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
704 #define BC_PARSE_LEAF(p, rparen) \
705 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
706 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
708 // We can calculate the conversion between tokens and exprs by subtracting the
709 // position of the first operator in the lex enum and adding the position of the
710 // first in the expr enum. Note: This only works for binary operators.
711 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
713 static BcStatus bc_parse_parse(BcParse *p);
714 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
720 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
722 static BcStatus dc_lex_token(BcLex *l);
724 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
728 typedef struct BcProgram {
769 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
771 #define BC_PROG_MAIN (0)
772 #define BC_PROG_READ (1)
775 #define BC_PROG_REQ_FUNCS (2)
778 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
779 #define BC_PROG_NUM(r, n) \
780 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
782 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
784 static void bc_program_addFunc(char *name, size_t *idx);
785 static BcStatus bc_program_reset(BcStatus s);
787 #define BC_FLAG_X (1 << 0)
788 #define BC_FLAG_W (1 << 1)
789 #define BC_FLAG_V (1 << 2)
790 #define BC_FLAG_S (1 << 3)
791 #define BC_FLAG_Q (1 << 4)
792 #define BC_FLAG_L (1 << 5)
793 #define BC_FLAG_I (1 << 6)
795 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
796 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
798 #define BC_MAX_OBASE ((unsigned long) 999)
799 #define BC_MAX_DIM ((unsigned long) INT_MAX)
800 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
801 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
802 #define BC_MAX_NAME BC_MAX_STRING
803 #define BC_MAX_NUM BC_MAX_STRING
804 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
805 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
822 #define G (*ptr_to_globals)
823 #define INIT_G() do { \
824 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
826 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
827 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
828 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
829 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
832 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
835 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
839 static void bc_vm_info(void);
841 static const char* const bc_args_env_name = "BC_ENV_ARGS";
843 static const char bc_err_fmt[] = "\n%s error: %s\n";
844 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
845 static const char bc_err_line[] = ":%zu\n\n";
847 static const char *bc_errs[] = {
859 static const uint8_t bc_err_ids[] = {
860 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
861 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
865 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
866 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
867 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
872 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
873 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
874 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
875 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
877 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
879 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
880 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
881 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
883 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
886 static const char *bc_err_msgs[] = {
889 "memory allocation error",
892 "path is a directory:",
895 "string end could not be found",
896 "comment end could not be found",
905 "bad print statement",
906 "bad function definition",
907 "bad assignment: left side must be scale, ibase, "
908 "obase, last, var, or array element",
909 "no auto variable found",
910 "function parameter or auto var has the same name as another",
911 "block end could not be found",
914 "non integer number",
919 "could not open file:",
920 "mismatched parameters",
921 "undefined function",
922 "file is not executable:",
923 "number too long: must be [1, BC_NUM_MAX]",
924 "name too long: must be [1, BC_NAME_MAX]",
925 "string too long: must be [1, BC_STRING_MAX]",
926 "array too long; must be [1, BC_DIM_MAX]",
927 "bad ibase; must be [2, 16]",
928 "bad scale; must be [0, BC_SCALE_MAX]",
929 "bad read() expression",
930 "read() call inside of a read() call",
931 "variable is wrong type",
932 "bad obase; must be [2, BC_BASE_MAX]",
933 "signal caught and not handled",
934 "stack has too few elements",
936 "index is out of bounds",
937 "item already exists",
940 "POSIX only allows one character names; the following is bad:",
941 "POSIX does not allow '#' script comments",
942 "POSIX does not allow the following keyword:",
943 "POSIX does not allow a period ('.') as a shortcut for the last result",
944 "POSIX requires parentheses around return expressions",
945 "POSIX does not allow boolean operators; the following is bad:",
946 "POSIX does not allow comparison operators outside if or loops",
947 "POSIX requires exactly one comparison operator per condition",
948 "POSIX does not allow an empty init expression in a for loop",
949 "POSIX does not allow an empty condition expression in a for loop",
950 "POSIX does not allow an empty update expression in a for loop",
951 "POSIX requires the left brace be on the same line as the function header",
956 static const char bc_func_main[] = "(main)";
957 static const char bc_func_read[] = "(read)";
960 static const BcLexKeyword bc_lex_kws[20] = {
961 BC_LEX_KW_ENTRY("auto", 4, true),
962 BC_LEX_KW_ENTRY("break", 5, true),
963 BC_LEX_KW_ENTRY("continue", 8, false),
964 BC_LEX_KW_ENTRY("define", 6, true),
965 BC_LEX_KW_ENTRY("else", 4, false),
966 BC_LEX_KW_ENTRY("for", 3, true),
967 BC_LEX_KW_ENTRY("halt", 4, false),
968 BC_LEX_KW_ENTRY("ibase", 5, true),
969 BC_LEX_KW_ENTRY("if", 2, true),
970 BC_LEX_KW_ENTRY("last", 4, false),
971 BC_LEX_KW_ENTRY("length", 6, true),
972 BC_LEX_KW_ENTRY("limits", 6, false),
973 BC_LEX_KW_ENTRY("obase", 5, true),
974 BC_LEX_KW_ENTRY("print", 5, false),
975 BC_LEX_KW_ENTRY("quit", 4, true),
976 BC_LEX_KW_ENTRY("read", 4, false),
977 BC_LEX_KW_ENTRY("return", 6, true),
978 BC_LEX_KW_ENTRY("scale", 5, true),
979 BC_LEX_KW_ENTRY("sqrt", 4, true),
980 BC_LEX_KW_ENTRY("while", 5, true),
983 // This is an array that corresponds to token types. An entry is
984 // true if the token is valid in an expression, false otherwise.
985 static const bool bc_parse_exprs[] = {
986 false, false, true, true, true, true, true, true, true, true, true, true,
987 true, true, true, true, true, true, true, true, true, true, true, true,
988 true, true, true, false, false, true, true, false, false, false, false,
989 false, false, false, true, true, false, false, false, false, false, false,
990 false, true, false, true, true, true, true, false, false, true, false, true,
994 // This is an array of data for operators that correspond to token types.
995 static const BcOp bc_parse_ops[] = {
996 { 0, false }, { 0, false },
999 { 3, true }, { 3, true }, { 3, true },
1000 { 4, true }, { 4, true },
1001 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1003 { 7, true }, { 7, true },
1004 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1005 { 5, false }, { 5, false },
1008 // These identify what tokens can come after expressions in certain cases.
1009 static const BcParseNext bc_parse_next_expr =
1010 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1011 static const BcParseNext bc_parse_next_param =
1012 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1013 static const BcParseNext bc_parse_next_print =
1014 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1015 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1016 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1017 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1018 static const BcParseNext bc_parse_next_read =
1019 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1023 static const BcLexType dc_lex_regs[] = {
1024 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1025 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1026 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1030 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1032 static const BcLexType dc_lex_tokens[] = {
1033 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1034 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1035 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1036 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1037 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1038 BC_LEX_INVALID, BC_LEX_INVALID,
1039 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1040 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1041 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1042 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1043 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1044 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1045 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1046 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1047 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1048 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1049 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1050 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1051 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1052 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1053 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1054 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1055 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1056 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1060 static const BcInst dc_parse_insts[] = {
1061 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1062 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1063 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1064 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1065 BC_INST_INVALID, BC_INST_INVALID,
1066 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1067 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1069 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1070 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1071 BC_INST_INVALID, BC_INST_INVALID,
1072 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1075 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1076 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1078 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1080 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1081 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1087 static const BcNumBinaryOp bc_program_ops[] = {
1088 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1091 static const char bc_program_stdin_name[] = "<stdin>";
1092 static const char bc_program_ready_msg[] = "ready for more input\n";
1095 static const char *bc_lib_name = "gen/lib.bc";
1097 static const char bc_lib[] = {
1098 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1099 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1100 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1101 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,
1102 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1103 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1104 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,
1105 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1106 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1107 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,
1108 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1109 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1110 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1111 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1112 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1113 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1114 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1115 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1116 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1117 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1118 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1119 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1120 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1121 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,
1122 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1123 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,
1124 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1125 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1126 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1127 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1128 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1129 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,
1130 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1131 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1132 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1133 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1134 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,
1135 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1136 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1137 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1138 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1139 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1140 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1141 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1142 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1143 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1144 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1145 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,
1146 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,
1147 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1148 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,
1149 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,
1150 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,
1151 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1152 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1153 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,
1154 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,
1155 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,
1156 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1157 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,
1158 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1159 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1160 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1161 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,
1162 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1163 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1164 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1165 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1166 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1167 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1168 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1169 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1170 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1171 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1172 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1173 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1174 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1175 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1176 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1177 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1181 static void bc_vec_grow(BcVec *v, size_t n)
1183 size_t cap = v->cap * 2;
1184 while (cap < v->len + n) cap *= 2;
1185 v->v = xrealloc(v->v, v->size * cap);
1189 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1192 v->cap = BC_VEC_START_CAP;
1195 v->v = xmalloc(esize * BC_VEC_START_CAP);
1198 static void bc_vec_expand(BcVec *v, size_t req)
1201 v->v = xrealloc(v->v, v->size * req);
1206 static void bc_vec_npop(BcVec *v, size_t n)
1211 size_t len = v->len - n;
1212 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1216 static void bc_vec_push(BcVec *v, const void *data)
1218 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1219 memmove(v->v + (v->size * v->len), data, v->size);
1223 static void bc_vec_pushByte(BcVec *v, char data)
1225 bc_vec_push(v, &data);
1228 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1231 bc_vec_push(v, data);
1236 if (v->len == v->cap) bc_vec_grow(v, 1);
1238 ptr = v->v + v->size * idx;
1240 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1241 memmove(ptr, data, v->size);
1245 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1247 bc_vec_npop(v, v->len);
1248 bc_vec_expand(v, len + 1);
1249 memcpy(v->v, str, len);
1252 bc_vec_pushByte(v, '\0');
1255 static void bc_vec_concat(BcVec *v, const char *str)
1259 if (v->len == 0) bc_vec_pushByte(v, '\0');
1261 len = v->len + strlen(str);
1263 if (v->cap < len) bc_vec_grow(v, len - v->len);
1269 static void *bc_vec_item(const BcVec *v, size_t idx)
1271 return v->v + v->size * idx;
1274 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1276 return v->v + v->size * (v->len - idx - 1);
1279 static void bc_vec_free(void *vec)
1281 BcVec *v = (BcVec *) vec;
1282 bc_vec_npop(v, v->len);
1286 static size_t bc_map_find(const BcVec *v, const void *ptr)
1288 size_t low = 0, high = v->len;
1290 while (low < high) {
1292 size_t mid = (low + high) / 2;
1293 BcId *id = bc_vec_item(v, mid);
1294 int result = bc_id_cmp(ptr, id);
1298 else if (result < 0)
1307 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1309 BcStatus s = BC_STATUS_SUCCESS;
1311 *i = bc_map_find(v, ptr);
1314 bc_vec_push(v, ptr);
1315 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1316 s = BC_STATUS_VEC_ITEM_EXISTS;
1318 bc_vec_pushAt(v, ptr, *i);
1323 static size_t bc_map_index(const BcVec *v, const void *ptr)
1325 size_t i = bc_map_find(v, ptr);
1326 if (i >= v->len) return BC_VEC_INVALID_IDX;
1327 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1330 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1335 bc_vec_npop(vec, vec->len);
1338 #if ENABLE_FEATURE_BC_SIGNALS
1339 if (bb_got_signal) { /* ^C was pressed */
1341 bb_got_signal = 0; /* resets G_interrupt to zero */
1343 ? "\ninterrupt (type \"quit\" to exit)\n"
1344 : "\ninterrupt (type \"q\" to exit)\n"
1348 if (G.ttyin && !G_posix)
1349 fputs(prompt, stderr);
1352 #if ENABLE_FEATURE_BC_SIGNALS
1357 if (ferror(stdout) || ferror(stderr))
1358 bb_perror_msg_and_die("output error");
1362 #if ENABLE_FEATURE_BC_SIGNALS
1363 if (bb_got_signal) /* ^C was pressed */
1368 #if ENABLE_FEATURE_BC_SIGNALS
1369 if (errno == EINTR) {
1375 bb_perror_msg_and_die("input error");
1376 return BC_STATUS_INPUT_EOF;
1379 c = (signed char) i;
1380 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1381 bc_vec_push(vec, &c);
1382 } while (c != '\n');
1384 bc_vec_pushByte(vec, '\0');
1386 return BC_STATUS_SUCCESS;
1389 static char* bc_read_file(const char *path)
1392 size_t size = ((size_t) -1);
1395 buf = xmalloc_open_read_close(path, &size);
1397 for (i = 0; i < size; ++i) {
1398 if (BC_READ_BIN_CHAR(buf[i])) {
1408 static void bc_args(int argc, char **argv)
1413 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1414 G.flags = getopt32long(argv, "xwvsqli",
1415 "extended-register\0" No_argument "x"
1416 "warn\0" No_argument "w"
1417 "version\0" No_argument "v"
1418 "standard\0" No_argument "s"
1419 "quiet\0" No_argument "q"
1420 "mathlib\0" No_argument "l"
1421 "interactive\0" No_argument "i"
1424 G.flags = getopt32(argv, "xwvsqli");
1427 if (G.flags & BC_FLAG_V) bc_vm_info();
1428 // should not be necessary, getopt32() handles this??
1429 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1431 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1434 static void bc_num_setToZero(BcNum *n, size_t scale)
1441 static void bc_num_zero(BcNum *n)
1443 bc_num_setToZero(n, 0);
1446 static void bc_num_one(BcNum *n)
1448 bc_num_setToZero(n, 0);
1453 static void bc_num_ten(BcNum *n)
1455 bc_num_setToZero(n, 0);
1461 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1465 for (i = 0; i < len; ++i) {
1466 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1473 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1477 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1478 return BC_NUM_NEG(i + 1, c < 0);
1481 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1483 size_t i, min, a_int, b_int, diff;
1484 BcDig *max_num, *min_num;
1485 bool a_max, neg = false;
1488 if (a == b) return 0;
1489 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1490 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1500 a_int = BC_NUM_INT(a);
1501 b_int = BC_NUM_INT(b);
1503 a_max = (a->rdx > b->rdx);
1505 if (a_int != 0) return (ssize_t) a_int;
1509 diff = a->rdx - b->rdx;
1510 max_num = a->num + diff;
1515 diff = b->rdx - a->rdx;
1516 max_num = b->num + diff;
1520 cmp = bc_num_compare(max_num, min_num, b_int + min);
1521 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1523 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1524 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1530 static void bc_num_truncate(BcNum *n, size_t places)
1532 if (places == 0) return;
1538 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1542 static void bc_num_extend(BcNum *n, size_t places)
1544 size_t len = n->len + places;
1548 if (n->cap < len) bc_num_expand(n, len);
1550 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1551 memset(n->num, 0, sizeof(BcDig) * places);
1558 static void bc_num_clean(BcNum *n)
1560 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1563 else if (n->len < n->rdx)
1567 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1570 bc_num_extend(n, scale - n->rdx);
1572 bc_num_truncate(n, n->rdx - scale);
1575 if (n->len != 0) n->neg = !neg1 != !neg2;
1578 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1583 b->len = n->len - idx;
1585 a->rdx = b->rdx = 0;
1587 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1588 memcpy(a->num, n->num, idx * sizeof(BcDig));
1599 static BcStatus bc_num_shift(BcNum *n, size_t places)
1601 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1602 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1604 if (n->rdx >= places)
1607 bc_num_extend(n, places - n->rdx);
1613 return BC_STATUS_SUCCESS;
1616 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1625 return bc_num_div(&one, a, b, scale);
1628 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1630 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1631 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1634 // Because this function doesn't need to use scale (per the bc spec),
1635 // I am hijacking it to say whether it's doing an add or a subtract.
1639 if (sub && c->len) c->neg = !c->neg;
1640 return BC_STATUS_SUCCESS;
1642 else if (b->len == 0) {
1644 return BC_STATUS_SUCCESS;
1648 c->rdx = BC_MAX(a->rdx, b->rdx);
1649 min_rdx = BC_MIN(a->rdx, b->rdx);
1652 if (a->rdx > b->rdx) {
1653 diff = a->rdx - b->rdx;
1655 ptr_a = a->num + diff;
1659 diff = b->rdx - a->rdx;
1662 ptr_b = b->num + diff;
1665 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1668 a_int = BC_NUM_INT(a);
1669 b_int = BC_NUM_INT(b);
1671 if (a_int > b_int) {
1682 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1683 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1685 ptr_c[i] = (BcDig)(in % 10);
1688 for (; i < max + min_rdx; ++i, ++c->len) {
1689 in = ((int) ptr[i]) + carry;
1691 ptr_c[i] = (BcDig)(in % 10);
1694 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1696 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1699 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1702 BcNum *minuend, *subtrahend;
1704 bool aneg, bneg, neg;
1706 // Because this function doesn't need to use scale (per the bc spec),
1707 // I am hijacking it to say whether it's doing an add or a subtract.
1711 if (sub && c->len) c->neg = !c->neg;
1712 return BC_STATUS_SUCCESS;
1714 else if (b->len == 0) {
1716 return BC_STATUS_SUCCESS;
1721 a->neg = b->neg = false;
1723 cmp = bc_num_cmp(a, b);
1729 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1730 return BC_STATUS_SUCCESS;
1739 if (sub) neg = !neg;
1744 bc_num_copy(c, minuend);
1747 if (c->rdx < subtrahend->rdx) {
1748 bc_num_extend(c, subtrahend->rdx - c->rdx);
1752 start = c->rdx - subtrahend->rdx;
1754 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1758 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1761 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1766 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1767 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1768 bool aone = BC_NUM_ONE(a);
1770 if (a->len == 0 || b->len == 0) {
1772 return BC_STATUS_SUCCESS;
1774 else if (aone || BC_NUM_ONE(b)) {
1775 bc_num_copy(c, aone ? b : a);
1776 return BC_STATUS_SUCCESS;
1779 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1780 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1782 bc_num_expand(c, a->len + b->len + 1);
1784 memset(c->num, 0, sizeof(BcDig) * c->cap);
1785 c->len = carry = len = 0;
1787 for (i = 0; i < b->len; ++i) {
1789 for (j = 0; j < a->len; ++j) {
1790 int in = (int) c->num[i + j];
1791 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1793 c->num[i + j] = (BcDig)(in % 10);
1796 c->num[i + j] += (BcDig) carry;
1797 len = BC_MAX(len, i + j + !!carry);
1803 return BC_STATUS_SUCCESS;
1806 bc_num_init(&l1, max);
1807 bc_num_init(&h1, max);
1808 bc_num_init(&l2, max);
1809 bc_num_init(&h2, max);
1810 bc_num_init(&m1, max);
1811 bc_num_init(&m2, max);
1812 bc_num_init(&z0, max);
1813 bc_num_init(&z1, max);
1814 bc_num_init(&z2, max);
1815 bc_num_init(&temp, max + max);
1817 bc_num_split(a, max2, &l1, &h1);
1818 bc_num_split(b, max2, &l2, &h2);
1820 s = bc_num_add(&h1, &l1, &m1, 0);
1822 s = bc_num_add(&h2, &l2, &m2, 0);
1825 s = bc_num_k(&h1, &h2, &z0);
1827 s = bc_num_k(&m1, &m2, &z1);
1829 s = bc_num_k(&l1, &l2, &z2);
1832 s = bc_num_sub(&z1, &z0, &temp, 0);
1834 s = bc_num_sub(&temp, &z2, &z1, 0);
1837 s = bc_num_shift(&z0, max2 * 2);
1839 s = bc_num_shift(&z1, max2);
1841 s = bc_num_add(&z0, &z1, &temp, 0);
1843 s = bc_num_add(&temp, &z2, c, 0);
1859 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1863 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1865 scale = BC_MAX(scale, a->rdx);
1866 scale = BC_MAX(scale, b->rdx);
1867 scale = BC_MIN(a->rdx + b->rdx, scale);
1868 maxrdx = BC_MAX(maxrdx, scale);
1870 bc_num_init(&cpa, a->len);
1871 bc_num_init(&cpb, b->len);
1873 bc_num_copy(&cpa, a);
1874 bc_num_copy(&cpb, b);
1875 cpa.neg = cpb.neg = false;
1877 s = bc_num_shift(&cpa, maxrdx);
1879 s = bc_num_shift(&cpb, maxrdx);
1881 s = bc_num_k(&cpa, &cpb, c);
1885 bc_num_expand(c, c->len + maxrdx);
1887 if (c->len < maxrdx) {
1888 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1893 bc_num_retireMul(c, scale, a->neg, b->neg);
1901 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1903 BcStatus s = BC_STATUS_SUCCESS;
1910 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1911 else if (a->len == 0) {
1912 bc_num_setToZero(c, scale);
1913 return BC_STATUS_SUCCESS;
1915 else if (BC_NUM_ONE(b)) {
1917 bc_num_retireMul(c, scale, a->neg, b->neg);
1918 return BC_STATUS_SUCCESS;
1921 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1922 bc_num_copy(&cp, a);
1926 bc_num_expand(&cp, len + 2);
1927 bc_num_extend(&cp, len - cp.len);
1930 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1932 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1934 if (b->rdx == b->len) {
1935 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1939 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1941 // We want an extra zero in front to make things simpler.
1942 cp.num[cp.len++] = 0;
1945 bc_num_expand(c, cp.len);
1948 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1953 for (i = end - 1; !s && i < end; --i) {
1955 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1956 bc_num_subArrays(n, p, len);
1960 bc_num_retireMul(c, scale, a->neg, b->neg);
1963 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1966 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1967 BcNum *restrict d, size_t scale, size_t ts)
1973 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1976 bc_num_setToZero(d, ts);
1977 return BC_STATUS_SUCCESS;
1980 bc_num_init(&temp, d->cap);
1981 bc_num_d(a, b, c, scale);
1983 if (scale != 0) scale = ts;
1985 s = bc_num_m(c, b, &temp, scale);
1987 s = bc_num_sub(a, &temp, d, scale);
1990 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1993 bc_num_retireMul(d, ts, a->neg, b->neg);
2001 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2005 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2007 bc_num_init(&c1, len);
2008 s = bc_num_r(a, b, &c1, c, scale, ts);
2014 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2016 BcStatus s = BC_STATUS_SUCCESS;
2019 size_t i, powrdx, resrdx;
2022 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2026 return BC_STATUS_SUCCESS;
2028 else if (a->len == 0) {
2029 bc_num_setToZero(c, scale);
2030 return BC_STATUS_SUCCESS;
2032 else if (BC_NUM_ONE(b)) {
2036 s = bc_num_inv(a, c, scale);
2043 s = bc_num_ulong(b, &pow);
2046 bc_num_init(©, a->len);
2047 bc_num_copy(©, a);
2049 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2053 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2055 s = bc_num_mul(©, ©, ©, powrdx);
2059 bc_num_copy(c, ©);
2061 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2064 s = bc_num_mul(©, ©, ©, powrdx);
2069 s = bc_num_mul(c, ©, c, resrdx);
2075 s = bc_num_inv(c, c, scale);
2079 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2081 // We can't use bc_num_clean() here.
2082 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2083 if (zero) bc_num_setToZero(c, scale);
2090 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2091 BcNumBinaryOp op, size_t req)
2094 BcNum num2, *ptr_a, *ptr_b;
2099 memcpy(ptr_a, c, sizeof(BcNum));
2108 memcpy(ptr_b, c, sizeof(BcNum));
2116 bc_num_init(c, req);
2118 bc_num_expand(c, req);
2120 s = op(ptr_a, ptr_b, c, scale);
2122 if (init) bc_num_free(&num2);
2127 static bool bc_num_strValid(const char *val, size_t base)
2130 bool small, radix = false;
2131 size_t i, len = strlen(val);
2133 if (!len) return true;
2136 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2138 for (i = 0; i < len; ++i) {
2144 if (radix) return false;
2150 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2157 static void bc_num_parseDecimal(BcNum *n, const char *val)
2163 for (i = 0; val[i] == '0'; ++i);
2170 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2171 bc_num_expand(n, len);
2174 ptr = strchr(val, '.');
2176 // Explicitly test for NULL here to produce either a 0 or 1.
2177 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2180 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2181 n->num[n->len] = val[i] - '0';
2185 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2188 BcNum temp, mult, result;
2192 size_t i, digits, len = strlen(val);
2196 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2199 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2200 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2202 for (i = 0; i < len; ++i) {
2205 if (c == '.') break;
2207 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2209 s = bc_num_mul(n, base, &mult, 0);
2210 if (s) goto int_err;
2211 bc_num_ulong2num(&temp, v);
2212 s = bc_num_add(&mult, &temp, n, 0);
2213 if (s) goto int_err;
2218 if (c == 0) goto int_err;
2221 bc_num_init(&result, base->len);
2222 bc_num_zero(&result);
2225 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2230 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2232 s = bc_num_mul(&result, base, &result, 0);
2234 bc_num_ulong2num(&temp, v);
2235 s = bc_num_add(&result, &temp, &result, 0);
2237 s = bc_num_mul(&mult, base, &mult, 0);
2241 s = bc_num_div(&result, &mult, &result, digits);
2243 s = bc_num_add(n, &result, n, digits);
2247 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2253 bc_num_free(&result);
2259 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2261 if (*nchars == line_len - 1) {
2269 static void bc_num_printChar(size_t num, size_t width, bool radix,
2270 size_t *nchars, size_t line_len)
2272 (void) radix, (void) line_len;
2273 bb_putchar((char) num);
2274 *nchars = *nchars + width;
2278 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2279 size_t *nchars, size_t line_len)
2283 bc_num_printNewline(nchars, line_len);
2284 bb_putchar(radix ? '.' : ' ');
2287 bc_num_printNewline(nchars, line_len);
2288 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2291 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2293 bc_num_printNewline(nchars, line_len);
2296 bb_putchar(((char) dig) + '0');
2300 static void bc_num_printHex(size_t num, size_t width, bool radix,
2301 size_t *nchars, size_t line_len)
2304 bc_num_printNewline(nchars, line_len);
2309 bc_num_printNewline(nchars, line_len);
2310 bb_putchar(bb_hexdigits_upcase[num]);
2311 *nchars = *nchars + width;
2314 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2316 size_t i, rdx = n->rdx - 1;
2318 if (n->neg) bb_putchar('-');
2319 (*nchars) += n->neg;
2321 for (i = n->len - 1; i < n->len; --i)
2322 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2325 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2326 size_t *nchars, size_t len, BcNumDigitOp print)
2330 BcNum intp, fracp, digit, frac_len;
2331 unsigned long dig, *ptr;
2336 print(0, width, false, nchars, len);
2337 return BC_STATUS_SUCCESS;
2340 bc_vec_init(&stack, sizeof(long), NULL);
2341 bc_num_init(&intp, n->len);
2342 bc_num_init(&fracp, n->rdx);
2343 bc_num_init(&digit, width);
2344 bc_num_init(&frac_len, BC_NUM_INT(n));
2345 bc_num_copy(&intp, n);
2346 bc_num_one(&frac_len);
2348 bc_num_truncate(&intp, intp.rdx);
2349 s = bc_num_sub(n, &intp, &fracp, 0);
2352 while (intp.len != 0) {
2353 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2355 s = bc_num_ulong(&digit, &dig);
2357 bc_vec_push(&stack, &dig);
2360 for (i = 0; i < stack.len; ++i) {
2361 ptr = bc_vec_item_rev(&stack, i);
2362 print(*ptr, width, false, nchars, len);
2365 if (!n->rdx) goto err;
2367 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2368 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2370 s = bc_num_ulong(&fracp, &dig);
2372 bc_num_ulong2num(&intp, dig);
2373 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2375 print(dig, width, radix, nchars, len);
2376 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2381 bc_num_free(&frac_len);
2382 bc_num_free(&digit);
2383 bc_num_free(&fracp);
2385 bc_vec_free(&stack);
2389 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2390 size_t *nchars, size_t line_len)
2397 if (neg) bb_putchar('-');
2402 if (base_t <= BC_NUM_MAX_IBASE) {
2404 print = bc_num_printHex;
2407 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2408 print = bc_num_printDigits;
2411 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2418 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2420 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2424 static void bc_num_init(BcNum *n, size_t req)
2426 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2427 memset(n, 0, sizeof(BcNum));
2428 n->num = xmalloc(req);
2432 static void bc_num_expand(BcNum *n, size_t req)
2434 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2436 n->num = xrealloc(n->num, req);
2441 static void bc_num_free(void *num)
2443 free(((BcNum *) num)->num);
2446 static void bc_num_copy(BcNum *d, BcNum *s)
2449 bc_num_expand(d, s->cap);
2453 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2457 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2460 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2463 bc_num_parseDecimal(n, val);
2465 bc_num_parseBase(n, val, base);
2467 return BC_STATUS_SUCCESS;
2470 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2471 size_t *nchars, size_t line_len)
2473 BcStatus s = BC_STATUS_SUCCESS;
2475 bc_num_printNewline(nchars, line_len);
2481 else if (base_t == 10)
2482 bc_num_printDecimal(n, nchars, line_len);
2484 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2494 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2499 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2501 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2503 unsigned long prev = *result, powprev = pow;
2505 *result += ((unsigned long) n->num[i]) * pow;
2508 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2511 return BC_STATUS_SUCCESS;
2514 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2522 if (val == 0) return;
2524 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2525 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2528 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2530 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2532 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2535 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2537 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2539 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2542 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2544 size_t req = BC_NUM_MREQ(a, b, scale);
2545 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2548 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2550 size_t req = BC_NUM_MREQ(a, b, scale);
2551 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2554 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2556 size_t req = BC_NUM_MREQ(a, b, scale);
2557 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2560 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2562 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2565 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2568 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2569 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2570 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2572 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2573 bc_num_expand(b, req);
2576 bc_num_setToZero(b, scale);
2577 return BC_STATUS_SUCCESS;
2580 return BC_STATUS_MATH_NEGATIVE;
2581 else if (BC_NUM_ONE(a)) {
2583 bc_num_extend(b, scale);
2584 return BC_STATUS_SUCCESS;
2587 scale = BC_MAX(scale, a->rdx) + 1;
2588 len = a->len + scale;
2590 bc_num_init(&num1, len);
2591 bc_num_init(&num2, len);
2592 bc_num_init(&half, BC_NUM_DEF_SIZE);
2598 bc_num_init(&f, len);
2599 bc_num_init(&fprime, len);
2605 pow = BC_NUM_INT(a);
2614 pow -= 2 - (pow & 1);
2616 bc_num_extend(x0, pow);
2618 // Make sure to move the radix back.
2622 x0->rdx = digs = digs1 = 0;
2624 len = BC_NUM_INT(x0) + resrdx - 1;
2626 while (cmp != 0 || digs < len) {
2628 s = bc_num_div(a, x0, &f, resrdx);
2630 s = bc_num_add(x0, &f, &fprime, resrdx);
2632 s = bc_num_mul(&fprime, &half, x1, resrdx);
2635 cmp = bc_num_cmp(x1, x0);
2636 digs = x1->len - (unsigned long long) llabs(cmp);
2638 if (cmp == cmp2 && digs == digs1)
2643 resrdx += times > 4;
2656 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2659 bc_num_free(&fprime);
2667 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2673 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2676 memcpy(&num2, c, sizeof(BcNum));
2678 bc_num_init(c, len);
2683 bc_num_expand(c, len);
2686 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2688 if (init) bc_num_free(&num2);
2694 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2697 BcNum base, exp, two, temp;
2699 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2700 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2701 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2703 bc_num_expand(d, c->len);
2704 bc_num_init(&base, c->len);
2705 bc_num_init(&exp, b->len);
2706 bc_num_init(&two, BC_NUM_DEF_SIZE);
2707 bc_num_init(&temp, b->len);
2713 s = bc_num_rem(a, c, &base, 0);
2715 bc_num_copy(&exp, b);
2717 while (exp.len != 0) {
2719 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2722 if (BC_NUM_ONE(&temp)) {
2723 s = bc_num_mul(d, &base, &temp, 0);
2725 s = bc_num_rem(&temp, c, d, 0);
2729 s = bc_num_mul(&base, &base, &temp, 0);
2731 s = bc_num_rem(&temp, c, &base, 0);
2744 static int bc_id_cmp(const void *e1, const void *e2)
2746 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2749 static void bc_id_free(void *id)
2751 free(((BcId *) id)->name);
2754 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2759 for (i = 0; i < f->autos.len; ++i) {
2760 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2761 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2767 bc_vec_push(&f->autos, &a);
2769 return BC_STATUS_SUCCESS;
2772 static void bc_func_init(BcFunc *f)
2774 bc_vec_init(&f->code, sizeof(char), NULL);
2775 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2776 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2780 static void bc_func_free(void *func)
2782 BcFunc *f = (BcFunc *) func;
2783 bc_vec_free(&f->code);
2784 bc_vec_free(&f->autos);
2785 bc_vec_free(&f->labels);
2788 static void bc_array_init(BcVec *a, bool nums)
2791 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2793 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2794 bc_array_expand(a, 1);
2797 static void bc_array_copy(BcVec *d, const BcVec *s)
2801 bc_vec_npop(d, d->len);
2802 bc_vec_expand(d, s->cap);
2805 for (i = 0; i < s->len; ++i) {
2806 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2807 bc_num_init(dnum, snum->len);
2808 bc_num_copy(dnum, snum);
2812 static void bc_array_expand(BcVec *a, size_t len)
2816 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2817 while (len > a->len) {
2818 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2819 bc_vec_push(a, &data.n);
2823 while (len > a->len) {
2824 bc_array_init(&data.v, true);
2825 bc_vec_push(a, &data.v);
2830 static void bc_string_free(void *string)
2832 free(*((char **) string));
2836 static void bc_result_copy(BcResult *d, BcResult *src)
2842 case BC_RESULT_TEMP:
2843 case BC_RESULT_IBASE:
2844 case BC_RESULT_SCALE:
2845 case BC_RESULT_OBASE:
2847 bc_num_init(&d->d.n, src->d.n.len);
2848 bc_num_copy(&d->d.n, &src->d.n);
2853 case BC_RESULT_ARRAY:
2854 case BC_RESULT_ARRAY_ELEM:
2856 d->d.id.name = xstrdup(src->d.id.name);
2860 case BC_RESULT_CONSTANT:
2861 case BC_RESULT_LAST:
2865 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2872 static void bc_result_free(void *result)
2874 BcResult *r = (BcResult *) result;
2878 case BC_RESULT_TEMP:
2879 case BC_RESULT_IBASE:
2880 case BC_RESULT_SCALE:
2881 case BC_RESULT_OBASE:
2883 bc_num_free(&r->d.n);
2888 case BC_RESULT_ARRAY:
2889 case BC_RESULT_ARRAY_ELEM:
2903 static void bc_lex_lineComment(BcLex *l)
2905 l->t.t = BC_LEX_WHITESPACE;
2906 while (l->i < l->len && l->buf[l->i++] != '\n');
2910 static void bc_lex_whitespace(BcLex *l)
2913 l->t.t = BC_LEX_WHITESPACE;
2914 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2917 static BcStatus bc_lex_number(BcLex *l, char start)
2919 const char *buf = l->buf + l->i;
2920 size_t len, hits = 0, bslashes = 0, i = 0, j;
2922 bool last_pt, pt = start == '.';
2925 l->t.t = BC_LEX_NUMBER;
2927 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2928 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2942 len = i + 1 * !last_pt - bslashes * 2;
2943 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2945 bc_vec_npop(&l->t.v, l->t.v.len);
2946 bc_vec_expand(&l->t.v, len + 1);
2947 bc_vec_push(&l->t.v, &start);
2949 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2953 // If we have hit a backslash, skip it. We don't have
2954 // to check for a newline because it's guaranteed.
2955 if (hits < bslashes && c == '\\') {
2961 bc_vec_push(&l->t.v, &c);
2964 bc_vec_pushByte(&l->t.v, '\0');
2967 return BC_STATUS_SUCCESS;
2970 static BcStatus bc_lex_name(BcLex *l)
2973 const char *buf = l->buf + l->i - 1;
2976 l->t.t = BC_LEX_NAME;
2978 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2980 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2981 bc_vec_string(&l->t.v, i, buf);
2983 // Increment the index. We minus 1 because it has already been incremented.
2986 return BC_STATUS_SUCCESS;
2989 static void bc_lex_init(BcLex *l, BcLexNext next)
2992 bc_vec_init(&l->t.v, sizeof(char), NULL);
2995 static void bc_lex_free(BcLex *l)
2997 bc_vec_free(&l->t.v);
3000 static void bc_lex_file(BcLex *l, const char *file)
3007 static BcStatus bc_lex_next(BcLex *l)
3012 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3014 l->line += l->newline;
3015 l->t.t = BC_LEX_EOF;
3017 l->newline = (l->i == l->len);
3018 if (l->newline) return BC_STATUS_SUCCESS;
3020 // Loop until failure or we don't have whitespace. This
3021 // is so the parser doesn't get inundated with whitespace.
3024 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3029 static BcStatus bc_lex_text(BcLex *l, const char *text)
3033 l->len = strlen(text);
3034 l->t.t = l->t.last = BC_LEX_INVALID;
3035 return bc_lex_next(l);
3039 static BcStatus bc_lex_identifier(BcLex *l)
3043 const char *buf = l->buf + l->i - 1;
3045 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3047 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3049 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3051 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3053 if (!bc_lex_kws[i].posix) {
3054 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3055 bc_lex_kws[i].name);
3059 // We minus 1 because the index has already been incremented.
3061 return BC_STATUS_SUCCESS;
3068 if (l->t.v.len - 1 > 1)
3069 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3074 static BcStatus bc_lex_string(BcLex *l)
3076 size_t len, nls = 0, i = l->i;
3079 l->t.t = BC_LEX_STR;
3081 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3085 return BC_STATUS_LEX_NO_STRING_END;
3089 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3090 bc_vec_string(&l->t.v, len, l->buf + l->i);
3095 return BC_STATUS_SUCCESS;
3098 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3100 if (l->buf[l->i] == '=') {
3108 static BcStatus bc_lex_comment(BcLex *l)
3111 const char *buf = l->buf;
3115 l->t.t = BC_LEX_WHITESPACE;
3117 for (i = ++l->i; !end; i += !end) {
3119 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3121 if (c == 0 || buf[i + 1] == '\0') {
3123 return BC_STATUS_LEX_NO_COMMENT_END;
3126 end = buf[i + 1] == '/';
3132 return BC_STATUS_SUCCESS;
3135 static BcStatus bc_lex_token(BcLex *l)
3137 BcStatus s = BC_STATUS_SUCCESS;
3138 char c = l->buf[l->i++], c2;
3140 // This is the workhorse of the lexer.
3147 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3157 bc_lex_whitespace(l);
3163 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3165 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3166 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3175 s = bc_lex_string(l);
3181 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3184 bc_lex_lineComment(l);
3191 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3200 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3204 l->t.t = BC_LEX_OP_BOOL_AND;
3207 l->t.t = BC_LEX_INVALID;
3208 s = BC_STATUS_LEX_BAD_CHAR;
3217 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3223 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3232 l->t.t = BC_LEX_OP_INC;
3235 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3241 l->t.t = BC_LEX_COMMA;
3250 l->t.t = BC_LEX_OP_DEC;
3253 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3259 if (isdigit(l->buf[l->i]))
3260 s = bc_lex_number(l, c);
3262 l->t.t = BC_LEX_KEY_LAST;
3263 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3272 s = bc_lex_comment(l);
3274 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3295 s = bc_lex_number(l, c);
3301 l->t.t = BC_LEX_SCOLON;
3307 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3313 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3319 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3326 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3332 if (l->buf[l->i] == '\n') {
3333 l->t.t = BC_LEX_WHITESPACE;
3337 s = BC_STATUS_LEX_BAD_CHAR;
3343 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3374 s = bc_lex_identifier(l);
3381 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3391 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3395 l->t.t = BC_LEX_OP_BOOL_OR;
3398 l->t.t = BC_LEX_INVALID;
3399 s = BC_STATUS_LEX_BAD_CHAR;
3407 l->t.t = BC_LEX_INVALID;
3408 s = BC_STATUS_LEX_BAD_CHAR;
3418 static BcStatus dc_lex_register(BcLex *l)
3420 BcStatus s = BC_STATUS_SUCCESS;
3422 if (isspace(l->buf[l->i - 1])) {
3423 bc_lex_whitespace(l);
3426 s = BC_STATUS_LEX_EXTENDED_REG;
3431 bc_vec_npop(&l->t.v, l->t.v.len);
3432 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3433 bc_vec_pushByte(&l->t.v, '\0');
3434 l->t.t = BC_LEX_NAME;
3440 static BcStatus dc_lex_string(BcLex *l)
3442 size_t depth = 1, nls = 0, i = l->i;
3445 l->t.t = BC_LEX_STR;
3446 bc_vec_npop(&l->t.v, l->t.v.len);
3448 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3450 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3451 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3454 if (depth) bc_vec_push(&l->t.v, &c);
3459 return BC_STATUS_LEX_NO_STRING_END;
3462 bc_vec_pushByte(&l->t.v, '\0');
3463 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3468 return BC_STATUS_SUCCESS;
3471 static BcStatus dc_lex_token(BcLex *l)
3473 BcStatus s = BC_STATUS_SUCCESS;
3474 char c = l->buf[l->i++], c2;
3477 for (i = 0; i < dc_lex_regs_len; ++i) {
3478 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3481 if (c >= '%' && c <= '~' &&
3482 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3487 // This is the workhorse of the lexer.
3492 l->t.t = BC_LEX_EOF;
3503 l->newline = (c == '\n');
3504 bc_lex_whitespace(l);
3513 l->t.t = BC_LEX_OP_REL_NE;
3515 l->t.t = BC_LEX_OP_REL_LE;
3517 l->t.t = BC_LEX_OP_REL_GE;
3519 return BC_STATUS_LEX_BAD_CHAR;
3527 bc_lex_lineComment(l);
3533 if (isdigit(l->buf[l->i]))
3534 s = bc_lex_number(l, c);
3536 s = BC_STATUS_LEX_BAD_CHAR;
3557 s = bc_lex_number(l, c);
3563 s = dc_lex_string(l);
3569 l->t.t = BC_LEX_INVALID;
3570 s = BC_STATUS_LEX_BAD_CHAR;
3579 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3581 bc_program_addFunc(name, idx);
3582 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3585 static void bc_parse_pushName(BcParse *p, char *name)
3587 size_t i = 0, len = strlen(name);
3589 for (; i < len; ++i) bc_parse_push(p, name[i]);
3590 bc_parse_push(p, BC_PARSE_STREND);
3595 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3597 unsigned char amt, i, nums[sizeof(size_t)];
3599 for (amt = 0; idx; ++amt) {
3600 nums[amt] = (char) idx;
3601 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3604 bc_parse_push(p, amt);
3605 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3608 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3610 char *num = xstrdup(p->l.t.v.v);
3611 size_t idx = G.prog.consts.len;
3613 bc_vec_push(&G.prog.consts, &num);
3615 bc_parse_push(p, BC_INST_NUM);
3616 bc_parse_pushIndex(p, idx);
3619 (*prev) = BC_INST_NUM;
3622 static BcStatus bc_parse_text(BcParse *p, const char *text)
3626 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3628 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3629 p->l.t.t = BC_LEX_INVALID;
3632 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3635 return bc_lex_text(&p->l, text);
3638 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3640 if (p->fidx != BC_PROG_MAIN) {
3642 p->func->nparams = 0;
3643 bc_vec_npop(&p->func->code, p->func->code.len);
3644 bc_vec_npop(&p->func->autos, p->func->autos.len);
3645 bc_vec_npop(&p->func->labels, p->func->labels.len);
3647 bc_parse_updateFunc(p, BC_PROG_MAIN);
3651 p->l.t.t = BC_LEX_EOF;
3652 p->auto_part = (p->nbraces = 0);
3654 bc_vec_npop(&p->flags, p->flags.len - 1);
3655 bc_vec_npop(&p->exits, p->exits.len);
3656 bc_vec_npop(&p->conds, p->conds.len);
3657 bc_vec_npop(&p->ops, p->ops.len);
3659 return bc_program_reset(s);
3662 static void bc_parse_free(BcParse *p)
3664 bc_vec_free(&p->flags);
3665 bc_vec_free(&p->exits);
3666 bc_vec_free(&p->conds);
3667 bc_vec_free(&p->ops);
3671 static void bc_parse_create(BcParse *p, size_t func,
3672 BcParseParse parse, BcLexNext next)
3674 memset(p, 0, sizeof(BcParse));
3676 bc_lex_init(&p->l, next);
3677 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3678 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3679 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3680 bc_vec_pushByte(&p->flags, 0);
3681 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3684 p->auto_part = (p->nbraces = 0);
3685 bc_parse_updateFunc(p, func);
3689 static BcStatus bc_parse_else(BcParse *p);
3690 static BcStatus bc_parse_stmt(BcParse *p);
3692 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3693 size_t *nexprs, bool next)
3695 BcStatus s = BC_STATUS_SUCCESS;
3697 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3698 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3700 while (p->ops.len > start) {
3702 t = BC_PARSE_TOP_OP(p);
3703 if (t == BC_LEX_LPAREN) break;
3705 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3706 if (l >= r && (l != r || !left)) break;
3708 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3709 bc_vec_pop(&p->ops);
3710 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3713 bc_vec_push(&p->ops, &type);
3714 if (next) s = bc_lex_next(&p->l);
3719 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3723 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3724 top = BC_PARSE_TOP_OP(p);
3726 while (top != BC_LEX_LPAREN) {
3728 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3730 bc_vec_pop(&p->ops);
3731 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3733 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3734 top = BC_PARSE_TOP_OP(p);
3737 bc_vec_pop(&p->ops);
3739 return bc_lex_next(&p->l);
3742 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3748 s = bc_lex_next(&p->l);
3751 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3753 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3754 s = bc_parse_expr(p, flags, bc_parse_next_param);
3757 comma = p->l.t.t == BC_LEX_COMMA;
3759 s = bc_lex_next(&p->l);
3764 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3765 bc_parse_push(p, BC_INST_CALL);
3766 bc_parse_pushIndex(p, nparams);
3768 return BC_STATUS_SUCCESS;
3771 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3774 BcId entry, *entry_ptr;
3779 s = bc_parse_params(p, flags);
3782 if (p->l.t.t != BC_LEX_RPAREN) {
3783 s = BC_STATUS_PARSE_BAD_TOKEN;
3787 idx = bc_map_index(&G.prog.fn_map, &entry);
3789 if (idx == BC_VEC_INVALID_IDX) {
3790 name = xstrdup(entry.name);
3791 bc_parse_addFunc(p, name, &idx);
3792 idx = bc_map_index(&G.prog.fn_map, &entry);
3798 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3799 bc_parse_pushIndex(p, entry_ptr->idx);
3801 return bc_lex_next(&p->l);
3808 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3813 name = xstrdup(p->l.t.v.v);
3814 s = bc_lex_next(&p->l);
3817 if (p->l.t.t == BC_LEX_LBRACKET) {
3819 s = bc_lex_next(&p->l);
3822 if (p->l.t.t == BC_LEX_RBRACKET) {
3824 if (!(flags & BC_PARSE_ARRAY)) {
3825 s = BC_STATUS_PARSE_BAD_EXP;
3829 *type = BC_INST_ARRAY;
3833 *type = BC_INST_ARRAY_ELEM;
3835 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3836 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3840 s = bc_lex_next(&p->l);
3842 bc_parse_push(p, *type);
3843 bc_parse_pushName(p, name);
3845 else if (p->l.t.t == BC_LEX_LPAREN) {
3847 if (flags & BC_PARSE_NOCALL) {
3848 s = BC_STATUS_PARSE_BAD_TOKEN;
3852 *type = BC_INST_CALL;
3853 s = bc_parse_call(p, name, flags);
3856 *type = BC_INST_VAR;
3857 bc_parse_push(p, BC_INST_VAR);
3858 bc_parse_pushName(p, name);
3868 static BcStatus bc_parse_read(BcParse *p)
3872 s = bc_lex_next(&p->l);
3874 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3876 s = bc_lex_next(&p->l);
3878 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3880 bc_parse_push(p, BC_INST_READ);
3882 return bc_lex_next(&p->l);
3885 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3890 s = bc_lex_next(&p->l);
3892 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3894 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3896 s = bc_lex_next(&p->l);
3899 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3902 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3904 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3905 bc_parse_push(p, *prev);
3907 return bc_lex_next(&p->l);
3910 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3914 s = bc_lex_next(&p->l);
3917 if (p->l.t.t != BC_LEX_LPAREN) {
3918 *type = BC_INST_SCALE;
3919 bc_parse_push(p, BC_INST_SCALE);
3920 return BC_STATUS_SUCCESS;
3923 *type = BC_INST_SCALE_FUNC;
3924 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3926 s = bc_lex_next(&p->l);
3929 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3931 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3932 bc_parse_push(p, BC_INST_SCALE_FUNC);
3934 return bc_lex_next(&p->l);
3937 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3938 size_t *nexprs, uint8_t flags)
3943 BcInst etype = *prev;
3945 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3946 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3947 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3949 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3950 bc_parse_push(p, inst);
3951 s = bc_lex_next(&p->l);
3955 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3958 s = bc_lex_next(&p->l);
3962 // Because we parse the next part of the expression
3963 // right here, we need to increment this.
3964 *nexprs = *nexprs + 1;
3970 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3974 case BC_LEX_KEY_IBASE:
3975 case BC_LEX_KEY_LAST:
3976 case BC_LEX_KEY_OBASE:
3978 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3979 s = bc_lex_next(&p->l);
3983 case BC_LEX_KEY_SCALE:
3985 s = bc_lex_next(&p->l);
3987 if (p->l.t.t == BC_LEX_LPAREN)
3988 s = BC_STATUS_PARSE_BAD_TOKEN;
3990 bc_parse_push(p, BC_INST_SCALE);
3996 s = BC_STATUS_PARSE_BAD_TOKEN;
4001 if (!s) bc_parse_push(p, inst);
4007 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4008 bool rparen, size_t *nexprs)
4012 BcInst etype = *prev;
4014 s = bc_lex_next(&p->l);
4017 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4018 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4021 *prev = BC_PARSE_TOKEN_INST(type);
4023 // We can just push onto the op stack because this is the largest
4024 // precedence operator that gets pushed. Inc/dec does not.
4025 if (type != BC_LEX_OP_MINUS)
4026 bc_vec_push(&p->ops, &type);
4028 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4033 static BcStatus bc_parse_string(BcParse *p, char inst)
4035 char *str = xstrdup(p->l.t.v.v);
4037 bc_parse_push(p, BC_INST_STR);
4038 bc_parse_pushIndex(p, G.prog.strs.len);
4039 bc_vec_push(&G.prog.strs, &str);
4040 bc_parse_push(p, inst);
4042 return bc_lex_next(&p->l);
4045 static BcStatus bc_parse_print(BcParse *p)
4051 s = bc_lex_next(&p->l);
4056 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4057 return BC_STATUS_PARSE_BAD_PRINT;
4059 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4061 if (type == BC_LEX_STR)
4062 s = bc_parse_string(p, BC_INST_PRINT_POP);
4064 s = bc_parse_expr(p, 0, bc_parse_next_print);
4066 bc_parse_push(p, BC_INST_PRINT_POP);
4071 comma = p->l.t.t == BC_LEX_COMMA;
4072 if (comma) s = bc_lex_next(&p->l);
4077 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4079 return bc_lex_next(&p->l);
4082 static BcStatus bc_parse_return(BcParse *p)
4088 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4090 s = bc_lex_next(&p->l);
4094 paren = t == BC_LEX_LPAREN;
4096 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4097 bc_parse_push(p, BC_INST_RET0);
4100 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4101 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4103 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4104 bc_parse_push(p, BC_INST_RET0);
4105 s = bc_lex_next(&p->l);
4109 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4110 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4114 bc_parse_push(p, BC_INST_RET);
4120 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4122 BcStatus s = BC_STATUS_SUCCESS;
4124 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4125 return BC_STATUS_PARSE_BAD_TOKEN;
4129 if (p->l.t.t == BC_LEX_RBRACE) {
4130 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4132 s = bc_lex_next(&p->l);
4136 return BC_STATUS_PARSE_BAD_TOKEN;
4139 if (BC_PARSE_IF(p)) {
4143 while (p->l.t.t == BC_LEX_NLINE) {
4144 s = bc_lex_next(&p->l);
4148 bc_vec_pop(&p->flags);
4150 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4151 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4153 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4155 else if (BC_PARSE_ELSE(p)) {
4160 bc_vec_pop(&p->flags);
4162 ip = bc_vec_top(&p->exits);
4163 label = bc_vec_item(&p->func->labels, ip->idx);
4164 *label = p->func->code.len;
4166 bc_vec_pop(&p->exits);
4168 else if (BC_PARSE_FUNC_INNER(p)) {
4169 bc_parse_push(p, BC_INST_RET0);
4170 bc_parse_updateFunc(p, BC_PROG_MAIN);
4171 bc_vec_pop(&p->flags);
4175 BcInstPtr *ip = bc_vec_top(&p->exits);
4176 size_t *label = bc_vec_top(&p->conds);
4178 bc_parse_push(p, BC_INST_JUMP);
4179 bc_parse_pushIndex(p, *label);
4181 label = bc_vec_item(&p->func->labels, ip->idx);
4182 *label = p->func->code.len;
4184 bc_vec_pop(&p->flags);
4185 bc_vec_pop(&p->exits);
4186 bc_vec_pop(&p->conds);
4192 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4194 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4195 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4196 flags |= BC_PARSE_FLAG_BODY;
4197 bc_vec_push(&p->flags, &flags);
4200 static void bc_parse_noElse(BcParse *p)
4204 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4206 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4208 ip = bc_vec_top(&p->exits);
4209 label = bc_vec_item(&p->func->labels, ip->idx);
4210 *label = p->func->code.len;
4212 bc_vec_pop(&p->exits);
4215 static BcStatus bc_parse_if(BcParse *p)
4220 s = bc_lex_next(&p->l);
4222 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4224 s = bc_lex_next(&p->l);
4226 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4228 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4230 s = bc_lex_next(&p->l);
4232 bc_parse_push(p, BC_INST_JUMP_ZERO);
4234 ip.idx = p->func->labels.len;
4235 ip.func = ip.len = 0;
4237 bc_parse_pushIndex(p, ip.idx);
4238 bc_vec_push(&p->exits, &ip);
4239 bc_vec_push(&p->func->labels, &ip.idx);
4240 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4242 return BC_STATUS_SUCCESS;
4245 static BcStatus bc_parse_else(BcParse *p)
4249 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4251 ip.idx = p->func->labels.len;
4252 ip.func = ip.len = 0;
4254 bc_parse_push(p, BC_INST_JUMP);
4255 bc_parse_pushIndex(p, ip.idx);
4259 bc_vec_push(&p->exits, &ip);
4260 bc_vec_push(&p->func->labels, &ip.idx);
4261 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4263 return bc_lex_next(&p->l);
4266 static BcStatus bc_parse_while(BcParse *p)
4271 s = bc_lex_next(&p->l);
4273 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4274 s = bc_lex_next(&p->l);
4277 ip.idx = p->func->labels.len;
4279 bc_vec_push(&p->func->labels, &p->func->code.len);
4280 bc_vec_push(&p->conds, &ip.idx);
4282 ip.idx = p->func->labels.len;
4286 bc_vec_push(&p->exits, &ip);
4287 bc_vec_push(&p->func->labels, &ip.idx);
4289 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4291 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4292 s = bc_lex_next(&p->l);
4295 bc_parse_push(p, BC_INST_JUMP_ZERO);
4296 bc_parse_pushIndex(p, ip.idx);
4297 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4299 return BC_STATUS_SUCCESS;
4302 static BcStatus bc_parse_for(BcParse *p)
4306 size_t cond_idx, exit_idx, body_idx, update_idx;
4308 s = bc_lex_next(&p->l);
4310 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4311 s = bc_lex_next(&p->l);
4314 if (p->l.t.t != BC_LEX_SCOLON)
4315 s = bc_parse_expr(p, 0, bc_parse_next_for);
4317 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4320 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4321 s = bc_lex_next(&p->l);
4324 cond_idx = p->func->labels.len;
4325 update_idx = cond_idx + 1;
4326 body_idx = update_idx + 1;
4327 exit_idx = body_idx + 1;
4329 bc_vec_push(&p->func->labels, &p->func->code.len);
4331 if (p->l.t.t != BC_LEX_SCOLON)
4332 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4334 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4337 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4339 s = bc_lex_next(&p->l);
4342 bc_parse_push(p, BC_INST_JUMP_ZERO);
4343 bc_parse_pushIndex(p, exit_idx);
4344 bc_parse_push(p, BC_INST_JUMP);
4345 bc_parse_pushIndex(p, body_idx);
4347 ip.idx = p->func->labels.len;
4349 bc_vec_push(&p->conds, &update_idx);
4350 bc_vec_push(&p->func->labels, &p->func->code.len);
4352 if (p->l.t.t != BC_LEX_RPAREN)
4353 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4355 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4359 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4360 bc_parse_push(p, BC_INST_JUMP);
4361 bc_parse_pushIndex(p, cond_idx);
4362 bc_vec_push(&p->func->labels, &p->func->code.len);
4368 bc_vec_push(&p->exits, &ip);
4369 bc_vec_push(&p->func->labels, &ip.idx);
4371 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4373 return BC_STATUS_SUCCESS;
4376 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4382 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4384 if (type == BC_LEX_KEY_BREAK) {
4386 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4388 i = p->exits.len - 1;
4389 ip = bc_vec_item(&p->exits, i);
4391 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4392 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4397 i = *((size_t *) bc_vec_top(&p->conds));
4399 bc_parse_push(p, BC_INST_JUMP);
4400 bc_parse_pushIndex(p, i);
4402 s = bc_lex_next(&p->l);
4405 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4406 return BC_STATUS_PARSE_BAD_TOKEN;
4408 return bc_lex_next(&p->l);
4411 static BcStatus bc_parse_func(BcParse *p)
4414 bool var, comma = false;
4418 s = bc_lex_next(&p->l);
4420 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4422 name = xstrdup(p->l.t.v.v);
4423 bc_parse_addFunc(p, name, &p->fidx);
4425 s = bc_lex_next(&p->l);
4427 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4428 s = bc_lex_next(&p->l);
4431 while (p->l.t.t != BC_LEX_RPAREN) {
4433 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4437 name = xstrdup(p->l.t.v.v);
4438 s = bc_lex_next(&p->l);
4441 var = p->l.t.t != BC_LEX_LBRACKET;
4445 s = bc_lex_next(&p->l);
4448 if (p->l.t.t != BC_LEX_RBRACKET) {
4449 s = BC_STATUS_PARSE_BAD_FUNC;
4453 s = bc_lex_next(&p->l);
4457 comma = p->l.t.t == BC_LEX_COMMA;
4459 s = bc_lex_next(&p->l);
4463 s = bc_func_insert(p->func, name, var);
4467 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4469 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4470 bc_parse_startBody(p, flags);
4472 s = bc_lex_next(&p->l);
4475 if (p->l.t.t != BC_LEX_LBRACE)
4476 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4485 static BcStatus bc_parse_auto(BcParse *p)
4488 bool comma, var, one;
4491 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4492 s = bc_lex_next(&p->l);
4495 p->auto_part = comma = false;
4496 one = p->l.t.t == BC_LEX_NAME;
4498 while (p->l.t.t == BC_LEX_NAME) {
4500 name = xstrdup(p->l.t.v.v);
4501 s = bc_lex_next(&p->l);
4504 var = p->l.t.t != BC_LEX_LBRACKET;
4507 s = bc_lex_next(&p->l);
4510 if (p->l.t.t != BC_LEX_RBRACKET) {
4511 s = BC_STATUS_PARSE_BAD_FUNC;
4515 s = bc_lex_next(&p->l);
4519 comma = p->l.t.t == BC_LEX_COMMA;
4521 s = bc_lex_next(&p->l);
4525 s = bc_func_insert(p->func, name, var);
4529 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4530 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4532 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4533 return BC_STATUS_PARSE_BAD_TOKEN;
4535 return bc_lex_next(&p->l);
4542 static BcStatus bc_parse_body(BcParse *p, bool brace)
4544 BcStatus s = BC_STATUS_SUCCESS;
4545 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4547 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4549 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4551 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4552 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4554 if (!p->auto_part) {
4555 s = bc_parse_auto(p);
4559 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4562 s = bc_parse_stmt(p);
4563 if (!s && !brace) s = bc_parse_endBody(p, false);
4569 static BcStatus bc_parse_stmt(BcParse *p)
4571 BcStatus s = BC_STATUS_SUCCESS;
4577 return bc_lex_next(&p->l);
4580 case BC_LEX_KEY_ELSE:
4582 p->auto_part = false;
4588 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4591 s = bc_lex_next(&p->l);
4594 return bc_parse_body(p, true);
4597 case BC_LEX_KEY_AUTO:
4599 return bc_parse_auto(p);
4604 p->auto_part = false;
4606 if (BC_PARSE_IF_END(p)) {
4608 return BC_STATUS_SUCCESS;
4610 else if (BC_PARSE_BODY(p))
4611 return bc_parse_body(p, false);
4621 case BC_LEX_OP_MINUS:
4622 case BC_LEX_OP_BOOL_NOT:
4626 case BC_LEX_KEY_IBASE:
4627 case BC_LEX_KEY_LAST:
4628 case BC_LEX_KEY_LENGTH:
4629 case BC_LEX_KEY_OBASE:
4630 case BC_LEX_KEY_READ:
4631 case BC_LEX_KEY_SCALE:
4632 case BC_LEX_KEY_SQRT:
4634 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4638 case BC_LEX_KEY_ELSE:
4640 s = bc_parse_else(p);
4646 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4652 s = bc_parse_endBody(p, true);
4658 s = bc_parse_string(p, BC_INST_PRINT_STR);
4662 case BC_LEX_KEY_BREAK:
4663 case BC_LEX_KEY_CONTINUE:
4665 s = bc_parse_loopExit(p, p->l.t.t);
4669 case BC_LEX_KEY_FOR:
4671 s = bc_parse_for(p);
4675 case BC_LEX_KEY_HALT:
4677 bc_parse_push(p, BC_INST_HALT);
4678 s = bc_lex_next(&p->l);
4688 case BC_LEX_KEY_LIMITS:
4690 s = bc_lex_next(&p->l);
4692 s = BC_STATUS_LIMITS;
4696 case BC_LEX_KEY_PRINT:
4698 s = bc_parse_print(p);
4702 case BC_LEX_KEY_QUIT:
4704 // Quit is a compile-time command. We don't exit directly,
4705 // so the vm can clean up. Limits do the same thing.
4710 case BC_LEX_KEY_RETURN:
4712 s = bc_parse_return(p);
4716 case BC_LEX_KEY_WHILE:
4718 s = bc_parse_while(p);
4724 s = BC_STATUS_PARSE_BAD_TOKEN;
4732 static BcStatus bc_parse_parse(BcParse *p)
4736 if (p->l.t.t == BC_LEX_EOF)
4737 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4738 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4739 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4740 s = bc_parse_func(p);
4743 s = bc_parse_stmt(p);
4745 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4746 s = bc_parse_reset(p, s);
4751 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4753 BcStatus s = BC_STATUS_SUCCESS;
4754 BcInst prev = BC_INST_PRINT;
4755 BcLexType top, t = p->l.t.t;
4756 size_t nexprs = 0, ops_bgn = p->ops.len;
4757 uint32_t i, nparens, nrelops;
4758 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4760 paren_first = p->l.t.t == BC_LEX_LPAREN;
4761 nparens = nrelops = 0;
4762 paren_expr = rprn = done = get_token = assign = false;
4765 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4771 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4772 rprn = get_token = bin_last = false;
4776 case BC_LEX_OP_MINUS:
4778 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4779 rprn = get_token = false;
4780 bin_last = prev == BC_INST_MINUS;
4784 case BC_LEX_OP_ASSIGN_POWER:
4785 case BC_LEX_OP_ASSIGN_MULTIPLY:
4786 case BC_LEX_OP_ASSIGN_DIVIDE:
4787 case BC_LEX_OP_ASSIGN_MODULUS:
4788 case BC_LEX_OP_ASSIGN_PLUS:
4789 case BC_LEX_OP_ASSIGN_MINUS:
4790 case BC_LEX_OP_ASSIGN:
4792 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4793 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4794 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4796 s = BC_STATUS_PARSE_BAD_ASSIGN;
4801 case BC_LEX_OP_POWER:
4802 case BC_LEX_OP_MULTIPLY:
4803 case BC_LEX_OP_DIVIDE:
4804 case BC_LEX_OP_MODULUS:
4805 case BC_LEX_OP_PLUS:
4806 case BC_LEX_OP_REL_EQ:
4807 case BC_LEX_OP_REL_LE:
4808 case BC_LEX_OP_REL_GE:
4809 case BC_LEX_OP_REL_NE:
4810 case BC_LEX_OP_REL_LT:
4811 case BC_LEX_OP_REL_GT:
4812 case BC_LEX_OP_BOOL_NOT:
4813 case BC_LEX_OP_BOOL_OR:
4814 case BC_LEX_OP_BOOL_AND:
4816 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4817 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4819 return BC_STATUS_PARSE_BAD_EXP;
4822 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4823 prev = BC_PARSE_TOKEN_INST(t);
4824 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4825 rprn = get_token = false;
4826 bin_last = t != BC_LEX_OP_BOOL_NOT;
4833 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4836 paren_expr = rprn = bin_last = false;
4838 bc_vec_push(&p->ops, &t);
4845 if (bin_last || prev == BC_INST_BOOL_NOT)
4846 return BC_STATUS_PARSE_BAD_EXP;
4849 s = BC_STATUS_SUCCESS;
4854 else if (!paren_expr)
4855 return BC_STATUS_PARSE_EMPTY_EXP;
4858 paren_expr = rprn = true;
4859 get_token = bin_last = false;
4861 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4868 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4871 rprn = get_token = bin_last = false;
4872 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4880 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4882 bc_parse_number(p, &prev, &nexprs);
4883 paren_expr = get_token = true;
4884 rprn = bin_last = false;
4889 case BC_LEX_KEY_IBASE:
4890 case BC_LEX_KEY_LAST:
4891 case BC_LEX_KEY_OBASE:
4893 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4895 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4896 bc_parse_push(p, (char) prev);
4898 paren_expr = get_token = true;
4899 rprn = bin_last = false;
4905 case BC_LEX_KEY_LENGTH:
4906 case BC_LEX_KEY_SQRT:
4908 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4910 s = bc_parse_builtin(p, t, flags, &prev);
4912 rprn = get_token = bin_last = false;
4918 case BC_LEX_KEY_READ:
4920 if (BC_PARSE_LEAF(prev, rprn))
4921 return BC_STATUS_PARSE_BAD_EXP;
4922 else if (flags & BC_PARSE_NOREAD)
4923 s = BC_STATUS_EXEC_REC_READ;
4925 s = bc_parse_read(p);
4928 rprn = get_token = bin_last = false;
4930 prev = BC_INST_READ;
4935 case BC_LEX_KEY_SCALE:
4937 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4939 s = bc_parse_scale(p, &prev, flags);
4941 rprn = get_token = bin_last = false;
4943 prev = BC_INST_SCALE;
4950 s = BC_STATUS_PARSE_BAD_TOKEN;
4955 if (!s && get_token) s = bc_lex_next(&p->l);
4959 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4961 while (p->ops.len > ops_bgn) {
4963 top = BC_PARSE_TOP_OP(p);
4964 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4966 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4967 return BC_STATUS_PARSE_BAD_EXP;
4969 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4971 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4972 bc_vec_pop(&p->ops);
4975 s = BC_STATUS_PARSE_BAD_EXP;
4976 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4978 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4981 if (!(flags & BC_PARSE_REL) && nrelops) {
4982 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4985 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4986 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4990 if (flags & BC_PARSE_PRINT) {
4991 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4992 bc_parse_push(p, BC_INST_POP);
4998 static void bc_parse_init(BcParse *p, size_t func)
5000 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
5003 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5005 return bc_parse_expr(p, flags, bc_parse_next_read);
5010 static BcStatus dc_parse_register(BcParse *p)
5015 s = bc_lex_next(&p->l);
5017 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5019 name = xstrdup(p->l.t.v.v);
5020 bc_parse_pushName(p, name);
5025 static BcStatus dc_parse_string(BcParse *p)
5027 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5028 size_t idx, len = G.prog.strs.len;
5030 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5033 str = xstrdup(p->l.t.v.v);
5034 bc_parse_push(p, BC_INST_STR);
5035 bc_parse_pushIndex(p, len);
5036 bc_vec_push(&G.prog.strs, &str);
5037 bc_parse_addFunc(p, name, &idx);
5039 return bc_lex_next(&p->l);
5042 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5046 bc_parse_push(p, inst);
5048 s = dc_parse_register(p);
5053 bc_parse_push(p, BC_INST_SWAP);
5054 bc_parse_push(p, BC_INST_ASSIGN);
5055 bc_parse_push(p, BC_INST_POP);
5058 return bc_lex_next(&p->l);
5061 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5065 bc_parse_push(p, inst);
5066 bc_parse_push(p, BC_INST_EXEC_COND);
5068 s = dc_parse_register(p);
5071 s = bc_lex_next(&p->l);
5074 if (p->l.t.t == BC_LEX_ELSE) {
5075 s = dc_parse_register(p);
5077 s = bc_lex_next(&p->l);
5080 bc_parse_push(p, BC_PARSE_STREND);
5085 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5087 BcStatus s = BC_STATUS_SUCCESS;
5090 bool assign, get_token = false;
5094 case BC_LEX_OP_REL_EQ:
5095 case BC_LEX_OP_REL_LE:
5096 case BC_LEX_OP_REL_GE:
5097 case BC_LEX_OP_REL_NE:
5098 case BC_LEX_OP_REL_LT:
5099 case BC_LEX_OP_REL_GT:
5101 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5108 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5114 s = dc_parse_string(p);
5121 if (t == BC_LEX_NEG) {
5122 s = bc_lex_next(&p->l);
5124 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5127 bc_parse_number(p, &prev, &p->nbraces);
5129 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5135 case BC_LEX_KEY_READ:
5137 if (flags & BC_PARSE_NOREAD)
5138 s = BC_STATUS_EXEC_REC_READ;
5140 bc_parse_push(p, BC_INST_READ);
5145 case BC_LEX_OP_ASSIGN:
5146 case BC_LEX_STORE_PUSH:
5148 assign = t == BC_LEX_OP_ASSIGN;
5149 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5150 s = dc_parse_mem(p, inst, true, assign);
5155 case BC_LEX_LOAD_POP:
5157 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5158 s = dc_parse_mem(p, inst, true, false);
5162 case BC_LEX_STORE_IBASE:
5163 case BC_LEX_STORE_SCALE:
5164 case BC_LEX_STORE_OBASE:
5166 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5167 s = dc_parse_mem(p, inst, false, true);
5173 s = BC_STATUS_PARSE_BAD_TOKEN;
5179 if (!s && get_token) s = bc_lex_next(&p->l);
5184 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5186 BcStatus s = BC_STATUS_SUCCESS;
5190 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5192 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5194 inst = dc_parse_insts[t];
5196 if (inst != BC_INST_INVALID) {
5197 bc_parse_push(p, inst);
5198 s = bc_lex_next(&p->l);
5201 s = dc_parse_token(p, t, flags);
5204 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5205 bc_parse_push(p, BC_INST_POP_EXEC);
5210 static BcStatus dc_parse_parse(BcParse *p)
5214 if (p->l.t.t == BC_LEX_EOF)
5215 s = BC_STATUS_LEX_EOF;
5217 s = dc_parse_expr(p, 0);
5219 if (s || G_interrupt) s = bc_parse_reset(p, s);
5224 static void dc_parse_init(BcParse *p, size_t func)
5226 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5230 static void common_parse_init(BcParse *p, size_t func)
5233 bc_parse_init(p, func);
5235 dc_parse_init(p, func);
5239 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5242 return bc_parse_expression(p, flags);
5244 return dc_parse_expr(p, flags);
5248 static BcVec* bc_program_search(char *id, bool var)
5257 v = var ? &G.prog.vars : &G.prog.arrs;
5258 map = var ? &G.prog.var_map : &G.prog.arr_map;
5262 s = bc_map_insert(map, &e, &i);
5263 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5266 bc_array_init(&data.v, var);
5267 bc_vec_push(v, &data.v);
5270 ptr = bc_vec_item(map, i);
5271 if (new) ptr->name = xstrdup(e.name);
5272 return bc_vec_item(v, ptr->idx);
5275 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5277 BcStatus s = BC_STATUS_SUCCESS;
5282 case BC_RESULT_TEMP:
5283 case BC_RESULT_IBASE:
5284 case BC_RESULT_SCALE:
5285 case BC_RESULT_OBASE:
5291 case BC_RESULT_CONSTANT:
5293 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5294 size_t base_t, len = strlen(*str);
5297 bc_num_init(&r->d.n, len);
5299 hex = hex && len == 1;
5300 base = hex ? &G.prog.hexb : &G.prog.ib;
5301 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5302 s = bc_num_parse(&r->d.n, *str, base, base_t);
5305 bc_num_free(&r->d.n);
5310 r->t = BC_RESULT_TEMP;
5316 case BC_RESULT_ARRAY:
5317 case BC_RESULT_ARRAY_ELEM:
5321 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5323 if (r->t == BC_RESULT_ARRAY_ELEM) {
5325 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5326 *num = bc_vec_item(v, r->d.id.idx);
5329 *num = bc_vec_top(v);
5334 case BC_RESULT_LAST:
5336 *num = &G.prog.last;
5350 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5351 BcResult **r, BcNum **rn, bool assign)
5355 BcResultType lt, rt;
5357 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5359 *r = bc_vec_item_rev(&G.prog.results, 0);
5360 *l = bc_vec_item_rev(&G.prog.results, 1);
5364 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5366 s = bc_program_num(*l, ln, false);
5368 s = bc_program_num(*r, rn, hex);
5371 // We run this again under these conditions in case any vector has been
5372 // reallocated out from under the BcNums or arrays we had.
5373 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5374 s = bc_program_num(*l, ln, false);
5378 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5379 return BC_STATUS_EXEC_BAD_TYPE;
5380 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5385 static void bc_program_binOpRetire(BcResult *r)
5387 r->t = BC_RESULT_TEMP;
5388 bc_vec_pop(&G.prog.results);
5389 bc_vec_pop(&G.prog.results);
5390 bc_vec_push(&G.prog.results, r);
5393 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5397 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5398 *r = bc_vec_top(&G.prog.results);
5400 s = bc_program_num(*r, n, false);
5403 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5408 static void bc_program_retire(BcResult *r, BcResultType t)
5411 bc_vec_pop(&G.prog.results);
5412 bc_vec_push(&G.prog.results, r);
5415 static BcStatus bc_program_op(char inst)
5418 BcResult *opd1, *opd2, res;
5419 BcNum *n1, *n2 = NULL;
5421 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5423 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5425 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5427 bc_program_binOpRetire(&res);
5432 bc_num_free(&res.d.n);
5436 static BcStatus bc_program_read(void)
5443 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5445 for (i = 0; i < G.prog.stack.len; ++i) {
5446 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5447 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5450 bc_vec_npop(&f->code, f->code.len);
5451 bc_vec_init(&buf, sizeof(char), NULL);
5453 s = bc_read_line(&buf, "read> ");
5456 common_parse_init(&parse, BC_PROG_READ);
5457 bc_lex_file(&parse.l, bc_program_stdin_name);
5459 s = bc_parse_text(&parse, buf.v);
5460 if (s) goto exec_err;
5461 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5462 if (s) goto exec_err;
5464 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5465 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5469 ip.func = BC_PROG_READ;
5471 ip.len = G.prog.results.len;
5473 // Update this pointer, just in case.
5474 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5476 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5477 bc_vec_push(&G.prog.stack, &ip);
5480 bc_parse_free(&parse);
5486 static size_t bc_program_index(char *code, size_t *bgn)
5488 char amt = code[(*bgn)++], i = 0;
5491 for (; i < amt; ++i, ++(*bgn))
5492 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5497 static char *bc_program_name(char *code, size_t *bgn)
5500 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5502 s = xmalloc(ptr - str + 1);
5505 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5513 static void bc_program_printString(const char *str, size_t *nchars)
5515 size_t i, len = strlen(str);
5524 for (i = 0; i < len; ++i, ++(*nchars)) {
5528 if (c != '\\' || i == len - 1)
5588 // Just print the backslash and following character.
5599 static BcStatus bc_program_print(char inst, size_t idx)
5601 BcStatus s = BC_STATUS_SUCCESS;
5606 bool pop = inst != BC_INST_PRINT;
5608 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5610 r = bc_vec_item_rev(&G.prog.results, idx);
5611 s = bc_program_num(r, &num, false);
5614 if (BC_PROG_NUM(r, num)) {
5615 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5616 if (!s) bc_num_copy(&G.prog.last, num);
5620 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5621 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5623 if (inst == BC_INST_PRINT_STR) {
5624 for (i = 0, len = strlen(str); i < len; ++i) {
5627 if (c == '\n') G.prog.nchars = SIZE_MAX;
5632 bc_program_printString(str, &G.prog.nchars);
5633 if (inst == BC_INST_PRINT) bb_putchar('\n');
5637 if (!s && pop) bc_vec_pop(&G.prog.results);
5642 static BcStatus bc_program_negate(void)
5648 s = bc_program_prep(&ptr, &num);
5651 bc_num_init(&res.d.n, num->len);
5652 bc_num_copy(&res.d.n, num);
5653 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5655 bc_program_retire(&res, BC_RESULT_TEMP);
5660 static BcStatus bc_program_logical(char inst)
5663 BcResult *opd1, *opd2, res;
5668 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5670 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5672 if (inst == BC_INST_BOOL_AND)
5673 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5674 else if (inst == BC_INST_BOOL_OR)
5675 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5678 cmp = bc_num_cmp(n1, n2);
5682 case BC_INST_REL_EQ:
5688 case BC_INST_REL_LE:
5694 case BC_INST_REL_GE:
5700 case BC_INST_REL_NE:
5706 case BC_INST_REL_LT:
5712 case BC_INST_REL_GT:
5720 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5722 bc_program_binOpRetire(&res);
5728 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5734 memset(&n2, 0, sizeof(BcNum));
5735 n2.rdx = res.d.id.idx = r->d.id.idx;
5736 res.t = BC_RESULT_STR;
5739 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5741 bc_vec_pop(&G.prog.results);
5744 bc_vec_pop(&G.prog.results);
5746 bc_vec_push(&G.prog.results, &res);
5747 bc_vec_push(v, &n2);
5749 return BC_STATUS_SUCCESS;
5753 static BcStatus bc_program_copyToVar(char *name, bool var)
5760 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5762 ptr = bc_vec_top(&G.prog.results);
5763 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5764 v = bc_program_search(name, var);
5767 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5768 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5771 s = bc_program_num(ptr, &n, false);
5774 // Do this once more to make sure that pointers were not invalidated.
5775 v = bc_program_search(name, var);
5778 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5779 bc_num_copy(&r.d.n, n);
5782 bc_array_init(&r.d.v, true);
5783 bc_array_copy(&r.d.v, (BcVec *) n);
5786 bc_vec_push(v, &r.d);
5787 bc_vec_pop(&G.prog.results);
5792 static BcStatus bc_program_assign(char inst)
5795 BcResult *left, *right, res;
5796 BcNum *l = NULL, *r = NULL;
5797 unsigned long val, max;
5798 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5800 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5803 ib = left->t == BC_RESULT_IBASE;
5804 sc = left->t == BC_RESULT_SCALE;
5808 if (right->t == BC_RESULT_STR) {
5812 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5813 v = bc_program_search(left->d.id.name, true);
5815 return bc_program_assignStr(right, v, false);
5819 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5820 return BC_STATUS_PARSE_BAD_ASSIGN;
5823 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5824 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5829 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5836 if (ib || sc || left->t == BC_RESULT_OBASE) {
5840 s = bc_num_ulong(l, &val);
5842 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5846 ptr = &G.prog.scale;
5849 if (val < BC_NUM_MIN_BASE) return s;
5850 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5851 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5854 if (val > max) return s;
5855 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5857 *ptr = (size_t) val;
5858 s = BC_STATUS_SUCCESS;
5861 bc_num_init(&res.d.n, l->len);
5862 bc_num_copy(&res.d.n, l);
5863 bc_program_binOpRetire(&res);
5868 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5869 bool pop, bool copy)
5871 BcStatus s = BC_STATUS_SUCCESS;
5873 char *name = bc_program_name(code, bgn);
5874 #if ENABLE_DC // Exclude
5878 (void) pop, (void) copy;
5881 r.t = BC_RESULT_VAR;
5885 v = bc_program_search(name, true);
5886 num = bc_vec_top(v);
5890 if (!BC_PROG_STACK(v, 2 - copy)) {
5892 return BC_STATUS_EXEC_STACK;
5898 if (!BC_PROG_STR(num)) {
5900 r.t = BC_RESULT_TEMP;
5902 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5903 bc_num_copy(&r.d.n, num);
5906 r.t = BC_RESULT_STR;
5907 r.d.id.idx = num->rdx;
5910 if (!copy) bc_vec_pop(v);
5914 bc_vec_push(&G.prog.results, &r);
5919 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5922 BcStatus s = BC_STATUS_SUCCESS;
5926 r.d.id.name = bc_program_name(code, bgn);
5928 if (inst == BC_INST_ARRAY) {
5929 r.t = BC_RESULT_ARRAY;
5930 bc_vec_push(&G.prog.results, &r);
5937 s = bc_program_prep(&operand, &num);
5939 s = bc_num_ulong(num, &temp);
5942 if (temp > BC_MAX_DIM) {
5943 s = BC_STATUS_EXEC_ARRAY_LEN;
5947 r.d.id.idx = (size_t) temp;
5948 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5952 if (s) free(r.d.id.name);
5957 static BcStatus bc_program_incdec(char inst)
5960 BcResult *ptr, res, copy;
5964 s = bc_program_prep(&ptr, &num);
5967 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5968 copy.t = BC_RESULT_TEMP;
5969 bc_num_init(©.d.n, num->len);
5970 bc_num_copy(©.d.n, num);
5973 res.t = BC_RESULT_ONE;
5974 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5975 BC_INST_ASSIGN_PLUS :
5976 BC_INST_ASSIGN_MINUS;
5978 bc_vec_push(&G.prog.results, &res);
5979 bc_program_assign(inst);
5981 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5982 bc_vec_pop(&G.prog.results);
5983 bc_vec_push(&G.prog.results, ©);
5989 static BcStatus bc_program_call(char *code, size_t *idx)
5991 BcStatus s = BC_STATUS_SUCCESS;
5993 size_t i, nparams = bc_program_index(code, idx);
6000 ip.func = bc_program_index(code, idx);
6001 func = bc_vec_item(&G.prog.fns, ip.func);
6003 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6004 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6005 ip.len = G.prog.results.len - nparams;
6007 for (i = 0; i < nparams; ++i) {
6009 a = bc_vec_item(&func->autos, nparams - 1 - i);
6010 arg = bc_vec_top(&G.prog.results);
6012 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6013 return BC_STATUS_EXEC_BAD_TYPE;
6015 s = bc_program_copyToVar(a->name, a->idx);
6019 for (; i < func->autos.len; ++i) {
6022 a = bc_vec_item(&func->autos, i);
6023 v = bc_program_search(a->name, a->idx);
6026 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6027 bc_vec_push(v, ¶m.n);
6030 bc_array_init(¶m.v, true);
6031 bc_vec_push(v, ¶m.v);
6035 bc_vec_push(&G.prog.stack, &ip);
6037 return BC_STATUS_SUCCESS;
6040 static BcStatus bc_program_return(char inst)
6046 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6048 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6049 return BC_STATUS_EXEC_STACK;
6051 f = bc_vec_item(&G.prog.fns, ip->func);
6052 res.t = BC_RESULT_TEMP;
6054 if (inst == BC_INST_RET) {
6057 BcResult *operand = bc_vec_top(&G.prog.results);
6059 s = bc_program_num(operand, &num, false);
6061 bc_num_init(&res.d.n, num->len);
6062 bc_num_copy(&res.d.n, num);
6065 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6066 bc_num_zero(&res.d.n);
6069 // We need to pop arguments as well, so this takes that into account.
6070 for (i = 0; i < f->autos.len; ++i) {
6073 BcId *a = bc_vec_item(&f->autos, i);
6075 v = bc_program_search(a->name, a->idx);
6079 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6080 bc_vec_push(&G.prog.results, &res);
6081 bc_vec_pop(&G.prog.stack);
6083 return BC_STATUS_SUCCESS;
6087 static unsigned long bc_program_scale(BcNum *n)
6089 return (unsigned long) n->rdx;
6092 static unsigned long bc_program_len(BcNum *n)
6094 unsigned long len = n->len;
6097 if (n->rdx != n->len) return len;
6098 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6103 static BcStatus bc_program_builtin(char inst)
6109 bool len = inst == BC_INST_LENGTH;
6111 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6112 opnd = bc_vec_top(&G.prog.results);
6114 s = bc_program_num(opnd, &num, false);
6118 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6121 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6123 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6125 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6126 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6130 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6133 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6135 str = bc_vec_item(&G.prog.strs, idx);
6136 bc_num_ulong2num(&res.d.n, strlen(*str));
6140 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6141 bc_num_ulong2num(&res.d.n, f(num));
6144 bc_program_retire(&res, BC_RESULT_TEMP);
6150 static BcStatus bc_program_divmod(void)
6153 BcResult *opd1, *opd2, res, res2;
6154 BcNum *n1, *n2 = NULL;
6156 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6159 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6160 bc_num_init(&res2.d.n, n2->len);
6162 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6165 bc_program_binOpRetire(&res2);
6166 res.t = BC_RESULT_TEMP;
6167 bc_vec_push(&G.prog.results, &res);
6172 bc_num_free(&res2.d.n);
6173 bc_num_free(&res.d.n);
6177 static BcStatus bc_program_modexp(void)
6180 BcResult *r1, *r2, *r3, res;
6181 BcNum *n1, *n2, *n3;
6183 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6184 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6187 r1 = bc_vec_item_rev(&G.prog.results, 2);
6188 s = bc_program_num(r1, &n1, false);
6190 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6192 // Make sure that the values have their pointers updated, if necessary.
6193 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6195 if (r1->t == r2->t) {
6196 s = bc_program_num(r2, &n2, false);
6200 if (r1->t == r3->t) {
6201 s = bc_program_num(r3, &n3, false);
6206 bc_num_init(&res.d.n, n3->len);
6207 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6210 bc_vec_pop(&G.prog.results);
6211 bc_program_binOpRetire(&res);
6216 bc_num_free(&res.d.n);
6220 static void bc_program_stackLen(void)
6223 size_t len = G.prog.results.len;
6225 res.t = BC_RESULT_TEMP;
6227 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6228 bc_num_ulong2num(&res.d.n, len);
6229 bc_vec_push(&G.prog.results, &res);
6232 static BcStatus bc_program_asciify(void)
6236 BcNum *num = NULL, n;
6237 char *str, *str2, c;
6238 size_t len = G.prog.strs.len, idx;
6241 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6242 r = bc_vec_top(&G.prog.results);
6244 s = bc_program_num(r, &num, false);
6247 if (BC_PROG_NUM(r, num)) {
6249 bc_num_init(&n, BC_NUM_DEF_SIZE);
6250 bc_num_copy(&n, num);
6251 bc_num_truncate(&n, n.rdx);
6253 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6254 if (s) goto num_err;
6255 s = bc_num_ulong(&n, &val);
6256 if (s) goto num_err;
6263 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6264 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6272 str2 = xstrdup(str);
6273 bc_program_addFunc(str2, &idx);
6275 if (idx != len + BC_PROG_REQ_FUNCS) {
6277 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6278 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6287 bc_vec_push(&G.prog.strs, &str);
6289 res.t = BC_RESULT_STR;
6291 bc_vec_pop(&G.prog.results);
6292 bc_vec_push(&G.prog.results, &res);
6294 return BC_STATUS_SUCCESS;
6301 static BcStatus bc_program_printStream(void)
6309 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6310 r = bc_vec_top(&G.prog.results);
6312 s = bc_program_num(r, &n, false);
6315 if (BC_PROG_NUM(r, n))
6316 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6318 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6319 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6326 static BcStatus bc_program_nquit(void)
6333 s = bc_program_prep(&opnd, &num);
6335 s = bc_num_ulong(num, &val);
6338 bc_vec_pop(&G.prog.results);
6340 if (G.prog.stack.len < val)
6341 return BC_STATUS_EXEC_STACK;
6342 else if (G.prog.stack.len == val)
6343 return BC_STATUS_QUIT;
6345 bc_vec_npop(&G.prog.stack, val);
6350 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6353 BcStatus s = BC_STATUS_SUCCESS;
6363 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6365 r = bc_vec_top(&G.prog.results);
6369 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6371 if (code[*bgn] == BC_PARSE_STREND)
6374 else_name = bc_program_name(code, bgn);
6376 exec = r->d.n.len != 0;
6380 else if (else_name != NULL) {
6387 v = bc_program_search(name, true);
6394 if (!exec) goto exit;
6395 if (!BC_PROG_STR(n)) {
6396 s = BC_STATUS_EXEC_BAD_TYPE;
6404 if (r->t == BC_RESULT_STR)
6406 else if (r->t == BC_RESULT_VAR) {
6407 s = bc_program_num(r, &n, false);
6408 if (s || !BC_PROG_STR(n)) goto exit;
6415 fidx = sidx + BC_PROG_REQ_FUNCS;
6417 str = bc_vec_item(&G.prog.strs, sidx);
6418 f = bc_vec_item(&G.prog.fns, fidx);
6420 if (f->code.len == 0) {
6421 common_parse_init(&prs, fidx);
6422 s = bc_parse_text(&prs, *str);
6424 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6427 if (prs.l.t.t != BC_LEX_EOF) {
6428 s = BC_STATUS_PARSE_BAD_EXP;
6432 bc_parse_free(&prs);
6436 ip.len = G.prog.results.len;
6439 bc_vec_pop(&G.prog.results);
6440 bc_vec_push(&G.prog.stack, &ip);
6442 return BC_STATUS_SUCCESS;
6445 bc_parse_free(&prs);
6446 f = bc_vec_item(&G.prog.fns, fidx);
6447 bc_vec_npop(&f->code, f->code.len);
6449 bc_vec_pop(&G.prog.results);
6454 static void bc_program_pushGlobal(char inst)
6459 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6460 if (inst == BC_INST_IBASE)
6461 val = (unsigned long) G.prog.ib_t;
6462 else if (inst == BC_INST_SCALE)
6463 val = (unsigned long) G.prog.scale;
6465 val = (unsigned long) G.prog.ob_t;
6467 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6468 bc_num_ulong2num(&res.d.n, val);
6469 bc_vec_push(&G.prog.results, &res);
6472 static void bc_program_addFunc(char *name, size_t *idx)
6475 BcId entry, *entry_ptr;
6479 entry.idx = G.prog.fns.len;
6481 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6484 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6485 *idx = entry_ptr->idx;
6487 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6489 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6491 // We need to reset these, so the function can be repopulated.
6493 bc_vec_npop(&func->autos, func->autos.len);
6494 bc_vec_npop(&func->code, func->code.len);
6495 bc_vec_npop(&func->labels, func->labels.len);
6499 bc_vec_push(&G.prog.fns, &f);
6503 static BcStatus bc_program_reset(BcStatus s)
6508 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6509 bc_vec_npop(&G.prog.results, G.prog.results.len);
6511 f = bc_vec_item(&G.prog.fns, 0);
6512 ip = bc_vec_top(&G.prog.stack);
6513 ip->idx = f->code.len;
6515 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6517 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6520 fputs(bc_program_ready_msg, stderr);
6522 s = BC_STATUS_SUCCESS;
6531 static BcStatus bc_program_exec(void)
6533 BcStatus s = BC_STATUS_SUCCESS;
6537 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6538 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6539 char *code = func->code.v;
6542 while (!s && ip->idx < func->code.len) {
6544 char inst = code[(ip->idx)++];
6549 case BC_INST_JUMP_ZERO:
6551 s = bc_program_prep(&ptr, &num);
6553 cond = !bc_num_cmp(num, &G.prog.zero);
6554 bc_vec_pop(&G.prog.results);
6560 idx = bc_program_index(code, &ip->idx);
6561 addr = bc_vec_item(&func->labels, idx);
6562 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6568 s = bc_program_call(code, &ip->idx);
6572 case BC_INST_INC_PRE:
6573 case BC_INST_DEC_PRE:
6574 case BC_INST_INC_POST:
6575 case BC_INST_DEC_POST:
6577 s = bc_program_incdec(inst);
6590 s = bc_program_return(inst);
6594 case BC_INST_BOOL_OR:
6595 case BC_INST_BOOL_AND:
6597 case BC_INST_REL_EQ:
6598 case BC_INST_REL_LE:
6599 case BC_INST_REL_GE:
6600 case BC_INST_REL_NE:
6601 case BC_INST_REL_LT:
6602 case BC_INST_REL_GT:
6604 s = bc_program_logical(inst);
6610 s = bc_program_read();
6616 s = bc_program_pushVar(code, &ip->idx, false, false);
6620 case BC_INST_ARRAY_ELEM:
6623 s = bc_program_pushArray(code, &ip->idx, inst);
6629 r.t = BC_RESULT_LAST;
6630 bc_vec_push(&G.prog.results, &r);
6638 bc_program_pushGlobal(inst);
6642 case BC_INST_SCALE_FUNC:
6643 case BC_INST_LENGTH:
6646 s = bc_program_builtin(inst);
6652 r.t = BC_RESULT_CONSTANT;
6653 r.d.id.idx = bc_program_index(code, &ip->idx);
6654 bc_vec_push(&G.prog.results, &r);
6660 if (!BC_PROG_STACK(&G.prog.results, 1))
6661 s = BC_STATUS_EXEC_STACK;
6663 bc_vec_pop(&G.prog.results);
6667 case BC_INST_POP_EXEC:
6669 bc_vec_pop(&G.prog.stack);
6674 case BC_INST_PRINT_POP:
6675 case BC_INST_PRINT_STR:
6677 s = bc_program_print(inst, 0);
6683 r.t = BC_RESULT_STR;
6684 r.d.id.idx = bc_program_index(code, &ip->idx);
6685 bc_vec_push(&G.prog.results, &r);
6690 case BC_INST_MULTIPLY:
6691 case BC_INST_DIVIDE:
6692 case BC_INST_MODULUS:
6696 s = bc_program_op(inst);
6700 case BC_INST_BOOL_NOT:
6702 s = bc_program_prep(&ptr, &num);
6705 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6706 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6707 bc_program_retire(&r, BC_RESULT_TEMP);
6714 s = bc_program_negate();
6719 case BC_INST_ASSIGN_POWER:
6720 case BC_INST_ASSIGN_MULTIPLY:
6721 case BC_INST_ASSIGN_DIVIDE:
6722 case BC_INST_ASSIGN_MODULUS:
6723 case BC_INST_ASSIGN_PLUS:
6724 case BC_INST_ASSIGN_MINUS:
6726 case BC_INST_ASSIGN:
6728 s = bc_program_assign(inst);
6732 case BC_INST_MODEXP:
6734 s = bc_program_modexp();
6738 case BC_INST_DIVMOD:
6740 s = bc_program_divmod();
6744 case BC_INST_EXECUTE:
6745 case BC_INST_EXEC_COND:
6747 cond = inst == BC_INST_EXEC_COND;
6748 s = bc_program_execStr(code, &ip->idx, cond);
6752 case BC_INST_PRINT_STACK:
6754 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6755 s = bc_program_print(BC_INST_PRINT, idx);
6759 case BC_INST_CLEAR_STACK:
6761 bc_vec_npop(&G.prog.results, G.prog.results.len);
6765 case BC_INST_STACK_LEN:
6767 bc_program_stackLen();
6771 case BC_INST_DUPLICATE:
6773 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6774 ptr = bc_vec_top(&G.prog.results);
6775 bc_result_copy(&r, ptr);
6776 bc_vec_push(&G.prog.results, &r);
6784 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6786 ptr = bc_vec_item_rev(&G.prog.results, 0);
6787 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6788 memcpy(&r, ptr, sizeof(BcResult));
6789 memcpy(ptr, ptr2, sizeof(BcResult));
6790 memcpy(ptr2, &r, sizeof(BcResult));
6795 case BC_INST_ASCIIFY:
6797 s = bc_program_asciify();
6801 case BC_INST_PRINT_STREAM:
6803 s = bc_program_printStream();
6808 case BC_INST_PUSH_VAR:
6810 bool copy = inst == BC_INST_LOAD;
6811 s = bc_program_pushVar(code, &ip->idx, true, copy);
6815 case BC_INST_PUSH_TO_VAR:
6817 char *name = bc_program_name(code, &ip->idx);
6818 s = bc_program_copyToVar(name, true);
6825 if (G.prog.stack.len <= 2)
6828 bc_vec_npop(&G.prog.stack, 2);
6834 s = bc_program_nquit();
6840 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
6842 // If the stack has changed, pointers may be invalid.
6843 ip = bc_vec_top(&G.prog.stack);
6844 func = bc_vec_item(&G.prog.fns, ip->func);
6845 code = func->code.v;
6851 static void bc_vm_info(void)
6853 printf("%s "BB_VER"\n"
6854 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6855 "Report bugs at: https://github.com/gavinhoward/bc\n"
6856 "This is free software with ABSOLUTELY NO WARRANTY\n"
6860 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6862 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6864 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6865 fprintf(stderr, " %s", file);
6866 fprintf(stderr, bc_err_line + 4 * !line, line);
6868 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6872 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6875 int p = (int) G_posix, w = (int) G_warn;
6876 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6878 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6880 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6881 if (msg) fprintf(stderr, " %s\n", msg);
6882 fprintf(stderr, " %s", file);
6883 fprintf(stderr, bc_err_line + 4 * !line, line);
6885 return s * (!G.ttyin && !!p);
6888 static void bc_vm_envArgs(void)
6891 char *env_args = getenv(bc_args_env_name), *buf;
6893 if (!env_args) return;
6895 G.env_args = xstrdup(env_args);
6898 bc_vec_init(&v, sizeof(char *), NULL);
6899 bc_vec_push(&v, &bc_args_env_name);
6902 if (!isspace(*buf)) {
6903 bc_vec_push(&v, &buf);
6904 while (*buf != 0 && !isspace(*buf)) ++buf;
6905 if (*buf != 0) (*(buf++)) = '\0';
6911 bc_args((int) v.len, (char **) v.v);
6917 static size_t bc_vm_envLen(const char *var)
6919 char *lenv = getenv(var);
6920 size_t i, len = BC_NUM_PRINT_WIDTH;
6923 if (!lenv) return len;
6927 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6929 len = (size_t) atoi(lenv) - 1;
6930 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6933 len = BC_NUM_PRINT_WIDTH;
6938 static BcStatus bc_vm_process(const char *text)
6940 BcStatus s = bc_parse_text(&G.prs, text);
6942 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6945 while (G.prs.l.t.t != BC_LEX_EOF) {
6947 s = G.prs.parse(&G.prs);
6949 if (s == BC_STATUS_LIMITS) {
6952 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
6953 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
6954 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
6955 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
6956 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
6957 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
6958 printf("Max Exponent = %lu\n", BC_MAX_EXP);
6959 printf("Number of Vars = %lu\n", BC_MAX_VARS);
6962 s = BC_STATUS_SUCCESS;
6965 if (s == BC_STATUS_QUIT) return s;
6966 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6971 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6972 s = bc_program_exec();
6973 if (!s && G.tty) fflush(stdout);
6974 if (s && s != BC_STATUS_QUIT)
6975 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6981 static BcStatus bc_vm_file(const char *file)
6989 data = bc_read_file(file);
6990 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
6992 bc_lex_file(&G.prs.l, file);
6993 s = bc_vm_process(data);
6996 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6997 ip = bc_vec_item(&G.prog.stack, 0);
6999 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7006 static BcStatus bc_vm_stdin(void)
7010 size_t len, i, str = 0;
7011 bool comment = false;
7013 G.prog.file = bc_program_stdin_name;
7014 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7016 bc_vec_init(&buffer, sizeof(char), NULL);
7017 bc_vec_init(&buf, sizeof(char), NULL);
7018 bc_vec_pushByte(&buffer, '\0');
7020 // This loop is complex because the vm tries not to send any lines that end
7021 // with a backslash to the parser. The reason for that is because the parser
7022 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7023 // case, and for strings and comments, the parser will expect more stuff.
7024 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7026 char *string = buf.v;
7031 if (str && buf.v[0] == G.send)
7033 else if (buf.v[0] == G.sbgn)
7036 else if (len > 1 || comment) {
7038 for (i = 0; i < len; ++i) {
7040 bool notend = len > i + 1;
7043 if (i - 1 > len || string[i - 1] != '\\') {
7044 if (G.sbgn == G.send)
7046 else if (c == G.send)
7048 else if (c == G.sbgn)
7052 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7056 else if (c == '*' && notend && comment && string[i + 1] == '/')
7060 if (str || comment || string[len - 2] == '\\') {
7061 bc_vec_concat(&buffer, buf.v);
7066 bc_vec_concat(&buffer, buf.v);
7067 s = bc_vm_process(buffer.v);
7070 bc_vec_npop(&buffer, buffer.len);
7073 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7075 // INPUT_EOF will always happen when stdin is
7076 // closed. It's not a problem in that case.
7077 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7078 s = BC_STATUS_SUCCESS;
7081 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7084 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7089 bc_vec_free(&buffer);
7093 static BcStatus bc_vm_exec(void)
7095 BcStatus s = BC_STATUS_SUCCESS;
7099 if (G.flags & BC_FLAG_L) {
7101 bc_lex_file(&G.prs.l, bc_lib_name);
7102 s = bc_parse_text(&G.prs, bc_lib);
7104 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7107 s = bc_program_exec();
7112 for (i = 0; !s && i < G.files.len; ++i)
7113 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7114 if (s && s != BC_STATUS_QUIT) return s;
7116 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7117 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7119 if (s == BC_STATUS_QUIT)
7120 s = BC_STATUS_SUCCESS;
7124 #if ENABLE_FEATURE_CLEAN_UP
7125 static void bc_program_free()
7127 bc_num_free(&G.prog.ib);
7128 bc_num_free(&G.prog.ob);
7129 bc_num_free(&G.prog.hexb);
7131 bc_num_free(&G.prog.strmb);
7133 bc_vec_free(&G.prog.fns);
7134 bc_vec_free(&G.prog.fn_map);
7135 bc_vec_free(&G.prog.vars);
7136 bc_vec_free(&G.prog.var_map);
7137 bc_vec_free(&G.prog.arrs);
7138 bc_vec_free(&G.prog.arr_map);
7139 bc_vec_free(&G.prog.strs);
7140 bc_vec_free(&G.prog.consts);
7141 bc_vec_free(&G.prog.results);
7142 bc_vec_free(&G.prog.stack);
7143 bc_num_free(&G.prog.last);
7144 bc_num_free(&G.prog.zero);
7145 bc_num_free(&G.prog.one);
7148 static void bc_vm_free(void)
7150 bc_vec_free(&G.files);
7152 bc_parse_free(&G.prs);
7157 static void bc_program_init(size_t line_len)
7162 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7163 memset(&ip, 0, sizeof(BcInstPtr));
7165 /* G.prog.nchars = G.prog.scale = 0; - already is */
7166 G.prog.len = line_len;
7168 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7169 bc_num_ten(&G.prog.ib);
7172 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7173 bc_num_ten(&G.prog.ob);
7176 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7177 bc_num_ten(&G.prog.hexb);
7178 G.prog.hexb.num[0] = 6;
7181 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7182 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7185 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7186 bc_num_zero(&G.prog.last);
7188 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7189 bc_num_zero(&G.prog.zero);
7191 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7192 bc_num_one(&G.prog.one);
7194 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7195 bc_map_init(&G.prog.fn_map);
7197 bc_program_addFunc(xstrdup(bc_func_main), &idx);
7198 bc_program_addFunc(xstrdup(bc_func_read), &idx);
7200 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7201 bc_map_init(&G.prog.var_map);
7203 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7204 bc_map_init(&G.prog.arr_map);
7206 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7207 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7208 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7209 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7210 bc_vec_push(&G.prog.stack, &ip);
7213 static void bc_vm_init(const char *env_len)
7215 size_t len = bc_vm_envLen(env_len);
7217 #if ENABLE_FEATURE_BC_SIGNALS
7218 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7221 bc_vec_init(&G.files, sizeof(char *), NULL);
7224 if (getenv("POSIXLY_CORRECT"))
7225 G.flags |= BC_FLAG_S;
7229 bc_program_init(len);
7231 bc_parse_init(&G.prs, BC_PROG_MAIN);
7233 dc_parse_init(&G.prs, BC_PROG_MAIN);
7237 static BcStatus bc_vm_run(int argc, char *argv[],
7238 const char *env_len)
7242 bc_vm_init(env_len);
7243 bc_args(argc, argv);
7245 G.ttyin = isatty(0);
7246 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7248 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7251 #if ENABLE_FEATURE_CLEAN_UP
7258 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7259 int bc_main(int argc, char **argv)
7262 G.sbgn = G.send = '"';
7264 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7269 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7270 int dc_main(int argc, char **argv)
7276 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");