1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
177 BC_STATUS_PATH_IS_DIR,
179 BC_STATUS_LEX_BAD_CHAR,
180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
184 BC_STATUS_LEX_EXTENDED_REG,
187 BC_STATUS_PARSE_BAD_TOKEN,
188 BC_STATUS_PARSE_BAD_EXP,
189 BC_STATUS_PARSE_EMPTY_EXP,
190 BC_STATUS_PARSE_BAD_PRINT,
191 BC_STATUS_PARSE_BAD_FUNC,
192 BC_STATUS_PARSE_BAD_ASSIGN,
193 BC_STATUS_PARSE_NO_AUTO,
194 BC_STATUS_PARSE_DUPLICATE_LOCAL,
195 BC_STATUS_PARSE_NO_BLOCK_END,
197 BC_STATUS_MATH_NEGATIVE,
198 BC_STATUS_MATH_NON_INTEGER,
199 BC_STATUS_MATH_OVERFLOW,
200 BC_STATUS_MATH_DIVIDE_BY_ZERO,
201 BC_STATUS_MATH_BAD_STRING,
203 BC_STATUS_EXEC_FILE_ERR,
204 BC_STATUS_EXEC_MISMATCHED_PARAMS,
205 BC_STATUS_EXEC_UNDEFINED_FUNC,
206 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
207 BC_STATUS_EXEC_NUM_LEN,
208 BC_STATUS_EXEC_NAME_LEN,
209 BC_STATUS_EXEC_STRING_LEN,
210 BC_STATUS_EXEC_ARRAY_LEN,
211 BC_STATUS_EXEC_BAD_IBASE,
212 BC_STATUS_EXEC_BAD_SCALE,
213 BC_STATUS_EXEC_BAD_READ_EXPR,
214 BC_STATUS_EXEC_REC_READ,
215 BC_STATUS_EXEC_BAD_TYPE,
216 BC_STATUS_EXEC_BAD_OBASE,
217 BC_STATUS_EXEC_SIGNAL,
218 BC_STATUS_EXEC_STACK,
220 BC_STATUS_VEC_OUT_OF_BOUNDS,
221 BC_STATUS_VEC_ITEM_EXISTS,
224 BC_STATUS_POSIX_NAME_LEN,
225 BC_STATUS_POSIX_COMMENT,
226 BC_STATUS_POSIX_BAD_KW,
229 BC_STATUS_POSIX_BOOL,
230 BC_STATUS_POSIX_REL_POS,
231 BC_STATUS_POSIX_MULTIREL,
232 BC_STATUS_POSIX_FOR1,
233 BC_STATUS_POSIX_FOR2,
234 BC_STATUS_POSIX_FOR3,
235 BC_STATUS_POSIX_BRACE,
241 BC_STATUS_INVALID_OPTION,
245 #define BC_ERR_IDX_VM (0)
246 #define BC_ERR_IDX_LEX (1)
247 #define BC_ERR_IDX_PARSE (2)
248 #define BC_ERR_IDX_MATH (3)
249 #define BC_ERR_IDX_EXEC (4)
250 #define BC_ERR_IDX_VEC (5)
252 #define BC_ERR_IDX_POSIX (6)
255 #define BC_VEC_INVALID_IDX ((size_t) -1)
256 #define BC_VEC_START_CAP (1 << 5)
258 typedef void (*BcVecFree)(void *);
260 typedef struct BcVec {
268 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
269 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
271 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
273 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
275 typedef signed char BcDig;
277 typedef struct BcNum {
285 #define BC_NUM_MIN_BASE ((unsigned long) 2)
286 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
287 #define BC_NUM_DEF_SIZE (16)
288 #define BC_NUM_PRINT_WIDTH (69)
290 #define BC_NUM_KARATSUBA_LEN (32)
292 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
293 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
294 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
295 #define BC_NUM_AREQ(a, b) \
296 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
297 #define BC_NUM_MREQ(a, b, scale) \
298 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
300 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
301 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
303 static void bc_num_init(BcNum *n, size_t req);
304 static void bc_num_expand(BcNum *n, size_t req);
305 static void bc_num_copy(BcNum *d, BcNum *s);
306 static void bc_num_free(void *num);
308 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
309 static void bc_num_ulong2num(BcNum *n, unsigned long val);
311 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
312 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
313 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
314 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
315 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
316 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
317 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
318 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
321 typedef enum BcInst {
351 BC_INST_ASSIGN_POWER,
352 BC_INST_ASSIGN_MULTIPLY,
353 BC_INST_ASSIGN_DIVIDE,
354 BC_INST_ASSIGN_MODULUS,
356 BC_INST_ASSIGN_MINUS,
402 BC_INST_PRINT_STREAM,
417 BC_INST_INVALID = -1,
422 typedef struct BcId {
427 typedef struct BcFunc {
434 typedef enum BcResultType {
439 BC_RESULT_ARRAY_ELEM,
448 // These are between to calculate ibase, obase, and last from instructions.
456 typedef union BcResultData {
462 typedef struct BcResult {
467 typedef struct BcInstPtr {
473 static void bc_array_expand(BcVec *a, size_t len);
474 static int bc_id_cmp(const void *e1, const void *e2);
476 // BC_LEX_NEG is not used in lexing; it is only for parsing.
477 typedef enum BcLexType {
505 BC_LEX_OP_ASSIGN_POWER,
506 BC_LEX_OP_ASSIGN_MULTIPLY,
507 BC_LEX_OP_ASSIGN_DIVIDE,
508 BC_LEX_OP_ASSIGN_MODULUS,
509 BC_LEX_OP_ASSIGN_PLUS,
510 BC_LEX_OP_ASSIGN_MINUS,
584 typedef BcStatus (*BcLexNext)(struct BcLex *);
586 typedef struct BcLex {
605 #define BC_PARSE_STREND ((char) UCHAR_MAX)
607 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
608 #define bc_parse_updateFunc(p, f) \
609 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
611 #define BC_PARSE_REL (1 << 0)
612 #define BC_PARSE_PRINT (1 << 1)
613 #define BC_PARSE_NOCALL (1 << 2)
614 #define BC_PARSE_NOREAD (1 << 3)
615 #define BC_PARSE_ARRAY (1 << 4)
617 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
618 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
620 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
621 #define BC_PARSE_FUNC_INNER(parse) \
622 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
624 #define BC_PARSE_FLAG_FUNC (1 << 1)
625 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
627 #define BC_PARSE_FLAG_BODY (1 << 2)
628 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
630 #define BC_PARSE_FLAG_LOOP (1 << 3)
631 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
633 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
634 #define BC_PARSE_LOOP_INNER(parse) \
635 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
637 #define BC_PARSE_FLAG_IF (1 << 5)
638 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
640 #define BC_PARSE_FLAG_ELSE (1 << 6)
641 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
643 #define BC_PARSE_FLAG_IF_END (1 << 7)
644 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
646 #define BC_PARSE_CAN_EXEC(parse) \
647 (!(BC_PARSE_TOP_FLAG(parse) & \
648 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
649 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
650 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
652 typedef struct BcOp {
657 typedef struct BcParseNext {
662 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
663 #define BC_PARSE_NEXT(a, ...) \
665 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
672 typedef BcStatus (*BcParseParse)(struct BcParse *);
674 typedef struct BcParse {
697 typedef struct BcLexKeyword {
703 #define BC_LEX_KW_ENTRY(a, b, c) \
705 .name = a, .len = (b), .posix = (c) \
708 static BcStatus bc_lex_token(BcLex *l);
710 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
711 #define BC_PARSE_LEAF(p, rparen) \
712 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
713 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
715 // We can calculate the conversion between tokens and exprs by subtracting the
716 // position of the first operator in the lex enum and adding the position of the
717 // first in the expr enum. Note: This only works for binary operators.
718 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
720 static BcStatus bc_parse_parse(BcParse *p);
721 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
727 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
729 static BcStatus dc_lex_token(BcLex *l);
731 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
735 typedef struct BcProgram {
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(char *name, size_t *idx);
792 static BcStatus bc_program_reset(BcStatus s);
794 #define BC_FLAG_X (1 << 0)
795 #define BC_FLAG_W (1 << 1)
796 #define BC_FLAG_V (1 << 2)
797 #define BC_FLAG_S (1 << 3)
798 #define BC_FLAG_Q (1 << 4)
799 #define BC_FLAG_L (1 << 5)
800 #define BC_FLAG_I (1 << 6)
802 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
803 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
805 #define BC_MAX_OBASE ((unsigned long) 999)
806 #define BC_MAX_DIM ((unsigned long) INT_MAX)
807 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
808 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
809 #define BC_MAX_NAME BC_MAX_STRING
810 #define BC_MAX_NUM BC_MAX_STRING
811 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
812 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
829 #define G (*ptr_to_globals)
830 #define INIT_G() do { \
831 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
833 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
834 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
835 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
836 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
839 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
842 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
846 static void bc_vm_info(void);
848 static const char* const bc_args_env_name = "BC_ENV_ARGS";
850 static const char bc_err_fmt[] = "\n%s error: %s\n";
851 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
852 static const char bc_err_line[] = ":%zu\n\n";
854 static const char *bc_errs[] = {
866 static const uint8_t bc_err_ids[] = {
867 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
868 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
872 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
873 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
874 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
879 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
880 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
881 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
882 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
884 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
886 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
887 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
888 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
890 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
893 static const char *bc_err_msgs[] = {
896 "memory allocation error",
899 "path is a directory:",
902 "string end could not be found",
903 "comment end could not be found",
912 "bad print statement",
913 "bad function definition",
914 "bad assignment: left side must be scale, ibase, "
915 "obase, last, var, or array element",
916 "no auto variable found",
917 "function parameter or auto var has the same name as another",
918 "block end could not be found",
921 "non integer number",
926 "could not open file:",
927 "mismatched parameters",
928 "undefined function",
929 "file is not executable:",
930 "number too long: must be [1, BC_NUM_MAX]",
931 "name too long: must be [1, BC_NAME_MAX]",
932 "string too long: must be [1, BC_STRING_MAX]",
933 "array too long; must be [1, BC_DIM_MAX]",
934 "bad ibase; must be [2, 16]",
935 "bad scale; must be [0, BC_SCALE_MAX]",
936 "bad read() expression",
937 "read() call inside of a read() call",
938 "variable is wrong type",
939 "bad obase; must be [2, BC_BASE_MAX]",
940 "signal caught and not handled",
941 "stack has too few elements",
943 "index is out of bounds",
944 "item already exists",
947 "POSIX only allows one character names; the following is bad:",
948 "POSIX does not allow '#' script comments",
949 "POSIX does not allow the following keyword:",
950 "POSIX does not allow a period ('.') as a shortcut for the last result",
951 "POSIX requires parentheses around return expressions",
952 "POSIX does not allow boolean operators; the following is bad:",
953 "POSIX does not allow comparison operators outside if or loops",
954 "POSIX requires exactly one comparison operator per condition",
955 "POSIX does not allow an empty init expression in a for loop",
956 "POSIX does not allow an empty condition expression in a for loop",
957 "POSIX does not allow an empty update expression in a for loop",
958 "POSIX requires the left brace be on the same line as the function header",
963 static const char bc_func_main[] = "(main)";
964 static const char bc_func_read[] = "(read)";
967 static const BcLexKeyword bc_lex_kws[20] = {
968 BC_LEX_KW_ENTRY("auto", 4, true),
969 BC_LEX_KW_ENTRY("break", 5, true),
970 BC_LEX_KW_ENTRY("continue", 8, false),
971 BC_LEX_KW_ENTRY("define", 6, true),
972 BC_LEX_KW_ENTRY("else", 4, false),
973 BC_LEX_KW_ENTRY("for", 3, true),
974 BC_LEX_KW_ENTRY("halt", 4, false),
975 BC_LEX_KW_ENTRY("ibase", 5, true),
976 BC_LEX_KW_ENTRY("if", 2, true),
977 BC_LEX_KW_ENTRY("last", 4, false),
978 BC_LEX_KW_ENTRY("length", 6, true),
979 BC_LEX_KW_ENTRY("limits", 6, false),
980 BC_LEX_KW_ENTRY("obase", 5, true),
981 BC_LEX_KW_ENTRY("print", 5, false),
982 BC_LEX_KW_ENTRY("quit", 4, true),
983 BC_LEX_KW_ENTRY("read", 4, false),
984 BC_LEX_KW_ENTRY("return", 6, true),
985 BC_LEX_KW_ENTRY("scale", 5, true),
986 BC_LEX_KW_ENTRY("sqrt", 4, true),
987 BC_LEX_KW_ENTRY("while", 5, true),
990 // This is an array that corresponds to token types. An entry is
991 // true if the token is valid in an expression, false otherwise.
992 static const bool bc_parse_exprs[] = {
993 false, false, true, true, true, true, true, true, true, true, true, true,
994 true, true, true, true, true, true, true, true, true, true, true, true,
995 true, true, true, false, false, true, true, false, false, false, false,
996 false, false, false, true, true, false, false, false, false, false, false,
997 false, true, false, true, true, true, true, false, false, true, false, true,
1001 // This is an array of data for operators that correspond to token types.
1002 static const BcOp bc_parse_ops[] = {
1003 { 0, false }, { 0, false },
1006 { 3, true }, { 3, true }, { 3, true },
1007 { 4, true }, { 4, true },
1008 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1010 { 7, true }, { 7, true },
1011 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1012 { 5, false }, { 5, false },
1015 // These identify what tokens can come after expressions in certain cases.
1016 static const BcParseNext bc_parse_next_expr =
1017 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1018 static const BcParseNext bc_parse_next_param =
1019 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1020 static const BcParseNext bc_parse_next_print =
1021 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1022 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1023 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1024 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1025 static const BcParseNext bc_parse_next_read =
1026 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1030 static const BcLexType dc_lex_regs[] = {
1031 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1032 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1033 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1037 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1039 static const BcLexType dc_lex_tokens[] = {
1040 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1041 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1042 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1043 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1044 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1045 BC_LEX_INVALID, BC_LEX_INVALID,
1046 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1047 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1048 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1049 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1050 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1051 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1052 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1053 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1054 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1055 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1056 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1057 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1058 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1059 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1060 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1061 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1062 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1063 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1067 static const BcInst dc_parse_insts[] = {
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1069 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1070 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1071 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1072 BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1075 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1076 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1078 BC_INST_INVALID, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1080 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1081 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1083 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1085 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1086 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1087 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1088 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1094 static const BcNumBinaryOp bc_program_ops[] = {
1095 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1098 static const char bc_program_stdin_name[] = "<stdin>";
1099 static const char bc_program_ready_msg[] = "ready for more input\n";
1102 static const char *bc_lib_name = "gen/lib.bc";
1104 static const char bc_lib[] = {
1105 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1106 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1107 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1108 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
1109 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1110 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1111 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
1112 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1113 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1114 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
1115 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1116 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1117 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1118 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1119 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1120 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1121 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1122 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1123 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1124 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1125 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1126 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1127 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1128 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
1129 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1130 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
1131 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1132 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1133 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1134 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1135 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1136 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
1137 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1138 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1139 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1140 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1141 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
1142 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1143 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1144 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1145 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1146 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1147 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1148 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1149 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1150 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1151 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1152 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
1153 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
1154 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1155 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
1156 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
1157 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
1158 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1159 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1160 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
1161 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
1162 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
1163 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1164 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
1165 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1166 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1167 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1168 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
1169 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1170 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1171 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1172 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1173 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1174 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1175 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1176 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1177 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1178 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1179 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1180 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1181 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1182 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1183 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1184 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1188 static void bc_vec_grow(BcVec *v, size_t n)
1190 size_t cap = v->cap * 2;
1191 while (cap < v->len + n) cap *= 2;
1192 v->v = xrealloc(v->v, v->size * cap);
1196 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1199 v->cap = BC_VEC_START_CAP;
1202 v->v = xmalloc(esize * BC_VEC_START_CAP);
1205 static void bc_vec_expand(BcVec *v, size_t req)
1208 v->v = xrealloc(v->v, v->size * req);
1213 static void bc_vec_npop(BcVec *v, size_t n)
1218 size_t len = v->len - n;
1219 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1223 static void bc_vec_push(BcVec *v, const void *data)
1225 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1226 memmove(v->v + (v->size * v->len), data, v->size);
1230 static void bc_vec_pushByte(BcVec *v, char data)
1232 bc_vec_push(v, &data);
1235 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1238 bc_vec_push(v, data);
1243 if (v->len == v->cap) bc_vec_grow(v, 1);
1245 ptr = v->v + v->size * idx;
1247 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1248 memmove(ptr, data, v->size);
1252 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1254 bc_vec_npop(v, v->len);
1255 bc_vec_expand(v, len + 1);
1256 memcpy(v->v, str, len);
1259 bc_vec_pushByte(v, '\0');
1262 static void bc_vec_concat(BcVec *v, const char *str)
1266 if (v->len == 0) bc_vec_pushByte(v, '\0');
1268 len = v->len + strlen(str);
1270 if (v->cap < len) bc_vec_grow(v, len - v->len);
1276 static void *bc_vec_item(const BcVec *v, size_t idx)
1278 return v->v + v->size * idx;
1281 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1283 return v->v + v->size * (v->len - idx - 1);
1286 static void bc_vec_free(void *vec)
1288 BcVec *v = (BcVec *) vec;
1289 bc_vec_npop(v, v->len);
1293 static size_t bc_map_find(const BcVec *v, const void *ptr)
1295 size_t low = 0, high = v->len;
1297 while (low < high) {
1299 size_t mid = (low + high) / 2;
1300 BcId *id = bc_vec_item(v, mid);
1301 int result = bc_id_cmp(ptr, id);
1305 else if (result < 0)
1314 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1316 BcStatus s = BC_STATUS_SUCCESS;
1318 *i = bc_map_find(v, ptr);
1321 bc_vec_push(v, ptr);
1322 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1323 s = BC_STATUS_VEC_ITEM_EXISTS;
1325 bc_vec_pushAt(v, ptr, *i);
1330 static size_t bc_map_index(const BcVec *v, const void *ptr)
1332 size_t i = bc_map_find(v, ptr);
1333 if (i >= v->len) return BC_VEC_INVALID_IDX;
1334 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1337 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1342 bc_vec_npop(vec, vec->len);
1345 #if ENABLE_FEATURE_BC_SIGNALS
1346 if (bb_got_signal) { /* ^C was pressed */
1348 bb_got_signal = 0; /* resets G_interrupt to zero */
1350 ? "\ninterrupt (type \"quit\" to exit)\n"
1351 : "\ninterrupt (type \"q\" to exit)\n"
1355 if (G.ttyin && !G_posix)
1356 fputs(prompt, stderr);
1359 #if ENABLE_FEATURE_BC_SIGNALS
1364 if (ferror(stdout) || ferror(stderr))
1365 bb_perror_msg_and_die("output error");
1369 #if ENABLE_FEATURE_BC_SIGNALS
1370 if (bb_got_signal) /* ^C was pressed */
1375 #if ENABLE_FEATURE_BC_SIGNALS
1376 if (errno == EINTR) {
1382 bb_perror_msg_and_die("input error");
1383 return BC_STATUS_INPUT_EOF;
1386 c = (signed char) i;
1387 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1388 bc_vec_push(vec, &c);
1389 } while (c != '\n');
1391 bc_vec_pushByte(vec, '\0');
1393 return BC_STATUS_SUCCESS;
1396 static char* bc_read_file(const char *path)
1399 size_t size = ((size_t) -1);
1402 buf = xmalloc_open_read_close(path, &size);
1404 for (i = 0; i < size; ++i) {
1405 if (BC_READ_BIN_CHAR(buf[i])) {
1415 static void bc_args(int argc, char **argv)
1420 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1421 G.flags = getopt32long(argv, "xwvsqli",
1422 "extended-register\0" No_argument "x"
1423 "warn\0" No_argument "w"
1424 "version\0" No_argument "v"
1425 "standard\0" No_argument "s"
1426 "quiet\0" No_argument "q"
1427 "mathlib\0" No_argument "l"
1428 "interactive\0" No_argument "i"
1431 G.flags = getopt32(argv, "xwvsqli");
1434 if (G.flags & BC_FLAG_V) bc_vm_info();
1435 // should not be necessary, getopt32() handles this??
1436 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1438 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1441 static void bc_num_setToZero(BcNum *n, size_t scale)
1448 static void bc_num_zero(BcNum *n)
1450 bc_num_setToZero(n, 0);
1453 static void bc_num_one(BcNum *n)
1455 bc_num_setToZero(n, 0);
1460 static void bc_num_ten(BcNum *n)
1462 bc_num_setToZero(n, 0);
1468 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1472 for (i = 0; i < len; ++i) {
1473 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1480 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1484 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1485 return BC_NUM_NEG(i + 1, c < 0);
1488 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1490 size_t i, min, a_int, b_int, diff;
1491 BcDig *max_num, *min_num;
1492 bool a_max, neg = false;
1495 if (a == b) return 0;
1496 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1497 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1507 a_int = BC_NUM_INT(a);
1508 b_int = BC_NUM_INT(b);
1510 a_max = (a->rdx > b->rdx);
1512 if (a_int != 0) return (ssize_t) a_int;
1516 diff = a->rdx - b->rdx;
1517 max_num = a->num + diff;
1522 diff = b->rdx - a->rdx;
1523 max_num = b->num + diff;
1527 cmp = bc_num_compare(max_num, min_num, b_int + min);
1528 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1530 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1531 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1537 static void bc_num_truncate(BcNum *n, size_t places)
1539 if (places == 0) return;
1545 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1549 static void bc_num_extend(BcNum *n, size_t places)
1551 size_t len = n->len + places;
1555 if (n->cap < len) bc_num_expand(n, len);
1557 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1558 memset(n->num, 0, sizeof(BcDig) * places);
1565 static void bc_num_clean(BcNum *n)
1567 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1570 else if (n->len < n->rdx)
1574 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1577 bc_num_extend(n, scale - n->rdx);
1579 bc_num_truncate(n, n->rdx - scale);
1582 if (n->len != 0) n->neg = !neg1 != !neg2;
1585 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1590 b->len = n->len - idx;
1592 a->rdx = b->rdx = 0;
1594 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1595 memcpy(a->num, n->num, idx * sizeof(BcDig));
1606 static BcStatus bc_num_shift(BcNum *n, size_t places)
1608 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1609 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1611 if (n->rdx >= places)
1614 bc_num_extend(n, places - n->rdx);
1620 return BC_STATUS_SUCCESS;
1623 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1632 return bc_num_div(&one, a, b, scale);
1635 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1637 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1638 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1641 // Because this function doesn't need to use scale (per the bc spec),
1642 // I am hijacking it to say whether it's doing an add or a subtract.
1646 if (sub && c->len) c->neg = !c->neg;
1647 return BC_STATUS_SUCCESS;
1649 else if (b->len == 0) {
1651 return BC_STATUS_SUCCESS;
1655 c->rdx = BC_MAX(a->rdx, b->rdx);
1656 min_rdx = BC_MIN(a->rdx, b->rdx);
1659 if (a->rdx > b->rdx) {
1660 diff = a->rdx - b->rdx;
1662 ptr_a = a->num + diff;
1666 diff = b->rdx - a->rdx;
1669 ptr_b = b->num + diff;
1672 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1675 a_int = BC_NUM_INT(a);
1676 b_int = BC_NUM_INT(b);
1678 if (a_int > b_int) {
1689 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1690 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1692 ptr_c[i] = (BcDig)(in % 10);
1695 for (; i < max + min_rdx; ++i, ++c->len) {
1696 in = ((int) ptr[i]) + carry;
1698 ptr_c[i] = (BcDig)(in % 10);
1701 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1703 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1706 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1709 BcNum *minuend, *subtrahend;
1711 bool aneg, bneg, neg;
1713 // Because this function doesn't need to use scale (per the bc spec),
1714 // I am hijacking it to say whether it's doing an add or a subtract.
1718 if (sub && c->len) c->neg = !c->neg;
1719 return BC_STATUS_SUCCESS;
1721 else if (b->len == 0) {
1723 return BC_STATUS_SUCCESS;
1728 a->neg = b->neg = false;
1730 cmp = bc_num_cmp(a, b);
1736 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1737 return BC_STATUS_SUCCESS;
1746 if (sub) neg = !neg;
1751 bc_num_copy(c, minuend);
1754 if (c->rdx < subtrahend->rdx) {
1755 bc_num_extend(c, subtrahend->rdx - c->rdx);
1759 start = c->rdx - subtrahend->rdx;
1761 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1765 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1768 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1773 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1774 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1775 bool aone = BC_NUM_ONE(a);
1777 if (a->len == 0 || b->len == 0) {
1779 return BC_STATUS_SUCCESS;
1781 else if (aone || BC_NUM_ONE(b)) {
1782 bc_num_copy(c, aone ? b : a);
1783 return BC_STATUS_SUCCESS;
1786 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1787 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1789 bc_num_expand(c, a->len + b->len + 1);
1791 memset(c->num, 0, sizeof(BcDig) * c->cap);
1792 c->len = carry = len = 0;
1794 for (i = 0; i < b->len; ++i) {
1796 for (j = 0; j < a->len; ++j) {
1797 int in = (int) c->num[i + j];
1798 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1800 c->num[i + j] = (BcDig)(in % 10);
1803 c->num[i + j] += (BcDig) carry;
1804 len = BC_MAX(len, i + j + !!carry);
1810 return BC_STATUS_SUCCESS;
1813 bc_num_init(&l1, max);
1814 bc_num_init(&h1, max);
1815 bc_num_init(&l2, max);
1816 bc_num_init(&h2, max);
1817 bc_num_init(&m1, max);
1818 bc_num_init(&m2, max);
1819 bc_num_init(&z0, max);
1820 bc_num_init(&z1, max);
1821 bc_num_init(&z2, max);
1822 bc_num_init(&temp, max + max);
1824 bc_num_split(a, max2, &l1, &h1);
1825 bc_num_split(b, max2, &l2, &h2);
1827 s = bc_num_add(&h1, &l1, &m1, 0);
1829 s = bc_num_add(&h2, &l2, &m2, 0);
1832 s = bc_num_k(&h1, &h2, &z0);
1834 s = bc_num_k(&m1, &m2, &z1);
1836 s = bc_num_k(&l1, &l2, &z2);
1839 s = bc_num_sub(&z1, &z0, &temp, 0);
1841 s = bc_num_sub(&temp, &z2, &z1, 0);
1844 s = bc_num_shift(&z0, max2 * 2);
1846 s = bc_num_shift(&z1, max2);
1848 s = bc_num_add(&z0, &z1, &temp, 0);
1850 s = bc_num_add(&temp, &z2, c, 0);
1866 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1870 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1872 scale = BC_MAX(scale, a->rdx);
1873 scale = BC_MAX(scale, b->rdx);
1874 scale = BC_MIN(a->rdx + b->rdx, scale);
1875 maxrdx = BC_MAX(maxrdx, scale);
1877 bc_num_init(&cpa, a->len);
1878 bc_num_init(&cpb, b->len);
1880 bc_num_copy(&cpa, a);
1881 bc_num_copy(&cpb, b);
1882 cpa.neg = cpb.neg = false;
1884 s = bc_num_shift(&cpa, maxrdx);
1886 s = bc_num_shift(&cpb, maxrdx);
1888 s = bc_num_k(&cpa, &cpb, c);
1892 bc_num_expand(c, c->len + maxrdx);
1894 if (c->len < maxrdx) {
1895 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1900 bc_num_retireMul(c, scale, a->neg, b->neg);
1908 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1910 BcStatus s = BC_STATUS_SUCCESS;
1917 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1918 else if (a->len == 0) {
1919 bc_num_setToZero(c, scale);
1920 return BC_STATUS_SUCCESS;
1922 else if (BC_NUM_ONE(b)) {
1924 bc_num_retireMul(c, scale, a->neg, b->neg);
1925 return BC_STATUS_SUCCESS;
1928 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1929 bc_num_copy(&cp, a);
1933 bc_num_expand(&cp, len + 2);
1934 bc_num_extend(&cp, len - cp.len);
1937 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1939 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1941 if (b->rdx == b->len) {
1942 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1946 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1948 // We want an extra zero in front to make things simpler.
1949 cp.num[cp.len++] = 0;
1952 bc_num_expand(c, cp.len);
1955 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1960 for (i = end - 1; !s && i < end; --i) {
1962 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1963 bc_num_subArrays(n, p, len);
1967 bc_num_retireMul(c, scale, a->neg, b->neg);
1970 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1973 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1974 BcNum *restrict d, size_t scale, size_t ts)
1980 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1983 bc_num_setToZero(d, ts);
1984 return BC_STATUS_SUCCESS;
1987 bc_num_init(&temp, d->cap);
1988 bc_num_d(a, b, c, scale);
1990 if (scale != 0) scale = ts;
1992 s = bc_num_m(c, b, &temp, scale);
1994 s = bc_num_sub(a, &temp, d, scale);
1997 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2000 bc_num_retireMul(d, ts, a->neg, b->neg);
2008 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2012 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2014 bc_num_init(&c1, len);
2015 s = bc_num_r(a, b, &c1, c, scale, ts);
2021 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2023 BcStatus s = BC_STATUS_SUCCESS;
2026 size_t i, powrdx, resrdx;
2029 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2033 return BC_STATUS_SUCCESS;
2035 else if (a->len == 0) {
2036 bc_num_setToZero(c, scale);
2037 return BC_STATUS_SUCCESS;
2039 else if (BC_NUM_ONE(b)) {
2043 s = bc_num_inv(a, c, scale);
2050 s = bc_num_ulong(b, &pow);
2053 bc_num_init(©, a->len);
2054 bc_num_copy(©, a);
2056 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2060 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2062 s = bc_num_mul(©, ©, ©, powrdx);
2066 bc_num_copy(c, ©);
2068 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2071 s = bc_num_mul(©, ©, ©, powrdx);
2076 s = bc_num_mul(c, ©, c, resrdx);
2082 s = bc_num_inv(c, c, scale);
2086 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2088 // We can't use bc_num_clean() here.
2089 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2090 if (zero) bc_num_setToZero(c, scale);
2097 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2098 BcNumBinaryOp op, size_t req)
2101 BcNum num2, *ptr_a, *ptr_b;
2106 memcpy(ptr_a, c, sizeof(BcNum));
2115 memcpy(ptr_b, c, sizeof(BcNum));
2123 bc_num_init(c, req);
2125 bc_num_expand(c, req);
2127 s = op(ptr_a, ptr_b, c, scale);
2129 if (init) bc_num_free(&num2);
2134 static bool bc_num_strValid(const char *val, size_t base)
2137 bool small, radix = false;
2138 size_t i, len = strlen(val);
2140 if (!len) return true;
2143 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2145 for (i = 0; i < len; ++i) {
2151 if (radix) return false;
2157 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2164 static void bc_num_parseDecimal(BcNum *n, const char *val)
2170 for (i = 0; val[i] == '0'; ++i);
2177 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2178 bc_num_expand(n, len);
2181 ptr = strchr(val, '.');
2183 // Explicitly test for NULL here to produce either a 0 or 1.
2184 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2187 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2188 n->num[n->len] = val[i] - '0';
2192 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2195 BcNum temp, mult, result;
2199 size_t i, digits, len = strlen(val);
2203 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2206 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2207 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2209 for (i = 0; i < len; ++i) {
2212 if (c == '.') break;
2214 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2216 s = bc_num_mul(n, base, &mult, 0);
2217 if (s) goto int_err;
2218 bc_num_ulong2num(&temp, v);
2219 s = bc_num_add(&mult, &temp, n, 0);
2220 if (s) goto int_err;
2225 if (c == 0) goto int_err;
2228 bc_num_init(&result, base->len);
2229 bc_num_zero(&result);
2232 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2237 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2239 s = bc_num_mul(&result, base, &result, 0);
2241 bc_num_ulong2num(&temp, v);
2242 s = bc_num_add(&result, &temp, &result, 0);
2244 s = bc_num_mul(&mult, base, &mult, 0);
2248 s = bc_num_div(&result, &mult, &result, digits);
2250 s = bc_num_add(n, &result, n, digits);
2254 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2260 bc_num_free(&result);
2266 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2268 if (*nchars == line_len - 1) {
2276 static void bc_num_printChar(size_t num, size_t width, bool radix,
2277 size_t *nchars, size_t line_len)
2279 (void) radix, (void) line_len;
2280 bb_putchar((char) num);
2281 *nchars = *nchars + width;
2285 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2286 size_t *nchars, size_t line_len)
2290 bc_num_printNewline(nchars, line_len);
2291 bb_putchar(radix ? '.' : ' ');
2294 bc_num_printNewline(nchars, line_len);
2295 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2298 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2300 bc_num_printNewline(nchars, line_len);
2303 bb_putchar(((char) dig) + '0');
2307 static void bc_num_printHex(size_t num, size_t width, bool radix,
2308 size_t *nchars, size_t line_len)
2311 bc_num_printNewline(nchars, line_len);
2316 bc_num_printNewline(nchars, line_len);
2317 bb_putchar(bb_hexdigits_upcase[num]);
2318 *nchars = *nchars + width;
2321 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2323 size_t i, rdx = n->rdx - 1;
2325 if (n->neg) bb_putchar('-');
2326 (*nchars) += n->neg;
2328 for (i = n->len - 1; i < n->len; --i)
2329 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2332 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2333 size_t *nchars, size_t len, BcNumDigitOp print)
2337 BcNum intp, fracp, digit, frac_len;
2338 unsigned long dig, *ptr;
2343 print(0, width, false, nchars, len);
2344 return BC_STATUS_SUCCESS;
2347 bc_vec_init(&stack, sizeof(long), NULL);
2348 bc_num_init(&intp, n->len);
2349 bc_num_init(&fracp, n->rdx);
2350 bc_num_init(&digit, width);
2351 bc_num_init(&frac_len, BC_NUM_INT(n));
2352 bc_num_copy(&intp, n);
2353 bc_num_one(&frac_len);
2355 bc_num_truncate(&intp, intp.rdx);
2356 s = bc_num_sub(n, &intp, &fracp, 0);
2359 while (intp.len != 0) {
2360 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2362 s = bc_num_ulong(&digit, &dig);
2364 bc_vec_push(&stack, &dig);
2367 for (i = 0; i < stack.len; ++i) {
2368 ptr = bc_vec_item_rev(&stack, i);
2369 print(*ptr, width, false, nchars, len);
2372 if (!n->rdx) goto err;
2374 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2375 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2377 s = bc_num_ulong(&fracp, &dig);
2379 bc_num_ulong2num(&intp, dig);
2380 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2382 print(dig, width, radix, nchars, len);
2383 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2388 bc_num_free(&frac_len);
2389 bc_num_free(&digit);
2390 bc_num_free(&fracp);
2392 bc_vec_free(&stack);
2396 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2397 size_t *nchars, size_t line_len)
2404 if (neg) bb_putchar('-');
2409 if (base_t <= BC_NUM_MAX_IBASE) {
2411 print = bc_num_printHex;
2414 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2415 print = bc_num_printDigits;
2418 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2425 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2427 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2431 static void bc_num_init(BcNum *n, size_t req)
2433 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2434 memset(n, 0, sizeof(BcNum));
2435 n->num = xmalloc(req);
2439 static void bc_num_expand(BcNum *n, size_t req)
2441 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2443 n->num = xrealloc(n->num, req);
2448 static void bc_num_free(void *num)
2450 free(((BcNum *) num)->num);
2453 static void bc_num_copy(BcNum *d, BcNum *s)
2456 bc_num_expand(d, s->cap);
2460 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2464 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2467 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2470 bc_num_parseDecimal(n, val);
2472 bc_num_parseBase(n, val, base);
2474 return BC_STATUS_SUCCESS;
2477 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2478 size_t *nchars, size_t line_len)
2480 BcStatus s = BC_STATUS_SUCCESS;
2482 bc_num_printNewline(nchars, line_len);
2488 else if (base_t == 10)
2489 bc_num_printDecimal(n, nchars, line_len);
2491 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2501 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2506 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2508 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2510 unsigned long prev = *result, powprev = pow;
2512 *result += ((unsigned long) n->num[i]) * pow;
2515 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2518 return BC_STATUS_SUCCESS;
2521 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2529 if (val == 0) return;
2531 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2532 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2535 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2537 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2539 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2542 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2544 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2546 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2549 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2551 size_t req = BC_NUM_MREQ(a, b, scale);
2552 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2555 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2557 size_t req = BC_NUM_MREQ(a, b, scale);
2558 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2561 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2563 size_t req = BC_NUM_MREQ(a, b, scale);
2564 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2567 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2569 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2572 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2575 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2576 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2577 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2579 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2580 bc_num_expand(b, req);
2583 bc_num_setToZero(b, scale);
2584 return BC_STATUS_SUCCESS;
2587 return BC_STATUS_MATH_NEGATIVE;
2588 else if (BC_NUM_ONE(a)) {
2590 bc_num_extend(b, scale);
2591 return BC_STATUS_SUCCESS;
2594 scale = BC_MAX(scale, a->rdx) + 1;
2595 len = a->len + scale;
2597 bc_num_init(&num1, len);
2598 bc_num_init(&num2, len);
2599 bc_num_init(&half, BC_NUM_DEF_SIZE);
2605 bc_num_init(&f, len);
2606 bc_num_init(&fprime, len);
2612 pow = BC_NUM_INT(a);
2621 pow -= 2 - (pow & 1);
2623 bc_num_extend(x0, pow);
2625 // Make sure to move the radix back.
2629 x0->rdx = digs = digs1 = 0;
2631 len = BC_NUM_INT(x0) + resrdx - 1;
2633 while (cmp != 0 || digs < len) {
2635 s = bc_num_div(a, x0, &f, resrdx);
2637 s = bc_num_add(x0, &f, &fprime, resrdx);
2639 s = bc_num_mul(&fprime, &half, x1, resrdx);
2642 cmp = bc_num_cmp(x1, x0);
2643 digs = x1->len - (unsigned long long) llabs(cmp);
2645 if (cmp == cmp2 && digs == digs1)
2650 resrdx += times > 4;
2663 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2666 bc_num_free(&fprime);
2674 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2680 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2683 memcpy(&num2, c, sizeof(BcNum));
2685 bc_num_init(c, len);
2690 bc_num_expand(c, len);
2693 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2695 if (init) bc_num_free(&num2);
2701 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2704 BcNum base, exp, two, temp;
2706 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2707 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2708 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2710 bc_num_expand(d, c->len);
2711 bc_num_init(&base, c->len);
2712 bc_num_init(&exp, b->len);
2713 bc_num_init(&two, BC_NUM_DEF_SIZE);
2714 bc_num_init(&temp, b->len);
2720 s = bc_num_rem(a, c, &base, 0);
2722 bc_num_copy(&exp, b);
2724 while (exp.len != 0) {
2726 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2729 if (BC_NUM_ONE(&temp)) {
2730 s = bc_num_mul(d, &base, &temp, 0);
2732 s = bc_num_rem(&temp, c, d, 0);
2736 s = bc_num_mul(&base, &base, &temp, 0);
2738 s = bc_num_rem(&temp, c, &base, 0);
2751 static int bc_id_cmp(const void *e1, const void *e2)
2753 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2756 static void bc_id_free(void *id)
2758 free(((BcId *) id)->name);
2761 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2766 for (i = 0; i < f->autos.len; ++i) {
2767 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2768 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2774 bc_vec_push(&f->autos, &a);
2776 return BC_STATUS_SUCCESS;
2779 static void bc_func_init(BcFunc *f)
2781 bc_vec_init(&f->code, sizeof(char), NULL);
2782 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2783 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2787 static void bc_func_free(void *func)
2789 BcFunc *f = (BcFunc *) func;
2790 bc_vec_free(&f->code);
2791 bc_vec_free(&f->autos);
2792 bc_vec_free(&f->labels);
2795 static void bc_array_init(BcVec *a, bool nums)
2798 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2800 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2801 bc_array_expand(a, 1);
2804 static void bc_array_copy(BcVec *d, const BcVec *s)
2808 bc_vec_npop(d, d->len);
2809 bc_vec_expand(d, s->cap);
2812 for (i = 0; i < s->len; ++i) {
2813 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2814 bc_num_init(dnum, snum->len);
2815 bc_num_copy(dnum, snum);
2819 static void bc_array_expand(BcVec *a, size_t len)
2823 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2824 while (len > a->len) {
2825 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2826 bc_vec_push(a, &data.n);
2830 while (len > a->len) {
2831 bc_array_init(&data.v, true);
2832 bc_vec_push(a, &data.v);
2837 static void bc_string_free(void *string)
2839 free(*((char **) string));
2843 static void bc_result_copy(BcResult *d, BcResult *src)
2849 case BC_RESULT_TEMP:
2850 case BC_RESULT_IBASE:
2851 case BC_RESULT_SCALE:
2852 case BC_RESULT_OBASE:
2854 bc_num_init(&d->d.n, src->d.n.len);
2855 bc_num_copy(&d->d.n, &src->d.n);
2860 case BC_RESULT_ARRAY:
2861 case BC_RESULT_ARRAY_ELEM:
2863 d->d.id.name = xstrdup(src->d.id.name);
2867 case BC_RESULT_CONSTANT:
2868 case BC_RESULT_LAST:
2872 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2879 static void bc_result_free(void *result)
2881 BcResult *r = (BcResult *) result;
2885 case BC_RESULT_TEMP:
2886 case BC_RESULT_IBASE:
2887 case BC_RESULT_SCALE:
2888 case BC_RESULT_OBASE:
2890 bc_num_free(&r->d.n);
2895 case BC_RESULT_ARRAY:
2896 case BC_RESULT_ARRAY_ELEM:
2910 static void bc_lex_lineComment(BcLex *l)
2912 l->t.t = BC_LEX_WHITESPACE;
2913 while (l->i < l->len && l->buf[l->i++] != '\n');
2917 static void bc_lex_whitespace(BcLex *l)
2920 l->t.t = BC_LEX_WHITESPACE;
2921 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2924 static BcStatus bc_lex_number(BcLex *l, char start)
2926 const char *buf = l->buf + l->i;
2927 size_t len, hits = 0, bslashes = 0, i = 0, j;
2929 bool last_pt, pt = start == '.';
2932 l->t.t = BC_LEX_NUMBER;
2934 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2935 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2949 len = i + 1 * !last_pt - bslashes * 2;
2950 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2952 bc_vec_npop(&l->t.v, l->t.v.len);
2953 bc_vec_expand(&l->t.v, len + 1);
2954 bc_vec_push(&l->t.v, &start);
2956 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2960 // If we have hit a backslash, skip it. We don't have
2961 // to check for a newline because it's guaranteed.
2962 if (hits < bslashes && c == '\\') {
2968 bc_vec_push(&l->t.v, &c);
2971 bc_vec_pushByte(&l->t.v, '\0');
2974 return BC_STATUS_SUCCESS;
2977 static BcStatus bc_lex_name(BcLex *l)
2980 const char *buf = l->buf + l->i - 1;
2983 l->t.t = BC_LEX_NAME;
2985 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2987 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2988 bc_vec_string(&l->t.v, i, buf);
2990 // Increment the index. We minus 1 because it has already been incremented.
2993 return BC_STATUS_SUCCESS;
2996 static void bc_lex_init(BcLex *l, BcLexNext next)
2999 bc_vec_init(&l->t.v, sizeof(char), NULL);
3002 static void bc_lex_free(BcLex *l)
3004 bc_vec_free(&l->t.v);
3007 static void bc_lex_file(BcLex *l, const char *file)
3014 static BcStatus bc_lex_next(BcLex *l)
3019 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3021 l->line += l->newline;
3022 l->t.t = BC_LEX_EOF;
3024 l->newline = (l->i == l->len);
3025 if (l->newline) return BC_STATUS_SUCCESS;
3027 // Loop until failure or we don't have whitespace. This
3028 // is so the parser doesn't get inundated with whitespace.
3031 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3036 static BcStatus bc_lex_text(BcLex *l, const char *text)
3040 l->len = strlen(text);
3041 l->t.t = l->t.last = BC_LEX_INVALID;
3042 return bc_lex_next(l);
3046 static BcStatus bc_lex_identifier(BcLex *l)
3050 const char *buf = l->buf + l->i - 1;
3052 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3054 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3056 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3058 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3060 if (!bc_lex_kws[i].posix) {
3061 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3062 bc_lex_kws[i].name);
3066 // We minus 1 because the index has already been incremented.
3068 return BC_STATUS_SUCCESS;
3075 if (l->t.v.len - 1 > 1)
3076 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3081 static BcStatus bc_lex_string(BcLex *l)
3083 size_t len, nls = 0, i = l->i;
3086 l->t.t = BC_LEX_STR;
3088 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3092 return BC_STATUS_LEX_NO_STRING_END;
3096 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3097 bc_vec_string(&l->t.v, len, l->buf + l->i);
3102 return BC_STATUS_SUCCESS;
3105 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3107 if (l->buf[l->i] == '=') {
3115 static BcStatus bc_lex_comment(BcLex *l)
3118 const char *buf = l->buf;
3122 l->t.t = BC_LEX_WHITESPACE;
3124 for (i = ++l->i; !end; i += !end) {
3126 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3128 if (c == 0 || buf[i + 1] == '\0') {
3130 return BC_STATUS_LEX_NO_COMMENT_END;
3133 end = buf[i + 1] == '/';
3139 return BC_STATUS_SUCCESS;
3142 static BcStatus bc_lex_token(BcLex *l)
3144 BcStatus s = BC_STATUS_SUCCESS;
3145 char c = l->buf[l->i++], c2;
3147 // This is the workhorse of the lexer.
3154 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3164 bc_lex_whitespace(l);
3170 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3172 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3173 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3182 s = bc_lex_string(l);
3188 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3191 bc_lex_lineComment(l);
3198 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3207 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3211 l->t.t = BC_LEX_OP_BOOL_AND;
3214 l->t.t = BC_LEX_INVALID;
3215 s = BC_STATUS_LEX_BAD_CHAR;
3224 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3230 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3239 l->t.t = BC_LEX_OP_INC;
3242 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3248 l->t.t = BC_LEX_COMMA;
3257 l->t.t = BC_LEX_OP_DEC;
3260 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3266 if (isdigit(l->buf[l->i]))
3267 s = bc_lex_number(l, c);
3269 l->t.t = BC_LEX_KEY_LAST;
3270 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3279 s = bc_lex_comment(l);
3281 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3302 s = bc_lex_number(l, c);
3308 l->t.t = BC_LEX_SCOLON;
3314 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3320 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3326 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3333 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3339 if (l->buf[l->i] == '\n') {
3340 l->t.t = BC_LEX_WHITESPACE;
3344 s = BC_STATUS_LEX_BAD_CHAR;
3350 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3381 s = bc_lex_identifier(l);
3388 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3398 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3402 l->t.t = BC_LEX_OP_BOOL_OR;
3405 l->t.t = BC_LEX_INVALID;
3406 s = BC_STATUS_LEX_BAD_CHAR;
3414 l->t.t = BC_LEX_INVALID;
3415 s = BC_STATUS_LEX_BAD_CHAR;
3425 static BcStatus dc_lex_register(BcLex *l)
3427 BcStatus s = BC_STATUS_SUCCESS;
3429 if (isspace(l->buf[l->i - 1])) {
3430 bc_lex_whitespace(l);
3433 s = BC_STATUS_LEX_EXTENDED_REG;
3438 bc_vec_npop(&l->t.v, l->t.v.len);
3439 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3440 bc_vec_pushByte(&l->t.v, '\0');
3441 l->t.t = BC_LEX_NAME;
3447 static BcStatus dc_lex_string(BcLex *l)
3449 size_t depth = 1, nls = 0, i = l->i;
3452 l->t.t = BC_LEX_STR;
3453 bc_vec_npop(&l->t.v, l->t.v.len);
3455 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3457 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3458 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3461 if (depth) bc_vec_push(&l->t.v, &c);
3466 return BC_STATUS_LEX_NO_STRING_END;
3469 bc_vec_pushByte(&l->t.v, '\0');
3470 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3475 return BC_STATUS_SUCCESS;
3478 static BcStatus dc_lex_token(BcLex *l)
3480 BcStatus s = BC_STATUS_SUCCESS;
3481 char c = l->buf[l->i++], c2;
3484 for (i = 0; i < dc_lex_regs_len; ++i) {
3485 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3488 if (c >= '%' && c <= '~' &&
3489 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3494 // This is the workhorse of the lexer.
3499 l->t.t = BC_LEX_EOF;
3510 l->newline = (c == '\n');
3511 bc_lex_whitespace(l);
3520 l->t.t = BC_LEX_OP_REL_NE;
3522 l->t.t = BC_LEX_OP_REL_LE;
3524 l->t.t = BC_LEX_OP_REL_GE;
3526 return BC_STATUS_LEX_BAD_CHAR;
3534 bc_lex_lineComment(l);
3540 if (isdigit(l->buf[l->i]))
3541 s = bc_lex_number(l, c);
3543 s = BC_STATUS_LEX_BAD_CHAR;
3564 s = bc_lex_number(l, c);
3570 s = dc_lex_string(l);
3576 l->t.t = BC_LEX_INVALID;
3577 s = BC_STATUS_LEX_BAD_CHAR;
3586 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3588 bc_program_addFunc(name, idx);
3589 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3592 static void bc_parse_pushName(BcParse *p, char *name)
3594 size_t i = 0, len = strlen(name);
3596 for (; i < len; ++i) bc_parse_push(p, name[i]);
3597 bc_parse_push(p, BC_PARSE_STREND);
3602 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3604 unsigned char amt, i, nums[sizeof(size_t)];
3606 for (amt = 0; idx; ++amt) {
3607 nums[amt] = (char) idx;
3608 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3611 bc_parse_push(p, amt);
3612 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3615 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3617 char *num = xstrdup(p->l.t.v.v);
3618 size_t idx = G.prog.consts.len;
3620 bc_vec_push(&G.prog.consts, &num);
3622 bc_parse_push(p, BC_INST_NUM);
3623 bc_parse_pushIndex(p, idx);
3626 (*prev) = BC_INST_NUM;
3629 static BcStatus bc_parse_text(BcParse *p, const char *text)
3633 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3635 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3636 p->l.t.t = BC_LEX_INVALID;
3639 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3642 return bc_lex_text(&p->l, text);
3645 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3647 if (p->fidx != BC_PROG_MAIN) {
3649 p->func->nparams = 0;
3650 bc_vec_npop(&p->func->code, p->func->code.len);
3651 bc_vec_npop(&p->func->autos, p->func->autos.len);
3652 bc_vec_npop(&p->func->labels, p->func->labels.len);
3654 bc_parse_updateFunc(p, BC_PROG_MAIN);
3658 p->l.t.t = BC_LEX_EOF;
3659 p->auto_part = (p->nbraces = 0);
3661 bc_vec_npop(&p->flags, p->flags.len - 1);
3662 bc_vec_npop(&p->exits, p->exits.len);
3663 bc_vec_npop(&p->conds, p->conds.len);
3664 bc_vec_npop(&p->ops, p->ops.len);
3666 return bc_program_reset(s);
3669 static void bc_parse_free(BcParse *p)
3671 bc_vec_free(&p->flags);
3672 bc_vec_free(&p->exits);
3673 bc_vec_free(&p->conds);
3674 bc_vec_free(&p->ops);
3678 static void bc_parse_create(BcParse *p, size_t func,
3679 BcParseParse parse, BcLexNext next)
3681 memset(p, 0, sizeof(BcParse));
3683 bc_lex_init(&p->l, next);
3684 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3685 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3686 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3687 bc_vec_pushByte(&p->flags, 0);
3688 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3691 p->auto_part = (p->nbraces = 0);
3692 bc_parse_updateFunc(p, func);
3696 static BcStatus bc_parse_else(BcParse *p);
3697 static BcStatus bc_parse_stmt(BcParse *p);
3699 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3700 size_t *nexprs, bool next)
3702 BcStatus s = BC_STATUS_SUCCESS;
3704 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3705 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3707 while (p->ops.len > start) {
3709 t = BC_PARSE_TOP_OP(p);
3710 if (t == BC_LEX_LPAREN) break;
3712 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3713 if (l >= r && (l != r || !left)) break;
3715 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3716 bc_vec_pop(&p->ops);
3717 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3720 bc_vec_push(&p->ops, &type);
3721 if (next) s = bc_lex_next(&p->l);
3726 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3730 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3731 top = BC_PARSE_TOP_OP(p);
3733 while (top != BC_LEX_LPAREN) {
3735 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3737 bc_vec_pop(&p->ops);
3738 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3740 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3741 top = BC_PARSE_TOP_OP(p);
3744 bc_vec_pop(&p->ops);
3746 return bc_lex_next(&p->l);
3749 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3755 s = bc_lex_next(&p->l);
3758 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3760 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3761 s = bc_parse_expr(p, flags, bc_parse_next_param);
3764 comma = p->l.t.t == BC_LEX_COMMA;
3766 s = bc_lex_next(&p->l);
3771 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3772 bc_parse_push(p, BC_INST_CALL);
3773 bc_parse_pushIndex(p, nparams);
3775 return BC_STATUS_SUCCESS;
3778 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3781 BcId entry, *entry_ptr;
3786 s = bc_parse_params(p, flags);
3789 if (p->l.t.t != BC_LEX_RPAREN) {
3790 s = BC_STATUS_PARSE_BAD_TOKEN;
3794 idx = bc_map_index(&G.prog.fn_map, &entry);
3796 if (idx == BC_VEC_INVALID_IDX) {
3797 name = xstrdup(entry.name);
3798 bc_parse_addFunc(p, name, &idx);
3799 idx = bc_map_index(&G.prog.fn_map, &entry);
3805 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3806 bc_parse_pushIndex(p, entry_ptr->idx);
3808 return bc_lex_next(&p->l);
3815 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3820 name = xstrdup(p->l.t.v.v);
3821 s = bc_lex_next(&p->l);
3824 if (p->l.t.t == BC_LEX_LBRACKET) {
3826 s = bc_lex_next(&p->l);
3829 if (p->l.t.t == BC_LEX_RBRACKET) {
3831 if (!(flags & BC_PARSE_ARRAY)) {
3832 s = BC_STATUS_PARSE_BAD_EXP;
3836 *type = BC_INST_ARRAY;
3840 *type = BC_INST_ARRAY_ELEM;
3842 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3843 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3847 s = bc_lex_next(&p->l);
3849 bc_parse_push(p, *type);
3850 bc_parse_pushName(p, name);
3852 else if (p->l.t.t == BC_LEX_LPAREN) {
3854 if (flags & BC_PARSE_NOCALL) {
3855 s = BC_STATUS_PARSE_BAD_TOKEN;
3859 *type = BC_INST_CALL;
3860 s = bc_parse_call(p, name, flags);
3863 *type = BC_INST_VAR;
3864 bc_parse_push(p, BC_INST_VAR);
3865 bc_parse_pushName(p, name);
3875 static BcStatus bc_parse_read(BcParse *p)
3879 s = bc_lex_next(&p->l);
3881 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3883 s = bc_lex_next(&p->l);
3885 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3887 bc_parse_push(p, BC_INST_READ);
3889 return bc_lex_next(&p->l);
3892 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3897 s = bc_lex_next(&p->l);
3899 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3901 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3903 s = bc_lex_next(&p->l);
3906 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3909 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3911 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3912 bc_parse_push(p, *prev);
3914 return bc_lex_next(&p->l);
3917 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3921 s = bc_lex_next(&p->l);
3924 if (p->l.t.t != BC_LEX_LPAREN) {
3925 *type = BC_INST_SCALE;
3926 bc_parse_push(p, BC_INST_SCALE);
3927 return BC_STATUS_SUCCESS;
3930 *type = BC_INST_SCALE_FUNC;
3931 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3933 s = bc_lex_next(&p->l);
3936 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3938 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3939 bc_parse_push(p, BC_INST_SCALE_FUNC);
3941 return bc_lex_next(&p->l);
3944 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3945 size_t *nexprs, uint8_t flags)
3950 BcInst etype = *prev;
3952 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3953 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3954 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3956 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3957 bc_parse_push(p, inst);
3958 s = bc_lex_next(&p->l);
3962 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3965 s = bc_lex_next(&p->l);
3969 // Because we parse the next part of the expression
3970 // right here, we need to increment this.
3971 *nexprs = *nexprs + 1;
3977 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3981 case BC_LEX_KEY_IBASE:
3982 case BC_LEX_KEY_LAST:
3983 case BC_LEX_KEY_OBASE:
3985 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3986 s = bc_lex_next(&p->l);
3990 case BC_LEX_KEY_SCALE:
3992 s = bc_lex_next(&p->l);
3994 if (p->l.t.t == BC_LEX_LPAREN)
3995 s = BC_STATUS_PARSE_BAD_TOKEN;
3997 bc_parse_push(p, BC_INST_SCALE);
4003 s = BC_STATUS_PARSE_BAD_TOKEN;
4008 if (!s) bc_parse_push(p, inst);
4014 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4015 bool rparen, size_t *nexprs)
4019 BcInst etype = *prev;
4021 s = bc_lex_next(&p->l);
4024 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4025 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4028 *prev = BC_PARSE_TOKEN_INST(type);
4030 // We can just push onto the op stack because this is the largest
4031 // precedence operator that gets pushed. Inc/dec does not.
4032 if (type != BC_LEX_OP_MINUS)
4033 bc_vec_push(&p->ops, &type);
4035 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4040 static BcStatus bc_parse_string(BcParse *p, char inst)
4042 char *str = xstrdup(p->l.t.v.v);
4044 bc_parse_push(p, BC_INST_STR);
4045 bc_parse_pushIndex(p, G.prog.strs.len);
4046 bc_vec_push(&G.prog.strs, &str);
4047 bc_parse_push(p, inst);
4049 return bc_lex_next(&p->l);
4052 static BcStatus bc_parse_print(BcParse *p)
4058 s = bc_lex_next(&p->l);
4063 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4064 return BC_STATUS_PARSE_BAD_PRINT;
4066 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4068 if (type == BC_LEX_STR)
4069 s = bc_parse_string(p, BC_INST_PRINT_POP);
4071 s = bc_parse_expr(p, 0, bc_parse_next_print);
4073 bc_parse_push(p, BC_INST_PRINT_POP);
4078 comma = p->l.t.t == BC_LEX_COMMA;
4079 if (comma) s = bc_lex_next(&p->l);
4084 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4086 return bc_lex_next(&p->l);
4089 static BcStatus bc_parse_return(BcParse *p)
4095 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4097 s = bc_lex_next(&p->l);
4101 paren = t == BC_LEX_LPAREN;
4103 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4104 bc_parse_push(p, BC_INST_RET0);
4107 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4108 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4110 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4111 bc_parse_push(p, BC_INST_RET0);
4112 s = bc_lex_next(&p->l);
4116 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4117 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4121 bc_parse_push(p, BC_INST_RET);
4127 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4129 BcStatus s = BC_STATUS_SUCCESS;
4131 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4132 return BC_STATUS_PARSE_BAD_TOKEN;
4136 if (p->l.t.t == BC_LEX_RBRACE) {
4137 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4139 s = bc_lex_next(&p->l);
4143 return BC_STATUS_PARSE_BAD_TOKEN;
4146 if (BC_PARSE_IF(p)) {
4150 while (p->l.t.t == BC_LEX_NLINE) {
4151 s = bc_lex_next(&p->l);
4155 bc_vec_pop(&p->flags);
4157 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4158 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4160 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4162 else if (BC_PARSE_ELSE(p)) {
4167 bc_vec_pop(&p->flags);
4169 ip = bc_vec_top(&p->exits);
4170 label = bc_vec_item(&p->func->labels, ip->idx);
4171 *label = p->func->code.len;
4173 bc_vec_pop(&p->exits);
4175 else if (BC_PARSE_FUNC_INNER(p)) {
4176 bc_parse_push(p, BC_INST_RET0);
4177 bc_parse_updateFunc(p, BC_PROG_MAIN);
4178 bc_vec_pop(&p->flags);
4182 BcInstPtr *ip = bc_vec_top(&p->exits);
4183 size_t *label = bc_vec_top(&p->conds);
4185 bc_parse_push(p, BC_INST_JUMP);
4186 bc_parse_pushIndex(p, *label);
4188 label = bc_vec_item(&p->func->labels, ip->idx);
4189 *label = p->func->code.len;
4191 bc_vec_pop(&p->flags);
4192 bc_vec_pop(&p->exits);
4193 bc_vec_pop(&p->conds);
4199 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4201 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4202 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4203 flags |= BC_PARSE_FLAG_BODY;
4204 bc_vec_push(&p->flags, &flags);
4207 static void bc_parse_noElse(BcParse *p)
4211 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4213 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4215 ip = bc_vec_top(&p->exits);
4216 label = bc_vec_item(&p->func->labels, ip->idx);
4217 *label = p->func->code.len;
4219 bc_vec_pop(&p->exits);
4222 static BcStatus bc_parse_if(BcParse *p)
4227 s = bc_lex_next(&p->l);
4229 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4231 s = bc_lex_next(&p->l);
4233 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4235 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4237 s = bc_lex_next(&p->l);
4239 bc_parse_push(p, BC_INST_JUMP_ZERO);
4241 ip.idx = p->func->labels.len;
4242 ip.func = ip.len = 0;
4244 bc_parse_pushIndex(p, ip.idx);
4245 bc_vec_push(&p->exits, &ip);
4246 bc_vec_push(&p->func->labels, &ip.idx);
4247 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4249 return BC_STATUS_SUCCESS;
4252 static BcStatus bc_parse_else(BcParse *p)
4256 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4258 ip.idx = p->func->labels.len;
4259 ip.func = ip.len = 0;
4261 bc_parse_push(p, BC_INST_JUMP);
4262 bc_parse_pushIndex(p, ip.idx);
4266 bc_vec_push(&p->exits, &ip);
4267 bc_vec_push(&p->func->labels, &ip.idx);
4268 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4270 return bc_lex_next(&p->l);
4273 static BcStatus bc_parse_while(BcParse *p)
4278 s = bc_lex_next(&p->l);
4280 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4281 s = bc_lex_next(&p->l);
4284 ip.idx = p->func->labels.len;
4286 bc_vec_push(&p->func->labels, &p->func->code.len);
4287 bc_vec_push(&p->conds, &ip.idx);
4289 ip.idx = p->func->labels.len;
4293 bc_vec_push(&p->exits, &ip);
4294 bc_vec_push(&p->func->labels, &ip.idx);
4296 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4298 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4299 s = bc_lex_next(&p->l);
4302 bc_parse_push(p, BC_INST_JUMP_ZERO);
4303 bc_parse_pushIndex(p, ip.idx);
4304 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4306 return BC_STATUS_SUCCESS;
4309 static BcStatus bc_parse_for(BcParse *p)
4313 size_t cond_idx, exit_idx, body_idx, update_idx;
4315 s = bc_lex_next(&p->l);
4317 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4318 s = bc_lex_next(&p->l);
4321 if (p->l.t.t != BC_LEX_SCOLON)
4322 s = bc_parse_expr(p, 0, bc_parse_next_for);
4324 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4327 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4328 s = bc_lex_next(&p->l);
4331 cond_idx = p->func->labels.len;
4332 update_idx = cond_idx + 1;
4333 body_idx = update_idx + 1;
4334 exit_idx = body_idx + 1;
4336 bc_vec_push(&p->func->labels, &p->func->code.len);
4338 if (p->l.t.t != BC_LEX_SCOLON)
4339 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4341 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4344 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4346 s = bc_lex_next(&p->l);
4349 bc_parse_push(p, BC_INST_JUMP_ZERO);
4350 bc_parse_pushIndex(p, exit_idx);
4351 bc_parse_push(p, BC_INST_JUMP);
4352 bc_parse_pushIndex(p, body_idx);
4354 ip.idx = p->func->labels.len;
4356 bc_vec_push(&p->conds, &update_idx);
4357 bc_vec_push(&p->func->labels, &p->func->code.len);
4359 if (p->l.t.t != BC_LEX_RPAREN)
4360 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4362 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4366 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4367 bc_parse_push(p, BC_INST_JUMP);
4368 bc_parse_pushIndex(p, cond_idx);
4369 bc_vec_push(&p->func->labels, &p->func->code.len);
4375 bc_vec_push(&p->exits, &ip);
4376 bc_vec_push(&p->func->labels, &ip.idx);
4378 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4380 return BC_STATUS_SUCCESS;
4383 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4389 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4391 if (type == BC_LEX_KEY_BREAK) {
4393 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4395 i = p->exits.len - 1;
4396 ip = bc_vec_item(&p->exits, i);
4398 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4399 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4404 i = *((size_t *) bc_vec_top(&p->conds));
4406 bc_parse_push(p, BC_INST_JUMP);
4407 bc_parse_pushIndex(p, i);
4409 s = bc_lex_next(&p->l);
4412 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4413 return BC_STATUS_PARSE_BAD_TOKEN;
4415 return bc_lex_next(&p->l);
4418 static BcStatus bc_parse_func(BcParse *p)
4421 bool var, comma = false;
4425 s = bc_lex_next(&p->l);
4427 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4429 name = xstrdup(p->l.t.v.v);
4430 bc_parse_addFunc(p, name, &p->fidx);
4432 s = bc_lex_next(&p->l);
4434 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4435 s = bc_lex_next(&p->l);
4438 while (p->l.t.t != BC_LEX_RPAREN) {
4440 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4444 name = xstrdup(p->l.t.v.v);
4445 s = bc_lex_next(&p->l);
4448 var = p->l.t.t != BC_LEX_LBRACKET;
4452 s = bc_lex_next(&p->l);
4455 if (p->l.t.t != BC_LEX_RBRACKET) {
4456 s = BC_STATUS_PARSE_BAD_FUNC;
4460 s = bc_lex_next(&p->l);
4464 comma = p->l.t.t == BC_LEX_COMMA;
4466 s = bc_lex_next(&p->l);
4470 s = bc_func_insert(p->func, name, var);
4474 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4476 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4477 bc_parse_startBody(p, flags);
4479 s = bc_lex_next(&p->l);
4482 if (p->l.t.t != BC_LEX_LBRACE)
4483 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4492 static BcStatus bc_parse_auto(BcParse *p)
4495 bool comma, var, one;
4498 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4499 s = bc_lex_next(&p->l);
4502 p->auto_part = comma = false;
4503 one = p->l.t.t == BC_LEX_NAME;
4505 while (p->l.t.t == BC_LEX_NAME) {
4507 name = xstrdup(p->l.t.v.v);
4508 s = bc_lex_next(&p->l);
4511 var = p->l.t.t != BC_LEX_LBRACKET;
4514 s = bc_lex_next(&p->l);
4517 if (p->l.t.t != BC_LEX_RBRACKET) {
4518 s = BC_STATUS_PARSE_BAD_FUNC;
4522 s = bc_lex_next(&p->l);
4526 comma = p->l.t.t == BC_LEX_COMMA;
4528 s = bc_lex_next(&p->l);
4532 s = bc_func_insert(p->func, name, var);
4536 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4537 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4539 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4540 return BC_STATUS_PARSE_BAD_TOKEN;
4542 return bc_lex_next(&p->l);
4549 static BcStatus bc_parse_body(BcParse *p, bool brace)
4551 BcStatus s = BC_STATUS_SUCCESS;
4552 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4554 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4556 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4558 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4559 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4561 if (!p->auto_part) {
4562 s = bc_parse_auto(p);
4566 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4569 s = bc_parse_stmt(p);
4570 if (!s && !brace) s = bc_parse_endBody(p, false);
4576 static BcStatus bc_parse_stmt(BcParse *p)
4578 BcStatus s = BC_STATUS_SUCCESS;
4584 return bc_lex_next(&p->l);
4587 case BC_LEX_KEY_ELSE:
4589 p->auto_part = false;
4595 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4598 s = bc_lex_next(&p->l);
4601 return bc_parse_body(p, true);
4604 case BC_LEX_KEY_AUTO:
4606 return bc_parse_auto(p);
4611 p->auto_part = false;
4613 if (BC_PARSE_IF_END(p)) {
4615 return BC_STATUS_SUCCESS;
4617 else if (BC_PARSE_BODY(p))
4618 return bc_parse_body(p, false);
4628 case BC_LEX_OP_MINUS:
4629 case BC_LEX_OP_BOOL_NOT:
4633 case BC_LEX_KEY_IBASE:
4634 case BC_LEX_KEY_LAST:
4635 case BC_LEX_KEY_LENGTH:
4636 case BC_LEX_KEY_OBASE:
4637 case BC_LEX_KEY_READ:
4638 case BC_LEX_KEY_SCALE:
4639 case BC_LEX_KEY_SQRT:
4641 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4645 case BC_LEX_KEY_ELSE:
4647 s = bc_parse_else(p);
4653 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4659 s = bc_parse_endBody(p, true);
4665 s = bc_parse_string(p, BC_INST_PRINT_STR);
4669 case BC_LEX_KEY_BREAK:
4670 case BC_LEX_KEY_CONTINUE:
4672 s = bc_parse_loopExit(p, p->l.t.t);
4676 case BC_LEX_KEY_FOR:
4678 s = bc_parse_for(p);
4682 case BC_LEX_KEY_HALT:
4684 bc_parse_push(p, BC_INST_HALT);
4685 s = bc_lex_next(&p->l);
4695 case BC_LEX_KEY_LIMITS:
4697 s = bc_lex_next(&p->l);
4699 s = BC_STATUS_LIMITS;
4703 case BC_LEX_KEY_PRINT:
4705 s = bc_parse_print(p);
4709 case BC_LEX_KEY_QUIT:
4711 // Quit is a compile-time command. We don't exit directly,
4712 // so the vm can clean up. Limits do the same thing.
4717 case BC_LEX_KEY_RETURN:
4719 s = bc_parse_return(p);
4723 case BC_LEX_KEY_WHILE:
4725 s = bc_parse_while(p);
4731 s = BC_STATUS_PARSE_BAD_TOKEN;
4739 static BcStatus bc_parse_parse(BcParse *p)
4743 if (p->l.t.t == BC_LEX_EOF)
4744 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4745 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4746 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4747 s = bc_parse_func(p);
4750 s = bc_parse_stmt(p);
4752 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4753 s = bc_parse_reset(p, s);
4758 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4760 BcStatus s = BC_STATUS_SUCCESS;
4761 BcInst prev = BC_INST_PRINT;
4762 BcLexType top, t = p->l.t.t;
4763 size_t nexprs = 0, ops_bgn = p->ops.len;
4764 uint32_t i, nparens, nrelops;
4765 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4767 paren_first = p->l.t.t == BC_LEX_LPAREN;
4768 nparens = nrelops = 0;
4769 paren_expr = rprn = done = get_token = assign = false;
4772 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4778 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4779 rprn = get_token = bin_last = false;
4783 case BC_LEX_OP_MINUS:
4785 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4786 rprn = get_token = false;
4787 bin_last = prev == BC_INST_MINUS;
4791 case BC_LEX_OP_ASSIGN_POWER:
4792 case BC_LEX_OP_ASSIGN_MULTIPLY:
4793 case BC_LEX_OP_ASSIGN_DIVIDE:
4794 case BC_LEX_OP_ASSIGN_MODULUS:
4795 case BC_LEX_OP_ASSIGN_PLUS:
4796 case BC_LEX_OP_ASSIGN_MINUS:
4797 case BC_LEX_OP_ASSIGN:
4799 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4800 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4801 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4803 s = BC_STATUS_PARSE_BAD_ASSIGN;
4808 case BC_LEX_OP_POWER:
4809 case BC_LEX_OP_MULTIPLY:
4810 case BC_LEX_OP_DIVIDE:
4811 case BC_LEX_OP_MODULUS:
4812 case BC_LEX_OP_PLUS:
4813 case BC_LEX_OP_REL_EQ:
4814 case BC_LEX_OP_REL_LE:
4815 case BC_LEX_OP_REL_GE:
4816 case BC_LEX_OP_REL_NE:
4817 case BC_LEX_OP_REL_LT:
4818 case BC_LEX_OP_REL_GT:
4819 case BC_LEX_OP_BOOL_NOT:
4820 case BC_LEX_OP_BOOL_OR:
4821 case BC_LEX_OP_BOOL_AND:
4823 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4824 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4826 return BC_STATUS_PARSE_BAD_EXP;
4829 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4830 prev = BC_PARSE_TOKEN_INST(t);
4831 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4832 rprn = get_token = false;
4833 bin_last = t != BC_LEX_OP_BOOL_NOT;
4840 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4843 paren_expr = rprn = bin_last = false;
4845 bc_vec_push(&p->ops, &t);
4852 if (bin_last || prev == BC_INST_BOOL_NOT)
4853 return BC_STATUS_PARSE_BAD_EXP;
4856 s = BC_STATUS_SUCCESS;
4861 else if (!paren_expr)
4862 return BC_STATUS_PARSE_EMPTY_EXP;
4865 paren_expr = rprn = true;
4866 get_token = bin_last = false;
4868 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4875 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4878 rprn = get_token = bin_last = false;
4879 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4887 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4889 bc_parse_number(p, &prev, &nexprs);
4890 paren_expr = get_token = true;
4891 rprn = bin_last = false;
4896 case BC_LEX_KEY_IBASE:
4897 case BC_LEX_KEY_LAST:
4898 case BC_LEX_KEY_OBASE:
4900 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4902 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4903 bc_parse_push(p, (char) prev);
4905 paren_expr = get_token = true;
4906 rprn = bin_last = false;
4912 case BC_LEX_KEY_LENGTH:
4913 case BC_LEX_KEY_SQRT:
4915 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4917 s = bc_parse_builtin(p, t, flags, &prev);
4919 rprn = get_token = bin_last = false;
4925 case BC_LEX_KEY_READ:
4927 if (BC_PARSE_LEAF(prev, rprn))
4928 return BC_STATUS_PARSE_BAD_EXP;
4929 else if (flags & BC_PARSE_NOREAD)
4930 s = BC_STATUS_EXEC_REC_READ;
4932 s = bc_parse_read(p);
4935 rprn = get_token = bin_last = false;
4937 prev = BC_INST_READ;
4942 case BC_LEX_KEY_SCALE:
4944 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4946 s = bc_parse_scale(p, &prev, flags);
4948 rprn = get_token = bin_last = false;
4950 prev = BC_INST_SCALE;
4957 s = BC_STATUS_PARSE_BAD_TOKEN;
4962 if (!s && get_token) s = bc_lex_next(&p->l);
4966 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4968 while (p->ops.len > ops_bgn) {
4970 top = BC_PARSE_TOP_OP(p);
4971 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4973 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4974 return BC_STATUS_PARSE_BAD_EXP;
4976 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4978 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4979 bc_vec_pop(&p->ops);
4982 s = BC_STATUS_PARSE_BAD_EXP;
4983 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4985 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4988 if (!(flags & BC_PARSE_REL) && nrelops) {
4989 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4992 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4993 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4997 if (flags & BC_PARSE_PRINT) {
4998 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4999 bc_parse_push(p, BC_INST_POP);
5005 static void bc_parse_init(BcParse *p, size_t func)
5007 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
5010 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5012 return bc_parse_expr(p, flags, bc_parse_next_read);
5017 static BcStatus dc_parse_register(BcParse *p)
5022 s = bc_lex_next(&p->l);
5024 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5026 name = xstrdup(p->l.t.v.v);
5027 bc_parse_pushName(p, name);
5032 static BcStatus dc_parse_string(BcParse *p)
5034 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5035 size_t idx, len = G.prog.strs.len;
5037 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5040 str = xstrdup(p->l.t.v.v);
5041 bc_parse_push(p, BC_INST_STR);
5042 bc_parse_pushIndex(p, len);
5043 bc_vec_push(&G.prog.strs, &str);
5044 bc_parse_addFunc(p, name, &idx);
5046 return bc_lex_next(&p->l);
5049 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5053 bc_parse_push(p, inst);
5055 s = dc_parse_register(p);
5060 bc_parse_push(p, BC_INST_SWAP);
5061 bc_parse_push(p, BC_INST_ASSIGN);
5062 bc_parse_push(p, BC_INST_POP);
5065 return bc_lex_next(&p->l);
5068 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5072 bc_parse_push(p, inst);
5073 bc_parse_push(p, BC_INST_EXEC_COND);
5075 s = dc_parse_register(p);
5078 s = bc_lex_next(&p->l);
5081 if (p->l.t.t == BC_LEX_ELSE) {
5082 s = dc_parse_register(p);
5084 s = bc_lex_next(&p->l);
5087 bc_parse_push(p, BC_PARSE_STREND);
5092 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5094 BcStatus s = BC_STATUS_SUCCESS;
5097 bool assign, get_token = false;
5101 case BC_LEX_OP_REL_EQ:
5102 case BC_LEX_OP_REL_LE:
5103 case BC_LEX_OP_REL_GE:
5104 case BC_LEX_OP_REL_NE:
5105 case BC_LEX_OP_REL_LT:
5106 case BC_LEX_OP_REL_GT:
5108 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5115 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5121 s = dc_parse_string(p);
5128 if (t == BC_LEX_NEG) {
5129 s = bc_lex_next(&p->l);
5131 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5134 bc_parse_number(p, &prev, &p->nbraces);
5136 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5142 case BC_LEX_KEY_READ:
5144 if (flags & BC_PARSE_NOREAD)
5145 s = BC_STATUS_EXEC_REC_READ;
5147 bc_parse_push(p, BC_INST_READ);
5152 case BC_LEX_OP_ASSIGN:
5153 case BC_LEX_STORE_PUSH:
5155 assign = t == BC_LEX_OP_ASSIGN;
5156 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5157 s = dc_parse_mem(p, inst, true, assign);
5162 case BC_LEX_LOAD_POP:
5164 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5165 s = dc_parse_mem(p, inst, true, false);
5169 case BC_LEX_STORE_IBASE:
5170 case BC_LEX_STORE_SCALE:
5171 case BC_LEX_STORE_OBASE:
5173 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5174 s = dc_parse_mem(p, inst, false, true);
5180 s = BC_STATUS_PARSE_BAD_TOKEN;
5186 if (!s && get_token) s = bc_lex_next(&p->l);
5191 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5193 BcStatus s = BC_STATUS_SUCCESS;
5197 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5199 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5201 inst = dc_parse_insts[t];
5203 if (inst != BC_INST_INVALID) {
5204 bc_parse_push(p, inst);
5205 s = bc_lex_next(&p->l);
5208 s = dc_parse_token(p, t, flags);
5211 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5212 bc_parse_push(p, BC_INST_POP_EXEC);
5217 static BcStatus dc_parse_parse(BcParse *p)
5221 if (p->l.t.t == BC_LEX_EOF)
5222 s = BC_STATUS_LEX_EOF;
5224 s = dc_parse_expr(p, 0);
5226 if (s || G_interrupt) s = bc_parse_reset(p, s);
5231 static void dc_parse_init(BcParse *p, size_t func)
5233 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5237 static void common_parse_init(BcParse *p, size_t func)
5240 bc_parse_init(p, func);
5242 dc_parse_init(p, func);
5246 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5249 return bc_parse_expression(p, flags);
5251 return dc_parse_expr(p, flags);
5255 static BcVec* bc_program_search(char *id, bool var)
5264 v = var ? &G.prog.vars : &G.prog.arrs;
5265 map = var ? &G.prog.var_map : &G.prog.arr_map;
5269 s = bc_map_insert(map, &e, &i);
5270 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5273 bc_array_init(&data.v, var);
5274 bc_vec_push(v, &data.v);
5277 ptr = bc_vec_item(map, i);
5278 if (new) ptr->name = xstrdup(e.name);
5279 return bc_vec_item(v, ptr->idx);
5282 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5284 BcStatus s = BC_STATUS_SUCCESS;
5289 case BC_RESULT_TEMP:
5290 case BC_RESULT_IBASE:
5291 case BC_RESULT_SCALE:
5292 case BC_RESULT_OBASE:
5298 case BC_RESULT_CONSTANT:
5300 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5301 size_t base_t, len = strlen(*str);
5304 bc_num_init(&r->d.n, len);
5306 hex = hex && len == 1;
5307 base = hex ? &G.prog.hexb : &G.prog.ib;
5308 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5309 s = bc_num_parse(&r->d.n, *str, base, base_t);
5312 bc_num_free(&r->d.n);
5317 r->t = BC_RESULT_TEMP;
5323 case BC_RESULT_ARRAY:
5324 case BC_RESULT_ARRAY_ELEM:
5328 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5330 if (r->t == BC_RESULT_ARRAY_ELEM) {
5332 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5333 *num = bc_vec_item(v, r->d.id.idx);
5336 *num = bc_vec_top(v);
5341 case BC_RESULT_LAST:
5343 *num = &G.prog.last;
5357 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5358 BcResult **r, BcNum **rn, bool assign)
5362 BcResultType lt, rt;
5364 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5366 *r = bc_vec_item_rev(&G.prog.results, 0);
5367 *l = bc_vec_item_rev(&G.prog.results, 1);
5371 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5373 s = bc_program_num(*l, ln, false);
5375 s = bc_program_num(*r, rn, hex);
5378 // We run this again under these conditions in case any vector has been
5379 // reallocated out from under the BcNums or arrays we had.
5380 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5381 s = bc_program_num(*l, ln, false);
5385 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5386 return BC_STATUS_EXEC_BAD_TYPE;
5387 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5392 static void bc_program_binOpRetire(BcResult *r)
5394 r->t = BC_RESULT_TEMP;
5395 bc_vec_pop(&G.prog.results);
5396 bc_vec_pop(&G.prog.results);
5397 bc_vec_push(&G.prog.results, r);
5400 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5404 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5405 *r = bc_vec_top(&G.prog.results);
5407 s = bc_program_num(*r, n, false);
5410 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5415 static void bc_program_retire(BcResult *r, BcResultType t)
5418 bc_vec_pop(&G.prog.results);
5419 bc_vec_push(&G.prog.results, r);
5422 static BcStatus bc_program_op(char inst)
5425 BcResult *opd1, *opd2, res;
5426 BcNum *n1, *n2 = NULL;
5428 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5430 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5432 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5434 bc_program_binOpRetire(&res);
5439 bc_num_free(&res.d.n);
5443 static BcStatus bc_program_read(void)
5450 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5452 for (i = 0; i < G.prog.stack.len; ++i) {
5453 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5454 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5457 bc_vec_npop(&f->code, f->code.len);
5458 bc_vec_init(&buf, sizeof(char), NULL);
5460 s = bc_read_line(&buf, "read> ");
5463 common_parse_init(&parse, BC_PROG_READ);
5464 bc_lex_file(&parse.l, bc_program_stdin_name);
5466 s = bc_parse_text(&parse, buf.v);
5467 if (s) goto exec_err;
5468 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5469 if (s) goto exec_err;
5471 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5472 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5476 ip.func = BC_PROG_READ;
5478 ip.len = G.prog.results.len;
5480 // Update this pointer, just in case.
5481 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5483 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5484 bc_vec_push(&G.prog.stack, &ip);
5487 bc_parse_free(&parse);
5493 static size_t bc_program_index(char *code, size_t *bgn)
5495 char amt = code[(*bgn)++], i = 0;
5498 for (; i < amt; ++i, ++(*bgn))
5499 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5504 static char *bc_program_name(char *code, size_t *bgn)
5507 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5509 s = xmalloc(ptr - str + 1);
5512 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5520 static void bc_program_printString(const char *str, size_t *nchars)
5522 size_t i, len = strlen(str);
5531 for (i = 0; i < len; ++i, ++(*nchars)) {
5535 if (c != '\\' || i == len - 1)
5595 // Just print the backslash and following character.
5606 static BcStatus bc_program_print(char inst, size_t idx)
5608 BcStatus s = BC_STATUS_SUCCESS;
5613 bool pop = inst != BC_INST_PRINT;
5615 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5617 r = bc_vec_item_rev(&G.prog.results, idx);
5618 s = bc_program_num(r, &num, false);
5621 if (BC_PROG_NUM(r, num)) {
5622 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5623 if (!s) bc_num_copy(&G.prog.last, num);
5627 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5628 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5630 if (inst == BC_INST_PRINT_STR) {
5631 for (i = 0, len = strlen(str); i < len; ++i) {
5634 if (c == '\n') G.prog.nchars = SIZE_MAX;
5639 bc_program_printString(str, &G.prog.nchars);
5640 if (inst == BC_INST_PRINT) bb_putchar('\n');
5644 if (!s && pop) bc_vec_pop(&G.prog.results);
5649 static BcStatus bc_program_negate(void)
5655 s = bc_program_prep(&ptr, &num);
5658 bc_num_init(&res.d.n, num->len);
5659 bc_num_copy(&res.d.n, num);
5660 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5662 bc_program_retire(&res, BC_RESULT_TEMP);
5667 static BcStatus bc_program_logical(char inst)
5670 BcResult *opd1, *opd2, res;
5675 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5677 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5679 if (inst == BC_INST_BOOL_AND)
5680 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5681 else if (inst == BC_INST_BOOL_OR)
5682 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5685 cmp = bc_num_cmp(n1, n2);
5689 case BC_INST_REL_EQ:
5695 case BC_INST_REL_LE:
5701 case BC_INST_REL_GE:
5707 case BC_INST_REL_NE:
5713 case BC_INST_REL_LT:
5719 case BC_INST_REL_GT:
5727 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5729 bc_program_binOpRetire(&res);
5735 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5741 memset(&n2, 0, sizeof(BcNum));
5742 n2.rdx = res.d.id.idx = r->d.id.idx;
5743 res.t = BC_RESULT_STR;
5746 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5748 bc_vec_pop(&G.prog.results);
5751 bc_vec_pop(&G.prog.results);
5753 bc_vec_push(&G.prog.results, &res);
5754 bc_vec_push(v, &n2);
5756 return BC_STATUS_SUCCESS;
5760 static BcStatus bc_program_copyToVar(char *name, bool var)
5767 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5769 ptr = bc_vec_top(&G.prog.results);
5770 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5771 v = bc_program_search(name, var);
5774 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5775 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5778 s = bc_program_num(ptr, &n, false);
5781 // Do this once more to make sure that pointers were not invalidated.
5782 v = bc_program_search(name, var);
5785 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5786 bc_num_copy(&r.d.n, n);
5789 bc_array_init(&r.d.v, true);
5790 bc_array_copy(&r.d.v, (BcVec *) n);
5793 bc_vec_push(v, &r.d);
5794 bc_vec_pop(&G.prog.results);
5799 static BcStatus bc_program_assign(char inst)
5802 BcResult *left, *right, res;
5803 BcNum *l = NULL, *r = NULL;
5804 unsigned long val, max;
5805 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5807 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5810 ib = left->t == BC_RESULT_IBASE;
5811 sc = left->t == BC_RESULT_SCALE;
5815 if (right->t == BC_RESULT_STR) {
5819 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5820 v = bc_program_search(left->d.id.name, true);
5822 return bc_program_assignStr(right, v, false);
5826 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5827 return BC_STATUS_PARSE_BAD_ASSIGN;
5830 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5831 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5836 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5843 if (ib || sc || left->t == BC_RESULT_OBASE) {
5847 s = bc_num_ulong(l, &val);
5849 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5853 ptr = &G.prog.scale;
5856 if (val < BC_NUM_MIN_BASE) return s;
5857 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5858 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5861 if (val > max) return s;
5862 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5864 *ptr = (size_t) val;
5865 s = BC_STATUS_SUCCESS;
5868 bc_num_init(&res.d.n, l->len);
5869 bc_num_copy(&res.d.n, l);
5870 bc_program_binOpRetire(&res);
5875 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5876 bool pop, bool copy)
5878 BcStatus s = BC_STATUS_SUCCESS;
5880 char *name = bc_program_name(code, bgn);
5881 #if ENABLE_DC // Exclude
5885 (void) pop, (void) copy;
5888 r.t = BC_RESULT_VAR;
5892 v = bc_program_search(name, true);
5893 num = bc_vec_top(v);
5897 if (!BC_PROG_STACK(v, 2 - copy)) {
5899 return BC_STATUS_EXEC_STACK;
5905 if (!BC_PROG_STR(num)) {
5907 r.t = BC_RESULT_TEMP;
5909 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5910 bc_num_copy(&r.d.n, num);
5913 r.t = BC_RESULT_STR;
5914 r.d.id.idx = num->rdx;
5917 if (!copy) bc_vec_pop(v);
5921 bc_vec_push(&G.prog.results, &r);
5926 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5929 BcStatus s = BC_STATUS_SUCCESS;
5933 r.d.id.name = bc_program_name(code, bgn);
5935 if (inst == BC_INST_ARRAY) {
5936 r.t = BC_RESULT_ARRAY;
5937 bc_vec_push(&G.prog.results, &r);
5944 s = bc_program_prep(&operand, &num);
5946 s = bc_num_ulong(num, &temp);
5949 if (temp > BC_MAX_DIM) {
5950 s = BC_STATUS_EXEC_ARRAY_LEN;
5954 r.d.id.idx = (size_t) temp;
5955 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5959 if (s) free(r.d.id.name);
5964 static BcStatus bc_program_incdec(char inst)
5967 BcResult *ptr, res, copy;
5971 s = bc_program_prep(&ptr, &num);
5974 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5975 copy.t = BC_RESULT_TEMP;
5976 bc_num_init(©.d.n, num->len);
5977 bc_num_copy(©.d.n, num);
5980 res.t = BC_RESULT_ONE;
5981 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5982 BC_INST_ASSIGN_PLUS :
5983 BC_INST_ASSIGN_MINUS;
5985 bc_vec_push(&G.prog.results, &res);
5986 bc_program_assign(inst);
5988 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5989 bc_vec_pop(&G.prog.results);
5990 bc_vec_push(&G.prog.results, ©);
5996 static BcStatus bc_program_call(char *code, size_t *idx)
5998 BcStatus s = BC_STATUS_SUCCESS;
6000 size_t i, nparams = bc_program_index(code, idx);
6007 ip.func = bc_program_index(code, idx);
6008 func = bc_vec_item(&G.prog.fns, ip.func);
6010 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6011 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6012 ip.len = G.prog.results.len - nparams;
6014 for (i = 0; i < nparams; ++i) {
6016 a = bc_vec_item(&func->autos, nparams - 1 - i);
6017 arg = bc_vec_top(&G.prog.results);
6019 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6020 return BC_STATUS_EXEC_BAD_TYPE;
6022 s = bc_program_copyToVar(a->name, a->idx);
6026 for (; i < func->autos.len; ++i) {
6029 a = bc_vec_item(&func->autos, i);
6030 v = bc_program_search(a->name, a->idx);
6033 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6034 bc_vec_push(v, ¶m.n);
6037 bc_array_init(¶m.v, true);
6038 bc_vec_push(v, ¶m.v);
6042 bc_vec_push(&G.prog.stack, &ip);
6044 return BC_STATUS_SUCCESS;
6047 static BcStatus bc_program_return(char inst)
6053 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6055 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6056 return BC_STATUS_EXEC_STACK;
6058 f = bc_vec_item(&G.prog.fns, ip->func);
6059 res.t = BC_RESULT_TEMP;
6061 if (inst == BC_INST_RET) {
6064 BcResult *operand = bc_vec_top(&G.prog.results);
6066 s = bc_program_num(operand, &num, false);
6068 bc_num_init(&res.d.n, num->len);
6069 bc_num_copy(&res.d.n, num);
6072 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6073 bc_num_zero(&res.d.n);
6076 // We need to pop arguments as well, so this takes that into account.
6077 for (i = 0; i < f->autos.len; ++i) {
6080 BcId *a = bc_vec_item(&f->autos, i);
6082 v = bc_program_search(a->name, a->idx);
6086 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6087 bc_vec_push(&G.prog.results, &res);
6088 bc_vec_pop(&G.prog.stack);
6090 return BC_STATUS_SUCCESS;
6094 static unsigned long bc_program_scale(BcNum *n)
6096 return (unsigned long) n->rdx;
6099 static unsigned long bc_program_len(BcNum *n)
6101 unsigned long len = n->len;
6104 if (n->rdx != n->len) return len;
6105 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6110 static BcStatus bc_program_builtin(char inst)
6116 bool len = inst == BC_INST_LENGTH;
6118 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6119 opnd = bc_vec_top(&G.prog.results);
6121 s = bc_program_num(opnd, &num, false);
6125 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6128 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6130 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6132 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6133 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6137 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6140 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6142 str = bc_vec_item(&G.prog.strs, idx);
6143 bc_num_ulong2num(&res.d.n, strlen(*str));
6147 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6148 bc_num_ulong2num(&res.d.n, f(num));
6151 bc_program_retire(&res, BC_RESULT_TEMP);
6157 static BcStatus bc_program_divmod(void)
6160 BcResult *opd1, *opd2, res, res2;
6161 BcNum *n1, *n2 = NULL;
6163 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6166 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6167 bc_num_init(&res2.d.n, n2->len);
6169 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6172 bc_program_binOpRetire(&res2);
6173 res.t = BC_RESULT_TEMP;
6174 bc_vec_push(&G.prog.results, &res);
6179 bc_num_free(&res2.d.n);
6180 bc_num_free(&res.d.n);
6184 static BcStatus bc_program_modexp(void)
6187 BcResult *r1, *r2, *r3, res;
6188 BcNum *n1, *n2, *n3;
6190 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6191 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6194 r1 = bc_vec_item_rev(&G.prog.results, 2);
6195 s = bc_program_num(r1, &n1, false);
6197 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6199 // Make sure that the values have their pointers updated, if necessary.
6200 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6202 if (r1->t == r2->t) {
6203 s = bc_program_num(r2, &n2, false);
6207 if (r1->t == r3->t) {
6208 s = bc_program_num(r3, &n3, false);
6213 bc_num_init(&res.d.n, n3->len);
6214 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6217 bc_vec_pop(&G.prog.results);
6218 bc_program_binOpRetire(&res);
6223 bc_num_free(&res.d.n);
6227 static void bc_program_stackLen(void)
6230 size_t len = G.prog.results.len;
6232 res.t = BC_RESULT_TEMP;
6234 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6235 bc_num_ulong2num(&res.d.n, len);
6236 bc_vec_push(&G.prog.results, &res);
6239 static BcStatus bc_program_asciify(void)
6243 BcNum *num = NULL, n;
6244 char *str, *str2, c;
6245 size_t len = G.prog.strs.len, idx;
6248 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6249 r = bc_vec_top(&G.prog.results);
6251 s = bc_program_num(r, &num, false);
6254 if (BC_PROG_NUM(r, num)) {
6256 bc_num_init(&n, BC_NUM_DEF_SIZE);
6257 bc_num_copy(&n, num);
6258 bc_num_truncate(&n, n.rdx);
6260 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6261 if (s) goto num_err;
6262 s = bc_num_ulong(&n, &val);
6263 if (s) goto num_err;
6270 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6271 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6279 str2 = xstrdup(str);
6280 bc_program_addFunc(str2, &idx);
6282 if (idx != len + BC_PROG_REQ_FUNCS) {
6284 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6285 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6294 bc_vec_push(&G.prog.strs, &str);
6296 res.t = BC_RESULT_STR;
6298 bc_vec_pop(&G.prog.results);
6299 bc_vec_push(&G.prog.results, &res);
6301 return BC_STATUS_SUCCESS;
6308 static BcStatus bc_program_printStream(void)
6316 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6317 r = bc_vec_top(&G.prog.results);
6319 s = bc_program_num(r, &n, false);
6322 if (BC_PROG_NUM(r, n))
6323 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6325 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6326 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6333 static BcStatus bc_program_nquit(void)
6340 s = bc_program_prep(&opnd, &num);
6342 s = bc_num_ulong(num, &val);
6345 bc_vec_pop(&G.prog.results);
6347 if (G.prog.stack.len < val)
6348 return BC_STATUS_EXEC_STACK;
6349 else if (G.prog.stack.len == val)
6350 return BC_STATUS_QUIT;
6352 bc_vec_npop(&G.prog.stack, val);
6357 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6360 BcStatus s = BC_STATUS_SUCCESS;
6370 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6372 r = bc_vec_top(&G.prog.results);
6376 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6378 if (code[*bgn] == BC_PARSE_STREND)
6381 else_name = bc_program_name(code, bgn);
6383 exec = r->d.n.len != 0;
6387 else if (else_name != NULL) {
6394 v = bc_program_search(name, true);
6401 if (!exec) goto exit;
6402 if (!BC_PROG_STR(n)) {
6403 s = BC_STATUS_EXEC_BAD_TYPE;
6411 if (r->t == BC_RESULT_STR)
6413 else if (r->t == BC_RESULT_VAR) {
6414 s = bc_program_num(r, &n, false);
6415 if (s || !BC_PROG_STR(n)) goto exit;
6422 fidx = sidx + BC_PROG_REQ_FUNCS;
6424 str = bc_vec_item(&G.prog.strs, sidx);
6425 f = bc_vec_item(&G.prog.fns, fidx);
6427 if (f->code.len == 0) {
6428 common_parse_init(&prs, fidx);
6429 s = bc_parse_text(&prs, *str);
6431 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6434 if (prs.l.t.t != BC_LEX_EOF) {
6435 s = BC_STATUS_PARSE_BAD_EXP;
6439 bc_parse_free(&prs);
6443 ip.len = G.prog.results.len;
6446 bc_vec_pop(&G.prog.results);
6447 bc_vec_push(&G.prog.stack, &ip);
6449 return BC_STATUS_SUCCESS;
6452 bc_parse_free(&prs);
6453 f = bc_vec_item(&G.prog.fns, fidx);
6454 bc_vec_npop(&f->code, f->code.len);
6456 bc_vec_pop(&G.prog.results);
6461 static void bc_program_pushGlobal(char inst)
6466 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6467 if (inst == BC_INST_IBASE)
6468 val = (unsigned long) G.prog.ib_t;
6469 else if (inst == BC_INST_SCALE)
6470 val = (unsigned long) G.prog.scale;
6472 val = (unsigned long) G.prog.ob_t;
6474 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6475 bc_num_ulong2num(&res.d.n, val);
6476 bc_vec_push(&G.prog.results, &res);
6479 static void bc_program_addFunc(char *name, size_t *idx)
6482 BcId entry, *entry_ptr;
6486 entry.idx = G.prog.fns.len;
6488 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6491 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6492 *idx = entry_ptr->idx;
6494 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6496 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6498 // We need to reset these, so the function can be repopulated.
6500 bc_vec_npop(&func->autos, func->autos.len);
6501 bc_vec_npop(&func->code, func->code.len);
6502 bc_vec_npop(&func->labels, func->labels.len);
6506 bc_vec_push(&G.prog.fns, &f);
6510 static BcStatus bc_program_reset(BcStatus s)
6515 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6516 bc_vec_npop(&G.prog.results, G.prog.results.len);
6518 f = bc_vec_item(&G.prog.fns, 0);
6519 ip = bc_vec_top(&G.prog.stack);
6520 ip->idx = f->code.len;
6522 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6524 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6527 fputs(bc_program_ready_msg, stderr);
6529 s = BC_STATUS_SUCCESS;
6538 static BcStatus bc_program_exec(void)
6540 BcStatus s = BC_STATUS_SUCCESS;
6544 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6545 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6546 char *code = func->code.v;
6549 while (!s && ip->idx < func->code.len) {
6551 char inst = code[(ip->idx)++];
6556 case BC_INST_JUMP_ZERO:
6558 s = bc_program_prep(&ptr, &num);
6560 cond = !bc_num_cmp(num, &G.prog.zero);
6561 bc_vec_pop(&G.prog.results);
6567 idx = bc_program_index(code, &ip->idx);
6568 addr = bc_vec_item(&func->labels, idx);
6569 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6575 s = bc_program_call(code, &ip->idx);
6579 case BC_INST_INC_PRE:
6580 case BC_INST_DEC_PRE:
6581 case BC_INST_INC_POST:
6582 case BC_INST_DEC_POST:
6584 s = bc_program_incdec(inst);
6597 s = bc_program_return(inst);
6601 case BC_INST_BOOL_OR:
6602 case BC_INST_BOOL_AND:
6604 case BC_INST_REL_EQ:
6605 case BC_INST_REL_LE:
6606 case BC_INST_REL_GE:
6607 case BC_INST_REL_NE:
6608 case BC_INST_REL_LT:
6609 case BC_INST_REL_GT:
6611 s = bc_program_logical(inst);
6617 s = bc_program_read();
6623 s = bc_program_pushVar(code, &ip->idx, false, false);
6627 case BC_INST_ARRAY_ELEM:
6630 s = bc_program_pushArray(code, &ip->idx, inst);
6636 r.t = BC_RESULT_LAST;
6637 bc_vec_push(&G.prog.results, &r);
6645 bc_program_pushGlobal(inst);
6649 case BC_INST_SCALE_FUNC:
6650 case BC_INST_LENGTH:
6653 s = bc_program_builtin(inst);
6659 r.t = BC_RESULT_CONSTANT;
6660 r.d.id.idx = bc_program_index(code, &ip->idx);
6661 bc_vec_push(&G.prog.results, &r);
6667 if (!BC_PROG_STACK(&G.prog.results, 1))
6668 s = BC_STATUS_EXEC_STACK;
6670 bc_vec_pop(&G.prog.results);
6674 case BC_INST_POP_EXEC:
6676 bc_vec_pop(&G.prog.stack);
6681 case BC_INST_PRINT_POP:
6682 case BC_INST_PRINT_STR:
6684 s = bc_program_print(inst, 0);
6690 r.t = BC_RESULT_STR;
6691 r.d.id.idx = bc_program_index(code, &ip->idx);
6692 bc_vec_push(&G.prog.results, &r);
6697 case BC_INST_MULTIPLY:
6698 case BC_INST_DIVIDE:
6699 case BC_INST_MODULUS:
6703 s = bc_program_op(inst);
6707 case BC_INST_BOOL_NOT:
6709 s = bc_program_prep(&ptr, &num);
6712 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6713 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6714 bc_program_retire(&r, BC_RESULT_TEMP);
6721 s = bc_program_negate();
6726 case BC_INST_ASSIGN_POWER:
6727 case BC_INST_ASSIGN_MULTIPLY:
6728 case BC_INST_ASSIGN_DIVIDE:
6729 case BC_INST_ASSIGN_MODULUS:
6730 case BC_INST_ASSIGN_PLUS:
6731 case BC_INST_ASSIGN_MINUS:
6733 case BC_INST_ASSIGN:
6735 s = bc_program_assign(inst);
6739 case BC_INST_MODEXP:
6741 s = bc_program_modexp();
6745 case BC_INST_DIVMOD:
6747 s = bc_program_divmod();
6751 case BC_INST_EXECUTE:
6752 case BC_INST_EXEC_COND:
6754 cond = inst == BC_INST_EXEC_COND;
6755 s = bc_program_execStr(code, &ip->idx, cond);
6759 case BC_INST_PRINT_STACK:
6761 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6762 s = bc_program_print(BC_INST_PRINT, idx);
6766 case BC_INST_CLEAR_STACK:
6768 bc_vec_npop(&G.prog.results, G.prog.results.len);
6772 case BC_INST_STACK_LEN:
6774 bc_program_stackLen();
6778 case BC_INST_DUPLICATE:
6780 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6781 ptr = bc_vec_top(&G.prog.results);
6782 bc_result_copy(&r, ptr);
6783 bc_vec_push(&G.prog.results, &r);
6791 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6793 ptr = bc_vec_item_rev(&G.prog.results, 0);
6794 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6795 memcpy(&r, ptr, sizeof(BcResult));
6796 memcpy(ptr, ptr2, sizeof(BcResult));
6797 memcpy(ptr2, &r, sizeof(BcResult));
6802 case BC_INST_ASCIIFY:
6804 s = bc_program_asciify();
6808 case BC_INST_PRINT_STREAM:
6810 s = bc_program_printStream();
6815 case BC_INST_PUSH_VAR:
6817 bool copy = inst == BC_INST_LOAD;
6818 s = bc_program_pushVar(code, &ip->idx, true, copy);
6822 case BC_INST_PUSH_TO_VAR:
6824 char *name = bc_program_name(code, &ip->idx);
6825 s = bc_program_copyToVar(name, true);
6832 if (G.prog.stack.len <= 2)
6835 bc_vec_npop(&G.prog.stack, 2);
6841 s = bc_program_nquit();
6847 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
6849 // If the stack has changed, pointers may be invalid.
6850 ip = bc_vec_top(&G.prog.stack);
6851 func = bc_vec_item(&G.prog.fns, ip->func);
6852 code = func->code.v;
6858 static void bc_vm_info(void)
6860 printf("%s "BB_VER"\n"
6861 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6862 "Report bugs at: https://github.com/gavinhoward/bc\n"
6863 "This is free software with ABSOLUTELY NO WARRANTY\n"
6867 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6869 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6871 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6872 fprintf(stderr, " %s", file);
6873 fprintf(stderr, bc_err_line + 4 * !line, line);
6875 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6879 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6882 int p = (int) G_posix, w = (int) G_warn;
6883 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6885 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6887 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6888 if (msg) fprintf(stderr, " %s\n", msg);
6889 fprintf(stderr, " %s", file);
6890 fprintf(stderr, bc_err_line + 4 * !line, line);
6892 return s * (!G.ttyin && !!p);
6895 static void bc_vm_envArgs(void)
6898 char *env_args = getenv(bc_args_env_name), *buf;
6900 if (!env_args) return;
6902 G.env_args = xstrdup(env_args);
6905 bc_vec_init(&v, sizeof(char *), NULL);
6906 bc_vec_push(&v, &bc_args_env_name);
6909 if (!isspace(*buf)) {
6910 bc_vec_push(&v, &buf);
6911 while (*buf != 0 && !isspace(*buf)) ++buf;
6912 if (*buf != 0) (*(buf++)) = '\0';
6918 bc_args((int) v.len, (char **) v.v);
6924 static size_t bc_vm_envLen(const char *var)
6926 char *lenv = getenv(var);
6927 size_t i, len = BC_NUM_PRINT_WIDTH;
6930 if (!lenv) return len;
6934 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6936 len = (size_t) atoi(lenv) - 1;
6937 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6940 len = BC_NUM_PRINT_WIDTH;
6945 static BcStatus bc_vm_process(const char *text)
6947 BcStatus s = bc_parse_text(&G.prs, text);
6949 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6952 while (G.prs.l.t.t != BC_LEX_EOF) {
6954 s = G.prs.parse(&G.prs);
6956 if (s == BC_STATUS_LIMITS) {
6959 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
6960 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
6961 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
6962 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
6963 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
6964 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
6965 printf("Max Exponent = %lu\n", BC_MAX_EXP);
6966 printf("Number of Vars = %lu\n", BC_MAX_VARS);
6969 s = BC_STATUS_SUCCESS;
6972 if (s == BC_STATUS_QUIT) return s;
6973 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6978 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6979 s = bc_program_exec();
6980 if (!s && G.tty) fflush(stdout);
6981 if (s && s != BC_STATUS_QUIT)
6982 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6988 static BcStatus bc_vm_file(const char *file)
6996 data = bc_read_file(file);
6997 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
6999 bc_lex_file(&G.prs.l, file);
7000 s = bc_vm_process(data);
7003 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7004 ip = bc_vec_item(&G.prog.stack, 0);
7006 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7013 static BcStatus bc_vm_stdin(void)
7017 size_t len, i, str = 0;
7018 bool comment = false;
7020 G.prog.file = bc_program_stdin_name;
7021 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7023 bc_vec_init(&buffer, sizeof(char), NULL);
7024 bc_vec_init(&buf, sizeof(char), NULL);
7025 bc_vec_pushByte(&buffer, '\0');
7027 // This loop is complex because the vm tries not to send any lines that end
7028 // with a backslash to the parser. The reason for that is because the parser
7029 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7030 // case, and for strings and comments, the parser will expect more stuff.
7031 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7033 char *string = buf.v;
7038 if (str && buf.v[0] == G.send)
7040 else if (buf.v[0] == G.sbgn)
7043 else if (len > 1 || comment) {
7045 for (i = 0; i < len; ++i) {
7047 bool notend = len > i + 1;
7050 if (i - 1 > len || string[i - 1] != '\\') {
7051 if (G.sbgn == G.send)
7053 else if (c == G.send)
7055 else if (c == G.sbgn)
7059 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7063 else if (c == '*' && notend && comment && string[i + 1] == '/')
7067 if (str || comment || string[len - 2] == '\\') {
7068 bc_vec_concat(&buffer, buf.v);
7073 bc_vec_concat(&buffer, buf.v);
7074 s = bc_vm_process(buffer.v);
7077 bc_vec_npop(&buffer, buffer.len);
7080 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7082 // INPUT_EOF will always happen when stdin is
7083 // closed. It's not a problem in that case.
7084 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7085 s = BC_STATUS_SUCCESS;
7088 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7091 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7096 bc_vec_free(&buffer);
7100 static BcStatus bc_vm_exec(void)
7102 BcStatus s = BC_STATUS_SUCCESS;
7106 if (G.flags & BC_FLAG_L) {
7108 bc_lex_file(&G.prs.l, bc_lib_name);
7109 s = bc_parse_text(&G.prs, bc_lib);
7111 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7114 s = bc_program_exec();
7119 for (i = 0; !s && i < G.files.len; ++i)
7120 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7121 if (s && s != BC_STATUS_QUIT) return s;
7123 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7124 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7126 if (s == BC_STATUS_QUIT)
7127 s = BC_STATUS_SUCCESS;
7131 #if ENABLE_FEATURE_CLEAN_UP
7132 static void bc_program_free()
7134 bc_num_free(&G.prog.ib);
7135 bc_num_free(&G.prog.ob);
7136 bc_num_free(&G.prog.hexb);
7138 bc_num_free(&G.prog.strmb);
7140 bc_vec_free(&G.prog.fns);
7141 bc_vec_free(&G.prog.fn_map);
7142 bc_vec_free(&G.prog.vars);
7143 bc_vec_free(&G.prog.var_map);
7144 bc_vec_free(&G.prog.arrs);
7145 bc_vec_free(&G.prog.arr_map);
7146 bc_vec_free(&G.prog.strs);
7147 bc_vec_free(&G.prog.consts);
7148 bc_vec_free(&G.prog.results);
7149 bc_vec_free(&G.prog.stack);
7150 bc_num_free(&G.prog.last);
7151 bc_num_free(&G.prog.zero);
7152 bc_num_free(&G.prog.one);
7155 static void bc_vm_free(void)
7157 bc_vec_free(&G.files);
7159 bc_parse_free(&G.prs);
7164 static void bc_program_init(size_t line_len)
7169 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7170 memset(&ip, 0, sizeof(BcInstPtr));
7172 /* G.prog.nchars = G.prog.scale = 0; - already is */
7173 G.prog.len = line_len;
7175 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7176 bc_num_ten(&G.prog.ib);
7179 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7180 bc_num_ten(&G.prog.ob);
7183 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7184 bc_num_ten(&G.prog.hexb);
7185 G.prog.hexb.num[0] = 6;
7188 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7189 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7192 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7193 bc_num_zero(&G.prog.last);
7195 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7196 bc_num_zero(&G.prog.zero);
7198 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7199 bc_num_one(&G.prog.one);
7201 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7202 bc_map_init(&G.prog.fn_map);
7204 bc_program_addFunc(xstrdup(bc_func_main), &idx);
7205 bc_program_addFunc(xstrdup(bc_func_read), &idx);
7207 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7208 bc_map_init(&G.prog.var_map);
7210 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7211 bc_map_init(&G.prog.arr_map);
7213 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7214 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7215 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7216 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7217 bc_vec_push(&G.prog.stack, &ip);
7220 static void bc_vm_init(const char *env_len)
7222 size_t len = bc_vm_envLen(env_len);
7224 #if ENABLE_FEATURE_BC_SIGNALS
7225 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7228 bc_vec_init(&G.files, sizeof(char *), NULL);
7231 if (getenv("POSIXLY_CORRECT"))
7232 G.flags |= BC_FLAG_S;
7236 bc_program_init(len);
7238 bc_parse_init(&G.prs, BC_PROG_MAIN);
7240 dc_parse_init(&G.prs, BC_PROG_MAIN);
7244 static BcStatus bc_vm_run(int argc, char *argv[],
7245 const char *env_len)
7249 bc_vm_init(env_len);
7250 bc_args(argc, argv);
7252 G.ttyin = isatty(0);
7253 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7255 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7258 #if ENABLE_FEATURE_CLEAN_UP
7265 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7266 int bc_main(int argc, char **argv)
7269 G.sbgn = G.send = '"';
7271 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7276 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7277 int dc_main(int argc, char **argv)
7283 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");