1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //usage:#define bc_trivial_usage
118 //usage: "EXPRESSION...\n"
119 //usage: "function_definition\n"
121 //usage:#define bc_full_usage "\n\n"
122 //usage: "See www.gnu.org/software/bc/manual/bc.html\n"
124 //usage:#define bc_example_usage
125 //usage: "3 + 4.129\n"
126 //usage: "1903 - 2893\n"
127 //usage: "-129 * 213.28935\n"
128 //usage: "12 / -1932\n"
130 //usage: "34 ^ 189\n"
131 //usage: "scale = 13\n"
132 //usage: "ibase = 2\n"
133 //usage: "obase = A\n"
135 //usage:#define dc_trivial_usage
136 //usage: "EXPRESSION..."
138 //usage:#define dc_full_usage "\n\n"
139 //usage: "Tiny RPN calculator. Operations:\n"
140 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141 //usage: "modular exponentiation,\n"
142 //usage: "p - print top of the stack (without popping),\n"
143 //usage: "f - print entire stack,\n"
144 //usage: "k - pop the value and set the precision.\n"
145 //usage: "i - pop the value and set input radix.\n"
146 //usage: "o - pop the value and set output radix.\n"
147 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
149 //usage:#define dc_example_usage
150 //usage: "$ dc 2 2 + p\n"
152 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
154 //usage: "$ dc 0 1 and p\n"
156 //usage: "$ dc 0 1 or p\n"
158 //usage: "$ echo 72 9 div 8 mul p | dc\n"
163 typedef enum BcStatus {
170 BC_STATUS_PATH_IS_DIR,
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
177 BC_STATUS_LEX_EXTENDED_REG,
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
234 BC_STATUS_INVALID_OPTION,
238 #define BC_ERR_IDX_VM (0)
239 #define BC_ERR_IDX_LEX (1)
240 #define BC_ERR_IDX_PARSE (2)
241 #define BC_ERR_IDX_MATH (3)
242 #define BC_ERR_IDX_EXEC (4)
243 #define BC_ERR_IDX_VEC (5)
245 #define BC_ERR_IDX_POSIX (6)
248 #define BC_VEC_INVALID_IDX ((size_t) -1)
249 #define BC_VEC_START_CAP (1 << 5)
251 typedef void (*BcVecFree)(void *);
253 typedef struct BcVec {
261 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
262 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
264 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
266 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
268 typedef signed char BcDig;
270 typedef struct BcNum {
278 #define BC_NUM_MIN_BASE ((unsigned long) 2)
279 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
280 #define BC_NUM_DEF_SIZE (16)
281 #define BC_NUM_PRINT_WIDTH (69)
283 #define BC_NUM_KARATSUBA_LEN (32)
285 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
286 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
287 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
288 #define BC_NUM_AREQ(a, b) \
289 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
290 #define BC_NUM_MREQ(a, b, scale) \
291 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
293 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
294 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
296 static void bc_num_init(BcNum *n, size_t req);
297 static void bc_num_expand(BcNum *n, size_t req);
298 static void bc_num_copy(BcNum *d, BcNum *s);
299 static void bc_num_free(void *num);
301 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
302 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
304 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
311 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
314 typedef enum BcInst {
344 BC_INST_ASSIGN_POWER,
345 BC_INST_ASSIGN_MULTIPLY,
346 BC_INST_ASSIGN_DIVIDE,
347 BC_INST_ASSIGN_MODULUS,
349 BC_INST_ASSIGN_MINUS,
395 BC_INST_PRINT_STREAM,
410 BC_INST_INVALID = -1,
415 typedef struct BcId {
420 typedef struct BcFunc {
427 typedef enum BcResultType {
432 BC_RESULT_ARRAY_ELEM,
441 // These are between to calculate ibase, obase, and last from instructions.
449 typedef union BcResultData {
455 typedef struct BcResult {
460 typedef struct BcInstPtr {
466 static void bc_array_expand(BcVec *a, size_t len);
467 static int bc_id_cmp(const void *e1, const void *e2);
469 // BC_LEX_NEG is not used in lexing; it is only for parsing.
470 typedef enum BcLexType {
498 BC_LEX_OP_ASSIGN_POWER,
499 BC_LEX_OP_ASSIGN_MULTIPLY,
500 BC_LEX_OP_ASSIGN_DIVIDE,
501 BC_LEX_OP_ASSIGN_MODULUS,
502 BC_LEX_OP_ASSIGN_PLUS,
503 BC_LEX_OP_ASSIGN_MINUS,
577 typedef BcStatus (*BcLexNext)(struct BcLex *);
579 typedef struct BcLex {
598 #define BC_PARSE_STREND ((char) UCHAR_MAX)
600 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
601 #define bc_parse_updateFunc(p, f) \
602 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
604 #define BC_PARSE_REL (1 << 0)
605 #define BC_PARSE_PRINT (1 << 1)
606 #define BC_PARSE_NOCALL (1 << 2)
607 #define BC_PARSE_NOREAD (1 << 3)
608 #define BC_PARSE_ARRAY (1 << 4)
610 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
611 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
613 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
614 #define BC_PARSE_FUNC_INNER(parse) \
615 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
617 #define BC_PARSE_FLAG_FUNC (1 << 1)
618 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
620 #define BC_PARSE_FLAG_BODY (1 << 2)
621 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
623 #define BC_PARSE_FLAG_LOOP (1 << 3)
624 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
626 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
627 #define BC_PARSE_LOOP_INNER(parse) \
628 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
630 #define BC_PARSE_FLAG_IF (1 << 5)
631 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
633 #define BC_PARSE_FLAG_ELSE (1 << 6)
634 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
636 #define BC_PARSE_FLAG_IF_END (1 << 7)
637 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
639 #define BC_PARSE_CAN_EXEC(parse) \
640 (!(BC_PARSE_TOP_FLAG(parse) & \
641 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
642 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
643 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
645 typedef struct BcOp {
650 typedef struct BcParseNext {
655 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
656 #define BC_PARSE_NEXT(a, ...) \
658 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
665 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
666 typedef BcStatus (*BcParseParse)(struct BcParse *);
667 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
669 typedef struct BcParse {
682 struct BcProgram *prog;
693 typedef struct BcLexKeyword {
699 #define BC_LEX_KW_ENTRY(a, b, c) \
701 .name = a, .len = (b), .posix = (c) \
704 static BcStatus bc_lex_token(BcLex *l);
706 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
707 #define BC_PARSE_LEAF(p, rparen) \
708 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
709 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
711 // We can calculate the conversion between tokens and exprs by subtracting the
712 // position of the first operator in the lex enum and adding the position of the
713 // first in the expr enum. Note: This only works for binary operators.
714 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
716 static BcStatus bc_parse_parse(BcParse *p);
717 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
723 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
725 static BcStatus dc_lex_token(BcLex *l);
727 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
728 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
732 typedef struct BcProgram {
771 BcParseInit parse_init;
772 BcParseExpr parse_expr;
776 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
778 #define BC_PROG_MAIN (0)
779 #define BC_PROG_READ (1)
782 #define BC_PROG_REQ_FUNCS (2)
785 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
786 #define BC_PROG_NUM(r, n) \
787 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
789 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
791 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
792 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
793 static BcStatus bc_program_exec(BcProgram *p);
795 #define BC_FLAG_X (1 << 0)
796 #define BC_FLAG_W (1 << 1)
797 #define BC_FLAG_V (1 << 2)
798 #define BC_FLAG_S (1 << 3)
799 #define BC_FLAG_Q (1 << 4)
800 #define BC_FLAG_L (1 << 5)
801 #define BC_FLAG_I (1 << 6)
803 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
804 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
806 #define BC_MAX_OBASE ((unsigned long) 999)
807 #define BC_MAX_DIM ((unsigned long) INT_MAX)
808 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
809 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
810 #define BC_MAX_NAME BC_MAX_STRING
811 #define BC_MAX_NUM BC_MAX_STRING
812 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
813 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
829 unsigned sig; //counter?
830 unsigned sigc; //counter?
831 smallint signe; //flag
836 #if ENABLE_FEATURE_BC_SIGNALS
840 #define G (*ptr_to_globals)
841 #define INIT_G() do { \
842 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
844 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
845 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
846 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
849 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
852 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
856 static void bc_vm_info(void);
858 static const char* const bc_args_env_name = "BC_ENV_ARGS";
860 static const char bc_err_fmt[] = "\n%s error: %s\n";
861 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
862 static const char bc_err_line[] = ":%zu\n\n";
864 static const char *bc_errs[] = {
876 static const uint8_t bc_err_ids[] = {
877 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
878 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
882 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
883 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
884 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
889 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
890 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
891 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
892 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
894 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
896 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
897 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
898 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
900 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
903 static const char *bc_err_msgs[] = {
906 "memory allocation error",
909 "path is a directory:",
912 "string end could not be found",
913 "comment end could not be found",
922 "bad print statement",
923 "bad function definition",
924 "bad assignment: left side must be scale, ibase, "
925 "obase, last, var, or array element",
926 "no auto variable found",
927 "function parameter or auto var has the same name as another",
928 "block end could not be found",
931 "non integer number",
936 "could not open file:",
937 "mismatched parameters",
938 "undefined function",
939 "file is not executable:",
940 "number too long: must be [1, BC_NUM_MAX]",
941 "name too long: must be [1, BC_NAME_MAX]",
942 "string too long: must be [1, BC_STRING_MAX]",
943 "array too long; must be [1, BC_DIM_MAX]",
944 "bad ibase; must be [2, 16]",
945 "bad scale; must be [0, BC_SCALE_MAX]",
946 "bad read() expression",
947 "read() call inside of a read() call",
948 "variable is wrong type",
949 "bad obase; must be [2, BC_BASE_MAX]",
950 "signal caught and not handled",
951 "stack has too few elements",
953 "index is out of bounds",
954 "item already exists",
957 "POSIX only allows one character names; the following is bad:",
958 "POSIX does not allow '#' script comments",
959 "POSIX does not allow the following keyword:",
960 "POSIX does not allow a period ('.') as a shortcut for the last result",
961 "POSIX requires parentheses around return expressions",
962 "POSIX does not allow boolean operators; the following is bad:",
963 "POSIX does not allow comparison operators outside if or loops",
964 "POSIX requires exactly one comparison operator per condition",
965 "POSIX does not allow an empty init expression in a for loop",
966 "POSIX does not allow an empty condition expression in a for loop",
967 "POSIX does not allow an empty update expression in a for loop",
968 "POSIX requires the left brace be on the same line as the function header",
973 static const char bc_func_main[] = "(main)";
974 static const char bc_func_read[] = "(read)";
977 static const BcLexKeyword bc_lex_kws[20] = {
978 BC_LEX_KW_ENTRY("auto", 4, true),
979 BC_LEX_KW_ENTRY("break", 5, true),
980 BC_LEX_KW_ENTRY("continue", 8, false),
981 BC_LEX_KW_ENTRY("define", 6, true),
982 BC_LEX_KW_ENTRY("else", 4, false),
983 BC_LEX_KW_ENTRY("for", 3, true),
984 BC_LEX_KW_ENTRY("halt", 4, false),
985 BC_LEX_KW_ENTRY("ibase", 5, true),
986 BC_LEX_KW_ENTRY("if", 2, true),
987 BC_LEX_KW_ENTRY("last", 4, false),
988 BC_LEX_KW_ENTRY("length", 6, true),
989 BC_LEX_KW_ENTRY("limits", 6, false),
990 BC_LEX_KW_ENTRY("obase", 5, true),
991 BC_LEX_KW_ENTRY("print", 5, false),
992 BC_LEX_KW_ENTRY("quit", 4, true),
993 BC_LEX_KW_ENTRY("read", 4, false),
994 BC_LEX_KW_ENTRY("return", 6, true),
995 BC_LEX_KW_ENTRY("scale", 5, true),
996 BC_LEX_KW_ENTRY("sqrt", 4, true),
997 BC_LEX_KW_ENTRY("while", 5, true),
1000 // This is an array that corresponds to token types. An entry is
1001 // true if the token is valid in an expression, false otherwise.
1002 static const bool bc_parse_exprs[] = {
1003 false, false, true, true, true, true, true, true, true, true, true, true,
1004 true, true, true, true, true, true, true, true, true, true, true, true,
1005 true, true, true, false, false, true, true, false, false, false, false,
1006 false, false, false, true, true, false, false, false, false, false, false,
1007 false, true, false, true, true, true, true, false, false, true, false, true,
1011 // This is an array of data for operators that correspond to token types.
1012 static const BcOp bc_parse_ops[] = {
1013 { 0, false }, { 0, false },
1016 { 3, true }, { 3, true }, { 3, true },
1017 { 4, true }, { 4, true },
1018 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1020 { 7, true }, { 7, true },
1021 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1022 { 5, false }, { 5, false },
1025 // These identify what tokens can come after expressions in certain cases.
1026 static const BcParseNext bc_parse_next_expr =
1027 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1028 static const BcParseNext bc_parse_next_param =
1029 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1030 static const BcParseNext bc_parse_next_print =
1031 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1032 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1033 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1034 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1035 static const BcParseNext bc_parse_next_read =
1036 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1040 static const BcLexType dc_lex_regs[] = {
1041 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1042 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1043 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1047 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1049 static const BcLexType dc_lex_tokens[] = {
1050 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1051 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1052 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1053 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1054 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1055 BC_LEX_INVALID, BC_LEX_INVALID,
1056 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1057 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1058 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1059 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1060 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1061 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1062 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1063 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1064 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1065 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1066 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1067 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1068 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1069 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1070 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1071 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1072 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1073 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1077 static const BcInst dc_parse_insts[] = {
1078 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1079 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1080 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1081 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1082 BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1085 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1086 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1087 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1088 BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1091 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1092 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1093 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1094 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1095 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1096 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1097 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1098 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1099 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1100 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1104 static const BcNumBinaryOp bc_program_ops[] = {
1105 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1108 static const char bc_program_stdin_name[] = "<stdin>";
1109 static const char bc_program_ready_msg[] = "ready for more input\n";
1112 static const char *bc_lib_name = "gen/lib.bc";
1114 static const char bc_lib[] = {
1115 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1116 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1117 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1118 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,
1119 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1120 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1121 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,
1122 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1123 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1124 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,
1125 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1126 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1127 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1128 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1129 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1130 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1131 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1132 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1133 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1134 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1135 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1136 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1137 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1138 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,
1139 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1140 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,
1141 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1142 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1143 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1144 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1145 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1146 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,
1147 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1148 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1149 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1150 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1151 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,
1152 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1153 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1154 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1155 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1156 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1157 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1158 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1159 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1160 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1161 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1162 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,
1163 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,
1164 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1165 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,
1166 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,
1167 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,
1168 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1169 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1170 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,
1171 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,
1172 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,
1173 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1174 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,
1175 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1176 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1177 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1178 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,
1179 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1180 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1181 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1182 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1183 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1184 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1185 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1186 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1187 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1188 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1189 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1190 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1191 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1192 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1193 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1194 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1198 static void bc_vec_grow(BcVec *v, size_t n)
1200 size_t cap = v->cap * 2;
1201 while (cap < v->len + n) cap *= 2;
1202 v->v = xrealloc(v->v, v->size * cap);
1206 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1209 v->cap = BC_VEC_START_CAP;
1212 v->v = xmalloc(esize * BC_VEC_START_CAP);
1215 static void bc_vec_expand(BcVec *v, size_t req)
1218 v->v = xrealloc(v->v, v->size * req);
1223 static void bc_vec_npop(BcVec *v, size_t n)
1228 size_t len = v->len - n;
1229 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1233 static void bc_vec_push(BcVec *v, const void *data)
1235 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1236 memmove(v->v + (v->size * v->len), data, v->size);
1240 static void bc_vec_pushByte(BcVec *v, char data)
1242 bc_vec_push(v, &data);
1245 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1248 bc_vec_push(v, data);
1253 if (v->len == v->cap) bc_vec_grow(v, 1);
1255 ptr = v->v + v->size * idx;
1257 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1258 memmove(ptr, data, v->size);
1262 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1264 bc_vec_npop(v, v->len);
1265 bc_vec_expand(v, len + 1);
1266 memcpy(v->v, str, len);
1269 bc_vec_pushByte(v, '\0');
1272 static void bc_vec_concat(BcVec *v, const char *str)
1276 if (v->len == 0) bc_vec_pushByte(v, '\0');
1278 len = v->len + strlen(str);
1280 if (v->cap < len) bc_vec_grow(v, len - v->len);
1286 static void *bc_vec_item(const BcVec *v, size_t idx)
1288 return v->v + v->size * idx;
1291 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1293 return v->v + v->size * (v->len - idx - 1);
1296 static void bc_vec_free(void *vec)
1298 BcVec *v = (BcVec *) vec;
1299 bc_vec_npop(v, v->len);
1303 static size_t bc_map_find(const BcVec *v, const void *ptr)
1305 size_t low = 0, high = v->len;
1307 while (low < high) {
1309 size_t mid = (low + high) / 2;
1310 BcId *id = bc_vec_item(v, mid);
1311 int result = bc_id_cmp(ptr, id);
1315 else if (result < 0)
1324 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1326 BcStatus s = BC_STATUS_SUCCESS;
1328 *i = bc_map_find(v, ptr);
1331 bc_vec_push(v, ptr);
1332 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1333 s = BC_STATUS_VEC_ITEM_EXISTS;
1335 bc_vec_pushAt(v, ptr, *i);
1340 static size_t bc_map_index(const BcVec *v, const void *ptr)
1342 size_t i = bc_map_find(v, ptr);
1343 if (i >= v->len) return BC_VEC_INVALID_IDX;
1344 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1347 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1352 if (G.ttyin && !G_posix) {
1353 fputs(prompt, stderr);
1357 bc_vec_npop(vec, vec->len);
1360 if (ferror(stdout) || ferror(stderr))
1361 bb_perror_msg_and_die("output error");
1367 #if ENABLE_FEATURE_BC_SIGNALS
1368 if (errno == EINTR) {
1372 fputs(bc_program_ready_msg, stderr);
1373 if (!G_posix) fputs(prompt, stderr);
1380 bb_perror_msg_and_die("input error");
1382 return BC_STATUS_INPUT_EOF;
1385 c = (signed char) i;
1386 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1387 bc_vec_push(vec, &c);
1388 } while (c != '\n');
1390 bc_vec_pushByte(vec, '\0');
1392 return BC_STATUS_SUCCESS;
1395 static BcStatus bc_read_file(const char *path, char **buf)
1397 BcStatus s = BC_STATUS_BIN_FILE;
1398 size_t size = ((size_t) -1);
1401 *buf = xmalloc_open_read_close(path, &size);
1403 for (i = 0; i < size; ++i) {
1404 if (BC_READ_BIN_CHAR((*buf)[i]))
1408 return BC_STATUS_SUCCESS;
1415 static void bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1418 bool do_exit = false;
1421 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1422 *flags = getopt32long(argv, "xwvsqli",
1423 "extended-register\0" No_argument "x"
1424 "warn\0" No_argument "w"
1425 "version\0" No_argument "v"
1426 "standard\0" No_argument "s"
1427 "quiet\0" No_argument "q"
1428 "mathlib\0" No_argument "l"
1429 "interactive\0" No_argument "i"
1432 *flags = getopt32(argv, "xwvsqli");
1435 if ((*flags) & BC_FLAG_V) bc_vm_info();
1436 if (do_exit) exit(0);
1437 // should not be necessary, getopt32() handles this??
1438 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1440 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1443 static void bc_num_setToZero(BcNum *n, size_t scale)
1450 static void bc_num_zero(BcNum *n)
1452 bc_num_setToZero(n, 0);
1455 static void bc_num_one(BcNum *n)
1457 bc_num_setToZero(n, 0);
1462 static void bc_num_ten(BcNum *n)
1464 bc_num_setToZero(n, 0);
1470 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1474 for (i = 0; !G.signe && i < len; ++i) {
1475 for (a[i] -= b[i], j = 0; !G.signe && a[i + j] < 0;) {
1480 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1483 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1487 for (i = len - 1; !G.signe && i < len && !(c = a[i] - b[i]); --i);
1488 return BC_NUM_NEG(i + 1, c < 0);
1491 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1493 size_t i, min, a_int, b_int, diff;
1494 BcDig *max_num, *min_num;
1495 bool a_max, neg = false;
1498 if (a == b) return 0;
1499 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1500 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1510 a_int = BC_NUM_INT(a);
1511 b_int = BC_NUM_INT(b);
1513 a_max = (a->rdx > b->rdx);
1515 if (a_int != 0) return (ssize_t) a_int;
1519 diff = a->rdx - b->rdx;
1520 max_num = a->num + diff;
1525 diff = b->rdx - a->rdx;
1526 max_num = b->num + diff;
1530 cmp = bc_num_compare(max_num, min_num, b_int + min);
1531 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1533 for (max_num -= diff, i = diff - 1; !G.signe && i < diff; --i) {
1534 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1540 static void bc_num_truncate(BcNum *n, size_t places)
1542 if (places == 0) return;
1548 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1552 static void bc_num_extend(BcNum *n, size_t places)
1554 size_t len = n->len + places;
1558 if (n->cap < len) bc_num_expand(n, len);
1560 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1561 memset(n->num, 0, sizeof(BcDig) * places);
1568 static void bc_num_clean(BcNum *n)
1570 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1573 else if (n->len < n->rdx)
1577 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1580 bc_num_extend(n, scale - n->rdx);
1582 bc_num_truncate(n, n->rdx - scale);
1585 if (n->len != 0) n->neg = !neg1 != !neg2;
1588 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1593 b->len = n->len - idx;
1595 a->rdx = b->rdx = 0;
1597 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1598 memcpy(a->num, n->num, idx * sizeof(BcDig));
1609 static BcStatus bc_num_shift(BcNum *n, size_t places)
1611 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1612 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1614 if (n->rdx >= places)
1617 bc_num_extend(n, places - n->rdx);
1623 return BC_STATUS_SUCCESS;
1626 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1635 return bc_num_div(&one, a, b, scale);
1638 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1640 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1641 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1644 // Because this function doesn't need to use scale (per the bc spec),
1645 // I am hijacking it to say whether it's doing an add or a subtract.
1649 if (sub && c->len) c->neg = !c->neg;
1650 return BC_STATUS_SUCCESS;
1652 else if (b->len == 0) {
1654 return BC_STATUS_SUCCESS;
1658 c->rdx = BC_MAX(a->rdx, b->rdx);
1659 min_rdx = BC_MIN(a->rdx, b->rdx);
1662 if (a->rdx > b->rdx) {
1663 diff = a->rdx - b->rdx;
1665 ptr_a = a->num + diff;
1669 diff = b->rdx - a->rdx;
1672 ptr_b = b->num + diff;
1675 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1678 a_int = BC_NUM_INT(a);
1679 b_int = BC_NUM_INT(b);
1681 if (a_int > b_int) {
1692 for (carry = 0, i = 0; !G.signe && i < min_rdx + min_int; ++i, ++c->len) {
1693 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1695 ptr_c[i] = (BcDig)(in % 10);
1698 for (; !G.signe && i < max + min_rdx; ++i, ++c->len) {
1699 in = ((int) ptr[i]) + carry;
1701 ptr_c[i] = (BcDig)(in % 10);
1704 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1706 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1709 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1713 BcNum *minuend, *subtrahend;
1715 bool aneg, bneg, neg;
1717 // Because this function doesn't need to use scale (per the bc spec),
1718 // I am hijacking it to say whether it's doing an add or a subtract.
1722 if (sub && c->len) c->neg = !c->neg;
1723 return BC_STATUS_SUCCESS;
1725 else if (b->len == 0) {
1727 return BC_STATUS_SUCCESS;
1732 a->neg = b->neg = false;
1734 cmp = bc_num_cmp(a, b);
1740 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1741 return BC_STATUS_SUCCESS;
1750 if (sub) neg = !neg;
1755 bc_num_copy(c, minuend);
1758 if (c->rdx < subtrahend->rdx) {
1759 bc_num_extend(c, subtrahend->rdx - c->rdx);
1763 start = c->rdx - subtrahend->rdx;
1765 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1772 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1777 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1778 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1779 bool aone = BC_NUM_ONE(a);
1781 if (G.signe) return BC_STATUS_EXEC_SIGNAL;
1782 if (a->len == 0 || b->len == 0) {
1784 return BC_STATUS_SUCCESS;
1786 else if (aone || BC_NUM_ONE(b)) {
1787 bc_num_copy(c, aone ? b : a);
1788 return BC_STATUS_SUCCESS;
1791 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1792 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1794 bc_num_expand(c, a->len + b->len + 1);
1796 memset(c->num, 0, sizeof(BcDig) * c->cap);
1797 c->len = carry = len = 0;
1799 for (i = 0; !G.signe && i < b->len; ++i) {
1801 for (j = 0; !G.signe && j < a->len; ++j) {
1802 int in = (int) c->num[i + j];
1803 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1805 c->num[i + j] = (BcDig)(in % 10);
1808 c->num[i + j] += (BcDig) carry;
1809 len = BC_MAX(len, i + j + !!carry);
1815 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1818 bc_num_init(&l1, max);
1819 bc_num_init(&h1, max);
1820 bc_num_init(&l2, max);
1821 bc_num_init(&h2, max);
1822 bc_num_init(&m1, max);
1823 bc_num_init(&m2, max);
1824 bc_num_init(&z0, max);
1825 bc_num_init(&z1, max);
1826 bc_num_init(&z2, max);
1827 bc_num_init(&temp, max + max);
1829 bc_num_split(a, max2, &l1, &h1);
1830 bc_num_split(b, max2, &l2, &h2);
1832 s = bc_num_add(&h1, &l1, &m1, 0);
1834 s = bc_num_add(&h2, &l2, &m2, 0);
1837 s = bc_num_k(&h1, &h2, &z0);
1839 s = bc_num_k(&m1, &m2, &z1);
1841 s = bc_num_k(&l1, &l2, &z2);
1844 s = bc_num_sub(&z1, &z0, &temp, 0);
1846 s = bc_num_sub(&temp, &z2, &z1, 0);
1849 s = bc_num_shift(&z0, max2 * 2);
1851 s = bc_num_shift(&z1, max2);
1853 s = bc_num_add(&z0, &z1, &temp, 0);
1855 s = bc_num_add(&temp, &z2, c, 0);
1871 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1875 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1877 scale = BC_MAX(scale, a->rdx);
1878 scale = BC_MAX(scale, b->rdx);
1879 scale = BC_MIN(a->rdx + b->rdx, scale);
1880 maxrdx = BC_MAX(maxrdx, scale);
1882 bc_num_init(&cpa, a->len);
1883 bc_num_init(&cpb, b->len);
1885 bc_num_copy(&cpa, a);
1886 bc_num_copy(&cpb, b);
1887 cpa.neg = cpb.neg = false;
1889 s = bc_num_shift(&cpa, maxrdx);
1891 s = bc_num_shift(&cpb, maxrdx);
1893 s = bc_num_k(&cpa, &cpb, c);
1897 bc_num_expand(c, c->len + maxrdx);
1899 if (c->len < maxrdx) {
1900 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1905 bc_num_retireMul(c, scale, a->neg, b->neg);
1913 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1915 BcStatus s = BC_STATUS_SUCCESS;
1922 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1923 else if (a->len == 0) {
1924 bc_num_setToZero(c, scale);
1925 return BC_STATUS_SUCCESS;
1927 else if (BC_NUM_ONE(b)) {
1929 bc_num_retireMul(c, scale, a->neg, b->neg);
1930 return BC_STATUS_SUCCESS;
1933 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1934 bc_num_copy(&cp, a);
1938 bc_num_expand(&cp, len + 2);
1939 bc_num_extend(&cp, len - cp.len);
1942 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1944 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1946 if (b->rdx == b->len) {
1947 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1951 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1953 // We want an extra zero in front to make things simpler.
1954 cp.num[cp.len++] = 0;
1957 bc_num_expand(c, cp.len);
1960 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1965 for (i = end - 1; !G.signe && !s && i < end; --i) {
1967 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1968 s = bc_num_subArrays(n, p, len);
1972 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1978 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1979 BcNum *restrict d, size_t scale, size_t ts)
1985 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1988 bc_num_setToZero(d, ts);
1989 return BC_STATUS_SUCCESS;
1992 bc_num_init(&temp, d->cap);
1993 bc_num_d(a, b, c, scale);
1995 if (scale != 0) scale = ts;
1997 s = bc_num_m(c, b, &temp, scale);
1999 s = bc_num_sub(a, &temp, d, scale);
2002 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2005 bc_num_retireMul(d, ts, a->neg, b->neg);
2013 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2017 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2019 bc_num_init(&c1, len);
2020 s = bc_num_r(a, b, &c1, c, scale, ts);
2026 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2028 BcStatus s = BC_STATUS_SUCCESS;
2031 size_t i, powrdx, resrdx;
2034 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2038 return BC_STATUS_SUCCESS;
2040 else if (a->len == 0) {
2041 bc_num_setToZero(c, scale);
2042 return BC_STATUS_SUCCESS;
2044 else if (BC_NUM_ONE(b)) {
2048 s = bc_num_inv(a, c, scale);
2055 s = bc_num_ulong(b, &pow);
2058 bc_num_init(©, a->len);
2059 bc_num_copy(©, a);
2061 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2065 for (powrdx = a->rdx; !G.signe && !(pow & 1); pow >>= 1) {
2067 s = bc_num_mul(©, ©, ©, powrdx);
2072 s = BC_STATUS_EXEC_SIGNAL;
2076 bc_num_copy(c, ©);
2078 for (resrdx = powrdx, pow >>= 1; !G.signe && pow != 0; pow >>= 1) {
2081 s = bc_num_mul(©, ©, ©, powrdx);
2086 s = bc_num_mul(c, ©, c, resrdx);
2092 s = bc_num_inv(c, c, scale);
2097 s = BC_STATUS_EXEC_SIGNAL;
2101 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2103 // We can't use bc_num_clean() here.
2104 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2105 if (zero) bc_num_setToZero(c, scale);
2112 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2113 BcNumBinaryOp op, size_t req)
2116 BcNum num2, *ptr_a, *ptr_b;
2121 memcpy(ptr_a, c, sizeof(BcNum));
2130 memcpy(ptr_b, c, sizeof(BcNum));
2138 bc_num_init(c, req);
2140 bc_num_expand(c, req);
2142 s = op(ptr_a, ptr_b, c, scale);
2144 if (init) bc_num_free(&num2);
2149 static bool bc_num_strValid(const char *val, size_t base)
2152 bool small, radix = false;
2153 size_t i, len = strlen(val);
2155 if (!len) return true;
2158 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2160 for (i = 0; i < len; ++i) {
2166 if (radix) return false;
2172 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2179 static void bc_num_parseDecimal(BcNum *n, const char *val)
2185 for (i = 0; val[i] == '0'; ++i);
2192 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2193 bc_num_expand(n, len);
2196 ptr = strchr(val, '.');
2198 // Explicitly test for NULL here to produce either a 0 or 1.
2199 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2202 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2203 n->num[n->len] = val[i] - '0';
2207 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2210 BcNum temp, mult, result;
2214 size_t i, digits, len = strlen(val);
2218 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2221 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2222 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2224 for (i = 0; i < len; ++i) {
2227 if (c == '.') break;
2229 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2231 s = bc_num_mul(n, base, &mult, 0);
2232 if (s) goto int_err;
2233 s = bc_num_ulong2num(&temp, v);
2234 if (s) goto int_err;
2235 s = bc_num_add(&mult, &temp, n, 0);
2236 if (s) goto int_err;
2241 if (c == 0) goto int_err;
2244 bc_num_init(&result, base->len);
2245 bc_num_zero(&result);
2248 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2253 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2255 s = bc_num_mul(&result, base, &result, 0);
2257 s = bc_num_ulong2num(&temp, v);
2259 s = bc_num_add(&result, &temp, &result, 0);
2261 s = bc_num_mul(&mult, base, &mult, 0);
2265 s = bc_num_div(&result, &mult, &result, digits);
2267 s = bc_num_add(n, &result, n, digits);
2271 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2277 bc_num_free(&result);
2283 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2285 if (*nchars == line_len - 1) {
2293 static void bc_num_printChar(size_t num, size_t width, bool radix,
2294 size_t *nchars, size_t line_len)
2296 (void) radix, (void) line_len;
2297 bb_putchar((char) num);
2298 *nchars = *nchars + width;
2302 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2303 size_t *nchars, size_t line_len)
2307 bc_num_printNewline(nchars, line_len);
2308 bb_putchar(radix ? '.' : ' ');
2311 bc_num_printNewline(nchars, line_len);
2312 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2315 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2317 bc_num_printNewline(nchars, line_len);
2320 bb_putchar(((char) dig) + '0');
2324 static void bc_num_printHex(size_t num, size_t width, bool radix,
2325 size_t *nchars, size_t line_len)
2328 bc_num_printNewline(nchars, line_len);
2333 bc_num_printNewline(nchars, line_len);
2334 bb_putchar(bb_hexdigits_upcase[num]);
2335 *nchars = *nchars + width;
2338 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2340 size_t i, rdx = n->rdx - 1;
2342 if (n->neg) bb_putchar('-');
2343 (*nchars) += n->neg;
2345 for (i = n->len - 1; i < n->len; --i)
2346 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2349 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2350 size_t *nchars, size_t len, BcNumDigitOp print)
2354 BcNum intp, fracp, digit, frac_len;
2355 unsigned long dig, *ptr;
2360 print(0, width, false, nchars, len);
2361 return BC_STATUS_SUCCESS;
2364 bc_vec_init(&stack, sizeof(long), NULL);
2365 bc_num_init(&intp, n->len);
2366 bc_num_init(&fracp, n->rdx);
2367 bc_num_init(&digit, width);
2368 bc_num_init(&frac_len, BC_NUM_INT(n));
2369 bc_num_copy(&intp, n);
2370 bc_num_one(&frac_len);
2372 bc_num_truncate(&intp, intp.rdx);
2373 s = bc_num_sub(n, &intp, &fracp, 0);
2376 while (intp.len != 0) {
2377 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2379 s = bc_num_ulong(&digit, &dig);
2381 bc_vec_push(&stack, &dig);
2384 for (i = 0; i < stack.len; ++i) {
2385 ptr = bc_vec_item_rev(&stack, i);
2386 print(*ptr, width, false, nchars, len);
2389 if (!n->rdx) goto err;
2391 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2392 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2394 s = bc_num_ulong(&fracp, &dig);
2396 s = bc_num_ulong2num(&intp, dig);
2398 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2400 print(dig, width, radix, nchars, len);
2401 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2406 bc_num_free(&frac_len);
2407 bc_num_free(&digit);
2408 bc_num_free(&fracp);
2410 bc_vec_free(&stack);
2414 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2415 size_t *nchars, size_t line_len)
2422 if (neg) bb_putchar('-');
2427 if (base_t <= BC_NUM_MAX_IBASE) {
2429 print = bc_num_printHex;
2432 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2433 print = bc_num_printDigits;
2436 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2443 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2445 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2449 static void bc_num_init(BcNum *n, size_t req)
2451 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2452 memset(n, 0, sizeof(BcNum));
2453 n->num = xmalloc(req);
2457 static void bc_num_expand(BcNum *n, size_t req)
2459 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2461 n->num = xrealloc(n->num, req);
2466 static void bc_num_free(void *num)
2468 free(((BcNum *) num)->num);
2471 static void bc_num_copy(BcNum *d, BcNum *s)
2474 bc_num_expand(d, s->cap);
2478 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2482 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2485 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2488 bc_num_parseDecimal(n, val);
2490 bc_num_parseBase(n, val, base);
2492 return BC_STATUS_SUCCESS;
2495 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2496 size_t *nchars, size_t line_len)
2498 BcStatus s = BC_STATUS_SUCCESS;
2500 bc_num_printNewline(nchars, line_len);
2506 else if (base_t == 10)
2507 bc_num_printDecimal(n, nchars, line_len);
2509 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2519 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2524 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2526 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2528 unsigned long prev = *result, powprev = pow;
2530 *result += ((unsigned long) n->num[i]) * pow;
2533 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2536 return BC_STATUS_SUCCESS;
2539 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2547 if (val == 0) return BC_STATUS_SUCCESS;
2549 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2550 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2552 return BC_STATUS_SUCCESS;
2555 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2557 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2559 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2562 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2564 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2566 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2569 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2571 size_t req = BC_NUM_MREQ(a, b, scale);
2572 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2575 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2577 size_t req = BC_NUM_MREQ(a, b, scale);
2578 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2581 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2583 size_t req = BC_NUM_MREQ(a, b, scale);
2584 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2587 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2589 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2592 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2595 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2596 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2597 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2599 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2600 bc_num_expand(b, req);
2603 bc_num_setToZero(b, scale);
2604 return BC_STATUS_SUCCESS;
2607 return BC_STATUS_MATH_NEGATIVE;
2608 else if (BC_NUM_ONE(a)) {
2610 bc_num_extend(b, scale);
2611 return BC_STATUS_SUCCESS;
2614 scale = BC_MAX(scale, a->rdx) + 1;
2615 len = a->len + scale;
2617 bc_num_init(&num1, len);
2618 bc_num_init(&num2, len);
2619 bc_num_init(&half, BC_NUM_DEF_SIZE);
2625 bc_num_init(&f, len);
2626 bc_num_init(&fprime, len);
2632 pow = BC_NUM_INT(a);
2641 pow -= 2 - (pow & 1);
2643 bc_num_extend(x0, pow);
2645 // Make sure to move the radix back.
2649 x0->rdx = digs = digs1 = 0;
2651 len = BC_NUM_INT(x0) + resrdx - 1;
2653 while (!G.signe && (cmp != 0 || digs < len)) {
2655 s = bc_num_div(a, x0, &f, resrdx);
2657 s = bc_num_add(x0, &f, &fprime, resrdx);
2659 s = bc_num_mul(&fprime, &half, x1, resrdx);
2662 cmp = bc_num_cmp(x1, x0);
2663 digs = x1->len - (unsigned long long) llabs(cmp);
2665 if (cmp == cmp2 && digs == digs1)
2670 resrdx += times > 4;
2682 s = BC_STATUS_EXEC_SIGNAL;
2688 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2691 bc_num_free(&fprime);
2699 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2705 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2708 memcpy(&num2, c, sizeof(BcNum));
2710 bc_num_init(c, len);
2715 bc_num_expand(c, len);
2718 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2720 if (init) bc_num_free(&num2);
2726 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2729 BcNum base, exp, two, temp;
2731 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2732 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2733 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2735 bc_num_expand(d, c->len);
2736 bc_num_init(&base, c->len);
2737 bc_num_init(&exp, b->len);
2738 bc_num_init(&two, BC_NUM_DEF_SIZE);
2739 bc_num_init(&temp, b->len);
2745 s = bc_num_rem(a, c, &base, 0);
2747 bc_num_copy(&exp, b);
2749 while (exp.len != 0) {
2751 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2754 if (BC_NUM_ONE(&temp)) {
2755 s = bc_num_mul(d, &base, &temp, 0);
2757 s = bc_num_rem(&temp, c, d, 0);
2761 s = bc_num_mul(&base, &base, &temp, 0);
2763 s = bc_num_rem(&temp, c, &base, 0);
2776 static int bc_id_cmp(const void *e1, const void *e2)
2778 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2781 static void bc_id_free(void *id)
2783 free(((BcId *) id)->name);
2786 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2791 for (i = 0; i < f->autos.len; ++i) {
2792 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2793 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2799 bc_vec_push(&f->autos, &a);
2801 return BC_STATUS_SUCCESS;
2804 static void bc_func_init(BcFunc *f)
2806 bc_vec_init(&f->code, sizeof(char), NULL);
2807 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2808 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2812 static void bc_func_free(void *func)
2814 BcFunc *f = (BcFunc *) func;
2815 bc_vec_free(&f->code);
2816 bc_vec_free(&f->autos);
2817 bc_vec_free(&f->labels);
2820 static void bc_array_init(BcVec *a, bool nums)
2823 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2825 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2826 bc_array_expand(a, 1);
2829 static void bc_array_copy(BcVec *d, const BcVec *s)
2833 bc_vec_npop(d, d->len);
2834 bc_vec_expand(d, s->cap);
2837 for (i = 0; i < s->len; ++i) {
2838 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2839 bc_num_init(dnum, snum->len);
2840 bc_num_copy(dnum, snum);
2844 static void bc_array_expand(BcVec *a, size_t len)
2848 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2849 while (len > a->len) {
2850 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2851 bc_vec_push(a, &data.n);
2855 while (len > a->len) {
2856 bc_array_init(&data.v, true);
2857 bc_vec_push(a, &data.v);
2862 static void bc_string_free(void *string)
2864 free(*((char **) string));
2868 static void bc_result_copy(BcResult *d, BcResult *src)
2874 case BC_RESULT_TEMP:
2875 case BC_RESULT_IBASE:
2876 case BC_RESULT_SCALE:
2877 case BC_RESULT_OBASE:
2879 bc_num_init(&d->d.n, src->d.n.len);
2880 bc_num_copy(&d->d.n, &src->d.n);
2885 case BC_RESULT_ARRAY:
2886 case BC_RESULT_ARRAY_ELEM:
2888 d->d.id.name = xstrdup(src->d.id.name);
2892 case BC_RESULT_CONSTANT:
2893 case BC_RESULT_LAST:
2897 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2904 static void bc_result_free(void *result)
2906 BcResult *r = (BcResult *) result;
2910 case BC_RESULT_TEMP:
2911 case BC_RESULT_IBASE:
2912 case BC_RESULT_SCALE:
2913 case BC_RESULT_OBASE:
2915 bc_num_free(&r->d.n);
2920 case BC_RESULT_ARRAY:
2921 case BC_RESULT_ARRAY_ELEM:
2935 static void bc_lex_lineComment(BcLex *l)
2937 l->t.t = BC_LEX_WHITESPACE;
2938 while (l->i < l->len && l->buf[l->i++] != '\n');
2942 static void bc_lex_whitespace(BcLex *l)
2945 l->t.t = BC_LEX_WHITESPACE;
2946 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2949 static BcStatus bc_lex_number(BcLex *l, char start)
2951 const char *buf = l->buf + l->i;
2952 size_t len, hits = 0, bslashes = 0, i = 0, j;
2954 bool last_pt, pt = start == '.';
2957 l->t.t = BC_LEX_NUMBER;
2959 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2960 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2974 len = i + 1 * !last_pt - bslashes * 2;
2975 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2977 bc_vec_npop(&l->t.v, l->t.v.len);
2978 bc_vec_expand(&l->t.v, len + 1);
2979 bc_vec_push(&l->t.v, &start);
2981 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2985 // If we have hit a backslash, skip it. We don't have
2986 // to check for a newline because it's guaranteed.
2987 if (hits < bslashes && c == '\\') {
2993 bc_vec_push(&l->t.v, &c);
2996 bc_vec_pushByte(&l->t.v, '\0');
2999 return BC_STATUS_SUCCESS;
3002 static BcStatus bc_lex_name(BcLex *l)
3005 const char *buf = l->buf + l->i - 1;
3008 l->t.t = BC_LEX_NAME;
3010 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3012 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3013 bc_vec_string(&l->t.v, i, buf);
3015 // Increment the index. We minus 1 because it has already been incremented.
3018 return BC_STATUS_SUCCESS;
3021 static void bc_lex_init(BcLex *l, BcLexNext next)
3024 bc_vec_init(&l->t.v, sizeof(char), NULL);
3027 static void bc_lex_free(BcLex *l)
3029 bc_vec_free(&l->t.v);
3032 static void bc_lex_file(BcLex *l, const char *file)
3039 static BcStatus bc_lex_next(BcLex *l)
3044 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3046 l->line += l->newline;
3047 l->t.t = BC_LEX_EOF;
3049 l->newline = (l->i == l->len);
3050 if (l->newline) return BC_STATUS_SUCCESS;
3052 // Loop until failure or we don't have whitespace. This
3053 // is so the parser doesn't get inundated with whitespace.
3056 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3061 static BcStatus bc_lex_text(BcLex *l, const char *text)
3065 l->len = strlen(text);
3066 l->t.t = l->t.last = BC_LEX_INVALID;
3067 return bc_lex_next(l);
3071 static BcStatus bc_lex_identifier(BcLex *l)
3075 const char *buf = l->buf + l->i - 1;
3077 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3079 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3081 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3083 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3085 if (!bc_lex_kws[i].posix) {
3086 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3087 bc_lex_kws[i].name);
3091 // We minus 1 because the index has already been incremented.
3093 return BC_STATUS_SUCCESS;
3100 if (l->t.v.len - 1 > 1)
3101 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3106 static BcStatus bc_lex_string(BcLex *l)
3108 size_t len, nls = 0, i = l->i;
3111 l->t.t = BC_LEX_STR;
3113 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3117 return BC_STATUS_LEX_NO_STRING_END;
3121 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3122 bc_vec_string(&l->t.v, len, l->buf + l->i);
3127 return BC_STATUS_SUCCESS;
3130 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3132 if (l->buf[l->i] == '=') {
3140 static BcStatus bc_lex_comment(BcLex *l)
3143 const char *buf = l->buf;
3147 l->t.t = BC_LEX_WHITESPACE;
3149 for (i = ++l->i; !end; i += !end) {
3151 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3153 if (c == 0 || buf[i + 1] == '\0') {
3155 return BC_STATUS_LEX_NO_COMMENT_END;
3158 end = buf[i + 1] == '/';
3164 return BC_STATUS_SUCCESS;
3167 static BcStatus bc_lex_token(BcLex *l)
3169 BcStatus s = BC_STATUS_SUCCESS;
3170 char c = l->buf[l->i++], c2;
3172 // This is the workhorse of the lexer.
3179 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3189 bc_lex_whitespace(l);
3195 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3197 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3198 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3207 s = bc_lex_string(l);
3213 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3216 bc_lex_lineComment(l);
3223 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3232 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3236 l->t.t = BC_LEX_OP_BOOL_AND;
3239 l->t.t = BC_LEX_INVALID;
3240 s = BC_STATUS_LEX_BAD_CHAR;
3249 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3255 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3264 l->t.t = BC_LEX_OP_INC;
3267 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3273 l->t.t = BC_LEX_COMMA;
3282 l->t.t = BC_LEX_OP_DEC;
3285 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3291 if (isdigit(l->buf[l->i]))
3292 s = bc_lex_number(l, c);
3294 l->t.t = BC_LEX_KEY_LAST;
3295 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3304 s = bc_lex_comment(l);
3306 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3327 s = bc_lex_number(l, c);
3333 l->t.t = BC_LEX_SCOLON;
3339 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3345 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3351 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3358 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3364 if (l->buf[l->i] == '\n') {
3365 l->t.t = BC_LEX_WHITESPACE;
3369 s = BC_STATUS_LEX_BAD_CHAR;
3375 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3406 s = bc_lex_identifier(l);
3413 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3423 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3427 l->t.t = BC_LEX_OP_BOOL_OR;
3430 l->t.t = BC_LEX_INVALID;
3431 s = BC_STATUS_LEX_BAD_CHAR;
3439 l->t.t = BC_LEX_INVALID;
3440 s = BC_STATUS_LEX_BAD_CHAR;
3450 static BcStatus dc_lex_register(BcLex *l)
3452 BcStatus s = BC_STATUS_SUCCESS;
3454 if (isspace(l->buf[l->i - 1])) {
3455 bc_lex_whitespace(l);
3458 s = BC_STATUS_LEX_EXTENDED_REG;
3463 bc_vec_npop(&l->t.v, l->t.v.len);
3464 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3465 bc_vec_pushByte(&l->t.v, '\0');
3466 l->t.t = BC_LEX_NAME;
3472 static BcStatus dc_lex_string(BcLex *l)
3474 size_t depth = 1, nls = 0, i = l->i;
3477 l->t.t = BC_LEX_STR;
3478 bc_vec_npop(&l->t.v, l->t.v.len);
3480 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3482 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3483 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3486 if (depth) bc_vec_push(&l->t.v, &c);
3491 return BC_STATUS_LEX_NO_STRING_END;
3494 bc_vec_pushByte(&l->t.v, '\0');
3495 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3500 return BC_STATUS_SUCCESS;
3503 static BcStatus dc_lex_token(BcLex *l)
3505 BcStatus s = BC_STATUS_SUCCESS;
3506 char c = l->buf[l->i++], c2;
3509 for (i = 0; i < dc_lex_regs_len; ++i) {
3510 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3513 if (c >= '%' && c <= '~' &&
3514 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3519 // This is the workhorse of the lexer.
3524 l->t.t = BC_LEX_EOF;
3535 l->newline = (c == '\n');
3536 bc_lex_whitespace(l);
3545 l->t.t = BC_LEX_OP_REL_NE;
3547 l->t.t = BC_LEX_OP_REL_LE;
3549 l->t.t = BC_LEX_OP_REL_GE;
3551 return BC_STATUS_LEX_BAD_CHAR;
3559 bc_lex_lineComment(l);
3565 if (isdigit(l->buf[l->i]))
3566 s = bc_lex_number(l, c);
3568 s = BC_STATUS_LEX_BAD_CHAR;
3589 s = bc_lex_number(l, c);
3595 s = dc_lex_string(l);
3601 l->t.t = BC_LEX_INVALID;
3602 s = BC_STATUS_LEX_BAD_CHAR;
3611 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3613 bc_program_addFunc(p->prog, name, idx);
3614 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3617 static void bc_parse_pushName(BcParse *p, char *name)
3619 size_t i = 0, len = strlen(name);
3621 for (; i < len; ++i) bc_parse_push(p, name[i]);
3622 bc_parse_push(p, BC_PARSE_STREND);
3627 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3629 unsigned char amt, i, nums[sizeof(size_t)];
3631 for (amt = 0; idx; ++amt) {
3632 nums[amt] = (char) idx;
3633 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3636 bc_parse_push(p, amt);
3637 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3640 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3642 char *num = xstrdup(p->l.t.v.v);
3643 size_t idx = p->prog->consts.len;
3645 bc_vec_push(&p->prog->consts, &num);
3647 bc_parse_push(p, BC_INST_NUM);
3648 bc_parse_pushIndex(p, idx);
3651 (*prev) = BC_INST_NUM;
3654 static BcStatus bc_parse_text(BcParse *p, const char *text)
3658 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3660 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3661 p->l.t.t = BC_LEX_INVALID;
3664 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3667 return bc_lex_text(&p->l, text);
3670 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3672 if (p->fidx != BC_PROG_MAIN) {
3674 p->func->nparams = 0;
3675 bc_vec_npop(&p->func->code, p->func->code.len);
3676 bc_vec_npop(&p->func->autos, p->func->autos.len);
3677 bc_vec_npop(&p->func->labels, p->func->labels.len);
3679 bc_parse_updateFunc(p, BC_PROG_MAIN);
3683 p->l.t.t = BC_LEX_EOF;
3684 p->auto_part = (p->nbraces = 0);
3686 bc_vec_npop(&p->flags, p->flags.len - 1);
3687 bc_vec_npop(&p->exits, p->exits.len);
3688 bc_vec_npop(&p->conds, p->conds.len);
3689 bc_vec_npop(&p->ops, p->ops.len);
3691 return bc_program_reset(p->prog, s);
3694 static void bc_parse_free(BcParse *p)
3696 bc_vec_free(&p->flags);
3697 bc_vec_free(&p->exits);
3698 bc_vec_free(&p->conds);
3699 bc_vec_free(&p->ops);
3703 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3704 BcParseParse parse, BcLexNext next)
3706 memset(p, 0, sizeof(BcParse));
3708 bc_lex_init(&p->l, next);
3709 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3710 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3711 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3712 bc_vec_pushByte(&p->flags, 0);
3713 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3717 p->auto_part = (p->nbraces = 0);
3718 bc_parse_updateFunc(p, func);
3722 static BcStatus bc_parse_else(BcParse *p);
3723 static BcStatus bc_parse_stmt(BcParse *p);
3725 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3726 size_t *nexprs, bool next)
3728 BcStatus s = BC_STATUS_SUCCESS;
3730 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3731 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3733 while (p->ops.len > start) {
3735 t = BC_PARSE_TOP_OP(p);
3736 if (t == BC_LEX_LPAREN) break;
3738 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3739 if (l >= r && (l != r || !left)) break;
3741 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3742 bc_vec_pop(&p->ops);
3743 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3746 bc_vec_push(&p->ops, &type);
3747 if (next) s = bc_lex_next(&p->l);
3752 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3756 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3757 top = BC_PARSE_TOP_OP(p);
3759 while (top != BC_LEX_LPAREN) {
3761 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3763 bc_vec_pop(&p->ops);
3764 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3766 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3767 top = BC_PARSE_TOP_OP(p);
3770 bc_vec_pop(&p->ops);
3772 return bc_lex_next(&p->l);
3775 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3781 s = bc_lex_next(&p->l);
3784 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3786 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3787 s = bc_parse_expr(p, flags, bc_parse_next_param);
3790 comma = p->l.t.t == BC_LEX_COMMA;
3792 s = bc_lex_next(&p->l);
3797 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3798 bc_parse_push(p, BC_INST_CALL);
3799 bc_parse_pushIndex(p, nparams);
3801 return BC_STATUS_SUCCESS;
3804 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3807 BcId entry, *entry_ptr;
3812 s = bc_parse_params(p, flags);
3815 if (p->l.t.t != BC_LEX_RPAREN) {
3816 s = BC_STATUS_PARSE_BAD_TOKEN;
3820 idx = bc_map_index(&p->prog->fn_map, &entry);
3822 if (idx == BC_VEC_INVALID_IDX) {
3823 name = xstrdup(entry.name);
3824 bc_parse_addFunc(p, name, &idx);
3825 idx = bc_map_index(&p->prog->fn_map, &entry);
3831 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3832 bc_parse_pushIndex(p, entry_ptr->idx);
3834 return bc_lex_next(&p->l);
3841 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3846 name = xstrdup(p->l.t.v.v);
3847 s = bc_lex_next(&p->l);
3850 if (p->l.t.t == BC_LEX_LBRACKET) {
3852 s = bc_lex_next(&p->l);
3855 if (p->l.t.t == BC_LEX_RBRACKET) {
3857 if (!(flags & BC_PARSE_ARRAY)) {
3858 s = BC_STATUS_PARSE_BAD_EXP;
3862 *type = BC_INST_ARRAY;
3866 *type = BC_INST_ARRAY_ELEM;
3868 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3869 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3873 s = bc_lex_next(&p->l);
3875 bc_parse_push(p, *type);
3876 bc_parse_pushName(p, name);
3878 else if (p->l.t.t == BC_LEX_LPAREN) {
3880 if (flags & BC_PARSE_NOCALL) {
3881 s = BC_STATUS_PARSE_BAD_TOKEN;
3885 *type = BC_INST_CALL;
3886 s = bc_parse_call(p, name, flags);
3889 *type = BC_INST_VAR;
3890 bc_parse_push(p, BC_INST_VAR);
3891 bc_parse_pushName(p, name);
3901 static BcStatus bc_parse_read(BcParse *p)
3905 s = bc_lex_next(&p->l);
3907 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3909 s = bc_lex_next(&p->l);
3911 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3913 bc_parse_push(p, BC_INST_READ);
3915 return bc_lex_next(&p->l);
3918 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3923 s = bc_lex_next(&p->l);
3925 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3927 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3929 s = bc_lex_next(&p->l);
3932 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3935 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3937 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3938 bc_parse_push(p, *prev);
3940 return bc_lex_next(&p->l);
3943 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3947 s = bc_lex_next(&p->l);
3950 if (p->l.t.t != BC_LEX_LPAREN) {
3951 *type = BC_INST_SCALE;
3952 bc_parse_push(p, BC_INST_SCALE);
3953 return BC_STATUS_SUCCESS;
3956 *type = BC_INST_SCALE_FUNC;
3957 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3959 s = bc_lex_next(&p->l);
3962 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3964 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3965 bc_parse_push(p, BC_INST_SCALE_FUNC);
3967 return bc_lex_next(&p->l);
3970 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3971 size_t *nexprs, uint8_t flags)
3976 BcInst etype = *prev;
3978 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3979 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3980 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3982 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3983 bc_parse_push(p, inst);
3984 s = bc_lex_next(&p->l);
3988 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3991 s = bc_lex_next(&p->l);
3995 // Because we parse the next part of the expression
3996 // right here, we need to increment this.
3997 *nexprs = *nexprs + 1;
4003 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4007 case BC_LEX_KEY_IBASE:
4008 case BC_LEX_KEY_LAST:
4009 case BC_LEX_KEY_OBASE:
4011 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4012 s = bc_lex_next(&p->l);
4016 case BC_LEX_KEY_SCALE:
4018 s = bc_lex_next(&p->l);
4020 if (p->l.t.t == BC_LEX_LPAREN)
4021 s = BC_STATUS_PARSE_BAD_TOKEN;
4023 bc_parse_push(p, BC_INST_SCALE);
4029 s = BC_STATUS_PARSE_BAD_TOKEN;
4034 if (!s) bc_parse_push(p, inst);
4040 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4041 bool rparen, size_t *nexprs)
4045 BcInst etype = *prev;
4047 s = bc_lex_next(&p->l);
4050 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4051 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4054 *prev = BC_PARSE_TOKEN_INST(type);
4056 // We can just push onto the op stack because this is the largest
4057 // precedence operator that gets pushed. Inc/dec does not.
4058 if (type != BC_LEX_OP_MINUS)
4059 bc_vec_push(&p->ops, &type);
4061 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4066 static BcStatus bc_parse_string(BcParse *p, char inst)
4068 char *str = xstrdup(p->l.t.v.v);
4070 bc_parse_push(p, BC_INST_STR);
4071 bc_parse_pushIndex(p, p->prog->strs.len);
4072 bc_vec_push(&p->prog->strs, &str);
4073 bc_parse_push(p, inst);
4075 return bc_lex_next(&p->l);
4078 static BcStatus bc_parse_print(BcParse *p)
4084 s = bc_lex_next(&p->l);
4089 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4090 return BC_STATUS_PARSE_BAD_PRINT;
4092 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4094 if (type == BC_LEX_STR)
4095 s = bc_parse_string(p, BC_INST_PRINT_POP);
4097 s = bc_parse_expr(p, 0, bc_parse_next_print);
4099 bc_parse_push(p, BC_INST_PRINT_POP);
4104 comma = p->l.t.t == BC_LEX_COMMA;
4105 if (comma) s = bc_lex_next(&p->l);
4110 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4112 return bc_lex_next(&p->l);
4115 static BcStatus bc_parse_return(BcParse *p)
4121 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4123 s = bc_lex_next(&p->l);
4127 paren = t == BC_LEX_LPAREN;
4129 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4130 bc_parse_push(p, BC_INST_RET0);
4133 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4134 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4136 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4137 bc_parse_push(p, BC_INST_RET0);
4138 s = bc_lex_next(&p->l);
4142 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4143 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4147 bc_parse_push(p, BC_INST_RET);
4153 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4155 BcStatus s = BC_STATUS_SUCCESS;
4157 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4158 return BC_STATUS_PARSE_BAD_TOKEN;
4162 if (p->l.t.t == BC_LEX_RBRACE) {
4163 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4165 s = bc_lex_next(&p->l);
4169 return BC_STATUS_PARSE_BAD_TOKEN;
4172 if (BC_PARSE_IF(p)) {
4176 while (p->l.t.t == BC_LEX_NLINE) {
4177 s = bc_lex_next(&p->l);
4181 bc_vec_pop(&p->flags);
4183 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4184 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4186 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4188 else if (BC_PARSE_ELSE(p)) {
4193 bc_vec_pop(&p->flags);
4195 ip = bc_vec_top(&p->exits);
4196 label = bc_vec_item(&p->func->labels, ip->idx);
4197 *label = p->func->code.len;
4199 bc_vec_pop(&p->exits);
4201 else if (BC_PARSE_FUNC_INNER(p)) {
4202 bc_parse_push(p, BC_INST_RET0);
4203 bc_parse_updateFunc(p, BC_PROG_MAIN);
4204 bc_vec_pop(&p->flags);
4208 BcInstPtr *ip = bc_vec_top(&p->exits);
4209 size_t *label = bc_vec_top(&p->conds);
4211 bc_parse_push(p, BC_INST_JUMP);
4212 bc_parse_pushIndex(p, *label);
4214 label = bc_vec_item(&p->func->labels, ip->idx);
4215 *label = p->func->code.len;
4217 bc_vec_pop(&p->flags);
4218 bc_vec_pop(&p->exits);
4219 bc_vec_pop(&p->conds);
4225 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4227 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4228 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4229 flags |= BC_PARSE_FLAG_BODY;
4230 bc_vec_push(&p->flags, &flags);
4233 static void bc_parse_noElse(BcParse *p)
4237 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4239 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4241 ip = bc_vec_top(&p->exits);
4242 label = bc_vec_item(&p->func->labels, ip->idx);
4243 *label = p->func->code.len;
4245 bc_vec_pop(&p->exits);
4248 static BcStatus bc_parse_if(BcParse *p)
4253 s = bc_lex_next(&p->l);
4255 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4257 s = bc_lex_next(&p->l);
4259 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4261 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4263 s = bc_lex_next(&p->l);
4265 bc_parse_push(p, BC_INST_JUMP_ZERO);
4267 ip.idx = p->func->labels.len;
4268 ip.func = ip.len = 0;
4270 bc_parse_pushIndex(p, ip.idx);
4271 bc_vec_push(&p->exits, &ip);
4272 bc_vec_push(&p->func->labels, &ip.idx);
4273 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4275 return BC_STATUS_SUCCESS;
4278 static BcStatus bc_parse_else(BcParse *p)
4282 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4284 ip.idx = p->func->labels.len;
4285 ip.func = ip.len = 0;
4287 bc_parse_push(p, BC_INST_JUMP);
4288 bc_parse_pushIndex(p, ip.idx);
4292 bc_vec_push(&p->exits, &ip);
4293 bc_vec_push(&p->func->labels, &ip.idx);
4294 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4296 return bc_lex_next(&p->l);
4299 static BcStatus bc_parse_while(BcParse *p)
4304 s = bc_lex_next(&p->l);
4306 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4307 s = bc_lex_next(&p->l);
4310 ip.idx = p->func->labels.len;
4312 bc_vec_push(&p->func->labels, &p->func->code.len);
4313 bc_vec_push(&p->conds, &ip.idx);
4315 ip.idx = p->func->labels.len;
4319 bc_vec_push(&p->exits, &ip);
4320 bc_vec_push(&p->func->labels, &ip.idx);
4322 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4324 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4325 s = bc_lex_next(&p->l);
4328 bc_parse_push(p, BC_INST_JUMP_ZERO);
4329 bc_parse_pushIndex(p, ip.idx);
4330 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4332 return BC_STATUS_SUCCESS;
4335 static BcStatus bc_parse_for(BcParse *p)
4339 size_t cond_idx, exit_idx, body_idx, update_idx;
4341 s = bc_lex_next(&p->l);
4343 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4344 s = bc_lex_next(&p->l);
4347 if (p->l.t.t != BC_LEX_SCOLON)
4348 s = bc_parse_expr(p, 0, bc_parse_next_for);
4350 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4353 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4354 s = bc_lex_next(&p->l);
4357 cond_idx = p->func->labels.len;
4358 update_idx = cond_idx + 1;
4359 body_idx = update_idx + 1;
4360 exit_idx = body_idx + 1;
4362 bc_vec_push(&p->func->labels, &p->func->code.len);
4364 if (p->l.t.t != BC_LEX_SCOLON)
4365 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4367 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4370 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4372 s = bc_lex_next(&p->l);
4375 bc_parse_push(p, BC_INST_JUMP_ZERO);
4376 bc_parse_pushIndex(p, exit_idx);
4377 bc_parse_push(p, BC_INST_JUMP);
4378 bc_parse_pushIndex(p, body_idx);
4380 ip.idx = p->func->labels.len;
4382 bc_vec_push(&p->conds, &update_idx);
4383 bc_vec_push(&p->func->labels, &p->func->code.len);
4385 if (p->l.t.t != BC_LEX_RPAREN)
4386 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4388 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4392 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4393 bc_parse_push(p, BC_INST_JUMP);
4394 bc_parse_pushIndex(p, cond_idx);
4395 bc_vec_push(&p->func->labels, &p->func->code.len);
4401 bc_vec_push(&p->exits, &ip);
4402 bc_vec_push(&p->func->labels, &ip.idx);
4404 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4406 return BC_STATUS_SUCCESS;
4409 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4415 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4417 if (type == BC_LEX_KEY_BREAK) {
4419 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4421 i = p->exits.len - 1;
4422 ip = bc_vec_item(&p->exits, i);
4424 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4425 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4430 i = *((size_t *) bc_vec_top(&p->conds));
4432 bc_parse_push(p, BC_INST_JUMP);
4433 bc_parse_pushIndex(p, i);
4435 s = bc_lex_next(&p->l);
4438 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4439 return BC_STATUS_PARSE_BAD_TOKEN;
4441 return bc_lex_next(&p->l);
4444 static BcStatus bc_parse_func(BcParse *p)
4447 bool var, comma = false;
4451 s = bc_lex_next(&p->l);
4453 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4455 name = xstrdup(p->l.t.v.v);
4456 bc_parse_addFunc(p, name, &p->fidx);
4458 s = bc_lex_next(&p->l);
4460 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4461 s = bc_lex_next(&p->l);
4464 while (p->l.t.t != BC_LEX_RPAREN) {
4466 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4470 name = xstrdup(p->l.t.v.v);
4471 s = bc_lex_next(&p->l);
4474 var = p->l.t.t != BC_LEX_LBRACKET;
4478 s = bc_lex_next(&p->l);
4481 if (p->l.t.t != BC_LEX_RBRACKET) {
4482 s = BC_STATUS_PARSE_BAD_FUNC;
4486 s = bc_lex_next(&p->l);
4490 comma = p->l.t.t == BC_LEX_COMMA;
4492 s = bc_lex_next(&p->l);
4496 s = bc_func_insert(p->func, name, var);
4500 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4502 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4503 bc_parse_startBody(p, flags);
4505 s = bc_lex_next(&p->l);
4508 if (p->l.t.t != BC_LEX_LBRACE)
4509 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4518 static BcStatus bc_parse_auto(BcParse *p)
4521 bool comma, var, one;
4524 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4525 s = bc_lex_next(&p->l);
4528 p->auto_part = comma = false;
4529 one = p->l.t.t == BC_LEX_NAME;
4531 while (p->l.t.t == BC_LEX_NAME) {
4533 name = xstrdup(p->l.t.v.v);
4534 s = bc_lex_next(&p->l);
4537 var = p->l.t.t != BC_LEX_LBRACKET;
4540 s = bc_lex_next(&p->l);
4543 if (p->l.t.t != BC_LEX_RBRACKET) {
4544 s = BC_STATUS_PARSE_BAD_FUNC;
4548 s = bc_lex_next(&p->l);
4552 comma = p->l.t.t == BC_LEX_COMMA;
4554 s = bc_lex_next(&p->l);
4558 s = bc_func_insert(p->func, name, var);
4562 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4563 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4565 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4566 return BC_STATUS_PARSE_BAD_TOKEN;
4568 return bc_lex_next(&p->l);
4575 static BcStatus bc_parse_body(BcParse *p, bool brace)
4577 BcStatus s = BC_STATUS_SUCCESS;
4578 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4580 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4582 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4584 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4585 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4587 if (!p->auto_part) {
4588 s = bc_parse_auto(p);
4592 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4595 s = bc_parse_stmt(p);
4596 if (!s && !brace) s = bc_parse_endBody(p, false);
4602 static BcStatus bc_parse_stmt(BcParse *p)
4604 BcStatus s = BC_STATUS_SUCCESS;
4610 return bc_lex_next(&p->l);
4613 case BC_LEX_KEY_ELSE:
4615 p->auto_part = false;
4621 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4624 s = bc_lex_next(&p->l);
4627 return bc_parse_body(p, true);
4630 case BC_LEX_KEY_AUTO:
4632 return bc_parse_auto(p);
4637 p->auto_part = false;
4639 if (BC_PARSE_IF_END(p)) {
4641 return BC_STATUS_SUCCESS;
4643 else if (BC_PARSE_BODY(p))
4644 return bc_parse_body(p, false);
4654 case BC_LEX_OP_MINUS:
4655 case BC_LEX_OP_BOOL_NOT:
4659 case BC_LEX_KEY_IBASE:
4660 case BC_LEX_KEY_LAST:
4661 case BC_LEX_KEY_LENGTH:
4662 case BC_LEX_KEY_OBASE:
4663 case BC_LEX_KEY_READ:
4664 case BC_LEX_KEY_SCALE:
4665 case BC_LEX_KEY_SQRT:
4667 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4671 case BC_LEX_KEY_ELSE:
4673 s = bc_parse_else(p);
4679 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4685 s = bc_parse_endBody(p, true);
4691 s = bc_parse_string(p, BC_INST_PRINT_STR);
4695 case BC_LEX_KEY_BREAK:
4696 case BC_LEX_KEY_CONTINUE:
4698 s = bc_parse_loopExit(p, p->l.t.t);
4702 case BC_LEX_KEY_FOR:
4704 s = bc_parse_for(p);
4708 case BC_LEX_KEY_HALT:
4710 bc_parse_push(p, BC_INST_HALT);
4711 s = bc_lex_next(&p->l);
4721 case BC_LEX_KEY_LIMITS:
4723 s = bc_lex_next(&p->l);
4725 s = BC_STATUS_LIMITS;
4729 case BC_LEX_KEY_PRINT:
4731 s = bc_parse_print(p);
4735 case BC_LEX_KEY_QUIT:
4737 // Quit is a compile-time command. We don't exit directly,
4738 // so the vm can clean up. Limits do the same thing.
4743 case BC_LEX_KEY_RETURN:
4745 s = bc_parse_return(p);
4749 case BC_LEX_KEY_WHILE:
4751 s = bc_parse_while(p);
4757 s = BC_STATUS_PARSE_BAD_TOKEN;
4765 static BcStatus bc_parse_parse(BcParse *p)
4769 if (p->l.t.t == BC_LEX_EOF)
4770 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4771 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4772 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4773 s = bc_parse_func(p);
4776 s = bc_parse_stmt(p);
4778 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G.signe)
4779 s = bc_parse_reset(p, s);
4784 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4786 BcStatus s = BC_STATUS_SUCCESS;
4787 BcInst prev = BC_INST_PRINT;
4788 BcLexType top, t = p->l.t.t;
4789 size_t nexprs = 0, ops_bgn = p->ops.len;
4790 uint32_t i, nparens, nrelops;
4791 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4793 paren_first = p->l.t.t == BC_LEX_LPAREN;
4794 nparens = nrelops = 0;
4795 paren_expr = rprn = done = get_token = assign = false;
4798 for (; !G.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4804 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4805 rprn = get_token = bin_last = false;
4809 case BC_LEX_OP_MINUS:
4811 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4812 rprn = get_token = false;
4813 bin_last = prev == BC_INST_MINUS;
4817 case BC_LEX_OP_ASSIGN_POWER:
4818 case BC_LEX_OP_ASSIGN_MULTIPLY:
4819 case BC_LEX_OP_ASSIGN_DIVIDE:
4820 case BC_LEX_OP_ASSIGN_MODULUS:
4821 case BC_LEX_OP_ASSIGN_PLUS:
4822 case BC_LEX_OP_ASSIGN_MINUS:
4823 case BC_LEX_OP_ASSIGN:
4825 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4826 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4827 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4829 s = BC_STATUS_PARSE_BAD_ASSIGN;
4834 case BC_LEX_OP_POWER:
4835 case BC_LEX_OP_MULTIPLY:
4836 case BC_LEX_OP_DIVIDE:
4837 case BC_LEX_OP_MODULUS:
4838 case BC_LEX_OP_PLUS:
4839 case BC_LEX_OP_REL_EQ:
4840 case BC_LEX_OP_REL_LE:
4841 case BC_LEX_OP_REL_GE:
4842 case BC_LEX_OP_REL_NE:
4843 case BC_LEX_OP_REL_LT:
4844 case BC_LEX_OP_REL_GT:
4845 case BC_LEX_OP_BOOL_NOT:
4846 case BC_LEX_OP_BOOL_OR:
4847 case BC_LEX_OP_BOOL_AND:
4849 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4850 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4852 return BC_STATUS_PARSE_BAD_EXP;
4855 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4856 prev = BC_PARSE_TOKEN_INST(t);
4857 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4858 rprn = get_token = false;
4859 bin_last = t != BC_LEX_OP_BOOL_NOT;
4866 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4869 paren_expr = rprn = bin_last = false;
4871 bc_vec_push(&p->ops, &t);
4878 if (bin_last || prev == BC_INST_BOOL_NOT)
4879 return BC_STATUS_PARSE_BAD_EXP;
4882 s = BC_STATUS_SUCCESS;
4887 else if (!paren_expr)
4888 return BC_STATUS_PARSE_EMPTY_EXP;
4891 paren_expr = rprn = true;
4892 get_token = bin_last = false;
4894 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4901 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4904 rprn = get_token = bin_last = false;
4905 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4913 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4915 bc_parse_number(p, &prev, &nexprs);
4916 paren_expr = get_token = true;
4917 rprn = bin_last = false;
4922 case BC_LEX_KEY_IBASE:
4923 case BC_LEX_KEY_LAST:
4924 case BC_LEX_KEY_OBASE:
4926 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4928 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4929 bc_parse_push(p, (char) prev);
4931 paren_expr = get_token = true;
4932 rprn = bin_last = false;
4938 case BC_LEX_KEY_LENGTH:
4939 case BC_LEX_KEY_SQRT:
4941 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4943 s = bc_parse_builtin(p, t, flags, &prev);
4945 rprn = get_token = bin_last = false;
4951 case BC_LEX_KEY_READ:
4953 if (BC_PARSE_LEAF(prev, rprn))
4954 return BC_STATUS_PARSE_BAD_EXP;
4955 else if (flags & BC_PARSE_NOREAD)
4956 s = BC_STATUS_EXEC_REC_READ;
4958 s = bc_parse_read(p);
4961 rprn = get_token = bin_last = false;
4963 prev = BC_INST_READ;
4968 case BC_LEX_KEY_SCALE:
4970 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4972 s = bc_parse_scale(p, &prev, flags);
4974 rprn = get_token = bin_last = false;
4976 prev = BC_INST_SCALE;
4983 s = BC_STATUS_PARSE_BAD_TOKEN;
4988 if (!s && get_token) s = bc_lex_next(&p->l);
4992 if (G.signe) return BC_STATUS_EXEC_SIGNAL;
4994 while (p->ops.len > ops_bgn) {
4996 top = BC_PARSE_TOP_OP(p);
4997 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4999 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5000 return BC_STATUS_PARSE_BAD_EXP;
5002 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5004 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5005 bc_vec_pop(&p->ops);
5008 s = BC_STATUS_PARSE_BAD_EXP;
5009 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5011 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5014 if (!(flags & BC_PARSE_REL) && nrelops) {
5015 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5018 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5019 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5023 if (flags & BC_PARSE_PRINT) {
5024 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5025 bc_parse_push(p, BC_INST_POP);
5031 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5033 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5036 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5038 return bc_parse_expr(p, flags, bc_parse_next_read);
5043 static BcStatus dc_parse_register(BcParse *p)
5048 s = bc_lex_next(&p->l);
5050 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5052 name = xstrdup(p->l.t.v.v);
5053 bc_parse_pushName(p, name);
5058 static BcStatus dc_parse_string(BcParse *p)
5060 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5061 size_t idx, len = p->prog->strs.len;
5063 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5066 str = xstrdup(p->l.t.v.v);
5067 bc_parse_push(p, BC_INST_STR);
5068 bc_parse_pushIndex(p, len);
5069 bc_vec_push(&p->prog->strs, &str);
5070 bc_parse_addFunc(p, name, &idx);
5072 return bc_lex_next(&p->l);
5075 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5079 bc_parse_push(p, inst);
5081 s = dc_parse_register(p);
5086 bc_parse_push(p, BC_INST_SWAP);
5087 bc_parse_push(p, BC_INST_ASSIGN);
5088 bc_parse_push(p, BC_INST_POP);
5091 return bc_lex_next(&p->l);
5094 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5098 bc_parse_push(p, inst);
5099 bc_parse_push(p, BC_INST_EXEC_COND);
5101 s = dc_parse_register(p);
5104 s = bc_lex_next(&p->l);
5107 if (p->l.t.t == BC_LEX_ELSE) {
5108 s = dc_parse_register(p);
5110 s = bc_lex_next(&p->l);
5113 bc_parse_push(p, BC_PARSE_STREND);
5118 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5120 BcStatus s = BC_STATUS_SUCCESS;
5123 bool assign, get_token = false;
5127 case BC_LEX_OP_REL_EQ:
5128 case BC_LEX_OP_REL_LE:
5129 case BC_LEX_OP_REL_GE:
5130 case BC_LEX_OP_REL_NE:
5131 case BC_LEX_OP_REL_LT:
5132 case BC_LEX_OP_REL_GT:
5134 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5141 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5147 s = dc_parse_string(p);
5154 if (t == BC_LEX_NEG) {
5155 s = bc_lex_next(&p->l);
5157 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5160 bc_parse_number(p, &prev, &p->nbraces);
5162 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5168 case BC_LEX_KEY_READ:
5170 if (flags & BC_PARSE_NOREAD)
5171 s = BC_STATUS_EXEC_REC_READ;
5173 bc_parse_push(p, BC_INST_READ);
5178 case BC_LEX_OP_ASSIGN:
5179 case BC_LEX_STORE_PUSH:
5181 assign = t == BC_LEX_OP_ASSIGN;
5182 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5183 s = dc_parse_mem(p, inst, true, assign);
5188 case BC_LEX_LOAD_POP:
5190 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5191 s = dc_parse_mem(p, inst, true, false);
5195 case BC_LEX_STORE_IBASE:
5196 case BC_LEX_STORE_SCALE:
5197 case BC_LEX_STORE_OBASE:
5199 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5200 s = dc_parse_mem(p, inst, false, true);
5206 s = BC_STATUS_PARSE_BAD_TOKEN;
5212 if (!s && get_token) s = bc_lex_next(&p->l);
5217 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5219 BcStatus s = BC_STATUS_SUCCESS;
5223 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5225 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5227 inst = dc_parse_insts[t];
5229 if (inst != BC_INST_INVALID) {
5230 bc_parse_push(p, inst);
5231 s = bc_lex_next(&p->l);
5234 s = dc_parse_token(p, t, flags);
5237 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5238 bc_parse_push(p, BC_INST_POP_EXEC);
5243 static BcStatus dc_parse_parse(BcParse *p)
5247 if (p->l.t.t == BC_LEX_EOF)
5248 s = BC_STATUS_LEX_EOF;
5250 s = dc_parse_expr(p, 0);
5252 if (s || G.signe) s = bc_parse_reset(p, s);
5257 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5259 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5263 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5272 v = var ? &p->vars : &p->arrs;
5273 map = var ? &p->var_map : &p->arr_map;
5277 s = bc_map_insert(map, &e, &i);
5278 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5281 bc_array_init(&data.v, var);
5282 bc_vec_push(v, &data.v);
5285 ptr = bc_vec_item(map, i);
5286 if (new) ptr->name = xstrdup(e.name);
5287 *ret = bc_vec_item(v, ptr->idx);
5290 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5292 BcStatus s = BC_STATUS_SUCCESS;
5297 case BC_RESULT_TEMP:
5298 case BC_RESULT_IBASE:
5299 case BC_RESULT_SCALE:
5300 case BC_RESULT_OBASE:
5306 case BC_RESULT_CONSTANT:
5308 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5309 size_t base_t, len = strlen(*str);
5312 bc_num_init(&r->d.n, len);
5314 hex = hex && len == 1;
5315 base = hex ? &p->hexb : &p->ib;
5316 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5317 s = bc_num_parse(&r->d.n, *str, base, base_t);
5320 bc_num_free(&r->d.n);
5325 r->t = BC_RESULT_TEMP;
5331 case BC_RESULT_ARRAY:
5332 case BC_RESULT_ARRAY_ELEM:
5336 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5338 if (r->t == BC_RESULT_ARRAY_ELEM) {
5340 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5341 *num = bc_vec_item(v, r->d.id.idx);
5344 *num = bc_vec_top(v);
5349 case BC_RESULT_LAST:
5365 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5366 BcResult **r, BcNum **rn, bool assign)
5370 BcResultType lt, rt;
5372 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5374 *r = bc_vec_item_rev(&p->results, 0);
5375 *l = bc_vec_item_rev(&p->results, 1);
5379 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5381 s = bc_program_num(p, *l, ln, false);
5383 s = bc_program_num(p, *r, rn, hex);
5386 // We run this again under these conditions in case any vector has been
5387 // reallocated out from under the BcNums or arrays we had.
5388 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5389 s = bc_program_num(p, *l, ln, false);
5393 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5394 return BC_STATUS_EXEC_BAD_TYPE;
5395 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5400 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5402 r->t = BC_RESULT_TEMP;
5403 bc_vec_pop(&p->results);
5404 bc_vec_pop(&p->results);
5405 bc_vec_push(&p->results, r);
5408 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5412 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5413 *r = bc_vec_top(&p->results);
5415 s = bc_program_num(p, *r, n, false);
5418 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5423 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5426 bc_vec_pop(&p->results);
5427 bc_vec_push(&p->results, r);
5430 static BcStatus bc_program_op(BcProgram *p, char inst)
5433 BcResult *opd1, *opd2, res;
5434 BcNum *n1, *n2 = NULL;
5436 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5438 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5440 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5442 bc_program_binOpRetire(p, &res);
5447 bc_num_free(&res.d.n);
5451 static BcStatus bc_program_read(BcProgram *p)
5458 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5460 for (i = 0; i < p->stack.len; ++i) {
5461 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5462 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5465 bc_vec_npop(&f->code, f->code.len);
5466 bc_vec_init(&buf, sizeof(char), NULL);
5468 s = bc_read_line(&buf, "read> ");
5471 p->parse_init(&parse, p, BC_PROG_READ);
5472 bc_lex_file(&parse.l, bc_program_stdin_name);
5474 s = bc_parse_text(&parse, buf.v);
5475 if (s) goto exec_err;
5476 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5477 if (s) goto exec_err;
5479 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5480 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5484 ip.func = BC_PROG_READ;
5486 ip.len = p->results.len;
5488 // Update this pointer, just in case.
5489 f = bc_vec_item(&p->fns, BC_PROG_READ);
5491 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5492 bc_vec_push(&p->stack, &ip);
5495 bc_parse_free(&parse);
5501 static size_t bc_program_index(char *code, size_t *bgn)
5503 char amt = code[(*bgn)++], i = 0;
5506 for (; i < amt; ++i, ++(*bgn))
5507 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5512 static char *bc_program_name(char *code, size_t *bgn)
5515 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5517 s = xmalloc(ptr - str + 1);
5520 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5528 static void bc_program_printString(const char *str, size_t *nchars)
5530 size_t i, len = strlen(str);
5539 for (i = 0; i < len; ++i, ++(*nchars)) {
5543 if (c != '\\' || i == len - 1)
5603 // Just print the backslash and following character.
5614 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5616 BcStatus s = BC_STATUS_SUCCESS;
5621 bool pop = inst != BC_INST_PRINT;
5623 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5625 r = bc_vec_item_rev(&p->results, idx);
5626 s = bc_program_num(p, r, &num, false);
5629 if (BC_PROG_NUM(r, num)) {
5630 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5631 if (!s) bc_num_copy(&p->last, num);
5635 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5636 str = *((char **) bc_vec_item(&p->strs, idx));
5638 if (inst == BC_INST_PRINT_STR) {
5639 for (i = 0, len = strlen(str); i < len; ++i) {
5642 if (c == '\n') p->nchars = SIZE_MAX;
5647 bc_program_printString(str, &p->nchars);
5648 if (inst == BC_INST_PRINT) bb_putchar('\n');
5652 if (!s && pop) bc_vec_pop(&p->results);
5657 static BcStatus bc_program_negate(BcProgram *p)
5663 s = bc_program_prep(p, &ptr, &num);
5666 bc_num_init(&res.d.n, num->len);
5667 bc_num_copy(&res.d.n, num);
5668 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5670 bc_program_retire(p, &res, BC_RESULT_TEMP);
5675 static BcStatus bc_program_logical(BcProgram *p, char inst)
5678 BcResult *opd1, *opd2, res;
5683 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5685 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5687 if (inst == BC_INST_BOOL_AND)
5688 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5689 else if (inst == BC_INST_BOOL_OR)
5690 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5693 cmp = bc_num_cmp(n1, n2);
5697 case BC_INST_REL_EQ:
5703 case BC_INST_REL_LE:
5709 case BC_INST_REL_GE:
5715 case BC_INST_REL_NE:
5721 case BC_INST_REL_LT:
5727 case BC_INST_REL_GT:
5735 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5737 bc_program_binOpRetire(p, &res);
5743 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5749 memset(&n2, 0, sizeof(BcNum));
5750 n2.rdx = res.d.id.idx = r->d.id.idx;
5751 res.t = BC_RESULT_STR;
5754 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5756 bc_vec_pop(&p->results);
5759 bc_vec_pop(&p->results);
5761 bc_vec_push(&p->results, &res);
5762 bc_vec_push(v, &n2);
5764 return BC_STATUS_SUCCESS;
5768 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5775 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5777 ptr = bc_vec_top(&p->results);
5778 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5779 bc_program_search(p, name, &v, var);
5782 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5783 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5786 s = bc_program_num(p, ptr, &n, false);
5789 // Do this once more to make sure that pointers were not invalidated.
5790 bc_program_search(p, name, &v, var);
5793 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5794 bc_num_copy(&r.d.n, n);
5797 bc_array_init(&r.d.v, true);
5798 bc_array_copy(&r.d.v, (BcVec *) n);
5801 bc_vec_push(v, &r.d);
5802 bc_vec_pop(&p->results);
5807 static BcStatus bc_program_assign(BcProgram *p, char inst)
5810 BcResult *left, *right, res;
5811 BcNum *l = NULL, *r = NULL;
5812 unsigned long val, max;
5813 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5815 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5818 ib = left->t == BC_RESULT_IBASE;
5819 sc = left->t == BC_RESULT_SCALE;
5823 if (right->t == BC_RESULT_STR) {
5827 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5828 bc_program_search(p, left->d.id.name, &v, true);
5830 return bc_program_assignStr(p, right, v, false);
5834 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5835 return BC_STATUS_PARSE_BAD_ASSIGN;
5838 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5839 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5844 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5851 if (ib || sc || left->t == BC_RESULT_OBASE) {
5855 s = bc_num_ulong(l, &val);
5857 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5864 if (val < BC_NUM_MIN_BASE) return s;
5865 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5866 ptr = ib ? &p->ib_t : &p->ob_t;
5869 if (val > max) return s;
5870 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5872 *ptr = (size_t) val;
5873 s = BC_STATUS_SUCCESS;
5876 bc_num_init(&res.d.n, l->len);
5877 bc_num_copy(&res.d.n, l);
5878 bc_program_binOpRetire(p, &res);
5883 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5884 bool pop, bool copy)
5886 BcStatus s = BC_STATUS_SUCCESS;
5888 char *name = bc_program_name(code, bgn);
5889 #if ENABLE_DC // Exclude
5893 (void) pop, (void) copy;
5896 r.t = BC_RESULT_VAR;
5900 bc_program_search(p, name, &v, true);
5901 num = bc_vec_top(v);
5905 if (!BC_PROG_STACK(v, 2 - copy)) {
5907 return BC_STATUS_EXEC_STACK;
5913 if (!BC_PROG_STR(num)) {
5915 r.t = BC_RESULT_TEMP;
5917 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5918 bc_num_copy(&r.d.n, num);
5921 r.t = BC_RESULT_STR;
5922 r.d.id.idx = num->rdx;
5925 if (!copy) bc_vec_pop(v);
5929 bc_vec_push(&p->results, &r);
5934 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5937 BcStatus s = BC_STATUS_SUCCESS;
5941 r.d.id.name = bc_program_name(code, bgn);
5943 if (inst == BC_INST_ARRAY) {
5944 r.t = BC_RESULT_ARRAY;
5945 bc_vec_push(&p->results, &r);
5952 s = bc_program_prep(p, &operand, &num);
5954 s = bc_num_ulong(num, &temp);
5957 if (temp > BC_MAX_DIM) {
5958 s = BC_STATUS_EXEC_ARRAY_LEN;
5962 r.d.id.idx = (size_t) temp;
5963 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5967 if (s) free(r.d.id.name);
5972 static BcStatus bc_program_incdec(BcProgram *p, char inst)
5975 BcResult *ptr, res, copy;
5979 s = bc_program_prep(p, &ptr, &num);
5982 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5983 copy.t = BC_RESULT_TEMP;
5984 bc_num_init(©.d.n, num->len);
5985 bc_num_copy(©.d.n, num);
5988 res.t = BC_RESULT_ONE;
5989 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5990 BC_INST_ASSIGN_PLUS :
5991 BC_INST_ASSIGN_MINUS;
5993 bc_vec_push(&p->results, &res);
5994 bc_program_assign(p, inst);
5996 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5997 bc_vec_pop(&p->results);
5998 bc_vec_push(&p->results, ©);
6004 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6006 BcStatus s = BC_STATUS_SUCCESS;
6008 size_t i, nparams = bc_program_index(code, idx);
6016 ip.func = bc_program_index(code, idx);
6017 func = bc_vec_item(&p->fns, ip.func);
6019 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6020 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6021 ip.len = p->results.len - nparams;
6023 for (i = 0; i < nparams; ++i) {
6025 a = bc_vec_item(&func->autos, nparams - 1 - i);
6026 arg = bc_vec_top(&p->results);
6028 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6029 return BC_STATUS_EXEC_BAD_TYPE;
6031 s = bc_program_copyToVar(p, a->name, a->idx);
6035 for (; i < func->autos.len; ++i) {
6037 a = bc_vec_item(&func->autos, i);
6038 bc_program_search(p, a->name, &v, a->idx);
6041 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6042 bc_vec_push(v, ¶m.n);
6045 bc_array_init(¶m.v, true);
6046 bc_vec_push(v, ¶m.v);
6050 bc_vec_push(&p->stack, &ip);
6052 return BC_STATUS_SUCCESS;
6055 static BcStatus bc_program_return(BcProgram *p, char inst)
6061 BcInstPtr *ip = bc_vec_top(&p->stack);
6063 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6064 return BC_STATUS_EXEC_STACK;
6066 f = bc_vec_item(&p->fns, ip->func);
6067 res.t = BC_RESULT_TEMP;
6069 if (inst == BC_INST_RET) {
6072 BcResult *operand = bc_vec_top(&p->results);
6074 s = bc_program_num(p, operand, &num, false);
6076 bc_num_init(&res.d.n, num->len);
6077 bc_num_copy(&res.d.n, num);
6080 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6081 bc_num_zero(&res.d.n);
6084 // We need to pop arguments as well, so this takes that into account.
6085 for (i = 0; i < f->autos.len; ++i) {
6088 BcId *a = bc_vec_item(&f->autos, i);
6090 bc_program_search(p, a->name, &v, a->idx);
6094 bc_vec_npop(&p->results, p->results.len - ip->len);
6095 bc_vec_push(&p->results, &res);
6096 bc_vec_pop(&p->stack);
6098 return BC_STATUS_SUCCESS;
6102 static unsigned long bc_program_scale(BcNum *n)
6104 return (unsigned long) n->rdx;
6107 static unsigned long bc_program_len(BcNum *n)
6109 unsigned long len = n->len;
6112 if (n->rdx != n->len) return len;
6113 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6118 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6124 bool len = inst == BC_INST_LENGTH;
6126 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6127 opnd = bc_vec_top(&p->results);
6129 s = bc_program_num(p, opnd, &num, false);
6133 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6136 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6138 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6140 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6141 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6145 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6148 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6150 str = bc_vec_item(&p->strs, idx);
6151 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6156 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6157 s = bc_num_ulong2num(&res.d.n, f(num));
6161 bc_program_retire(p, &res, BC_RESULT_TEMP);
6166 bc_num_free(&res.d.n);
6171 static BcStatus bc_program_divmod(BcProgram *p)
6174 BcResult *opd1, *opd2, res, res2;
6175 BcNum *n1, *n2 = NULL;
6177 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6180 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6181 bc_num_init(&res2.d.n, n2->len);
6183 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6186 bc_program_binOpRetire(p, &res2);
6187 res.t = BC_RESULT_TEMP;
6188 bc_vec_push(&p->results, &res);
6193 bc_num_free(&res2.d.n);
6194 bc_num_free(&res.d.n);
6198 static BcStatus bc_program_modexp(BcProgram *p)
6201 BcResult *r1, *r2, *r3, res;
6202 BcNum *n1, *n2, *n3;
6204 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6205 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6208 r1 = bc_vec_item_rev(&p->results, 2);
6209 s = bc_program_num(p, r1, &n1, false);
6211 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6213 // Make sure that the values have their pointers updated, if necessary.
6214 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6216 if (r1->t == r2->t) {
6217 s = bc_program_num(p, r2, &n2, false);
6221 if (r1->t == r3->t) {
6222 s = bc_program_num(p, r3, &n3, false);
6227 bc_num_init(&res.d.n, n3->len);
6228 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6231 bc_vec_pop(&p->results);
6232 bc_program_binOpRetire(p, &res);
6237 bc_num_free(&res.d.n);
6241 static BcStatus bc_program_stackLen(BcProgram *p)
6245 size_t len = p->results.len;
6247 res.t = BC_RESULT_TEMP;
6249 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6250 s = bc_num_ulong2num(&res.d.n, len);
6252 bc_vec_push(&p->results, &res);
6257 bc_num_free(&res.d.n);
6261 static BcStatus bc_program_asciify(BcProgram *p)
6265 BcNum *num = NULL, n;
6266 char *str, *str2, c;
6267 size_t len = p->strs.len, idx;
6270 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6271 r = bc_vec_top(&p->results);
6273 s = bc_program_num(p, r, &num, false);
6276 if (BC_PROG_NUM(r, num)) {
6278 bc_num_init(&n, BC_NUM_DEF_SIZE);
6279 bc_num_copy(&n, num);
6280 bc_num_truncate(&n, n.rdx);
6282 s = bc_num_mod(&n, &p->strmb, &n, 0);
6283 if (s) goto num_err;
6284 s = bc_num_ulong(&n, &val);
6285 if (s) goto num_err;
6292 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6293 str2 = *((char **) bc_vec_item(&p->strs, idx));
6301 str2 = xstrdup(str);
6302 bc_program_addFunc(p, str2, &idx);
6304 if (idx != len + BC_PROG_REQ_FUNCS) {
6306 for (idx = 0; idx < p->strs.len; ++idx) {
6307 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6316 bc_vec_push(&p->strs, &str);
6318 res.t = BC_RESULT_STR;
6320 bc_vec_pop(&p->results);
6321 bc_vec_push(&p->results, &res);
6323 return BC_STATUS_SUCCESS;
6330 static BcStatus bc_program_printStream(BcProgram *p)
6338 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6339 r = bc_vec_top(&p->results);
6341 s = bc_program_num(p, r, &n, false);
6344 if (BC_PROG_NUM(r, n))
6345 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6347 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6348 str = *((char **) bc_vec_item(&p->strs, idx));
6355 static BcStatus bc_program_nquit(BcProgram *p)
6362 s = bc_program_prep(p, &opnd, &num);
6364 s = bc_num_ulong(num, &val);
6367 bc_vec_pop(&p->results);
6369 if (p->stack.len < val)
6370 return BC_STATUS_EXEC_STACK;
6371 else if (p->stack.len == val)
6372 return BC_STATUS_QUIT;
6374 bc_vec_npop(&p->stack, val);
6379 static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6382 BcStatus s = BC_STATUS_SUCCESS;
6392 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6394 r = bc_vec_top(&p->results);
6399 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6401 if (code[*bgn] == BC_PARSE_STREND)
6404 else_name = bc_program_name(code, bgn);
6406 exec = r->d.n.len != 0;
6410 else if (else_name != NULL) {
6416 bc_program_search(p, name, &v, true);
6423 if (!exec) goto exit;
6424 if (!BC_PROG_STR(n)) {
6425 s = BC_STATUS_EXEC_BAD_TYPE;
6433 if (r->t == BC_RESULT_STR)
6435 else if (r->t == BC_RESULT_VAR) {
6436 s = bc_program_num(p, r, &n, false);
6437 if (s || !BC_PROG_STR(n)) goto exit;
6444 fidx = sidx + BC_PROG_REQ_FUNCS;
6446 str = bc_vec_item(&p->strs, sidx);
6447 f = bc_vec_item(&p->fns, fidx);
6449 if (f->code.len == 0) {
6451 p->parse_init(&prs, p, fidx);
6452 s = bc_parse_text(&prs, *str);
6454 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6457 if (prs.l.t.t != BC_LEX_EOF) {
6458 s = BC_STATUS_PARSE_BAD_EXP;
6462 bc_parse_free(&prs);
6466 ip.len = p->results.len;
6469 bc_vec_pop(&p->results);
6470 bc_vec_push(&p->stack, &ip);
6472 return BC_STATUS_SUCCESS;
6475 bc_parse_free(&prs);
6476 f = bc_vec_item(&p->fns, fidx);
6477 bc_vec_npop(&f->code, f->code.len);
6479 bc_vec_pop(&p->results);
6484 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6490 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6491 if (inst == BC_INST_IBASE)
6492 val = (unsigned long) p->ib_t;
6493 else if (inst == BC_INST_SCALE)
6494 val = (unsigned long) p->scale;
6496 val = (unsigned long) p->ob_t;
6498 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6499 s = bc_num_ulong2num(&res.d.n, val);
6501 bc_vec_push(&p->results, &res);
6506 bc_num_free(&res.d.n);
6510 static void bc_program_free(BcProgram *p)
6512 bc_num_free(&p->ib);
6513 bc_num_free(&p->ob);
6514 bc_num_free(&p->hexb);
6516 bc_num_free(&p->strmb);
6518 bc_vec_free(&p->fns);
6519 bc_vec_free(&p->fn_map);
6520 bc_vec_free(&p->vars);
6521 bc_vec_free(&p->var_map);
6522 bc_vec_free(&p->arrs);
6523 bc_vec_free(&p->arr_map);
6524 bc_vec_free(&p->strs);
6525 bc_vec_free(&p->consts);
6526 bc_vec_free(&p->results);
6527 bc_vec_free(&p->stack);
6528 bc_num_free(&p->last);
6529 bc_num_free(&p->zero);
6530 bc_num_free(&p->one);
6533 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6539 memset(p, 0, sizeof(BcProgram));
6540 memset(&ip, 0, sizeof(BcInstPtr));
6542 p->nchars = p->scale = 0;
6544 p->parse_init = init;
6545 p->parse_expr = expr;
6547 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6551 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6555 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6556 bc_num_ten(&p->hexb);
6560 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6561 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6564 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6565 bc_num_zero(&p->last);
6567 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6568 bc_num_zero(&p->zero);
6570 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6571 bc_num_one(&p->one);
6573 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6574 bc_map_init(&p->fn_map);
6576 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6577 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6579 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6580 bc_map_init(&p->var_map);
6582 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6583 bc_map_init(&p->arr_map);
6585 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6586 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6587 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6588 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6589 bc_vec_push(&p->stack, &ip);
6592 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6595 BcId entry, *entry_ptr;
6599 entry.idx = p->fns.len;
6601 s = bc_map_insert(&p->fn_map, &entry, idx);
6604 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6605 *idx = entry_ptr->idx;
6607 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6609 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6611 // We need to reset these, so the function can be repopulated.
6613 bc_vec_npop(&func->autos, func->autos.len);
6614 bc_vec_npop(&func->code, func->code.len);
6615 bc_vec_npop(&func->labels, func->labels.len);
6619 bc_vec_push(&p->fns, &f);
6623 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6628 bc_vec_npop(&p->stack, p->stack.len - 1);
6629 bc_vec_npop(&p->results, p->results.len);
6631 f = bc_vec_item(&p->fns, 0);
6632 ip = bc_vec_top(&p->stack);
6633 ip->idx = f->code.len;
6635 if (!s && G.signe && !G.tty) return BC_STATUS_QUIT;
6638 G.signe = G.sig != G.sigc;
6640 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6642 fputs(bc_program_ready_msg, stderr);
6644 s = BC_STATUS_SUCCESS;
6653 static BcStatus bc_program_exec(BcProgram *p)
6655 BcStatus s = BC_STATUS_SUCCESS;
6659 BcInstPtr *ip = bc_vec_top(&p->stack);
6660 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6661 char *code = func->code.v;
6664 while (!s && ip->idx < func->code.len) {
6666 char inst = code[(ip->idx)++];
6671 case BC_INST_JUMP_ZERO:
6673 s = bc_program_prep(p, &ptr, &num);
6675 cond = !bc_num_cmp(num, &p->zero);
6676 bc_vec_pop(&p->results);
6682 idx = bc_program_index(code, &ip->idx);
6683 addr = bc_vec_item(&func->labels, idx);
6684 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6690 s = bc_program_call(p, code, &ip->idx);
6694 case BC_INST_INC_PRE:
6695 case BC_INST_DEC_PRE:
6696 case BC_INST_INC_POST:
6697 case BC_INST_DEC_POST:
6699 s = bc_program_incdec(p, inst);
6712 s = bc_program_return(p, inst);
6716 case BC_INST_BOOL_OR:
6717 case BC_INST_BOOL_AND:
6719 case BC_INST_REL_EQ:
6720 case BC_INST_REL_LE:
6721 case BC_INST_REL_GE:
6722 case BC_INST_REL_NE:
6723 case BC_INST_REL_LT:
6724 case BC_INST_REL_GT:
6726 s = bc_program_logical(p, inst);
6732 s = bc_program_read(p);
6738 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6742 case BC_INST_ARRAY_ELEM:
6745 s = bc_program_pushArray(p, code, &ip->idx, inst);
6751 r.t = BC_RESULT_LAST;
6752 bc_vec_push(&p->results, &r);
6760 s = bc_program_pushGlobal(p, inst);
6764 case BC_INST_SCALE_FUNC:
6765 case BC_INST_LENGTH:
6768 s = bc_program_builtin(p, inst);
6774 r.t = BC_RESULT_CONSTANT;
6775 r.d.id.idx = bc_program_index(code, &ip->idx);
6776 bc_vec_push(&p->results, &r);
6782 if (!BC_PROG_STACK(&p->results, 1))
6783 s = BC_STATUS_EXEC_STACK;
6785 bc_vec_pop(&p->results);
6789 case BC_INST_POP_EXEC:
6791 bc_vec_pop(&p->stack);
6796 case BC_INST_PRINT_POP:
6797 case BC_INST_PRINT_STR:
6799 s = bc_program_print(p, inst, 0);
6805 r.t = BC_RESULT_STR;
6806 r.d.id.idx = bc_program_index(code, &ip->idx);
6807 bc_vec_push(&p->results, &r);
6812 case BC_INST_MULTIPLY:
6813 case BC_INST_DIVIDE:
6814 case BC_INST_MODULUS:
6818 s = bc_program_op(p, inst);
6822 case BC_INST_BOOL_NOT:
6824 s = bc_program_prep(p, &ptr, &num);
6827 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6828 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6829 bc_program_retire(p, &r, BC_RESULT_TEMP);
6836 s = bc_program_negate(p);
6841 case BC_INST_ASSIGN_POWER:
6842 case BC_INST_ASSIGN_MULTIPLY:
6843 case BC_INST_ASSIGN_DIVIDE:
6844 case BC_INST_ASSIGN_MODULUS:
6845 case BC_INST_ASSIGN_PLUS:
6846 case BC_INST_ASSIGN_MINUS:
6848 case BC_INST_ASSIGN:
6850 s = bc_program_assign(p, inst);
6854 case BC_INST_MODEXP:
6856 s = bc_program_modexp(p);
6860 case BC_INST_DIVMOD:
6862 s = bc_program_divmod(p);
6866 case BC_INST_EXECUTE:
6867 case BC_INST_EXEC_COND:
6869 cond = inst == BC_INST_EXEC_COND;
6870 s = bc_program_execStr(p, code, &ip->idx, cond);
6874 case BC_INST_PRINT_STACK:
6876 for (idx = 0; !s && idx < p->results.len; ++idx)
6877 s = bc_program_print(p, BC_INST_PRINT, idx);
6881 case BC_INST_CLEAR_STACK:
6883 bc_vec_npop(&p->results, p->results.len);
6887 case BC_INST_STACK_LEN:
6889 s = bc_program_stackLen(p);
6893 case BC_INST_DUPLICATE:
6895 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6896 ptr = bc_vec_top(&p->results);
6897 bc_result_copy(&r, ptr);
6898 bc_vec_push(&p->results, &r);
6906 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6908 ptr = bc_vec_item_rev(&p->results, 0);
6909 ptr2 = bc_vec_item_rev(&p->results, 1);
6910 memcpy(&r, ptr, sizeof(BcResult));
6911 memcpy(ptr, ptr2, sizeof(BcResult));
6912 memcpy(ptr2, &r, sizeof(BcResult));
6917 case BC_INST_ASCIIFY:
6919 s = bc_program_asciify(p);
6923 case BC_INST_PRINT_STREAM:
6925 s = bc_program_printStream(p);
6930 case BC_INST_PUSH_VAR:
6932 bool copy = inst == BC_INST_LOAD;
6933 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6937 case BC_INST_PUSH_TO_VAR:
6939 char *name = bc_program_name(code, &ip->idx);
6940 s = bc_program_copyToVar(p, name, true);
6947 if (p->stack.len <= 2)
6950 bc_vec_npop(&p->stack, 2);
6956 s = bc_program_nquit(p);
6962 if ((s && s != BC_STATUS_QUIT) || G.signe) s = bc_program_reset(p, s);
6964 // If the stack has changed, pointers may be invalid.
6965 ip = bc_vec_top(&p->stack);
6966 func = bc_vec_item(&p->fns, ip->func);
6967 code = func->code.v;
6973 #if ENABLE_FEATURE_BC_SIGNALS
6974 static void bc_vm_sig(int sig)
6977 size_t len = strlen(G.sig_msg);
6978 if (sig == SIGINT && write(2, G.sig_msg, len) == (ssize_t) len) {
6979 G.signe = G.sig == G.sigc;
6986 static void bc_vm_info(void)
6988 printf("%s "BB_VER"\n"
6989 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6990 "Report bugs at: https://github.com/gavinhoward/bc\n"
6991 "This is free software with ABSOLUTELY NO WARRANTY\n"
6995 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6997 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6999 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7000 fprintf(stderr, " %s", file);
7001 fprintf(stderr, bc_err_line + 4 * !line, line);
7003 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
7007 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7010 int p = (int) G_posix, w = (int) G_warn;
7011 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7013 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7015 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7016 if (msg) fprintf(stderr, " %s\n", msg);
7017 fprintf(stderr, " %s", file);
7018 fprintf(stderr, bc_err_line + 4 * !line, line);
7020 return s * (!G.ttyin && !!p);
7023 static void bc_vm_envArgs(void)
7026 char *env_args = getenv(bc_args_env_name), *buf;
7028 if (!env_args) return;
7030 G.env_args = xstrdup(env_args);
7033 bc_vec_init(&v, sizeof(char *), NULL);
7034 bc_vec_push(&v, &bc_args_env_name);
7037 if (!isspace(*buf)) {
7038 bc_vec_push(&v, &buf);
7039 while (*buf != 0 && !isspace(*buf)) ++buf;
7040 if (*buf != 0) (*(buf++)) = '\0';
7046 bc_args((int) v.len, (char **) v.v, &G.flags, &G.files);
7052 static size_t bc_vm_envLen(const char *var)
7054 char *lenv = getenv(var);
7055 size_t i, len = BC_NUM_PRINT_WIDTH;
7058 if (!lenv) return len;
7062 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7064 len = (size_t) atoi(lenv) - 1;
7065 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7068 len = BC_NUM_PRINT_WIDTH;
7073 static BcStatus bc_vm_process(const char *text)
7075 BcStatus s = bc_parse_text(&G.prs, text);
7077 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7080 while (G.prs.l.t.t != BC_LEX_EOF) {
7082 s = G.prs.parse(&G.prs);
7084 if (s == BC_STATUS_LIMITS) {
7087 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7088 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7089 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7090 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7091 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7092 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7093 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7094 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7097 s = BC_STATUS_SUCCESS;
7100 if (s == BC_STATUS_QUIT) return s;
7101 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7106 if (BC_PARSE_CAN_EXEC(&G.prs)) {
7107 s = bc_program_exec(&G.prog);
7108 if (!s && G.tty) fflush(stdout);
7109 if (s && s != BC_STATUS_QUIT)
7110 s = bc_vm_error(bc_program_reset(&G.prog, s), G.prs.l.f, 0);
7116 static BcStatus bc_vm_file(const char *file)
7124 s = bc_read_file(file, &data);
7125 if (s) return bc_vm_error(s, file, 0);
7127 bc_lex_file(&G.prs.l, file);
7128 s = bc_vm_process(data);
7131 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7132 ip = bc_vec_item(&G.prog.stack, 0);
7134 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7141 static BcStatus bc_vm_stdin(void)
7143 BcStatus s = BC_STATUS_SUCCESS;
7146 size_t len, i, str = 0;
7147 bool comment = false, notend;
7149 G.prog.file = bc_program_stdin_name;
7150 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7152 bc_vec_init(&buffer, sizeof(char), NULL);
7153 bc_vec_init(&buf, sizeof(char), NULL);
7154 bc_vec_pushByte(&buffer, '\0');
7156 // This loop is complex because the vm tries not to send any lines that end
7157 // with a backslash to the parser. The reason for that is because the parser
7158 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7159 // case, and for strings and comments, the parser will expect more stuff.
7160 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7162 char *string = buf.v;
7167 if (str && buf.v[0] == G.send)
7169 else if (buf.v[0] == G.sbgn)
7172 else if (len > 1 || comment) {
7174 for (i = 0; i < len; ++i) {
7176 notend = len > i + 1;
7179 if (i - 1 > len || string[i - 1] != '\\') {
7180 if (G.sbgn == G.send)
7182 else if (c == G.send)
7184 else if (c == G.sbgn)
7188 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7192 else if (c == '*' && notend && comment && string[i + 1] == '/')
7196 if (str || comment || string[len - 2] == '\\') {
7197 bc_vec_concat(&buffer, buf.v);
7202 bc_vec_concat(&buffer, buf.v);
7203 s = bc_vm_process(buffer.v);
7206 bc_vec_npop(&buffer, buffer.len);
7209 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7211 // INPUT_EOF will always happen when stdin is
7212 // closed. It's not a problem in that case.
7213 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7214 s = BC_STATUS_SUCCESS;
7217 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7220 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7225 bc_vec_free(&buffer);
7229 static BcStatus bc_vm_exec(void)
7231 BcStatus s = BC_STATUS_SUCCESS;
7235 if (G.flags & BC_FLAG_L) {
7237 bc_lex_file(&G.prs.l, bc_lib_name);
7238 s = bc_parse_text(&G.prs, bc_lib);
7240 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7243 s = bc_program_exec(&G.prog);
7248 for (i = 0; !s && i < G.files.len; ++i)
7249 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7250 if (s && s != BC_STATUS_QUIT) return s;
7252 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7253 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7255 if (s == BC_STATUS_QUIT)
7256 s = BC_STATUS_SUCCESS;
7260 static void bc_vm_free(void)
7262 bc_vec_free(&G.files);
7263 bc_program_free(&G.prog);
7264 bc_parse_free(&G.prs);
7268 static void bc_vm_init(const char *env_len)
7270 size_t len = bc_vm_envLen(env_len);
7271 #if ENABLE_FEATURE_BC_SIGNALS
7272 struct sigaction sa;
7274 sigemptyset(&sa.sa_mask);
7275 sa.sa_handler = bc_vm_sig;
7277 sigaction(SIGINT, &sa, NULL);
7280 bc_vec_init(&G.files, sizeof(char *), NULL);
7283 G.flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
7284 if (IS_BC) bc_vm_envArgs();
7287 bc_program_init(&G.prog, len, G.init, G.exp);
7288 G.init(&G.prs, &G.prog, BC_PROG_MAIN);
7291 static BcStatus bc_vm_run(int argc, char *argv[],
7292 const char *env_len)
7296 bc_vm_init(env_len);
7297 bc_args(argc, argv, &G.flags, &G.files);
7299 G.ttyin = isatty(0);
7300 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7302 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7310 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7311 int bc_main(int argc, char **argv)
7314 # if ENABLE_FEATURE_BC_SIGNALS
7315 G.sig_msg = "\ninterrupt (type \"quit\" to exit)\n";
7317 G.init = bc_parse_init;
7318 G.exp = bc_parse_expression;
7319 G.sbgn = G.send = '"';
7321 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7326 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7327 int dc_main(int argc, char **argv)
7330 # if ENABLE_FEATURE_BC_SIGNALS
7331 G.sig_msg = "\ninterrupt (type \"q\" to exit)\n";
7333 G.init = dc_parse_init;
7334 G.exp = dc_parse_expr;
7338 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");