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_expr(BcParse *p, uint8_t flags, BcParseNext next);
726 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
728 static BcStatus dc_lex_token(BcLex *l);
730 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
734 typedef struct BcProgram {
775 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
777 #define BC_PROG_MAIN (0)
778 #define BC_PROG_READ (1)
781 #define BC_PROG_REQ_FUNCS (2)
784 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
785 #define BC_PROG_NUM(r, n) \
786 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
788 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
790 static void bc_program_addFunc(char *name, size_t *idx);
791 static BcStatus bc_program_reset(BcStatus s);
793 #define BC_FLAG_X (1 << 0)
794 #define BC_FLAG_W (1 << 1)
795 #define BC_FLAG_V (1 << 2)
796 #define BC_FLAG_S (1 << 3)
797 #define BC_FLAG_Q (1 << 4)
798 #define BC_FLAG_L (1 << 5)
799 #define BC_FLAG_I (1 << 6)
801 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
802 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
804 #define BC_MAX_OBASE ((unsigned) 999)
805 #define BC_MAX_DIM ((unsigned) INT_MAX)
806 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
807 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
808 #define BC_MAX_NAME BC_MAX_STRING
809 #define BC_MAX_NUM BC_MAX_STRING
810 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
811 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
828 #define G (*ptr_to_globals)
829 #define INIT_G() do { \
830 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
832 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
833 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
834 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
835 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
838 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
841 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
845 static void bc_vm_info(void);
847 static const char bc_err_fmt[] = "\n%s error: %s\n";
848 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
849 static const char bc_err_line[] = ":%zu\n\n";
851 static const char *bc_errs[] = {
863 static const uint8_t bc_err_ids[] = {
864 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
865 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
869 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
870 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
871 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
876 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
877 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
878 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
879 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
881 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
883 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
884 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
885 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
887 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
890 static const char *bc_err_msgs[] = {
893 "memory allocation error",
896 "path is a directory:",
899 "string end could not be found",
900 "comment end could not be found",
909 "bad print statement",
910 "bad function definition",
911 "bad assignment: left side must be scale, ibase, "
912 "obase, last, var, or array element",
913 "no auto variable found",
914 "function parameter or auto var has the same name as another",
915 "block end could not be found",
918 "non integer number",
923 "could not open file:",
924 "mismatched parameters",
925 "undefined function",
926 "file is not executable:",
927 "number too long: must be [1, BC_NUM_MAX]",
928 "name too long: must be [1, BC_NAME_MAX]",
929 "string too long: must be [1, BC_STRING_MAX]",
930 "array too long; must be [1, BC_DIM_MAX]",
931 "bad ibase; must be [2, 16]",
932 "bad scale; must be [0, BC_SCALE_MAX]",
933 "bad read() expression",
934 "read() call inside of a read() call",
935 "variable is wrong type",
936 "bad obase; must be [2, BC_BASE_MAX]",
937 "signal caught and not handled",
938 "stack has too few elements",
940 "index is out of bounds",
941 "item already exists",
944 "POSIX only allows one character names; the following is bad:",
945 "POSIX does not allow '#' script comments",
946 "POSIX does not allow the following keyword:",
947 "POSIX does not allow a period ('.') as a shortcut for the last result",
948 "POSIX requires parentheses around return expressions",
949 "POSIX does not allow boolean operators; the following is bad:",
950 "POSIX does not allow comparison operators outside if or loops",
951 "POSIX requires exactly one comparison operator per condition",
952 "POSIX does not allow an empty init expression in a for loop",
953 "POSIX does not allow an empty condition expression in a for loop",
954 "POSIX does not allow an empty update expression in a for loop",
955 "POSIX requires the left brace be on the same line as the function header",
961 static const BcLexKeyword bc_lex_kws[20] = {
962 BC_LEX_KW_ENTRY("auto", 4, true),
963 BC_LEX_KW_ENTRY("break", 5, true),
964 BC_LEX_KW_ENTRY("continue", 8, false),
965 BC_LEX_KW_ENTRY("define", 6, true),
966 BC_LEX_KW_ENTRY("else", 4, false),
967 BC_LEX_KW_ENTRY("for", 3, true),
968 BC_LEX_KW_ENTRY("halt", 4, false),
969 BC_LEX_KW_ENTRY("ibase", 5, true),
970 BC_LEX_KW_ENTRY("if", 2, true),
971 BC_LEX_KW_ENTRY("last", 4, false),
972 BC_LEX_KW_ENTRY("length", 6, true),
973 BC_LEX_KW_ENTRY("limits", 6, false),
974 BC_LEX_KW_ENTRY("obase", 5, true),
975 BC_LEX_KW_ENTRY("print", 5, false),
976 BC_LEX_KW_ENTRY("quit", 4, true),
977 BC_LEX_KW_ENTRY("read", 4, false),
978 BC_LEX_KW_ENTRY("return", 6, true),
979 BC_LEX_KW_ENTRY("scale", 5, true),
980 BC_LEX_KW_ENTRY("sqrt", 4, true),
981 BC_LEX_KW_ENTRY("while", 5, true),
984 // This is an array that corresponds to token types. An entry is
985 // true if the token is valid in an expression, false otherwise.
986 static const bool bc_parse_exprs[] = {
987 false, false, true, true, true, true, true, true, true, true, true, true,
988 true, true, true, true, true, true, true, true, true, true, true, true,
989 true, true, true, false, false, true, true, false, false, false, false,
990 false, false, false, true, true, false, false, false, false, false, false,
991 false, true, false, true, true, true, true, false, false, true, false, true,
995 // This is an array of data for operators that correspond to token types.
996 static const BcOp bc_parse_ops[] = {
997 { 0, false }, { 0, false },
1000 { 3, true }, { 3, true }, { 3, true },
1001 { 4, true }, { 4, true },
1002 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1004 { 7, true }, { 7, true },
1005 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1006 { 5, false }, { 5, false },
1009 // These identify what tokens can come after expressions in certain cases.
1010 static const BcParseNext bc_parse_next_expr =
1011 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1012 static const BcParseNext bc_parse_next_param =
1013 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1014 static const BcParseNext bc_parse_next_print =
1015 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1016 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1017 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1018 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1019 static const BcParseNext bc_parse_next_read =
1020 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1024 static const BcLexType dc_lex_regs[] = {
1025 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1026 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1027 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1031 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1033 static const BcLexType dc_lex_tokens[] = {
1034 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1035 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1036 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1037 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1038 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1039 BC_LEX_INVALID, BC_LEX_INVALID,
1040 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1041 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1042 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1043 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1044 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1045 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1046 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1047 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1048 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1049 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1050 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1051 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1052 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1053 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1054 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1055 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1056 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1057 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1061 static const BcInst dc_parse_insts[] = {
1062 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1063 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1064 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1065 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1066 BC_INST_INVALID, BC_INST_INVALID,
1067 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1069 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1070 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1071 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1072 BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_INVALID, 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, BC_INST_IBASE,
1076 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1077 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1078 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1079 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1080 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1081 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1082 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1084 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1088 static const BcNumBinaryOp bc_program_ops[] = {
1089 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1092 static const char bc_program_stdin_name[] = "<stdin>";
1093 static const char bc_program_ready_msg[] = "ready for more input\n";
1096 static const char *bc_lib_name = "gen/lib.bc";
1098 static const char bc_lib[] = {
1099 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1100 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1101 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1102 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,
1103 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1104 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1105 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,
1106 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1107 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1108 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,
1109 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1110 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1111 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1112 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1113 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1114 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1115 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1116 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1117 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1118 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1119 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1120 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1121 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1122 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,
1123 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1124 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,
1125 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1126 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1127 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1128 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1129 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1130 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,
1131 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1132 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1133 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1134 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1135 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,
1136 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1137 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1138 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1139 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1140 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1141 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1142 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1143 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1144 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1145 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1146 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,
1147 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,
1148 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1149 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,
1150 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,
1151 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,
1152 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1153 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1154 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,
1155 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,
1156 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,
1157 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1158 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,
1159 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1160 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1161 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1162 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,
1163 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1164 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1165 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1166 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1167 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1168 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1169 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1170 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1171 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1172 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1173 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1174 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1175 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1176 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1177 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1178 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1182 static void bc_vec_grow(BcVec *v, size_t n)
1184 size_t cap = v->cap * 2;
1185 while (cap < v->len + n) cap *= 2;
1186 v->v = xrealloc(v->v, v->size * cap);
1190 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1193 v->cap = BC_VEC_START_CAP;
1196 v->v = xmalloc(esize * BC_VEC_START_CAP);
1199 static void bc_vec_expand(BcVec *v, size_t req)
1202 v->v = xrealloc(v->v, v->size * req);
1207 static void bc_vec_npop(BcVec *v, size_t n)
1212 size_t len = v->len - n;
1213 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1217 static void bc_vec_push(BcVec *v, const void *data)
1219 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1220 memmove(v->v + (v->size * v->len), data, v->size);
1224 static void bc_vec_pushByte(BcVec *v, char data)
1226 bc_vec_push(v, &data);
1229 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1232 bc_vec_push(v, data);
1237 if (v->len == v->cap) bc_vec_grow(v, 1);
1239 ptr = v->v + v->size * idx;
1241 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1242 memmove(ptr, data, v->size);
1246 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1248 bc_vec_npop(v, v->len);
1249 bc_vec_expand(v, len + 1);
1250 memcpy(v->v, str, len);
1253 bc_vec_pushByte(v, '\0');
1256 static void bc_vec_concat(BcVec *v, const char *str)
1260 if (v->len == 0) bc_vec_pushByte(v, '\0');
1262 len = v->len + strlen(str);
1264 if (v->cap < len) bc_vec_grow(v, len - v->len);
1270 static void *bc_vec_item(const BcVec *v, size_t idx)
1272 return v->v + v->size * idx;
1275 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1277 return v->v + v->size * (v->len - idx - 1);
1280 static void bc_vec_free(void *vec)
1282 BcVec *v = (BcVec *) vec;
1283 bc_vec_npop(v, v->len);
1287 static size_t bc_map_find(const BcVec *v, const void *ptr)
1289 size_t low = 0, high = v->len;
1291 while (low < high) {
1293 size_t mid = (low + high) / 2;
1294 BcId *id = bc_vec_item(v, mid);
1295 int result = bc_id_cmp(ptr, id);
1299 else if (result < 0)
1308 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1310 BcStatus s = BC_STATUS_SUCCESS;
1312 *i = bc_map_find(v, ptr);
1315 bc_vec_push(v, ptr);
1316 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1317 s = BC_STATUS_VEC_ITEM_EXISTS;
1319 bc_vec_pushAt(v, ptr, *i);
1324 static size_t bc_map_index(const BcVec *v, const void *ptr)
1326 size_t i = bc_map_find(v, ptr);
1327 if (i >= v->len) return BC_VEC_INVALID_IDX;
1328 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1331 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1336 bc_vec_npop(vec, vec->len);
1339 #if ENABLE_FEATURE_BC_SIGNALS
1340 if (bb_got_signal) { /* ^C was pressed */
1342 bb_got_signal = 0; /* resets G_interrupt to zero */
1344 ? "\ninterrupt (type \"quit\" to exit)\n"
1345 : "\ninterrupt (type \"q\" to exit)\n"
1349 if (G.ttyin && !G_posix)
1350 fputs(prompt, stderr);
1353 #if ENABLE_FEATURE_BC_SIGNALS
1358 if (ferror(stdout) || ferror(stderr))
1359 bb_perror_msg_and_die("output error");
1363 #if ENABLE_FEATURE_BC_SIGNALS
1364 if (bb_got_signal) /* ^C was pressed */
1369 #if ENABLE_FEATURE_BC_SIGNALS
1370 if (errno == EINTR) {
1376 bb_perror_msg_and_die("input error");
1377 return BC_STATUS_INPUT_EOF;
1380 c = (signed char) i;
1381 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1382 bc_vec_push(vec, &c);
1383 } while (c != '\n');
1385 bc_vec_pushByte(vec, '\0');
1387 return BC_STATUS_SUCCESS;
1390 static char* bc_read_file(const char *path)
1393 size_t size = ((size_t) -1);
1396 buf = xmalloc_open_read_close(path, &size);
1398 for (i = 0; i < size; ++i) {
1399 if (BC_READ_BIN_CHAR(buf[i])) {
1409 static void bc_args(int argc, char **argv)
1414 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1415 G.flags = getopt32long(argv, "xwvsqli",
1416 "extended-register\0" No_argument "x"
1417 "warn\0" No_argument "w"
1418 "version\0" No_argument "v"
1419 "standard\0" No_argument "s"
1420 "quiet\0" No_argument "q"
1421 "mathlib\0" No_argument "l"
1422 "interactive\0" No_argument "i"
1425 G.flags = getopt32(argv, "xwvsqli");
1428 if (G.flags & BC_FLAG_V) bc_vm_info();
1429 // should not be necessary, getopt32() handles this??
1430 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1432 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1435 static void bc_num_setToZero(BcNum *n, size_t scale)
1442 static void bc_num_zero(BcNum *n)
1444 bc_num_setToZero(n, 0);
1447 static void bc_num_one(BcNum *n)
1449 bc_num_setToZero(n, 0);
1454 static void bc_num_ten(BcNum *n)
1456 bc_num_setToZero(n, 0);
1462 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1466 for (i = 0; i < len; ++i) {
1467 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1474 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1478 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1479 return BC_NUM_NEG(i + 1, c < 0);
1482 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1484 size_t i, min, a_int, b_int, diff;
1485 BcDig *max_num, *min_num;
1486 bool a_max, neg = false;
1489 if (a == b) return 0;
1490 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1491 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1501 a_int = BC_NUM_INT(a);
1502 b_int = BC_NUM_INT(b);
1504 a_max = (a->rdx > b->rdx);
1506 if (a_int != 0) return (ssize_t) a_int;
1510 diff = a->rdx - b->rdx;
1511 max_num = a->num + diff;
1516 diff = b->rdx - a->rdx;
1517 max_num = b->num + diff;
1521 cmp = bc_num_compare(max_num, min_num, b_int + min);
1522 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1524 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1525 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1531 static void bc_num_truncate(BcNum *n, size_t places)
1533 if (places == 0) return;
1539 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1543 static void bc_num_extend(BcNum *n, size_t places)
1545 size_t len = n->len + places;
1549 if (n->cap < len) bc_num_expand(n, len);
1551 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1552 memset(n->num, 0, sizeof(BcDig) * places);
1559 static void bc_num_clean(BcNum *n)
1561 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1564 else if (n->len < n->rdx)
1568 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1571 bc_num_extend(n, scale - n->rdx);
1573 bc_num_truncate(n, n->rdx - scale);
1576 if (n->len != 0) n->neg = !neg1 != !neg2;
1579 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1584 b->len = n->len - idx;
1586 a->rdx = b->rdx = 0;
1588 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1589 memcpy(a->num, n->num, idx * sizeof(BcDig));
1600 static BcStatus bc_num_shift(BcNum *n, size_t places)
1602 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1603 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1605 if (n->rdx >= places)
1608 bc_num_extend(n, places - n->rdx);
1614 return BC_STATUS_SUCCESS;
1617 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1626 return bc_num_div(&one, a, b, scale);
1629 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1631 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1632 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1635 // Because this function doesn't need to use scale (per the bc spec),
1636 // I am hijacking it to say whether it's doing an add or a subtract.
1640 if (sub && c->len) c->neg = !c->neg;
1641 return BC_STATUS_SUCCESS;
1643 else if (b->len == 0) {
1645 return BC_STATUS_SUCCESS;
1649 c->rdx = BC_MAX(a->rdx, b->rdx);
1650 min_rdx = BC_MIN(a->rdx, b->rdx);
1653 if (a->rdx > b->rdx) {
1654 diff = a->rdx - b->rdx;
1656 ptr_a = a->num + diff;
1660 diff = b->rdx - a->rdx;
1663 ptr_b = b->num + diff;
1666 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1669 a_int = BC_NUM_INT(a);
1670 b_int = BC_NUM_INT(b);
1672 if (a_int > b_int) {
1683 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1684 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1686 ptr_c[i] = (BcDig)(in % 10);
1689 for (; i < max + min_rdx; ++i, ++c->len) {
1690 in = ((int) ptr[i]) + carry;
1692 ptr_c[i] = (BcDig)(in % 10);
1695 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1697 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1700 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1703 BcNum *minuend, *subtrahend;
1705 bool aneg, bneg, neg;
1707 // Because this function doesn't need to use scale (per the bc spec),
1708 // I am hijacking it to say whether it's doing an add or a subtract.
1712 if (sub && c->len) c->neg = !c->neg;
1713 return BC_STATUS_SUCCESS;
1715 else if (b->len == 0) {
1717 return BC_STATUS_SUCCESS;
1722 a->neg = b->neg = false;
1724 cmp = bc_num_cmp(a, b);
1730 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1731 return BC_STATUS_SUCCESS;
1740 if (sub) neg = !neg;
1745 bc_num_copy(c, minuend);
1748 if (c->rdx < subtrahend->rdx) {
1749 bc_num_extend(c, subtrahend->rdx - c->rdx);
1753 start = c->rdx - subtrahend->rdx;
1755 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1759 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1762 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1767 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1768 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1769 bool aone = BC_NUM_ONE(a);
1771 if (a->len == 0 || b->len == 0) {
1773 return BC_STATUS_SUCCESS;
1775 else if (aone || BC_NUM_ONE(b)) {
1776 bc_num_copy(c, aone ? b : a);
1777 return BC_STATUS_SUCCESS;
1780 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1781 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1783 bc_num_expand(c, a->len + b->len + 1);
1785 memset(c->num, 0, sizeof(BcDig) * c->cap);
1786 c->len = carry = len = 0;
1788 for (i = 0; i < b->len; ++i) {
1790 for (j = 0; j < a->len; ++j) {
1791 int in = (int) c->num[i + j];
1792 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1794 c->num[i + j] = (BcDig)(in % 10);
1797 c->num[i + j] += (BcDig) carry;
1798 len = BC_MAX(len, i + j + !!carry);
1804 return BC_STATUS_SUCCESS;
1807 bc_num_init(&l1, max);
1808 bc_num_init(&h1, max);
1809 bc_num_init(&l2, max);
1810 bc_num_init(&h2, max);
1811 bc_num_init(&m1, max);
1812 bc_num_init(&m2, max);
1813 bc_num_init(&z0, max);
1814 bc_num_init(&z1, max);
1815 bc_num_init(&z2, max);
1816 bc_num_init(&temp, max + max);
1818 bc_num_split(a, max2, &l1, &h1);
1819 bc_num_split(b, max2, &l2, &h2);
1821 s = bc_num_add(&h1, &l1, &m1, 0);
1823 s = bc_num_add(&h2, &l2, &m2, 0);
1826 s = bc_num_k(&h1, &h2, &z0);
1828 s = bc_num_k(&m1, &m2, &z1);
1830 s = bc_num_k(&l1, &l2, &z2);
1833 s = bc_num_sub(&z1, &z0, &temp, 0);
1835 s = bc_num_sub(&temp, &z2, &z1, 0);
1838 s = bc_num_shift(&z0, max2 * 2);
1840 s = bc_num_shift(&z1, max2);
1842 s = bc_num_add(&z0, &z1, &temp, 0);
1844 s = bc_num_add(&temp, &z2, c, 0);
1860 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1864 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1866 scale = BC_MAX(scale, a->rdx);
1867 scale = BC_MAX(scale, b->rdx);
1868 scale = BC_MIN(a->rdx + b->rdx, scale);
1869 maxrdx = BC_MAX(maxrdx, scale);
1871 bc_num_init(&cpa, a->len);
1872 bc_num_init(&cpb, b->len);
1874 bc_num_copy(&cpa, a);
1875 bc_num_copy(&cpb, b);
1876 cpa.neg = cpb.neg = false;
1878 s = bc_num_shift(&cpa, maxrdx);
1880 s = bc_num_shift(&cpb, maxrdx);
1882 s = bc_num_k(&cpa, &cpb, c);
1886 bc_num_expand(c, c->len + maxrdx);
1888 if (c->len < maxrdx) {
1889 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1894 bc_num_retireMul(c, scale, a->neg, b->neg);
1902 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1904 BcStatus s = BC_STATUS_SUCCESS;
1911 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1912 else if (a->len == 0) {
1913 bc_num_setToZero(c, scale);
1914 return BC_STATUS_SUCCESS;
1916 else if (BC_NUM_ONE(b)) {
1918 bc_num_retireMul(c, scale, a->neg, b->neg);
1919 return BC_STATUS_SUCCESS;
1922 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1923 bc_num_copy(&cp, a);
1927 bc_num_expand(&cp, len + 2);
1928 bc_num_extend(&cp, len - cp.len);
1931 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1933 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1935 if (b->rdx == b->len) {
1936 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1940 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1942 // We want an extra zero in front to make things simpler.
1943 cp.num[cp.len++] = 0;
1946 bc_num_expand(c, cp.len);
1949 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1954 for (i = end - 1; !s && i < end; --i) {
1956 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1957 bc_num_subArrays(n, p, len);
1961 bc_num_retireMul(c, scale, a->neg, b->neg);
1964 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1967 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1968 BcNum *restrict d, size_t scale, size_t ts)
1974 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1977 bc_num_setToZero(d, ts);
1978 return BC_STATUS_SUCCESS;
1981 bc_num_init(&temp, d->cap);
1982 bc_num_d(a, b, c, scale);
1984 if (scale != 0) scale = ts;
1986 s = bc_num_m(c, b, &temp, scale);
1988 s = bc_num_sub(a, &temp, d, scale);
1991 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1994 bc_num_retireMul(d, ts, a->neg, b->neg);
2002 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2006 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2008 bc_num_init(&c1, len);
2009 s = bc_num_r(a, b, &c1, c, scale, ts);
2015 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2017 BcStatus s = BC_STATUS_SUCCESS;
2020 size_t i, powrdx, resrdx;
2023 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2027 return BC_STATUS_SUCCESS;
2029 else if (a->len == 0) {
2030 bc_num_setToZero(c, scale);
2031 return BC_STATUS_SUCCESS;
2033 else if (BC_NUM_ONE(b)) {
2037 s = bc_num_inv(a, c, scale);
2044 s = bc_num_ulong(b, &pow);
2047 bc_num_init(©, a->len);
2048 bc_num_copy(©, a);
2050 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2054 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2056 s = bc_num_mul(©, ©, ©, powrdx);
2060 bc_num_copy(c, ©);
2062 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2065 s = bc_num_mul(©, ©, ©, powrdx);
2070 s = bc_num_mul(c, ©, c, resrdx);
2076 s = bc_num_inv(c, c, scale);
2080 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2082 // We can't use bc_num_clean() here.
2083 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2084 if (zero) bc_num_setToZero(c, scale);
2091 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2092 BcNumBinaryOp op, size_t req)
2095 BcNum num2, *ptr_a, *ptr_b;
2100 memcpy(ptr_a, c, sizeof(BcNum));
2109 memcpy(ptr_b, c, sizeof(BcNum));
2117 bc_num_init(c, req);
2119 bc_num_expand(c, req);
2121 s = op(ptr_a, ptr_b, c, scale);
2123 if (init) bc_num_free(&num2);
2128 static bool bc_num_strValid(const char *val, size_t base)
2131 bool small, radix = false;
2132 size_t i, len = strlen(val);
2134 if (!len) return true;
2137 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2139 for (i = 0; i < len; ++i) {
2145 if (radix) return false;
2151 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2158 static void bc_num_parseDecimal(BcNum *n, const char *val)
2164 for (i = 0; val[i] == '0'; ++i);
2171 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2172 bc_num_expand(n, len);
2175 ptr = strchr(val, '.');
2177 // Explicitly test for NULL here to produce either a 0 or 1.
2178 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2181 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2182 n->num[n->len] = val[i] - '0';
2186 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2189 BcNum temp, mult, result;
2193 size_t i, digits, len = strlen(val);
2197 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2200 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2201 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2203 for (i = 0; i < len; ++i) {
2206 if (c == '.') break;
2208 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2210 s = bc_num_mul(n, base, &mult, 0);
2211 if (s) goto int_err;
2212 bc_num_ulong2num(&temp, v);
2213 s = bc_num_add(&mult, &temp, n, 0);
2214 if (s) goto int_err;
2219 if (c == 0) goto int_err;
2222 bc_num_init(&result, base->len);
2223 bc_num_zero(&result);
2226 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2231 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2233 s = bc_num_mul(&result, base, &result, 0);
2235 bc_num_ulong2num(&temp, v);
2236 s = bc_num_add(&result, &temp, &result, 0);
2238 s = bc_num_mul(&mult, base, &mult, 0);
2242 s = bc_num_div(&result, &mult, &result, digits);
2244 s = bc_num_add(n, &result, n, digits);
2248 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2254 bc_num_free(&result);
2260 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2262 if (*nchars == line_len - 1) {
2270 static void bc_num_printChar(size_t num, size_t width, bool radix,
2271 size_t *nchars, size_t line_len)
2273 (void) radix, (void) line_len;
2274 bb_putchar((char) num);
2275 *nchars = *nchars + width;
2279 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2280 size_t *nchars, size_t line_len)
2284 bc_num_printNewline(nchars, line_len);
2285 bb_putchar(radix ? '.' : ' ');
2288 bc_num_printNewline(nchars, line_len);
2289 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2292 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2294 bc_num_printNewline(nchars, line_len);
2297 bb_putchar(((char) dig) + '0');
2301 static void bc_num_printHex(size_t num, size_t width, bool radix,
2302 size_t *nchars, size_t line_len)
2305 bc_num_printNewline(nchars, line_len);
2310 bc_num_printNewline(nchars, line_len);
2311 bb_putchar(bb_hexdigits_upcase[num]);
2312 *nchars = *nchars + width;
2315 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2317 size_t i, rdx = n->rdx - 1;
2319 if (n->neg) bb_putchar('-');
2320 (*nchars) += n->neg;
2322 for (i = n->len - 1; i < n->len; --i)
2323 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2326 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2327 size_t *nchars, size_t len, BcNumDigitOp print)
2331 BcNum intp, fracp, digit, frac_len;
2332 unsigned long dig, *ptr;
2337 print(0, width, false, nchars, len);
2338 return BC_STATUS_SUCCESS;
2341 bc_vec_init(&stack, sizeof(long), NULL);
2342 bc_num_init(&intp, n->len);
2343 bc_num_init(&fracp, n->rdx);
2344 bc_num_init(&digit, width);
2345 bc_num_init(&frac_len, BC_NUM_INT(n));
2346 bc_num_copy(&intp, n);
2347 bc_num_one(&frac_len);
2349 bc_num_truncate(&intp, intp.rdx);
2350 s = bc_num_sub(n, &intp, &fracp, 0);
2353 while (intp.len != 0) {
2354 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2356 s = bc_num_ulong(&digit, &dig);
2358 bc_vec_push(&stack, &dig);
2361 for (i = 0; i < stack.len; ++i) {
2362 ptr = bc_vec_item_rev(&stack, i);
2363 print(*ptr, width, false, nchars, len);
2366 if (!n->rdx) goto err;
2368 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2369 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2371 s = bc_num_ulong(&fracp, &dig);
2373 bc_num_ulong2num(&intp, dig);
2374 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2376 print(dig, width, radix, nchars, len);
2377 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2382 bc_num_free(&frac_len);
2383 bc_num_free(&digit);
2384 bc_num_free(&fracp);
2386 bc_vec_free(&stack);
2390 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2391 size_t *nchars, size_t line_len)
2398 if (neg) bb_putchar('-');
2403 if (base_t <= BC_NUM_MAX_IBASE) {
2405 print = bc_num_printHex;
2408 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2409 print = bc_num_printDigits;
2412 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2419 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2421 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2425 static void bc_num_init(BcNum *n, size_t req)
2427 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2428 memset(n, 0, sizeof(BcNum));
2429 n->num = xmalloc(req);
2433 static void bc_num_expand(BcNum *n, size_t req)
2435 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2437 n->num = xrealloc(n->num, req);
2442 static void bc_num_free(void *num)
2444 free(((BcNum *) num)->num);
2447 static void bc_num_copy(BcNum *d, BcNum *s)
2450 bc_num_expand(d, s->cap);
2454 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2458 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2461 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2464 bc_num_parseDecimal(n, val);
2466 bc_num_parseBase(n, val, base);
2468 return BC_STATUS_SUCCESS;
2471 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2472 size_t *nchars, size_t line_len)
2474 BcStatus s = BC_STATUS_SUCCESS;
2476 bc_num_printNewline(nchars, line_len);
2482 else if (base_t == 10)
2483 bc_num_printDecimal(n, nchars, line_len);
2485 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2495 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2500 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2502 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2504 unsigned long prev = *result, powprev = pow;
2506 *result += ((unsigned long) n->num[i]) * pow;
2509 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2512 return BC_STATUS_SUCCESS;
2515 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2523 if (val == 0) return;
2525 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2526 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2529 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2531 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2533 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2536 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2538 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2540 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2543 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2545 size_t req = BC_NUM_MREQ(a, b, scale);
2546 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2549 static BcStatus bc_num_div(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_d, req);
2555 static BcStatus bc_num_mod(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_rem, req);
2561 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2563 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2566 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2569 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2570 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2571 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2573 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2574 bc_num_expand(b, req);
2577 bc_num_setToZero(b, scale);
2578 return BC_STATUS_SUCCESS;
2581 return BC_STATUS_MATH_NEGATIVE;
2582 else if (BC_NUM_ONE(a)) {
2584 bc_num_extend(b, scale);
2585 return BC_STATUS_SUCCESS;
2588 scale = BC_MAX(scale, a->rdx) + 1;
2589 len = a->len + scale;
2591 bc_num_init(&num1, len);
2592 bc_num_init(&num2, len);
2593 bc_num_init(&half, BC_NUM_DEF_SIZE);
2599 bc_num_init(&f, len);
2600 bc_num_init(&fprime, len);
2606 pow = BC_NUM_INT(a);
2615 pow -= 2 - (pow & 1);
2617 bc_num_extend(x0, pow);
2619 // Make sure to move the radix back.
2623 x0->rdx = digs = digs1 = 0;
2625 len = BC_NUM_INT(x0) + resrdx - 1;
2627 while (cmp != 0 || digs < len) {
2629 s = bc_num_div(a, x0, &f, resrdx);
2631 s = bc_num_add(x0, &f, &fprime, resrdx);
2633 s = bc_num_mul(&fprime, &half, x1, resrdx);
2636 cmp = bc_num_cmp(x1, x0);
2637 digs = x1->len - (unsigned long long) llabs(cmp);
2639 if (cmp == cmp2 && digs == digs1)
2644 resrdx += times > 4;
2657 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2660 bc_num_free(&fprime);
2668 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2674 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2677 memcpy(&num2, c, sizeof(BcNum));
2679 bc_num_init(c, len);
2684 bc_num_expand(c, len);
2687 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2689 if (init) bc_num_free(&num2);
2695 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2698 BcNum base, exp, two, temp;
2700 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2701 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2702 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2704 bc_num_expand(d, c->len);
2705 bc_num_init(&base, c->len);
2706 bc_num_init(&exp, b->len);
2707 bc_num_init(&two, BC_NUM_DEF_SIZE);
2708 bc_num_init(&temp, b->len);
2714 s = bc_num_rem(a, c, &base, 0);
2716 bc_num_copy(&exp, b);
2718 while (exp.len != 0) {
2720 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2723 if (BC_NUM_ONE(&temp)) {
2724 s = bc_num_mul(d, &base, &temp, 0);
2726 s = bc_num_rem(&temp, c, d, 0);
2730 s = bc_num_mul(&base, &base, &temp, 0);
2732 s = bc_num_rem(&temp, c, &base, 0);
2745 static int bc_id_cmp(const void *e1, const void *e2)
2747 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2750 static void bc_id_free(void *id)
2752 free(((BcId *) id)->name);
2755 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2760 for (i = 0; i < f->autos.len; ++i) {
2761 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2762 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2768 bc_vec_push(&f->autos, &a);
2770 return BC_STATUS_SUCCESS;
2773 static void bc_func_init(BcFunc *f)
2775 bc_vec_init(&f->code, sizeof(char), NULL);
2776 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2777 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2781 static void bc_func_free(void *func)
2783 BcFunc *f = (BcFunc *) func;
2784 bc_vec_free(&f->code);
2785 bc_vec_free(&f->autos);
2786 bc_vec_free(&f->labels);
2789 static void bc_array_init(BcVec *a, bool nums)
2792 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2794 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2795 bc_array_expand(a, 1);
2798 static void bc_array_copy(BcVec *d, const BcVec *s)
2802 bc_vec_npop(d, d->len);
2803 bc_vec_expand(d, s->cap);
2806 for (i = 0; i < s->len; ++i) {
2807 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2808 bc_num_init(dnum, snum->len);
2809 bc_num_copy(dnum, snum);
2813 static void bc_array_expand(BcVec *a, size_t len)
2817 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2818 while (len > a->len) {
2819 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2820 bc_vec_push(a, &data.n);
2824 while (len > a->len) {
2825 bc_array_init(&data.v, true);
2826 bc_vec_push(a, &data.v);
2831 static void bc_string_free(void *string)
2833 free(*((char **) string));
2837 static void bc_result_copy(BcResult *d, BcResult *src)
2843 case BC_RESULT_TEMP:
2844 case BC_RESULT_IBASE:
2845 case BC_RESULT_SCALE:
2846 case BC_RESULT_OBASE:
2848 bc_num_init(&d->d.n, src->d.n.len);
2849 bc_num_copy(&d->d.n, &src->d.n);
2854 case BC_RESULT_ARRAY:
2855 case BC_RESULT_ARRAY_ELEM:
2857 d->d.id.name = xstrdup(src->d.id.name);
2861 case BC_RESULT_CONSTANT:
2862 case BC_RESULT_LAST:
2866 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2873 static void bc_result_free(void *result)
2875 BcResult *r = (BcResult *) result;
2879 case BC_RESULT_TEMP:
2880 case BC_RESULT_IBASE:
2881 case BC_RESULT_SCALE:
2882 case BC_RESULT_OBASE:
2884 bc_num_free(&r->d.n);
2889 case BC_RESULT_ARRAY:
2890 case BC_RESULT_ARRAY_ELEM:
2904 static void bc_lex_lineComment(BcLex *l)
2906 l->t.t = BC_LEX_WHITESPACE;
2907 while (l->i < l->len && l->buf[l->i++] != '\n');
2911 static void bc_lex_whitespace(BcLex *l)
2914 l->t.t = BC_LEX_WHITESPACE;
2915 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2918 static BcStatus bc_lex_number(BcLex *l, char start)
2920 const char *buf = l->buf + l->i;
2921 size_t len, hits = 0, bslashes = 0, i = 0, j;
2923 bool last_pt, pt = start == '.';
2926 l->t.t = BC_LEX_NUMBER;
2928 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2929 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2943 len = i + 1 * !last_pt - bslashes * 2;
2944 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2946 bc_vec_npop(&l->t.v, l->t.v.len);
2947 bc_vec_expand(&l->t.v, len + 1);
2948 bc_vec_push(&l->t.v, &start);
2950 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2954 // If we have hit a backslash, skip it. We don't have
2955 // to check for a newline because it's guaranteed.
2956 if (hits < bslashes && c == '\\') {
2962 bc_vec_push(&l->t.v, &c);
2965 bc_vec_pushByte(&l->t.v, '\0');
2968 return BC_STATUS_SUCCESS;
2971 static BcStatus bc_lex_name(BcLex *l)
2974 const char *buf = l->buf + l->i - 1;
2977 l->t.t = BC_LEX_NAME;
2979 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2981 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2982 bc_vec_string(&l->t.v, i, buf);
2984 // Increment the index. We minus 1 because it has already been incremented.
2987 return BC_STATUS_SUCCESS;
2990 static void bc_lex_init(BcLex *l, BcLexNext next)
2993 bc_vec_init(&l->t.v, sizeof(char), NULL);
2996 static void bc_lex_free(BcLex *l)
2998 bc_vec_free(&l->t.v);
3001 static void bc_lex_file(BcLex *l, const char *file)
3008 static BcStatus bc_lex_next(BcLex *l)
3013 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3015 l->line += l->newline;
3016 l->t.t = BC_LEX_EOF;
3018 l->newline = (l->i == l->len);
3019 if (l->newline) return BC_STATUS_SUCCESS;
3021 // Loop until failure or we don't have whitespace. This
3022 // is so the parser doesn't get inundated with whitespace.
3025 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3030 static BcStatus bc_lex_text(BcLex *l, const char *text)
3034 l->len = strlen(text);
3035 l->t.t = l->t.last = BC_LEX_INVALID;
3036 return bc_lex_next(l);
3040 static BcStatus bc_lex_identifier(BcLex *l)
3044 const char *buf = l->buf + l->i - 1;
3046 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3048 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3050 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3052 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3054 if (!bc_lex_kws[i].posix) {
3055 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3056 bc_lex_kws[i].name);
3060 // We minus 1 because the index has already been incremented.
3062 return BC_STATUS_SUCCESS;
3069 if (l->t.v.len - 1 > 1)
3070 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3075 static BcStatus bc_lex_string(BcLex *l)
3077 size_t len, nls = 0, i = l->i;
3080 l->t.t = BC_LEX_STR;
3082 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3086 return BC_STATUS_LEX_NO_STRING_END;
3090 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3091 bc_vec_string(&l->t.v, len, l->buf + l->i);
3096 return BC_STATUS_SUCCESS;
3099 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3101 if (l->buf[l->i] == '=') {
3109 static BcStatus bc_lex_comment(BcLex *l)
3112 const char *buf = l->buf;
3116 l->t.t = BC_LEX_WHITESPACE;
3118 for (i = ++l->i; !end; i += !end) {
3120 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3122 if (c == 0 || buf[i + 1] == '\0') {
3124 return BC_STATUS_LEX_NO_COMMENT_END;
3127 end = buf[i + 1] == '/';
3133 return BC_STATUS_SUCCESS;
3136 static BcStatus bc_lex_token(BcLex *l)
3138 BcStatus s = BC_STATUS_SUCCESS;
3139 char c = l->buf[l->i++], c2;
3141 // This is the workhorse of the lexer.
3148 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3158 bc_lex_whitespace(l);
3164 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3166 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3167 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3176 s = bc_lex_string(l);
3182 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3185 bc_lex_lineComment(l);
3192 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3201 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3205 l->t.t = BC_LEX_OP_BOOL_AND;
3208 l->t.t = BC_LEX_INVALID;
3209 s = BC_STATUS_LEX_BAD_CHAR;
3218 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3224 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3233 l->t.t = BC_LEX_OP_INC;
3236 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3242 l->t.t = BC_LEX_COMMA;
3251 l->t.t = BC_LEX_OP_DEC;
3254 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3260 if (isdigit(l->buf[l->i]))
3261 s = bc_lex_number(l, c);
3263 l->t.t = BC_LEX_KEY_LAST;
3264 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3273 s = bc_lex_comment(l);
3275 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3296 s = bc_lex_number(l, c);
3302 l->t.t = BC_LEX_SCOLON;
3308 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3314 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3320 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3327 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3333 if (l->buf[l->i] == '\n') {
3334 l->t.t = BC_LEX_WHITESPACE;
3338 s = BC_STATUS_LEX_BAD_CHAR;
3344 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3375 s = bc_lex_identifier(l);
3382 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3392 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3396 l->t.t = BC_LEX_OP_BOOL_OR;
3399 l->t.t = BC_LEX_INVALID;
3400 s = BC_STATUS_LEX_BAD_CHAR;
3408 l->t.t = BC_LEX_INVALID;
3409 s = BC_STATUS_LEX_BAD_CHAR;
3419 static BcStatus dc_lex_register(BcLex *l)
3421 BcStatus s = BC_STATUS_SUCCESS;
3423 if (isspace(l->buf[l->i - 1])) {
3424 bc_lex_whitespace(l);
3427 s = BC_STATUS_LEX_EXTENDED_REG;
3432 bc_vec_npop(&l->t.v, l->t.v.len);
3433 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3434 bc_vec_pushByte(&l->t.v, '\0');
3435 l->t.t = BC_LEX_NAME;
3441 static BcStatus dc_lex_string(BcLex *l)
3443 size_t depth = 1, nls = 0, i = l->i;
3446 l->t.t = BC_LEX_STR;
3447 bc_vec_npop(&l->t.v, l->t.v.len);
3449 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3451 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3452 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3455 if (depth) bc_vec_push(&l->t.v, &c);
3460 return BC_STATUS_LEX_NO_STRING_END;
3463 bc_vec_pushByte(&l->t.v, '\0');
3464 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3469 return BC_STATUS_SUCCESS;
3472 static BcStatus dc_lex_token(BcLex *l)
3474 BcStatus s = BC_STATUS_SUCCESS;
3475 char c = l->buf[l->i++], c2;
3478 for (i = 0; i < dc_lex_regs_len; ++i) {
3479 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3482 if (c >= '%' && c <= '~' &&
3483 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3488 // This is the workhorse of the lexer.
3493 l->t.t = BC_LEX_EOF;
3504 l->newline = (c == '\n');
3505 bc_lex_whitespace(l);
3514 l->t.t = BC_LEX_OP_REL_NE;
3516 l->t.t = BC_LEX_OP_REL_LE;
3518 l->t.t = BC_LEX_OP_REL_GE;
3520 return BC_STATUS_LEX_BAD_CHAR;
3528 bc_lex_lineComment(l);
3534 if (isdigit(l->buf[l->i]))
3535 s = bc_lex_number(l, c);
3537 s = BC_STATUS_LEX_BAD_CHAR;
3558 s = bc_lex_number(l, c);
3564 s = dc_lex_string(l);
3570 l->t.t = BC_LEX_INVALID;
3571 s = BC_STATUS_LEX_BAD_CHAR;
3580 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3582 bc_program_addFunc(name, idx);
3583 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3586 static void bc_parse_pushName(BcParse *p, char *name)
3588 size_t i = 0, len = strlen(name);
3590 for (; i < len; ++i) bc_parse_push(p, name[i]);
3591 bc_parse_push(p, BC_PARSE_STREND);
3596 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3598 unsigned char amt, i, nums[sizeof(size_t)];
3600 for (amt = 0; idx; ++amt) {
3601 nums[amt] = (char) idx;
3602 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3605 bc_parse_push(p, amt);
3606 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3609 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3611 char *num = xstrdup(p->l.t.v.v);
3612 size_t idx = G.prog.consts.len;
3614 bc_vec_push(&G.prog.consts, &num);
3616 bc_parse_push(p, BC_INST_NUM);
3617 bc_parse_pushIndex(p, idx);
3620 (*prev) = BC_INST_NUM;
3623 static BcStatus bc_parse_text(BcParse *p, const char *text)
3627 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3629 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3630 p->l.t.t = BC_LEX_INVALID;
3633 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3636 return bc_lex_text(&p->l, text);
3639 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3641 if (p->fidx != BC_PROG_MAIN) {
3643 p->func->nparams = 0;
3644 bc_vec_npop(&p->func->code, p->func->code.len);
3645 bc_vec_npop(&p->func->autos, p->func->autos.len);
3646 bc_vec_npop(&p->func->labels, p->func->labels.len);
3648 bc_parse_updateFunc(p, BC_PROG_MAIN);
3652 p->l.t.t = BC_LEX_EOF;
3653 p->auto_part = (p->nbraces = 0);
3655 bc_vec_npop(&p->flags, p->flags.len - 1);
3656 bc_vec_npop(&p->exits, p->exits.len);
3657 bc_vec_npop(&p->conds, p->conds.len);
3658 bc_vec_npop(&p->ops, p->ops.len);
3660 return bc_program_reset(s);
3663 static void bc_parse_free(BcParse *p)
3665 bc_vec_free(&p->flags);
3666 bc_vec_free(&p->exits);
3667 bc_vec_free(&p->conds);
3668 bc_vec_free(&p->ops);
3672 static void bc_parse_create(BcParse *p, size_t func,
3673 BcParseParse parse, BcLexNext next)
3675 memset(p, 0, sizeof(BcParse));
3677 bc_lex_init(&p->l, next);
3678 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3679 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3680 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3681 bc_vec_pushByte(&p->flags, 0);
3682 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3685 p->auto_part = (p->nbraces = 0);
3686 bc_parse_updateFunc(p, func);
3690 static BcStatus bc_parse_else(BcParse *p);
3691 static BcStatus bc_parse_stmt(BcParse *p);
3693 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3694 size_t *nexprs, bool next)
3696 BcStatus s = BC_STATUS_SUCCESS;
3698 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3699 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3701 while (p->ops.len > start) {
3703 t = BC_PARSE_TOP_OP(p);
3704 if (t == BC_LEX_LPAREN) break;
3706 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3707 if (l >= r && (l != r || !left)) break;
3709 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3710 bc_vec_pop(&p->ops);
3711 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3714 bc_vec_push(&p->ops, &type);
3715 if (next) s = bc_lex_next(&p->l);
3720 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3724 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3725 top = BC_PARSE_TOP_OP(p);
3727 while (top != BC_LEX_LPAREN) {
3729 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3731 bc_vec_pop(&p->ops);
3732 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3734 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3735 top = BC_PARSE_TOP_OP(p);
3738 bc_vec_pop(&p->ops);
3740 return bc_lex_next(&p->l);
3743 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3749 s = bc_lex_next(&p->l);
3752 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3754 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3755 s = bc_parse_expr(p, flags, bc_parse_next_param);
3758 comma = p->l.t.t == BC_LEX_COMMA;
3760 s = bc_lex_next(&p->l);
3765 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3766 bc_parse_push(p, BC_INST_CALL);
3767 bc_parse_pushIndex(p, nparams);
3769 return BC_STATUS_SUCCESS;
3772 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3775 BcId entry, *entry_ptr;
3780 s = bc_parse_params(p, flags);
3783 if (p->l.t.t != BC_LEX_RPAREN) {
3784 s = BC_STATUS_PARSE_BAD_TOKEN;
3788 idx = bc_map_index(&G.prog.fn_map, &entry);
3790 if (idx == BC_VEC_INVALID_IDX) {
3791 name = xstrdup(entry.name);
3792 bc_parse_addFunc(p, name, &idx);
3793 idx = bc_map_index(&G.prog.fn_map, &entry);
3799 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3800 bc_parse_pushIndex(p, entry_ptr->idx);
3802 return bc_lex_next(&p->l);
3809 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3814 name = xstrdup(p->l.t.v.v);
3815 s = bc_lex_next(&p->l);
3818 if (p->l.t.t == BC_LEX_LBRACKET) {
3820 s = bc_lex_next(&p->l);
3823 if (p->l.t.t == BC_LEX_RBRACKET) {
3825 if (!(flags & BC_PARSE_ARRAY)) {
3826 s = BC_STATUS_PARSE_BAD_EXP;
3830 *type = BC_INST_ARRAY;
3834 *type = BC_INST_ARRAY_ELEM;
3836 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3837 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3841 s = bc_lex_next(&p->l);
3843 bc_parse_push(p, *type);
3844 bc_parse_pushName(p, name);
3846 else if (p->l.t.t == BC_LEX_LPAREN) {
3848 if (flags & BC_PARSE_NOCALL) {
3849 s = BC_STATUS_PARSE_BAD_TOKEN;
3853 *type = BC_INST_CALL;
3854 s = bc_parse_call(p, name, flags);
3857 *type = BC_INST_VAR;
3858 bc_parse_push(p, BC_INST_VAR);
3859 bc_parse_pushName(p, name);
3869 static BcStatus bc_parse_read(BcParse *p)
3873 s = bc_lex_next(&p->l);
3875 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3877 s = bc_lex_next(&p->l);
3879 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3881 bc_parse_push(p, BC_INST_READ);
3883 return bc_lex_next(&p->l);
3886 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3891 s = bc_lex_next(&p->l);
3893 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3895 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3897 s = bc_lex_next(&p->l);
3900 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3903 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3905 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3906 bc_parse_push(p, *prev);
3908 return bc_lex_next(&p->l);
3911 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3915 s = bc_lex_next(&p->l);
3918 if (p->l.t.t != BC_LEX_LPAREN) {
3919 *type = BC_INST_SCALE;
3920 bc_parse_push(p, BC_INST_SCALE);
3921 return BC_STATUS_SUCCESS;
3924 *type = BC_INST_SCALE_FUNC;
3925 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3927 s = bc_lex_next(&p->l);
3930 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3932 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3933 bc_parse_push(p, BC_INST_SCALE_FUNC);
3935 return bc_lex_next(&p->l);
3938 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3939 size_t *nexprs, uint8_t flags)
3944 BcInst etype = *prev;
3946 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3947 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3948 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3950 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3951 bc_parse_push(p, inst);
3952 s = bc_lex_next(&p->l);
3956 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3959 s = bc_lex_next(&p->l);
3963 // Because we parse the next part of the expression
3964 // right here, we need to increment this.
3965 *nexprs = *nexprs + 1;
3971 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3975 case BC_LEX_KEY_IBASE:
3976 case BC_LEX_KEY_LAST:
3977 case BC_LEX_KEY_OBASE:
3979 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3980 s = bc_lex_next(&p->l);
3984 case BC_LEX_KEY_SCALE:
3986 s = bc_lex_next(&p->l);
3988 if (p->l.t.t == BC_LEX_LPAREN)
3989 s = BC_STATUS_PARSE_BAD_TOKEN;
3991 bc_parse_push(p, BC_INST_SCALE);
3997 s = BC_STATUS_PARSE_BAD_TOKEN;
4002 if (!s) bc_parse_push(p, inst);
4008 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4009 bool rparen, size_t *nexprs)
4013 BcInst etype = *prev;
4015 s = bc_lex_next(&p->l);
4018 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4019 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4022 *prev = BC_PARSE_TOKEN_INST(type);
4024 // We can just push onto the op stack because this is the largest
4025 // precedence operator that gets pushed. Inc/dec does not.
4026 if (type != BC_LEX_OP_MINUS)
4027 bc_vec_push(&p->ops, &type);
4029 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4034 static BcStatus bc_parse_string(BcParse *p, char inst)
4036 char *str = xstrdup(p->l.t.v.v);
4038 bc_parse_push(p, BC_INST_STR);
4039 bc_parse_pushIndex(p, G.prog.strs.len);
4040 bc_vec_push(&G.prog.strs, &str);
4041 bc_parse_push(p, inst);
4043 return bc_lex_next(&p->l);
4046 static BcStatus bc_parse_print(BcParse *p)
4052 s = bc_lex_next(&p->l);
4057 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4058 return BC_STATUS_PARSE_BAD_PRINT;
4060 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4062 if (type == BC_LEX_STR)
4063 s = bc_parse_string(p, BC_INST_PRINT_POP);
4065 s = bc_parse_expr(p, 0, bc_parse_next_print);
4067 bc_parse_push(p, BC_INST_PRINT_POP);
4072 comma = p->l.t.t == BC_LEX_COMMA;
4073 if (comma) s = bc_lex_next(&p->l);
4078 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4080 return bc_lex_next(&p->l);
4083 static BcStatus bc_parse_return(BcParse *p)
4089 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4091 s = bc_lex_next(&p->l);
4095 paren = t == BC_LEX_LPAREN;
4097 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4098 bc_parse_push(p, BC_INST_RET0);
4101 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4102 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4104 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4105 bc_parse_push(p, BC_INST_RET0);
4106 s = bc_lex_next(&p->l);
4110 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4111 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4115 bc_parse_push(p, BC_INST_RET);
4121 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4123 BcStatus s = BC_STATUS_SUCCESS;
4125 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4126 return BC_STATUS_PARSE_BAD_TOKEN;
4130 if (p->l.t.t == BC_LEX_RBRACE) {
4131 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4133 s = bc_lex_next(&p->l);
4137 return BC_STATUS_PARSE_BAD_TOKEN;
4140 if (BC_PARSE_IF(p)) {
4144 while (p->l.t.t == BC_LEX_NLINE) {
4145 s = bc_lex_next(&p->l);
4149 bc_vec_pop(&p->flags);
4151 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4152 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4154 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4156 else if (BC_PARSE_ELSE(p)) {
4161 bc_vec_pop(&p->flags);
4163 ip = bc_vec_top(&p->exits);
4164 label = bc_vec_item(&p->func->labels, ip->idx);
4165 *label = p->func->code.len;
4167 bc_vec_pop(&p->exits);
4169 else if (BC_PARSE_FUNC_INNER(p)) {
4170 bc_parse_push(p, BC_INST_RET0);
4171 bc_parse_updateFunc(p, BC_PROG_MAIN);
4172 bc_vec_pop(&p->flags);
4176 BcInstPtr *ip = bc_vec_top(&p->exits);
4177 size_t *label = bc_vec_top(&p->conds);
4179 bc_parse_push(p, BC_INST_JUMP);
4180 bc_parse_pushIndex(p, *label);
4182 label = bc_vec_item(&p->func->labels, ip->idx);
4183 *label = p->func->code.len;
4185 bc_vec_pop(&p->flags);
4186 bc_vec_pop(&p->exits);
4187 bc_vec_pop(&p->conds);
4193 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4195 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4196 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4197 flags |= BC_PARSE_FLAG_BODY;
4198 bc_vec_push(&p->flags, &flags);
4201 static void bc_parse_noElse(BcParse *p)
4205 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4207 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4209 ip = bc_vec_top(&p->exits);
4210 label = bc_vec_item(&p->func->labels, ip->idx);
4211 *label = p->func->code.len;
4213 bc_vec_pop(&p->exits);
4216 static BcStatus bc_parse_if(BcParse *p)
4221 s = bc_lex_next(&p->l);
4223 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4225 s = bc_lex_next(&p->l);
4227 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4229 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4231 s = bc_lex_next(&p->l);
4233 bc_parse_push(p, BC_INST_JUMP_ZERO);
4235 ip.idx = p->func->labels.len;
4236 ip.func = ip.len = 0;
4238 bc_parse_pushIndex(p, ip.idx);
4239 bc_vec_push(&p->exits, &ip);
4240 bc_vec_push(&p->func->labels, &ip.idx);
4241 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4243 return BC_STATUS_SUCCESS;
4246 static BcStatus bc_parse_else(BcParse *p)
4250 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4252 ip.idx = p->func->labels.len;
4253 ip.func = ip.len = 0;
4255 bc_parse_push(p, BC_INST_JUMP);
4256 bc_parse_pushIndex(p, ip.idx);
4260 bc_vec_push(&p->exits, &ip);
4261 bc_vec_push(&p->func->labels, &ip.idx);
4262 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4264 return bc_lex_next(&p->l);
4267 static BcStatus bc_parse_while(BcParse *p)
4272 s = bc_lex_next(&p->l);
4274 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4275 s = bc_lex_next(&p->l);
4278 ip.idx = p->func->labels.len;
4280 bc_vec_push(&p->func->labels, &p->func->code.len);
4281 bc_vec_push(&p->conds, &ip.idx);
4283 ip.idx = p->func->labels.len;
4287 bc_vec_push(&p->exits, &ip);
4288 bc_vec_push(&p->func->labels, &ip.idx);
4290 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4292 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4293 s = bc_lex_next(&p->l);
4296 bc_parse_push(p, BC_INST_JUMP_ZERO);
4297 bc_parse_pushIndex(p, ip.idx);
4298 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4300 return BC_STATUS_SUCCESS;
4303 static BcStatus bc_parse_for(BcParse *p)
4307 size_t cond_idx, exit_idx, body_idx, update_idx;
4309 s = bc_lex_next(&p->l);
4311 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4312 s = bc_lex_next(&p->l);
4315 if (p->l.t.t != BC_LEX_SCOLON)
4316 s = bc_parse_expr(p, 0, bc_parse_next_for);
4318 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4321 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4322 s = bc_lex_next(&p->l);
4325 cond_idx = p->func->labels.len;
4326 update_idx = cond_idx + 1;
4327 body_idx = update_idx + 1;
4328 exit_idx = body_idx + 1;
4330 bc_vec_push(&p->func->labels, &p->func->code.len);
4332 if (p->l.t.t != BC_LEX_SCOLON)
4333 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4335 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4338 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4340 s = bc_lex_next(&p->l);
4343 bc_parse_push(p, BC_INST_JUMP_ZERO);
4344 bc_parse_pushIndex(p, exit_idx);
4345 bc_parse_push(p, BC_INST_JUMP);
4346 bc_parse_pushIndex(p, body_idx);
4348 ip.idx = p->func->labels.len;
4350 bc_vec_push(&p->conds, &update_idx);
4351 bc_vec_push(&p->func->labels, &p->func->code.len);
4353 if (p->l.t.t != BC_LEX_RPAREN)
4354 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4356 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4360 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4361 bc_parse_push(p, BC_INST_JUMP);
4362 bc_parse_pushIndex(p, cond_idx);
4363 bc_vec_push(&p->func->labels, &p->func->code.len);
4369 bc_vec_push(&p->exits, &ip);
4370 bc_vec_push(&p->func->labels, &ip.idx);
4372 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4374 return BC_STATUS_SUCCESS;
4377 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4383 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4385 if (type == BC_LEX_KEY_BREAK) {
4387 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4389 i = p->exits.len - 1;
4390 ip = bc_vec_item(&p->exits, i);
4392 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4393 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4398 i = *((size_t *) bc_vec_top(&p->conds));
4400 bc_parse_push(p, BC_INST_JUMP);
4401 bc_parse_pushIndex(p, i);
4403 s = bc_lex_next(&p->l);
4406 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4407 return BC_STATUS_PARSE_BAD_TOKEN;
4409 return bc_lex_next(&p->l);
4412 static BcStatus bc_parse_func(BcParse *p)
4415 bool var, comma = false;
4419 s = bc_lex_next(&p->l);
4421 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4423 name = xstrdup(p->l.t.v.v);
4424 bc_parse_addFunc(p, name, &p->fidx);
4426 s = bc_lex_next(&p->l);
4428 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4429 s = bc_lex_next(&p->l);
4432 while (p->l.t.t != BC_LEX_RPAREN) {
4434 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4438 name = xstrdup(p->l.t.v.v);
4439 s = bc_lex_next(&p->l);
4442 var = p->l.t.t != BC_LEX_LBRACKET;
4446 s = bc_lex_next(&p->l);
4449 if (p->l.t.t != BC_LEX_RBRACKET) {
4450 s = BC_STATUS_PARSE_BAD_FUNC;
4454 s = bc_lex_next(&p->l);
4458 comma = p->l.t.t == BC_LEX_COMMA;
4460 s = bc_lex_next(&p->l);
4464 s = bc_func_insert(p->func, name, var);
4468 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4470 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4471 bc_parse_startBody(p, flags);
4473 s = bc_lex_next(&p->l);
4476 if (p->l.t.t != BC_LEX_LBRACE)
4477 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4486 static BcStatus bc_parse_auto(BcParse *p)
4489 bool comma, var, one;
4492 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4493 s = bc_lex_next(&p->l);
4496 p->auto_part = comma = false;
4497 one = p->l.t.t == BC_LEX_NAME;
4499 while (p->l.t.t == BC_LEX_NAME) {
4501 name = xstrdup(p->l.t.v.v);
4502 s = bc_lex_next(&p->l);
4505 var = p->l.t.t != BC_LEX_LBRACKET;
4508 s = bc_lex_next(&p->l);
4511 if (p->l.t.t != BC_LEX_RBRACKET) {
4512 s = BC_STATUS_PARSE_BAD_FUNC;
4516 s = bc_lex_next(&p->l);
4520 comma = p->l.t.t == BC_LEX_COMMA;
4522 s = bc_lex_next(&p->l);
4526 s = bc_func_insert(p->func, name, var);
4530 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4531 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4533 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4534 return BC_STATUS_PARSE_BAD_TOKEN;
4536 return bc_lex_next(&p->l);
4543 static BcStatus bc_parse_body(BcParse *p, bool brace)
4545 BcStatus s = BC_STATUS_SUCCESS;
4546 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4548 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4550 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4552 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4553 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4555 if (!p->auto_part) {
4556 s = bc_parse_auto(p);
4560 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4563 s = bc_parse_stmt(p);
4564 if (!s && !brace) s = bc_parse_endBody(p, false);
4570 static BcStatus bc_parse_stmt(BcParse *p)
4572 BcStatus s = BC_STATUS_SUCCESS;
4578 return bc_lex_next(&p->l);
4581 case BC_LEX_KEY_ELSE:
4583 p->auto_part = false;
4589 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4592 s = bc_lex_next(&p->l);
4595 return bc_parse_body(p, true);
4598 case BC_LEX_KEY_AUTO:
4600 return bc_parse_auto(p);
4605 p->auto_part = false;
4607 if (BC_PARSE_IF_END(p)) {
4609 return BC_STATUS_SUCCESS;
4611 else if (BC_PARSE_BODY(p))
4612 return bc_parse_body(p, false);
4622 case BC_LEX_OP_MINUS:
4623 case BC_LEX_OP_BOOL_NOT:
4627 case BC_LEX_KEY_IBASE:
4628 case BC_LEX_KEY_LAST:
4629 case BC_LEX_KEY_LENGTH:
4630 case BC_LEX_KEY_OBASE:
4631 case BC_LEX_KEY_READ:
4632 case BC_LEX_KEY_SCALE:
4633 case BC_LEX_KEY_SQRT:
4635 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4639 case BC_LEX_KEY_ELSE:
4641 s = bc_parse_else(p);
4647 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4653 s = bc_parse_endBody(p, true);
4659 s = bc_parse_string(p, BC_INST_PRINT_STR);
4663 case BC_LEX_KEY_BREAK:
4664 case BC_LEX_KEY_CONTINUE:
4666 s = bc_parse_loopExit(p, p->l.t.t);
4670 case BC_LEX_KEY_FOR:
4672 s = bc_parse_for(p);
4676 case BC_LEX_KEY_HALT:
4678 bc_parse_push(p, BC_INST_HALT);
4679 s = bc_lex_next(&p->l);
4689 case BC_LEX_KEY_LIMITS:
4691 s = bc_lex_next(&p->l);
4693 s = BC_STATUS_LIMITS;
4697 case BC_LEX_KEY_PRINT:
4699 s = bc_parse_print(p);
4703 case BC_LEX_KEY_QUIT:
4705 // Quit is a compile-time command. We don't exit directly,
4706 // so the vm can clean up. Limits do the same thing.
4711 case BC_LEX_KEY_RETURN:
4713 s = bc_parse_return(p);
4717 case BC_LEX_KEY_WHILE:
4719 s = bc_parse_while(p);
4725 s = BC_STATUS_PARSE_BAD_TOKEN;
4733 static BcStatus bc_parse_parse(BcParse *p)
4737 if (p->l.t.t == BC_LEX_EOF)
4738 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4739 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4740 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4741 s = bc_parse_func(p);
4744 s = bc_parse_stmt(p);
4746 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4747 s = bc_parse_reset(p, s);
4752 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4754 BcStatus s = BC_STATUS_SUCCESS;
4755 BcInst prev = BC_INST_PRINT;
4756 BcLexType top, t = p->l.t.t;
4757 size_t nexprs = 0, ops_bgn = p->ops.len;
4758 uint32_t i, nparens, nrelops;
4759 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4761 paren_first = p->l.t.t == BC_LEX_LPAREN;
4762 nparens = nrelops = 0;
4763 paren_expr = rprn = done = get_token = assign = false;
4766 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4772 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4773 rprn = get_token = bin_last = false;
4777 case BC_LEX_OP_MINUS:
4779 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4780 rprn = get_token = false;
4781 bin_last = prev == BC_INST_MINUS;
4785 case BC_LEX_OP_ASSIGN_POWER:
4786 case BC_LEX_OP_ASSIGN_MULTIPLY:
4787 case BC_LEX_OP_ASSIGN_DIVIDE:
4788 case BC_LEX_OP_ASSIGN_MODULUS:
4789 case BC_LEX_OP_ASSIGN_PLUS:
4790 case BC_LEX_OP_ASSIGN_MINUS:
4791 case BC_LEX_OP_ASSIGN:
4793 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4794 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4795 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4797 s = BC_STATUS_PARSE_BAD_ASSIGN;
4802 case BC_LEX_OP_POWER:
4803 case BC_LEX_OP_MULTIPLY:
4804 case BC_LEX_OP_DIVIDE:
4805 case BC_LEX_OP_MODULUS:
4806 case BC_LEX_OP_PLUS:
4807 case BC_LEX_OP_REL_EQ:
4808 case BC_LEX_OP_REL_LE:
4809 case BC_LEX_OP_REL_GE:
4810 case BC_LEX_OP_REL_NE:
4811 case BC_LEX_OP_REL_LT:
4812 case BC_LEX_OP_REL_GT:
4813 case BC_LEX_OP_BOOL_NOT:
4814 case BC_LEX_OP_BOOL_OR:
4815 case BC_LEX_OP_BOOL_AND:
4817 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4818 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4820 return BC_STATUS_PARSE_BAD_EXP;
4823 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4824 prev = BC_PARSE_TOKEN_INST(t);
4825 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4826 rprn = get_token = false;
4827 bin_last = t != BC_LEX_OP_BOOL_NOT;
4834 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4837 paren_expr = rprn = bin_last = false;
4839 bc_vec_push(&p->ops, &t);
4846 if (bin_last || prev == BC_INST_BOOL_NOT)
4847 return BC_STATUS_PARSE_BAD_EXP;
4850 s = BC_STATUS_SUCCESS;
4855 else if (!paren_expr)
4856 return BC_STATUS_PARSE_EMPTY_EXP;
4859 paren_expr = rprn = true;
4860 get_token = bin_last = false;
4862 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4869 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4872 rprn = get_token = bin_last = false;
4873 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4881 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4883 bc_parse_number(p, &prev, &nexprs);
4884 paren_expr = get_token = true;
4885 rprn = bin_last = false;
4890 case BC_LEX_KEY_IBASE:
4891 case BC_LEX_KEY_LAST:
4892 case BC_LEX_KEY_OBASE:
4894 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4896 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4897 bc_parse_push(p, (char) prev);
4899 paren_expr = get_token = true;
4900 rprn = bin_last = false;
4906 case BC_LEX_KEY_LENGTH:
4907 case BC_LEX_KEY_SQRT:
4909 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4911 s = bc_parse_builtin(p, t, flags, &prev);
4913 rprn = get_token = bin_last = false;
4919 case BC_LEX_KEY_READ:
4921 if (BC_PARSE_LEAF(prev, rprn))
4922 return BC_STATUS_PARSE_BAD_EXP;
4923 else if (flags & BC_PARSE_NOREAD)
4924 s = BC_STATUS_EXEC_REC_READ;
4926 s = bc_parse_read(p);
4929 rprn = get_token = bin_last = false;
4931 prev = BC_INST_READ;
4936 case BC_LEX_KEY_SCALE:
4938 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4940 s = bc_parse_scale(p, &prev, flags);
4942 rprn = get_token = bin_last = false;
4944 prev = BC_INST_SCALE;
4951 s = BC_STATUS_PARSE_BAD_TOKEN;
4956 if (!s && get_token) s = bc_lex_next(&p->l);
4960 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4962 while (p->ops.len > ops_bgn) {
4964 top = BC_PARSE_TOP_OP(p);
4965 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4967 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4968 return BC_STATUS_PARSE_BAD_EXP;
4970 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4972 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4973 bc_vec_pop(&p->ops);
4976 s = BC_STATUS_PARSE_BAD_EXP;
4977 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4979 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4982 if (!(flags & BC_PARSE_REL) && nrelops) {
4983 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4986 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4987 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4991 if (flags & BC_PARSE_PRINT) {
4992 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4993 bc_parse_push(p, BC_INST_POP);
4999 static void bc_parse_init(BcParse *p, size_t func)
5001 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
5004 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5006 return bc_parse_expr(p, flags, bc_parse_next_read);
5011 static BcStatus dc_parse_register(BcParse *p)
5016 s = bc_lex_next(&p->l);
5018 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5020 name = xstrdup(p->l.t.v.v);
5021 bc_parse_pushName(p, name);
5026 static BcStatus dc_parse_string(BcParse *p)
5028 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5029 size_t idx, len = G.prog.strs.len;
5031 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5034 str = xstrdup(p->l.t.v.v);
5035 bc_parse_push(p, BC_INST_STR);
5036 bc_parse_pushIndex(p, len);
5037 bc_vec_push(&G.prog.strs, &str);
5038 bc_parse_addFunc(p, name, &idx);
5040 return bc_lex_next(&p->l);
5043 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5047 bc_parse_push(p, inst);
5049 s = dc_parse_register(p);
5054 bc_parse_push(p, BC_INST_SWAP);
5055 bc_parse_push(p, BC_INST_ASSIGN);
5056 bc_parse_push(p, BC_INST_POP);
5059 return bc_lex_next(&p->l);
5062 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5066 bc_parse_push(p, inst);
5067 bc_parse_push(p, BC_INST_EXEC_COND);
5069 s = dc_parse_register(p);
5072 s = bc_lex_next(&p->l);
5075 if (p->l.t.t == BC_LEX_ELSE) {
5076 s = dc_parse_register(p);
5078 s = bc_lex_next(&p->l);
5081 bc_parse_push(p, BC_PARSE_STREND);
5086 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5088 BcStatus s = BC_STATUS_SUCCESS;
5091 bool assign, get_token = false;
5095 case BC_LEX_OP_REL_EQ:
5096 case BC_LEX_OP_REL_LE:
5097 case BC_LEX_OP_REL_GE:
5098 case BC_LEX_OP_REL_NE:
5099 case BC_LEX_OP_REL_LT:
5100 case BC_LEX_OP_REL_GT:
5102 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5109 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5115 s = dc_parse_string(p);
5122 if (t == BC_LEX_NEG) {
5123 s = bc_lex_next(&p->l);
5125 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5128 bc_parse_number(p, &prev, &p->nbraces);
5130 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5136 case BC_LEX_KEY_READ:
5138 if (flags & BC_PARSE_NOREAD)
5139 s = BC_STATUS_EXEC_REC_READ;
5141 bc_parse_push(p, BC_INST_READ);
5146 case BC_LEX_OP_ASSIGN:
5147 case BC_LEX_STORE_PUSH:
5149 assign = t == BC_LEX_OP_ASSIGN;
5150 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5151 s = dc_parse_mem(p, inst, true, assign);
5156 case BC_LEX_LOAD_POP:
5158 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5159 s = dc_parse_mem(p, inst, true, false);
5163 case BC_LEX_STORE_IBASE:
5164 case BC_LEX_STORE_SCALE:
5165 case BC_LEX_STORE_OBASE:
5167 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5168 s = dc_parse_mem(p, inst, false, true);
5174 s = BC_STATUS_PARSE_BAD_TOKEN;
5180 if (!s && get_token) s = bc_lex_next(&p->l);
5185 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5187 BcStatus s = BC_STATUS_SUCCESS;
5191 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5193 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5195 inst = dc_parse_insts[t];
5197 if (inst != BC_INST_INVALID) {
5198 bc_parse_push(p, inst);
5199 s = bc_lex_next(&p->l);
5202 s = dc_parse_token(p, t, flags);
5205 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5206 bc_parse_push(p, BC_INST_POP_EXEC);
5211 static BcStatus dc_parse_parse(BcParse *p)
5215 if (p->l.t.t == BC_LEX_EOF)
5216 s = BC_STATUS_LEX_EOF;
5218 s = dc_parse_expr(p, 0);
5220 if (s || G_interrupt) s = bc_parse_reset(p, s);
5225 static void dc_parse_init(BcParse *p, size_t func)
5227 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5231 static void common_parse_init(BcParse *p, size_t func)
5234 bc_parse_init(p, func);
5236 dc_parse_init(p, func);
5240 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5243 return bc_parse_expression(p, flags);
5245 return dc_parse_expr(p, flags);
5249 static BcVec* bc_program_search(char *id, bool var)
5258 v = var ? &G.prog.vars : &G.prog.arrs;
5259 map = var ? &G.prog.var_map : &G.prog.arr_map;
5263 s = bc_map_insert(map, &e, &i);
5264 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5267 bc_array_init(&data.v, var);
5268 bc_vec_push(v, &data.v);
5271 ptr = bc_vec_item(map, i);
5272 if (new) ptr->name = xstrdup(e.name);
5273 return bc_vec_item(v, ptr->idx);
5276 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5278 BcStatus s = BC_STATUS_SUCCESS;
5283 case BC_RESULT_TEMP:
5284 case BC_RESULT_IBASE:
5285 case BC_RESULT_SCALE:
5286 case BC_RESULT_OBASE:
5292 case BC_RESULT_CONSTANT:
5294 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5295 size_t base_t, len = strlen(*str);
5298 bc_num_init(&r->d.n, len);
5300 hex = hex && len == 1;
5301 base = hex ? &G.prog.hexb : &G.prog.ib;
5302 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5303 s = bc_num_parse(&r->d.n, *str, base, base_t);
5306 bc_num_free(&r->d.n);
5311 r->t = BC_RESULT_TEMP;
5317 case BC_RESULT_ARRAY:
5318 case BC_RESULT_ARRAY_ELEM:
5322 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5324 if (r->t == BC_RESULT_ARRAY_ELEM) {
5326 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5327 *num = bc_vec_item(v, r->d.id.idx);
5330 *num = bc_vec_top(v);
5335 case BC_RESULT_LAST:
5337 *num = &G.prog.last;
5351 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5352 BcResult **r, BcNum **rn, bool assign)
5356 BcResultType lt, rt;
5358 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5360 *r = bc_vec_item_rev(&G.prog.results, 0);
5361 *l = bc_vec_item_rev(&G.prog.results, 1);
5365 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5367 s = bc_program_num(*l, ln, false);
5369 s = bc_program_num(*r, rn, hex);
5372 // We run this again under these conditions in case any vector has been
5373 // reallocated out from under the BcNums or arrays we had.
5374 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5375 s = bc_program_num(*l, ln, false);
5379 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5380 return BC_STATUS_EXEC_BAD_TYPE;
5381 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5386 static void bc_program_binOpRetire(BcResult *r)
5388 r->t = BC_RESULT_TEMP;
5389 bc_vec_pop(&G.prog.results);
5390 bc_vec_pop(&G.prog.results);
5391 bc_vec_push(&G.prog.results, r);
5394 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5398 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5399 *r = bc_vec_top(&G.prog.results);
5401 s = bc_program_num(*r, n, false);
5404 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5409 static void bc_program_retire(BcResult *r, BcResultType t)
5412 bc_vec_pop(&G.prog.results);
5413 bc_vec_push(&G.prog.results, r);
5416 static BcStatus bc_program_op(char inst)
5419 BcResult *opd1, *opd2, res;
5420 BcNum *n1, *n2 = NULL;
5422 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5424 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5426 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5428 bc_program_binOpRetire(&res);
5433 bc_num_free(&res.d.n);
5437 static BcStatus bc_program_read(void)
5444 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5446 for (i = 0; i < G.prog.stack.len; ++i) {
5447 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5448 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5451 bc_vec_npop(&f->code, f->code.len);
5452 bc_vec_init(&buf, sizeof(char), NULL);
5454 s = bc_read_line(&buf, "read> ");
5457 common_parse_init(&parse, BC_PROG_READ);
5458 bc_lex_file(&parse.l, bc_program_stdin_name);
5460 s = bc_parse_text(&parse, buf.v);
5461 if (s) goto exec_err;
5462 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5463 if (s) goto exec_err;
5465 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5466 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5470 ip.func = BC_PROG_READ;
5472 ip.len = G.prog.results.len;
5474 // Update this pointer, just in case.
5475 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5477 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5478 bc_vec_push(&G.prog.stack, &ip);
5481 bc_parse_free(&parse);
5487 static size_t bc_program_index(char *code, size_t *bgn)
5489 char amt = code[(*bgn)++], i = 0;
5492 for (; i < amt; ++i, ++(*bgn))
5493 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5498 static char *bc_program_name(char *code, size_t *bgn)
5501 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5503 s = xmalloc(ptr - str + 1);
5506 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5514 static void bc_program_printString(const char *str, size_t *nchars)
5516 size_t i, len = strlen(str);
5525 for (i = 0; i < len; ++i, ++(*nchars)) {
5529 if (c != '\\' || i == len - 1)
5589 // Just print the backslash and following character.
5600 static BcStatus bc_program_print(char inst, size_t idx)
5602 BcStatus s = BC_STATUS_SUCCESS;
5607 bool pop = inst != BC_INST_PRINT;
5609 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5611 r = bc_vec_item_rev(&G.prog.results, idx);
5612 s = bc_program_num(r, &num, false);
5615 if (BC_PROG_NUM(r, num)) {
5616 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5617 if (!s) bc_num_copy(&G.prog.last, num);
5621 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5622 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5624 if (inst == BC_INST_PRINT_STR) {
5625 for (i = 0, len = strlen(str); i < len; ++i) {
5628 if (c == '\n') G.prog.nchars = SIZE_MAX;
5633 bc_program_printString(str, &G.prog.nchars);
5634 if (inst == BC_INST_PRINT) bb_putchar('\n');
5638 if (!s && pop) bc_vec_pop(&G.prog.results);
5643 static BcStatus bc_program_negate(void)
5649 s = bc_program_prep(&ptr, &num);
5652 bc_num_init(&res.d.n, num->len);
5653 bc_num_copy(&res.d.n, num);
5654 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5656 bc_program_retire(&res, BC_RESULT_TEMP);
5661 static BcStatus bc_program_logical(char inst)
5664 BcResult *opd1, *opd2, res;
5669 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5671 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5673 if (inst == BC_INST_BOOL_AND)
5674 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5675 else if (inst == BC_INST_BOOL_OR)
5676 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5679 cmp = bc_num_cmp(n1, n2);
5683 case BC_INST_REL_EQ:
5689 case BC_INST_REL_LE:
5695 case BC_INST_REL_GE:
5701 case BC_INST_REL_NE:
5707 case BC_INST_REL_LT:
5713 case BC_INST_REL_GT:
5721 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5723 bc_program_binOpRetire(&res);
5729 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5735 memset(&n2, 0, sizeof(BcNum));
5736 n2.rdx = res.d.id.idx = r->d.id.idx;
5737 res.t = BC_RESULT_STR;
5740 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5742 bc_vec_pop(&G.prog.results);
5745 bc_vec_pop(&G.prog.results);
5747 bc_vec_push(&G.prog.results, &res);
5748 bc_vec_push(v, &n2);
5750 return BC_STATUS_SUCCESS;
5754 static BcStatus bc_program_copyToVar(char *name, bool var)
5761 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5763 ptr = bc_vec_top(&G.prog.results);
5764 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5765 v = bc_program_search(name, var);
5768 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5769 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5772 s = bc_program_num(ptr, &n, false);
5775 // Do this once more to make sure that pointers were not invalidated.
5776 v = bc_program_search(name, var);
5779 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5780 bc_num_copy(&r.d.n, n);
5783 bc_array_init(&r.d.v, true);
5784 bc_array_copy(&r.d.v, (BcVec *) n);
5787 bc_vec_push(v, &r.d);
5788 bc_vec_pop(&G.prog.results);
5793 static BcStatus bc_program_assign(char inst)
5796 BcResult *left, *right, res;
5797 BcNum *l = NULL, *r = NULL;
5798 unsigned long val, max;
5799 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5801 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5804 ib = left->t == BC_RESULT_IBASE;
5805 sc = left->t == BC_RESULT_SCALE;
5809 if (right->t == BC_RESULT_STR) {
5813 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5814 v = bc_program_search(left->d.id.name, true);
5816 return bc_program_assignStr(right, v, false);
5820 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5821 return BC_STATUS_PARSE_BAD_ASSIGN;
5824 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5825 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5830 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5837 if (ib || sc || left->t == BC_RESULT_OBASE) {
5841 s = bc_num_ulong(l, &val);
5843 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5847 ptr = &G.prog.scale;
5850 if (val < BC_NUM_MIN_BASE) return s;
5851 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5852 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5855 if (val > max) return s;
5856 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5858 *ptr = (size_t) val;
5859 s = BC_STATUS_SUCCESS;
5862 bc_num_init(&res.d.n, l->len);
5863 bc_num_copy(&res.d.n, l);
5864 bc_program_binOpRetire(&res);
5870 #define bc_program_pushVar(code, bgn, pop, copy) \
5871 bc_program_pushVar(code, bgn)
5872 // for bc, 'pop' and 'copy' are always false
5874 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5875 bool pop, bool copy)
5877 BcStatus s = BC_STATUS_SUCCESS;
5879 char *name = bc_program_name(code, bgn);
5881 r.t = BC_RESULT_VAR;
5886 BcVec *v = bc_program_search(name, true);
5887 BcNum *num = bc_vec_top(v);
5891 if (!BC_PROG_STACK(v, 2 - copy)) {
5893 return BC_STATUS_EXEC_STACK;
5899 if (!BC_PROG_STR(num)) {
5901 r.t = BC_RESULT_TEMP;
5903 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5904 bc_num_copy(&r.d.n, num);
5907 r.t = BC_RESULT_STR;
5908 r.d.id.idx = num->rdx;
5911 if (!copy) bc_vec_pop(v);
5916 bc_vec_push(&G.prog.results, &r);
5921 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5924 BcStatus s = BC_STATUS_SUCCESS;
5928 r.d.id.name = bc_program_name(code, bgn);
5930 if (inst == BC_INST_ARRAY) {
5931 r.t = BC_RESULT_ARRAY;
5932 bc_vec_push(&G.prog.results, &r);
5939 s = bc_program_prep(&operand, &num);
5941 s = bc_num_ulong(num, &temp);
5944 if (temp > BC_MAX_DIM) {
5945 s = BC_STATUS_EXEC_ARRAY_LEN;
5949 r.d.id.idx = (size_t) temp;
5950 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5954 if (s) free(r.d.id.name);
5959 static BcStatus bc_program_incdec(char inst)
5962 BcResult *ptr, res, copy;
5966 s = bc_program_prep(&ptr, &num);
5969 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5970 copy.t = BC_RESULT_TEMP;
5971 bc_num_init(©.d.n, num->len);
5972 bc_num_copy(©.d.n, num);
5975 res.t = BC_RESULT_ONE;
5976 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5977 BC_INST_ASSIGN_PLUS :
5978 BC_INST_ASSIGN_MINUS;
5980 bc_vec_push(&G.prog.results, &res);
5981 bc_program_assign(inst);
5983 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5984 bc_vec_pop(&G.prog.results);
5985 bc_vec_push(&G.prog.results, ©);
5991 static BcStatus bc_program_call(char *code, size_t *idx)
5993 BcStatus s = BC_STATUS_SUCCESS;
5995 size_t i, nparams = bc_program_index(code, idx);
6002 ip.func = bc_program_index(code, idx);
6003 func = bc_vec_item(&G.prog.fns, ip.func);
6005 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6006 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6007 ip.len = G.prog.results.len - nparams;
6009 for (i = 0; i < nparams; ++i) {
6011 a = bc_vec_item(&func->autos, nparams - 1 - i);
6012 arg = bc_vec_top(&G.prog.results);
6014 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6015 return BC_STATUS_EXEC_BAD_TYPE;
6017 s = bc_program_copyToVar(a->name, a->idx);
6021 for (; i < func->autos.len; ++i) {
6024 a = bc_vec_item(&func->autos, i);
6025 v = bc_program_search(a->name, a->idx);
6028 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6029 bc_vec_push(v, ¶m.n);
6032 bc_array_init(¶m.v, true);
6033 bc_vec_push(v, ¶m.v);
6037 bc_vec_push(&G.prog.stack, &ip);
6039 return BC_STATUS_SUCCESS;
6042 static BcStatus bc_program_return(char inst)
6048 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6050 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6051 return BC_STATUS_EXEC_STACK;
6053 f = bc_vec_item(&G.prog.fns, ip->func);
6054 res.t = BC_RESULT_TEMP;
6056 if (inst == BC_INST_RET) {
6059 BcResult *operand = bc_vec_top(&G.prog.results);
6061 s = bc_program_num(operand, &num, false);
6063 bc_num_init(&res.d.n, num->len);
6064 bc_num_copy(&res.d.n, num);
6067 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6068 bc_num_zero(&res.d.n);
6071 // We need to pop arguments as well, so this takes that into account.
6072 for (i = 0; i < f->autos.len; ++i) {
6075 BcId *a = bc_vec_item(&f->autos, i);
6077 v = bc_program_search(a->name, a->idx);
6081 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6082 bc_vec_push(&G.prog.results, &res);
6083 bc_vec_pop(&G.prog.stack);
6085 return BC_STATUS_SUCCESS;
6089 static unsigned long bc_program_scale(BcNum *n)
6091 return (unsigned long) n->rdx;
6094 static unsigned long bc_program_len(BcNum *n)
6096 unsigned long len = n->len;
6099 if (n->rdx != n->len) return len;
6100 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6105 static BcStatus bc_program_builtin(char inst)
6111 bool len = inst == BC_INST_LENGTH;
6113 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6114 opnd = bc_vec_top(&G.prog.results);
6116 s = bc_program_num(opnd, &num, false);
6120 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6123 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6125 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6127 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6128 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6132 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6135 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6137 str = bc_vec_item(&G.prog.strs, idx);
6138 bc_num_ulong2num(&res.d.n, strlen(*str));
6142 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6143 bc_num_ulong2num(&res.d.n, f(num));
6146 bc_program_retire(&res, BC_RESULT_TEMP);
6152 static BcStatus bc_program_divmod(void)
6155 BcResult *opd1, *opd2, res, res2;
6156 BcNum *n1, *n2 = NULL;
6158 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6161 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6162 bc_num_init(&res2.d.n, n2->len);
6164 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6167 bc_program_binOpRetire(&res2);
6168 res.t = BC_RESULT_TEMP;
6169 bc_vec_push(&G.prog.results, &res);
6174 bc_num_free(&res2.d.n);
6175 bc_num_free(&res.d.n);
6179 static BcStatus bc_program_modexp(void)
6182 BcResult *r1, *r2, *r3, res;
6183 BcNum *n1, *n2, *n3;
6185 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6186 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6189 r1 = bc_vec_item_rev(&G.prog.results, 2);
6190 s = bc_program_num(r1, &n1, false);
6192 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6194 // Make sure that the values have their pointers updated, if necessary.
6195 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6197 if (r1->t == r2->t) {
6198 s = bc_program_num(r2, &n2, false);
6202 if (r1->t == r3->t) {
6203 s = bc_program_num(r3, &n3, false);
6208 bc_num_init(&res.d.n, n3->len);
6209 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6212 bc_vec_pop(&G.prog.results);
6213 bc_program_binOpRetire(&res);
6218 bc_num_free(&res.d.n);
6222 static void bc_program_stackLen(void)
6225 size_t len = G.prog.results.len;
6227 res.t = BC_RESULT_TEMP;
6229 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6230 bc_num_ulong2num(&res.d.n, len);
6231 bc_vec_push(&G.prog.results, &res);
6234 static BcStatus bc_program_asciify(void)
6238 BcNum *num = NULL, n;
6239 char *str, *str2, c;
6240 size_t len = G.prog.strs.len, idx;
6243 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6244 r = bc_vec_top(&G.prog.results);
6246 s = bc_program_num(r, &num, false);
6249 if (BC_PROG_NUM(r, num)) {
6251 bc_num_init(&n, BC_NUM_DEF_SIZE);
6252 bc_num_copy(&n, num);
6253 bc_num_truncate(&n, n.rdx);
6255 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6256 if (s) goto num_err;
6257 s = bc_num_ulong(&n, &val);
6258 if (s) goto num_err;
6265 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6266 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6274 str2 = xstrdup(str);
6275 bc_program_addFunc(str2, &idx);
6277 if (idx != len + BC_PROG_REQ_FUNCS) {
6279 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6280 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6289 bc_vec_push(&G.prog.strs, &str);
6291 res.t = BC_RESULT_STR;
6293 bc_vec_pop(&G.prog.results);
6294 bc_vec_push(&G.prog.results, &res);
6296 return BC_STATUS_SUCCESS;
6303 static BcStatus bc_program_printStream(void)
6311 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6312 r = bc_vec_top(&G.prog.results);
6314 s = bc_program_num(r, &n, false);
6317 if (BC_PROG_NUM(r, n))
6318 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6320 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6321 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6328 static BcStatus bc_program_nquit(void)
6335 s = bc_program_prep(&opnd, &num);
6337 s = bc_num_ulong(num, &val);
6340 bc_vec_pop(&G.prog.results);
6342 if (G.prog.stack.len < val)
6343 return BC_STATUS_EXEC_STACK;
6344 else if (G.prog.stack.len == val)
6345 return BC_STATUS_QUIT;
6347 bc_vec_npop(&G.prog.stack, val);
6352 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6355 BcStatus s = BC_STATUS_SUCCESS;
6365 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6367 r = bc_vec_top(&G.prog.results);
6371 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6373 if (code[*bgn] == BC_PARSE_STREND)
6376 else_name = bc_program_name(code, bgn);
6378 exec = r->d.n.len != 0;
6382 else if (else_name != NULL) {
6389 v = bc_program_search(name, true);
6396 if (!exec) goto exit;
6397 if (!BC_PROG_STR(n)) {
6398 s = BC_STATUS_EXEC_BAD_TYPE;
6406 if (r->t == BC_RESULT_STR)
6408 else if (r->t == BC_RESULT_VAR) {
6409 s = bc_program_num(r, &n, false);
6410 if (s || !BC_PROG_STR(n)) goto exit;
6417 fidx = sidx + BC_PROG_REQ_FUNCS;
6419 str = bc_vec_item(&G.prog.strs, sidx);
6420 f = bc_vec_item(&G.prog.fns, fidx);
6422 if (f->code.len == 0) {
6423 common_parse_init(&prs, fidx);
6424 s = bc_parse_text(&prs, *str);
6426 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6429 if (prs.l.t.t != BC_LEX_EOF) {
6430 s = BC_STATUS_PARSE_BAD_EXP;
6434 bc_parse_free(&prs);
6438 ip.len = G.prog.results.len;
6441 bc_vec_pop(&G.prog.results);
6442 bc_vec_push(&G.prog.stack, &ip);
6444 return BC_STATUS_SUCCESS;
6447 bc_parse_free(&prs);
6448 f = bc_vec_item(&G.prog.fns, fidx);
6449 bc_vec_npop(&f->code, f->code.len);
6451 bc_vec_pop(&G.prog.results);
6456 static void bc_program_pushGlobal(char inst)
6461 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6462 if (inst == BC_INST_IBASE)
6463 val = (unsigned long) G.prog.ib_t;
6464 else if (inst == BC_INST_SCALE)
6465 val = (unsigned long) G.prog.scale;
6467 val = (unsigned long) G.prog.ob_t;
6469 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6470 bc_num_ulong2num(&res.d.n, val);
6471 bc_vec_push(&G.prog.results, &res);
6474 static void bc_program_addFunc(char *name, size_t *idx)
6477 BcId entry, *entry_ptr;
6481 entry.idx = G.prog.fns.len;
6483 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6486 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6487 *idx = entry_ptr->idx;
6489 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6491 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6493 // We need to reset these, so the function can be repopulated.
6495 bc_vec_npop(&func->autos, func->autos.len);
6496 bc_vec_npop(&func->code, func->code.len);
6497 bc_vec_npop(&func->labels, func->labels.len);
6501 bc_vec_push(&G.prog.fns, &f);
6505 static BcStatus bc_program_reset(BcStatus s)
6510 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6511 bc_vec_npop(&G.prog.results, G.prog.results.len);
6513 f = bc_vec_item(&G.prog.fns, 0);
6514 ip = bc_vec_top(&G.prog.stack);
6515 ip->idx = f->code.len;
6517 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6519 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6522 fputs(bc_program_ready_msg, stderr);
6524 s = BC_STATUS_SUCCESS;
6533 static BcStatus bc_program_exec(void)
6535 BcStatus s = BC_STATUS_SUCCESS;
6539 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6540 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6541 char *code = func->code.v;
6544 while (!s && ip->idx < func->code.len) {
6546 char inst = code[(ip->idx)++];
6551 case BC_INST_JUMP_ZERO:
6553 s = bc_program_prep(&ptr, &num);
6555 cond = !bc_num_cmp(num, &G.prog.zero);
6556 bc_vec_pop(&G.prog.results);
6562 idx = bc_program_index(code, &ip->idx);
6563 addr = bc_vec_item(&func->labels, idx);
6564 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6570 s = bc_program_call(code, &ip->idx);
6574 case BC_INST_INC_PRE:
6575 case BC_INST_DEC_PRE:
6576 case BC_INST_INC_POST:
6577 case BC_INST_DEC_POST:
6579 s = bc_program_incdec(inst);
6592 s = bc_program_return(inst);
6596 case BC_INST_BOOL_OR:
6597 case BC_INST_BOOL_AND:
6599 case BC_INST_REL_EQ:
6600 case BC_INST_REL_LE:
6601 case BC_INST_REL_GE:
6602 case BC_INST_REL_NE:
6603 case BC_INST_REL_LT:
6604 case BC_INST_REL_GT:
6606 s = bc_program_logical(inst);
6612 s = bc_program_read();
6618 s = bc_program_pushVar(code, &ip->idx, false, false);
6622 case BC_INST_ARRAY_ELEM:
6625 s = bc_program_pushArray(code, &ip->idx, inst);
6631 r.t = BC_RESULT_LAST;
6632 bc_vec_push(&G.prog.results, &r);
6640 bc_program_pushGlobal(inst);
6644 case BC_INST_SCALE_FUNC:
6645 case BC_INST_LENGTH:
6648 s = bc_program_builtin(inst);
6654 r.t = BC_RESULT_CONSTANT;
6655 r.d.id.idx = bc_program_index(code, &ip->idx);
6656 bc_vec_push(&G.prog.results, &r);
6662 if (!BC_PROG_STACK(&G.prog.results, 1))
6663 s = BC_STATUS_EXEC_STACK;
6665 bc_vec_pop(&G.prog.results);
6669 case BC_INST_POP_EXEC:
6671 bc_vec_pop(&G.prog.stack);
6676 case BC_INST_PRINT_POP:
6677 case BC_INST_PRINT_STR:
6679 s = bc_program_print(inst, 0);
6685 r.t = BC_RESULT_STR;
6686 r.d.id.idx = bc_program_index(code, &ip->idx);
6687 bc_vec_push(&G.prog.results, &r);
6692 case BC_INST_MULTIPLY:
6693 case BC_INST_DIVIDE:
6694 case BC_INST_MODULUS:
6698 s = bc_program_op(inst);
6702 case BC_INST_BOOL_NOT:
6704 s = bc_program_prep(&ptr, &num);
6707 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6708 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6709 bc_program_retire(&r, BC_RESULT_TEMP);
6716 s = bc_program_negate();
6721 case BC_INST_ASSIGN_POWER:
6722 case BC_INST_ASSIGN_MULTIPLY:
6723 case BC_INST_ASSIGN_DIVIDE:
6724 case BC_INST_ASSIGN_MODULUS:
6725 case BC_INST_ASSIGN_PLUS:
6726 case BC_INST_ASSIGN_MINUS:
6728 case BC_INST_ASSIGN:
6730 s = bc_program_assign(inst);
6734 case BC_INST_MODEXP:
6736 s = bc_program_modexp();
6740 case BC_INST_DIVMOD:
6742 s = bc_program_divmod();
6746 case BC_INST_EXECUTE:
6747 case BC_INST_EXEC_COND:
6749 cond = inst == BC_INST_EXEC_COND;
6750 s = bc_program_execStr(code, &ip->idx, cond);
6754 case BC_INST_PRINT_STACK:
6756 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6757 s = bc_program_print(BC_INST_PRINT, idx);
6761 case BC_INST_CLEAR_STACK:
6763 bc_vec_npop(&G.prog.results, G.prog.results.len);
6767 case BC_INST_STACK_LEN:
6769 bc_program_stackLen();
6773 case BC_INST_DUPLICATE:
6775 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6776 ptr = bc_vec_top(&G.prog.results);
6777 bc_result_copy(&r, ptr);
6778 bc_vec_push(&G.prog.results, &r);
6786 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6788 ptr = bc_vec_item_rev(&G.prog.results, 0);
6789 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6790 memcpy(&r, ptr, sizeof(BcResult));
6791 memcpy(ptr, ptr2, sizeof(BcResult));
6792 memcpy(ptr2, &r, sizeof(BcResult));
6797 case BC_INST_ASCIIFY:
6799 s = bc_program_asciify();
6803 case BC_INST_PRINT_STREAM:
6805 s = bc_program_printStream();
6810 case BC_INST_PUSH_VAR:
6812 bool copy = inst == BC_INST_LOAD;
6813 s = bc_program_pushVar(code, &ip->idx, true, copy);
6817 case BC_INST_PUSH_TO_VAR:
6819 char *name = bc_program_name(code, &ip->idx);
6820 s = bc_program_copyToVar(name, true);
6827 if (G.prog.stack.len <= 2)
6830 bc_vec_npop(&G.prog.stack, 2);
6836 s = bc_program_nquit();
6842 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
6844 // If the stack has changed, pointers may be invalid.
6845 ip = bc_vec_top(&G.prog.stack);
6846 func = bc_vec_item(&G.prog.fns, ip->func);
6847 code = func->code.v;
6853 static void bc_vm_info(void)
6855 printf("%s "BB_VER"\n"
6856 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6857 "Report bugs at: https://github.com/gavinhoward/bc\n"
6858 "This is free software with ABSOLUTELY NO WARRANTY\n"
6862 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6864 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6866 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6867 fprintf(stderr, " %s", file);
6868 fprintf(stderr, bc_err_line + 4 * !line, line);
6870 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6874 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6877 int p = (int) G_posix, w = (int) G_warn;
6878 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6880 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6882 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6883 if (msg) fprintf(stderr, " %s\n", msg);
6884 fprintf(stderr, " %s", file);
6885 fprintf(stderr, bc_err_line + 4 * !line, line);
6887 return s * (!G.ttyin && !!p);
6890 static void bc_vm_envArgs(void)
6892 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6895 char *env_args = getenv(bc_args_env_name), *buf;
6897 if (!env_args) return;
6899 G.env_args = xstrdup(env_args);
6902 bc_vec_init(&v, sizeof(char *), NULL);
6903 bc_vec_push(&v, &bc_args_env_name);
6906 if (!isspace(*buf)) {
6907 bc_vec_push(&v, &buf);
6908 while (*buf != 0 && !isspace(*buf)) ++buf;
6909 if (*buf != 0) (*(buf++)) = '\0';
6915 bc_args((int) v.len, (char **) v.v);
6921 static size_t bc_vm_envLen(const char *var)
6923 char *lenv = getenv(var);
6924 size_t i, len = BC_NUM_PRINT_WIDTH;
6927 if (!lenv) return len;
6931 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6933 len = (size_t) atoi(lenv) - 1;
6934 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6937 len = BC_NUM_PRINT_WIDTH;
6942 static BcStatus bc_vm_process(const char *text)
6944 BcStatus s = bc_parse_text(&G.prs, text);
6946 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6949 while (G.prs.l.t.t != BC_LEX_EOF) {
6951 s = G.prs.parse(&G.prs);
6953 if (s == BC_STATUS_LIMITS) {
6955 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
6956 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
6957 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
6958 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
6959 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
6960 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
6961 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
6962 printf("Number of vars = %lu\n", BC_MAX_VARS);
6964 s = BC_STATUS_SUCCESS;
6967 if (s == BC_STATUS_QUIT) return s;
6968 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6973 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6974 s = bc_program_exec();
6975 if (!s && G.tty) fflush(stdout);
6976 if (s && s != BC_STATUS_QUIT)
6977 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6983 static BcStatus bc_vm_file(const char *file)
6991 data = bc_read_file(file);
6992 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
6994 bc_lex_file(&G.prs.l, file);
6995 s = bc_vm_process(data);
6998 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6999 ip = bc_vec_item(&G.prog.stack, 0);
7001 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7008 static BcStatus bc_vm_stdin(void)
7012 size_t len, i, str = 0;
7013 bool comment = false;
7015 G.prog.file = bc_program_stdin_name;
7016 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7018 bc_vec_init(&buffer, sizeof(char), NULL);
7019 bc_vec_init(&buf, sizeof(char), NULL);
7020 bc_vec_pushByte(&buffer, '\0');
7022 // This loop is complex because the vm tries not to send any lines that end
7023 // with a backslash to the parser. The reason for that is because the parser
7024 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7025 // case, and for strings and comments, the parser will expect more stuff.
7026 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7028 char *string = buf.v;
7033 if (str && buf.v[0] == G.send)
7035 else if (buf.v[0] == G.sbgn)
7038 else if (len > 1 || comment) {
7040 for (i = 0; i < len; ++i) {
7042 bool notend = len > i + 1;
7045 if (i - 1 > len || string[i - 1] != '\\') {
7046 if (G.sbgn == G.send)
7048 else if (c == G.send)
7050 else if (c == G.sbgn)
7054 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7058 else if (c == '*' && notend && comment && string[i + 1] == '/')
7062 if (str || comment || string[len - 2] == '\\') {
7063 bc_vec_concat(&buffer, buf.v);
7068 bc_vec_concat(&buffer, buf.v);
7069 s = bc_vm_process(buffer.v);
7072 bc_vec_npop(&buffer, buffer.len);
7075 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7077 // INPUT_EOF will always happen when stdin is
7078 // closed. It's not a problem in that case.
7079 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7080 s = BC_STATUS_SUCCESS;
7083 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7086 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7091 bc_vec_free(&buffer);
7095 static BcStatus bc_vm_exec(void)
7097 BcStatus s = BC_STATUS_SUCCESS;
7101 if (G.flags & BC_FLAG_L) {
7103 bc_lex_file(&G.prs.l, bc_lib_name);
7104 s = bc_parse_text(&G.prs, bc_lib);
7106 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7109 s = bc_program_exec();
7114 for (i = 0; !s && i < G.files.len; ++i)
7115 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7116 if (s && s != BC_STATUS_QUIT) return s;
7118 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7119 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7121 if (s == BC_STATUS_QUIT)
7122 s = BC_STATUS_SUCCESS;
7126 #if ENABLE_FEATURE_CLEAN_UP
7127 static void bc_program_free()
7129 bc_num_free(&G.prog.ib);
7130 bc_num_free(&G.prog.ob);
7131 bc_num_free(&G.prog.hexb);
7133 bc_num_free(&G.prog.strmb);
7135 bc_vec_free(&G.prog.fns);
7136 bc_vec_free(&G.prog.fn_map);
7137 bc_vec_free(&G.prog.vars);
7138 bc_vec_free(&G.prog.var_map);
7139 bc_vec_free(&G.prog.arrs);
7140 bc_vec_free(&G.prog.arr_map);
7141 bc_vec_free(&G.prog.strs);
7142 bc_vec_free(&G.prog.consts);
7143 bc_vec_free(&G.prog.results);
7144 bc_vec_free(&G.prog.stack);
7145 bc_num_free(&G.prog.last);
7146 bc_num_free(&G.prog.zero);
7147 bc_num_free(&G.prog.one);
7150 static void bc_vm_free(void)
7152 bc_vec_free(&G.files);
7154 bc_parse_free(&G.prs);
7159 static void bc_program_init(size_t line_len)
7164 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7165 memset(&ip, 0, sizeof(BcInstPtr));
7167 /* G.prog.nchars = G.prog.scale = 0; - already is */
7168 G.prog.len = line_len;
7170 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7171 bc_num_ten(&G.prog.ib);
7174 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7175 bc_num_ten(&G.prog.ob);
7178 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7179 bc_num_ten(&G.prog.hexb);
7180 G.prog.hexb.num[0] = 6;
7183 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7184 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7187 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7188 bc_num_zero(&G.prog.last);
7190 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7191 bc_num_zero(&G.prog.zero);
7193 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7194 bc_num_one(&G.prog.one);
7196 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7197 bc_map_init(&G.prog.fn_map);
7199 bc_program_addFunc(xstrdup("(main)"), &idx);
7200 bc_program_addFunc(xstrdup("(read)"), &idx);
7202 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7203 bc_map_init(&G.prog.var_map);
7205 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7206 bc_map_init(&G.prog.arr_map);
7208 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7209 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7210 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7211 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7212 bc_vec_push(&G.prog.stack, &ip);
7215 static void bc_vm_init(const char *env_len)
7217 size_t len = bc_vm_envLen(env_len);
7219 #if ENABLE_FEATURE_BC_SIGNALS
7220 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7223 bc_vec_init(&G.files, sizeof(char *), NULL);
7226 if (getenv("POSIXLY_CORRECT"))
7227 G.flags |= BC_FLAG_S;
7231 bc_program_init(len);
7233 bc_parse_init(&G.prs, BC_PROG_MAIN);
7235 dc_parse_init(&G.prs, BC_PROG_MAIN);
7239 static BcStatus bc_vm_run(int argc, char *argv[],
7240 const char *env_len)
7244 bc_vm_init(env_len);
7245 bc_args(argc, argv);
7247 G.ttyin = isatty(0);
7248 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7250 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7253 #if ENABLE_FEATURE_CLEAN_UP
7260 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7261 int bc_main(int argc, char **argv)
7264 G.sbgn = G.send = '"';
7266 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7271 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7272 int dc_main(int argc, char **argv)
7278 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");