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 {
173 // BC_STATUS_ALLOC_ERR,
176 // BC_STATUS_PATH_IS_DIR,
178 BC_STATUS_LEX_BAD_CHAR,
179 BC_STATUS_LEX_NO_STRING_END,
180 BC_STATUS_LEX_NO_COMMENT_END,
183 BC_STATUS_LEX_EXTENDED_REG,
185 BC_STATUS_PARSE_BAD_TOKEN,
186 BC_STATUS_PARSE_BAD_EXP,
187 BC_STATUS_PARSE_EMPTY_EXP,
188 BC_STATUS_PARSE_BAD_PRINT,
189 BC_STATUS_PARSE_BAD_FUNC,
190 BC_STATUS_PARSE_BAD_ASSIGN,
191 BC_STATUS_PARSE_NO_AUTO,
192 BC_STATUS_PARSE_DUPLICATE_LOCAL,
193 BC_STATUS_PARSE_NO_BLOCK_END,
195 BC_STATUS_MATH_NEGATIVE,
196 BC_STATUS_MATH_NON_INTEGER,
197 BC_STATUS_MATH_OVERFLOW,
198 BC_STATUS_MATH_DIVIDE_BY_ZERO,
199 BC_STATUS_MATH_BAD_STRING,
201 // BC_STATUS_EXEC_FILE_ERR,
202 BC_STATUS_EXEC_MISMATCHED_PARAMS,
203 BC_STATUS_EXEC_UNDEFINED_FUNC,
204 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
205 BC_STATUS_EXEC_NUM_LEN,
206 BC_STATUS_EXEC_NAME_LEN,
207 BC_STATUS_EXEC_STRING_LEN,
208 BC_STATUS_EXEC_ARRAY_LEN,
209 BC_STATUS_EXEC_BAD_IBASE,
210 // BC_STATUS_EXEC_BAD_SCALE,
211 BC_STATUS_EXEC_BAD_READ_EXPR,
212 BC_STATUS_EXEC_REC_READ,
213 BC_STATUS_EXEC_BAD_TYPE,
214 // BC_STATUS_EXEC_BAD_OBASE,
215 BC_STATUS_EXEC_SIGNAL,
216 BC_STATUS_EXEC_STACK,
218 // BC_STATUS_VEC_OUT_OF_BOUNDS,
219 BC_STATUS_VEC_ITEM_EXISTS,
221 BC_STATUS_POSIX_NAME_LEN,
222 BC_STATUS_POSIX_COMMENT,
223 BC_STATUS_POSIX_BAD_KW,
226 BC_STATUS_POSIX_BOOL,
227 BC_STATUS_POSIX_REL_POS,
228 BC_STATUS_POSIX_MULTIREL,
229 BC_STATUS_POSIX_FOR1,
230 BC_STATUS_POSIX_FOR2,
231 BC_STATUS_POSIX_FOR3,
232 BC_STATUS_POSIX_BRACE,
237 // BC_STATUS_INVALID_OPTION,
239 // Keep enum above and messages below in sync!
240 static const char *const bc_err_msgs[] = {
242 // "memory allocation error",
245 // "path is a directory:",
248 "string end could not be found",
249 "comment end could not be found",
257 "bad print statement",
258 "bad function definition",
259 "bad assignment: left side must be scale, ibase, "
260 "obase, last, var, or array element",
261 "no auto variable found",
262 "function parameter or auto var has the same name as another",
263 "block end could not be found",
266 "non integer number",
271 // "could not open file:",
272 "mismatched parameters", // wrong number of them, to be exact
273 "undefined function",
274 "file is not executable:",
275 "number too long: must be [1, BC_NUM_MAX]",
276 "name too long: must be [1, BC_NAME_MAX]",
277 "string too long: must be [1, BC_STRING_MAX]",
278 "array too long; must be [1, BC_DIM_MAX]",
279 "bad ibase; must be [2, 16]",
280 // "bad scale; must be [0, BC_SCALE_MAX]",
281 "bad read() expression",
282 "read() call inside of a read() call",
283 "variable is wrong type",
284 // "bad obase; must be [2, BC_BASE_MAX]",
285 "signal caught and not handled",
286 "stack has too few elements",
288 // "index is out of bounds",
289 "item already exists",
291 "POSIX only allows one character names; the following is bad:",
292 "POSIX does not allow '#' script comments",
293 "POSIX does not allow the following keyword:",
294 "POSIX does not allow a period ('.') as a shortcut for the last result",
295 "POSIX requires parentheses around return expressions",
296 "POSIX does not allow boolean operators; the following is bad:",
297 "POSIX does not allow comparison operators outside if or loops",
298 "POSIX requires exactly one comparison operator per condition",
299 "POSIX does not allow an empty init expression in a for loop",
300 "POSIX does not allow an empty condition expression in a for loop",
301 "POSIX does not allow an empty update expression in a for loop",
302 "POSIX requires the left brace be on the same line as the function header",
306 #define BC_VEC_INVALID_IDX ((size_t) -1)
307 #define BC_VEC_START_CAP (1 << 5)
309 typedef void (*BcVecFree)(void *);
311 typedef struct BcVec {
319 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
320 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
322 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
324 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
326 typedef signed char BcDig;
328 typedef struct BcNum {
336 #define BC_NUM_MIN_BASE ((unsigned long) 2)
337 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
338 #define BC_NUM_DEF_SIZE (16)
339 #define BC_NUM_PRINT_WIDTH (69)
341 #define BC_NUM_KARATSUBA_LEN (32)
343 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
344 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
345 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
346 #define BC_NUM_AREQ(a, b) \
347 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
348 #define BC_NUM_MREQ(a, b, scale) \
349 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
351 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
352 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
354 static void bc_num_init(BcNum *n, size_t req);
355 static void bc_num_expand(BcNum *n, size_t req);
356 static void bc_num_copy(BcNum *d, BcNum *s);
357 static void bc_num_free(void *num);
359 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
360 static void bc_num_ulong2num(BcNum *n, unsigned long val);
362 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
363 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
364 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
369 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
372 typedef enum BcInst {
402 BC_INST_ASSIGN_POWER,
403 BC_INST_ASSIGN_MULTIPLY,
404 BC_INST_ASSIGN_DIVIDE,
405 BC_INST_ASSIGN_MODULUS,
407 BC_INST_ASSIGN_MINUS,
453 BC_INST_PRINT_STREAM,
468 BC_INST_INVALID = -1,
473 typedef struct BcId {
478 typedef struct BcFunc {
485 typedef enum BcResultType {
490 BC_RESULT_ARRAY_ELEM,
499 // These are between to calculate ibase, obase, and last from instructions.
507 typedef union BcResultData {
513 typedef struct BcResult {
518 typedef struct BcInstPtr {
524 static void bc_array_expand(BcVec *a, size_t len);
525 static int bc_id_cmp(const void *e1, const void *e2);
527 // BC_LEX_NEG is not used in lexing; it is only for parsing.
528 typedef enum BcLexType {
556 BC_LEX_OP_ASSIGN_POWER,
557 BC_LEX_OP_ASSIGN_MULTIPLY,
558 BC_LEX_OP_ASSIGN_DIVIDE,
559 BC_LEX_OP_ASSIGN_MODULUS,
560 BC_LEX_OP_ASSIGN_PLUS,
561 BC_LEX_OP_ASSIGN_MINUS,
635 typedef BcStatus (*BcLexNext)(struct BcLex *);
637 typedef struct BcLex {
656 #define BC_PARSE_STREND ((char) UCHAR_MAX)
658 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
659 #define bc_parse_updateFunc(p, f) \
660 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
662 #define BC_PARSE_REL (1 << 0)
663 #define BC_PARSE_PRINT (1 << 1)
664 #define BC_PARSE_NOCALL (1 << 2)
665 #define BC_PARSE_NOREAD (1 << 3)
666 #define BC_PARSE_ARRAY (1 << 4)
668 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
669 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
671 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
672 #define BC_PARSE_FUNC_INNER(parse) \
673 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
675 #define BC_PARSE_FLAG_FUNC (1 << 1)
676 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
678 #define BC_PARSE_FLAG_BODY (1 << 2)
679 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
681 #define BC_PARSE_FLAG_LOOP (1 << 3)
682 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
684 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
685 #define BC_PARSE_LOOP_INNER(parse) \
686 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
688 #define BC_PARSE_FLAG_IF (1 << 5)
689 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
691 #define BC_PARSE_FLAG_ELSE (1 << 6)
692 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
694 #define BC_PARSE_FLAG_IF_END (1 << 7)
695 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
697 #define BC_PARSE_CAN_EXEC(parse) \
698 (!(BC_PARSE_TOP_FLAG(parse) & \
699 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
700 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
701 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
703 typedef struct BcOp {
708 typedef struct BcParseNext {
713 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
714 #define BC_PARSE_NEXT(a, ...) \
716 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
723 typedef BcStatus (*BcParseParse)(struct BcParse *);
725 typedef struct BcParse {
748 typedef struct BcLexKeyword {
754 #define BC_LEX_KW_ENTRY(a, b, c) \
756 .name = a, .len = (b), .posix = (c) \
759 static BcStatus bc_lex_token(BcLex *l);
761 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
762 #define BC_PARSE_LEAF(p, rparen) \
763 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
764 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
766 // We can calculate the conversion between tokens and exprs by subtracting the
767 // position of the first operator in the lex enum and adding the position of the
768 // first in the expr enum. Note: This only works for binary operators.
769 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
771 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
777 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
779 static BcStatus dc_lex_token(BcLex *l);
781 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
785 typedef struct BcProgram {
826 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
828 #define BC_PROG_MAIN (0)
829 #define BC_PROG_READ (1)
832 #define BC_PROG_REQ_FUNCS (2)
835 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
836 #define BC_PROG_NUM(r, n) \
837 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
839 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
841 static void bc_program_addFunc(char *name, size_t *idx);
842 static BcStatus bc_program_reset(BcStatus s);
844 #define BC_FLAG_X (1 << 0)
845 #define BC_FLAG_W (1 << 1)
846 #define BC_FLAG_V (1 << 2)
847 #define BC_FLAG_S (1 << 3)
848 #define BC_FLAG_Q (1 << 4)
849 #define BC_FLAG_L (1 << 5)
850 #define BC_FLAG_I (1 << 6)
852 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
853 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
855 #define BC_MAX_OBASE ((unsigned) 999)
856 #define BC_MAX_DIM ((unsigned) INT_MAX)
857 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
858 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
859 #define BC_MAX_NAME BC_MAX_STRING
860 #define BC_MAX_NUM BC_MAX_STRING
861 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
862 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
879 #define G (*ptr_to_globals)
880 #define INIT_G() do { \
881 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
883 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
884 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
885 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
886 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
889 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
892 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
896 static void bc_vm_info(void);
898 static const char bc_err_fmt[] = "\nerror: %s\n";
899 static const char bc_warn_fmt[] = "\nwarning: %s\n";
900 static const char bc_err_line[] = ":%zu\n\n";
903 static const BcLexKeyword bc_lex_kws[20] = {
904 BC_LEX_KW_ENTRY("auto", 4, true),
905 BC_LEX_KW_ENTRY("break", 5, true),
906 BC_LEX_KW_ENTRY("continue", 8, false),
907 BC_LEX_KW_ENTRY("define", 6, true),
908 BC_LEX_KW_ENTRY("else", 4, false),
909 BC_LEX_KW_ENTRY("for", 3, true),
910 BC_LEX_KW_ENTRY("halt", 4, false),
911 BC_LEX_KW_ENTRY("ibase", 5, true),
912 BC_LEX_KW_ENTRY("if", 2, true),
913 BC_LEX_KW_ENTRY("last", 4, false),
914 BC_LEX_KW_ENTRY("length", 6, true),
915 BC_LEX_KW_ENTRY("limits", 6, false),
916 BC_LEX_KW_ENTRY("obase", 5, true),
917 BC_LEX_KW_ENTRY("print", 5, false),
918 BC_LEX_KW_ENTRY("quit", 4, true),
919 BC_LEX_KW_ENTRY("read", 4, false),
920 BC_LEX_KW_ENTRY("return", 6, true),
921 BC_LEX_KW_ENTRY("scale", 5, true),
922 BC_LEX_KW_ENTRY("sqrt", 4, true),
923 BC_LEX_KW_ENTRY("while", 5, true),
926 // This is an array that corresponds to token types. An entry is
927 // true if the token is valid in an expression, false otherwise.
928 static const bool bc_parse_exprs[] = {
929 false, false, true, true, true, true, true, true, true, true, true, true,
930 true, true, true, true, true, true, true, true, true, true, true, true,
931 true, true, true, false, false, true, true, false, false, false, false,
932 false, false, false, true, true, false, false, false, false, false, false,
933 false, true, false, true, true, true, true, false, false, true, false, true,
937 // This is an array of data for operators that correspond to token types.
938 static const BcOp bc_parse_ops[] = {
939 { 0, false }, { 0, false },
942 { 3, true }, { 3, true }, { 3, true },
943 { 4, true }, { 4, true },
944 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
946 { 7, true }, { 7, true },
947 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
948 { 5, false }, { 5, false },
951 // These identify what tokens can come after expressions in certain cases.
952 static const BcParseNext bc_parse_next_expr =
953 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
954 static const BcParseNext bc_parse_next_param =
955 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
956 static const BcParseNext bc_parse_next_print =
957 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
958 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
959 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
960 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
961 static const BcParseNext bc_parse_next_read =
962 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
966 static const BcLexType dc_lex_regs[] = {
967 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
968 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
969 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
973 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
975 static const BcLexType dc_lex_tokens[] = {
976 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
977 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
978 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
979 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
980 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
981 BC_LEX_INVALID, BC_LEX_INVALID,
982 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
983 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
984 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
985 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
986 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
987 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
988 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
989 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
990 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
991 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
992 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
993 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
994 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
995 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
996 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
997 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
998 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
999 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1003 static const BcInst dc_parse_insts[] = {
1004 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1005 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1006 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1007 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1008 BC_INST_INVALID, BC_INST_INVALID,
1009 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1010 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1014 BC_INST_INVALID, BC_INST_INVALID,
1015 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1016 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1019 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1020 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1021 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1022 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1023 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1024 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1025 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1026 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1030 static const BcNumBinaryOp bc_program_ops[] = {
1031 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1034 static const char bc_program_stdin_name[] = "<stdin>";
1035 static const char bc_program_ready_msg[] = "ready for more input\n";
1038 static const char *bc_lib_name = "gen/lib.bc";
1040 static const char bc_lib[] = {
1041 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1042 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1043 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1044 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,
1045 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1046 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1047 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,
1048 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1049 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1050 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,
1051 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1052 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1053 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1054 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1055 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1056 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1057 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1058 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1059 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1060 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1061 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1062 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1063 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1064 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,
1065 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1066 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,
1067 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1068 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1069 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1070 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1071 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1072 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,
1073 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1074 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1075 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1076 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1077 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,
1078 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1079 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1080 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1081 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1082 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1083 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1084 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1085 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1086 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1087 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1088 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,
1089 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,
1090 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1091 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,
1092 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,
1093 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,
1094 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1095 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1096 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,
1097 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,
1098 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,
1099 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1100 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,
1101 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1102 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1103 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1104 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,
1105 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1106 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1107 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1108 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1109 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1110 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1111 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1112 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1113 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1114 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1115 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1116 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1117 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1118 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1119 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1120 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1124 static void bc_vec_grow(BcVec *v, size_t n)
1126 size_t cap = v->cap * 2;
1127 while (cap < v->len + n) cap *= 2;
1128 v->v = xrealloc(v->v, v->size * cap);
1132 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1135 v->cap = BC_VEC_START_CAP;
1138 v->v = xmalloc(esize * BC_VEC_START_CAP);
1141 static void bc_vec_expand(BcVec *v, size_t req)
1144 v->v = xrealloc(v->v, v->size * req);
1149 static void bc_vec_npop(BcVec *v, size_t n)
1154 size_t len = v->len - n;
1155 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1159 static void bc_vec_push(BcVec *v, const void *data)
1161 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1162 memmove(v->v + (v->size * v->len), data, v->size);
1166 static void bc_vec_pushByte(BcVec *v, char data)
1168 bc_vec_push(v, &data);
1171 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1174 bc_vec_push(v, data);
1179 if (v->len == v->cap) bc_vec_grow(v, 1);
1181 ptr = v->v + v->size * idx;
1183 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1184 memmove(ptr, data, v->size);
1188 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1190 bc_vec_npop(v, v->len);
1191 bc_vec_expand(v, len + 1);
1192 memcpy(v->v, str, len);
1195 bc_vec_pushByte(v, '\0');
1198 static void bc_vec_concat(BcVec *v, const char *str)
1202 if (v->len == 0) bc_vec_pushByte(v, '\0');
1204 len = v->len + strlen(str);
1206 if (v->cap < len) bc_vec_grow(v, len - v->len);
1212 static void *bc_vec_item(const BcVec *v, size_t idx)
1214 return v->v + v->size * idx;
1217 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1219 return v->v + v->size * (v->len - idx - 1);
1222 static void bc_vec_free(void *vec)
1224 BcVec *v = (BcVec *) vec;
1225 bc_vec_npop(v, v->len);
1229 static size_t bc_map_find(const BcVec *v, const void *ptr)
1231 size_t low = 0, high = v->len;
1233 while (low < high) {
1235 size_t mid = (low + high) / 2;
1236 BcId *id = bc_vec_item(v, mid);
1237 int result = bc_id_cmp(ptr, id);
1241 else if (result < 0)
1250 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1252 BcStatus s = BC_STATUS_SUCCESS;
1254 *i = bc_map_find(v, ptr);
1257 bc_vec_push(v, ptr);
1258 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1259 s = BC_STATUS_VEC_ITEM_EXISTS;
1261 bc_vec_pushAt(v, ptr, *i);
1266 static size_t bc_map_index(const BcVec *v, const void *ptr)
1268 size_t i = bc_map_find(v, ptr);
1269 if (i >= v->len) return BC_VEC_INVALID_IDX;
1270 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1273 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1278 bc_vec_npop(vec, vec->len);
1281 #if ENABLE_FEATURE_BC_SIGNALS
1282 if (bb_got_signal) { /* ^C was pressed */
1284 bb_got_signal = 0; /* resets G_interrupt to zero */
1286 ? "\ninterrupt (type \"quit\" to exit)\n"
1287 : "\ninterrupt (type \"q\" to exit)\n"
1291 if (G.ttyin && !G_posix)
1292 fputs(prompt, stderr);
1295 #if ENABLE_FEATURE_BC_SIGNALS
1300 if (ferror(stdout) || ferror(stderr))
1301 bb_perror_msg_and_die("output error");
1305 #if ENABLE_FEATURE_BC_SIGNALS
1306 if (bb_got_signal) /* ^C was pressed */
1311 #if ENABLE_FEATURE_BC_SIGNALS
1312 if (errno == EINTR) {
1318 bb_perror_msg_and_die("input error");
1319 return BC_STATUS_INPUT_EOF;
1322 c = (signed char) i;
1323 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1324 bc_vec_push(vec, &c);
1325 } while (c != '\n');
1327 bc_vec_pushByte(vec, '\0');
1329 return BC_STATUS_SUCCESS;
1332 static char* bc_read_file(const char *path)
1335 size_t size = ((size_t) -1);
1338 buf = xmalloc_open_read_close(path, &size);
1340 for (i = 0; i < size; ++i) {
1341 if (BC_READ_BIN_CHAR(buf[i])) {
1351 static void bc_args(int argc, char **argv)
1356 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1357 G.flags = getopt32long(argv, "xwvsqli",
1358 "extended-register\0" No_argument "x"
1359 "warn\0" No_argument "w"
1360 "version\0" No_argument "v"
1361 "standard\0" No_argument "s"
1362 "quiet\0" No_argument "q"
1363 "mathlib\0" No_argument "l"
1364 "interactive\0" No_argument "i"
1367 G.flags = getopt32(argv, "xwvsqli");
1370 if (G.flags & BC_FLAG_V) bc_vm_info();
1371 // should not be necessary, getopt32() handles this??
1372 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1374 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1377 static void bc_num_setToZero(BcNum *n, size_t scale)
1384 static void bc_num_zero(BcNum *n)
1386 bc_num_setToZero(n, 0);
1389 static void bc_num_one(BcNum *n)
1391 bc_num_setToZero(n, 0);
1396 static void bc_num_ten(BcNum *n)
1398 bc_num_setToZero(n, 0);
1404 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1408 for (i = 0; i < len; ++i) {
1409 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1416 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1420 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1421 return BC_NUM_NEG(i + 1, c < 0);
1424 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1426 size_t i, min, a_int, b_int, diff;
1427 BcDig *max_num, *min_num;
1428 bool a_max, neg = false;
1431 if (a == b) return 0;
1432 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1433 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1443 a_int = BC_NUM_INT(a);
1444 b_int = BC_NUM_INT(b);
1446 a_max = (a->rdx > b->rdx);
1448 if (a_int != 0) return (ssize_t) a_int;
1452 diff = a->rdx - b->rdx;
1453 max_num = a->num + diff;
1458 diff = b->rdx - a->rdx;
1459 max_num = b->num + diff;
1463 cmp = bc_num_compare(max_num, min_num, b_int + min);
1464 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1466 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1467 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1473 static void bc_num_truncate(BcNum *n, size_t places)
1475 if (places == 0) return;
1481 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1485 static void bc_num_extend(BcNum *n, size_t places)
1487 size_t len = n->len + places;
1491 if (n->cap < len) bc_num_expand(n, len);
1493 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1494 memset(n->num, 0, sizeof(BcDig) * places);
1501 static void bc_num_clean(BcNum *n)
1503 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1506 else if (n->len < n->rdx)
1510 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1513 bc_num_extend(n, scale - n->rdx);
1515 bc_num_truncate(n, n->rdx - scale);
1518 if (n->len != 0) n->neg = !neg1 != !neg2;
1521 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1526 b->len = n->len - idx;
1528 a->rdx = b->rdx = 0;
1530 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1531 memcpy(a->num, n->num, idx * sizeof(BcDig));
1542 static BcStatus bc_num_shift(BcNum *n, size_t places)
1544 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1545 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1547 if (n->rdx >= places)
1550 bc_num_extend(n, places - n->rdx);
1556 return BC_STATUS_SUCCESS;
1559 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1568 return bc_num_div(&one, a, b, scale);
1571 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1573 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1574 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1577 // Because this function doesn't need to use scale (per the bc spec),
1578 // I am hijacking it to say whether it's doing an add or a subtract.
1582 if (sub && c->len) c->neg = !c->neg;
1583 return BC_STATUS_SUCCESS;
1585 else if (b->len == 0) {
1587 return BC_STATUS_SUCCESS;
1591 c->rdx = BC_MAX(a->rdx, b->rdx);
1592 min_rdx = BC_MIN(a->rdx, b->rdx);
1595 if (a->rdx > b->rdx) {
1596 diff = a->rdx - b->rdx;
1598 ptr_a = a->num + diff;
1602 diff = b->rdx - a->rdx;
1605 ptr_b = b->num + diff;
1608 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1611 a_int = BC_NUM_INT(a);
1612 b_int = BC_NUM_INT(b);
1614 if (a_int > b_int) {
1625 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1626 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1628 ptr_c[i] = (BcDig)(in % 10);
1631 for (; i < max + min_rdx; ++i, ++c->len) {
1632 in = ((int) ptr[i]) + carry;
1634 ptr_c[i] = (BcDig)(in % 10);
1637 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1639 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1642 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1645 BcNum *minuend, *subtrahend;
1647 bool aneg, bneg, neg;
1649 // Because this function doesn't need to use scale (per the bc spec),
1650 // I am hijacking it to say whether it's doing an add or a subtract.
1654 if (sub && c->len) c->neg = !c->neg;
1655 return BC_STATUS_SUCCESS;
1657 else if (b->len == 0) {
1659 return BC_STATUS_SUCCESS;
1664 a->neg = b->neg = false;
1666 cmp = bc_num_cmp(a, b);
1672 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1673 return BC_STATUS_SUCCESS;
1682 if (sub) neg = !neg;
1687 bc_num_copy(c, minuend);
1690 if (c->rdx < subtrahend->rdx) {
1691 bc_num_extend(c, subtrahend->rdx - c->rdx);
1695 start = c->rdx - subtrahend->rdx;
1697 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1701 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1704 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1709 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1710 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1711 bool aone = BC_NUM_ONE(a);
1713 if (a->len == 0 || b->len == 0) {
1715 return BC_STATUS_SUCCESS;
1717 else if (aone || BC_NUM_ONE(b)) {
1718 bc_num_copy(c, aone ? b : a);
1719 return BC_STATUS_SUCCESS;
1722 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1723 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1725 bc_num_expand(c, a->len + b->len + 1);
1727 memset(c->num, 0, sizeof(BcDig) * c->cap);
1728 c->len = carry = len = 0;
1730 for (i = 0; i < b->len; ++i) {
1732 for (j = 0; j < a->len; ++j) {
1733 int in = (int) c->num[i + j];
1734 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1736 c->num[i + j] = (BcDig)(in % 10);
1739 c->num[i + j] += (BcDig) carry;
1740 len = BC_MAX(len, i + j + !!carry);
1746 return BC_STATUS_SUCCESS;
1749 bc_num_init(&l1, max);
1750 bc_num_init(&h1, max);
1751 bc_num_init(&l2, max);
1752 bc_num_init(&h2, max);
1753 bc_num_init(&m1, max);
1754 bc_num_init(&m2, max);
1755 bc_num_init(&z0, max);
1756 bc_num_init(&z1, max);
1757 bc_num_init(&z2, max);
1758 bc_num_init(&temp, max + max);
1760 bc_num_split(a, max2, &l1, &h1);
1761 bc_num_split(b, max2, &l2, &h2);
1763 s = bc_num_add(&h1, &l1, &m1, 0);
1765 s = bc_num_add(&h2, &l2, &m2, 0);
1768 s = bc_num_k(&h1, &h2, &z0);
1770 s = bc_num_k(&m1, &m2, &z1);
1772 s = bc_num_k(&l1, &l2, &z2);
1775 s = bc_num_sub(&z1, &z0, &temp, 0);
1777 s = bc_num_sub(&temp, &z2, &z1, 0);
1780 s = bc_num_shift(&z0, max2 * 2);
1782 s = bc_num_shift(&z1, max2);
1784 s = bc_num_add(&z0, &z1, &temp, 0);
1786 s = bc_num_add(&temp, &z2, c, 0);
1802 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1806 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1808 scale = BC_MAX(scale, a->rdx);
1809 scale = BC_MAX(scale, b->rdx);
1810 scale = BC_MIN(a->rdx + b->rdx, scale);
1811 maxrdx = BC_MAX(maxrdx, scale);
1813 bc_num_init(&cpa, a->len);
1814 bc_num_init(&cpb, b->len);
1816 bc_num_copy(&cpa, a);
1817 bc_num_copy(&cpb, b);
1818 cpa.neg = cpb.neg = false;
1820 s = bc_num_shift(&cpa, maxrdx);
1822 s = bc_num_shift(&cpb, maxrdx);
1824 s = bc_num_k(&cpa, &cpb, c);
1828 bc_num_expand(c, c->len + maxrdx);
1830 if (c->len < maxrdx) {
1831 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1836 bc_num_retireMul(c, scale, a->neg, b->neg);
1844 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1846 BcStatus s = BC_STATUS_SUCCESS;
1853 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1854 else if (a->len == 0) {
1855 bc_num_setToZero(c, scale);
1856 return BC_STATUS_SUCCESS;
1858 else if (BC_NUM_ONE(b)) {
1860 bc_num_retireMul(c, scale, a->neg, b->neg);
1861 return BC_STATUS_SUCCESS;
1864 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1865 bc_num_copy(&cp, a);
1869 bc_num_expand(&cp, len + 2);
1870 bc_num_extend(&cp, len - cp.len);
1873 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1875 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1877 if (b->rdx == b->len) {
1878 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1882 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1884 // We want an extra zero in front to make things simpler.
1885 cp.num[cp.len++] = 0;
1888 bc_num_expand(c, cp.len);
1891 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1896 for (i = end - 1; !s && i < end; --i) {
1898 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1899 bc_num_subArrays(n, p, len);
1903 bc_num_retireMul(c, scale, a->neg, b->neg);
1906 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1909 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1910 BcNum *restrict d, size_t scale, size_t ts)
1916 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1919 bc_num_setToZero(d, ts);
1920 return BC_STATUS_SUCCESS;
1923 bc_num_init(&temp, d->cap);
1924 bc_num_d(a, b, c, scale);
1926 if (scale != 0) scale = ts;
1928 s = bc_num_m(c, b, &temp, scale);
1930 s = bc_num_sub(a, &temp, d, scale);
1933 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1936 bc_num_retireMul(d, ts, a->neg, b->neg);
1944 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1948 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1950 bc_num_init(&c1, len);
1951 s = bc_num_r(a, b, &c1, c, scale, ts);
1957 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1959 BcStatus s = BC_STATUS_SUCCESS;
1962 size_t i, powrdx, resrdx;
1965 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
1969 return BC_STATUS_SUCCESS;
1971 else if (a->len == 0) {
1972 bc_num_setToZero(c, scale);
1973 return BC_STATUS_SUCCESS;
1975 else if (BC_NUM_ONE(b)) {
1979 s = bc_num_inv(a, c, scale);
1986 s = bc_num_ulong(b, &pow);
1989 bc_num_init(©, a->len);
1990 bc_num_copy(©, a);
1992 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1996 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1998 s = bc_num_mul(©, ©, ©, powrdx);
2002 bc_num_copy(c, ©);
2004 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2007 s = bc_num_mul(©, ©, ©, powrdx);
2012 s = bc_num_mul(c, ©, c, resrdx);
2018 s = bc_num_inv(c, c, scale);
2022 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2024 // We can't use bc_num_clean() here.
2025 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2026 if (zero) bc_num_setToZero(c, scale);
2033 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2034 BcNumBinaryOp op, size_t req)
2037 BcNum num2, *ptr_a, *ptr_b;
2042 memcpy(ptr_a, c, sizeof(BcNum));
2051 memcpy(ptr_b, c, sizeof(BcNum));
2059 bc_num_init(c, req);
2061 bc_num_expand(c, req);
2063 s = op(ptr_a, ptr_b, c, scale);
2065 if (init) bc_num_free(&num2);
2070 static bool bc_num_strValid(const char *val, size_t base)
2073 bool small, radix = false;
2074 size_t i, len = strlen(val);
2076 if (!len) return true;
2079 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2081 for (i = 0; i < len; ++i) {
2087 if (radix) return false;
2093 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2100 static void bc_num_parseDecimal(BcNum *n, const char *val)
2106 for (i = 0; val[i] == '0'; ++i);
2113 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2114 bc_num_expand(n, len);
2117 ptr = strchr(val, '.');
2119 // Explicitly test for NULL here to produce either a 0 or 1.
2120 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2123 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2124 n->num[n->len] = val[i] - '0';
2128 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2131 BcNum temp, mult, result;
2135 size_t i, digits, len = strlen(val);
2139 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2142 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2143 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2145 for (i = 0; i < len; ++i) {
2148 if (c == '.') break;
2150 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2152 s = bc_num_mul(n, base, &mult, 0);
2153 if (s) goto int_err;
2154 bc_num_ulong2num(&temp, v);
2155 s = bc_num_add(&mult, &temp, n, 0);
2156 if (s) goto int_err;
2161 if (c == 0) goto int_err;
2164 bc_num_init(&result, base->len);
2165 bc_num_zero(&result);
2168 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2173 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2175 s = bc_num_mul(&result, base, &result, 0);
2177 bc_num_ulong2num(&temp, v);
2178 s = bc_num_add(&result, &temp, &result, 0);
2180 s = bc_num_mul(&mult, base, &mult, 0);
2184 s = bc_num_div(&result, &mult, &result, digits);
2186 s = bc_num_add(n, &result, n, digits);
2190 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2196 bc_num_free(&result);
2202 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2204 if (*nchars == line_len - 1) {
2212 static void bc_num_printChar(size_t num, size_t width, bool radix,
2213 size_t *nchars, size_t line_len)
2215 (void) radix, (void) line_len;
2216 bb_putchar((char) num);
2217 *nchars = *nchars + width;
2221 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2222 size_t *nchars, size_t line_len)
2226 bc_num_printNewline(nchars, line_len);
2227 bb_putchar(radix ? '.' : ' ');
2230 bc_num_printNewline(nchars, line_len);
2231 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2234 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2236 bc_num_printNewline(nchars, line_len);
2239 bb_putchar(((char) dig) + '0');
2243 static void bc_num_printHex(size_t num, size_t width, bool radix,
2244 size_t *nchars, size_t line_len)
2247 bc_num_printNewline(nchars, line_len);
2252 bc_num_printNewline(nchars, line_len);
2253 bb_putchar(bb_hexdigits_upcase[num]);
2254 *nchars = *nchars + width;
2257 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2259 size_t i, rdx = n->rdx - 1;
2261 if (n->neg) bb_putchar('-');
2262 (*nchars) += n->neg;
2264 for (i = n->len - 1; i < n->len; --i)
2265 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2268 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2269 size_t *nchars, size_t len, BcNumDigitOp print)
2273 BcNum intp, fracp, digit, frac_len;
2274 unsigned long dig, *ptr;
2279 print(0, width, false, nchars, len);
2280 return BC_STATUS_SUCCESS;
2283 bc_vec_init(&stack, sizeof(long), NULL);
2284 bc_num_init(&intp, n->len);
2285 bc_num_init(&fracp, n->rdx);
2286 bc_num_init(&digit, width);
2287 bc_num_init(&frac_len, BC_NUM_INT(n));
2288 bc_num_copy(&intp, n);
2289 bc_num_one(&frac_len);
2291 bc_num_truncate(&intp, intp.rdx);
2292 s = bc_num_sub(n, &intp, &fracp, 0);
2295 while (intp.len != 0) {
2296 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2298 s = bc_num_ulong(&digit, &dig);
2300 bc_vec_push(&stack, &dig);
2303 for (i = 0; i < stack.len; ++i) {
2304 ptr = bc_vec_item_rev(&stack, i);
2305 print(*ptr, width, false, nchars, len);
2308 if (!n->rdx) goto err;
2310 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2311 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2313 s = bc_num_ulong(&fracp, &dig);
2315 bc_num_ulong2num(&intp, dig);
2316 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2318 print(dig, width, radix, nchars, len);
2319 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2324 bc_num_free(&frac_len);
2325 bc_num_free(&digit);
2326 bc_num_free(&fracp);
2328 bc_vec_free(&stack);
2332 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2333 size_t *nchars, size_t line_len)
2340 if (neg) bb_putchar('-');
2345 if (base_t <= BC_NUM_MAX_IBASE) {
2347 print = bc_num_printHex;
2350 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2351 print = bc_num_printDigits;
2354 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2361 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2363 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2367 static void bc_num_init(BcNum *n, size_t req)
2369 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2370 memset(n, 0, sizeof(BcNum));
2371 n->num = xmalloc(req);
2375 static void bc_num_expand(BcNum *n, size_t req)
2377 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2379 n->num = xrealloc(n->num, req);
2384 static void bc_num_free(void *num)
2386 free(((BcNum *) num)->num);
2389 static void bc_num_copy(BcNum *d, BcNum *s)
2392 bc_num_expand(d, s->cap);
2396 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2400 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2403 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2406 bc_num_parseDecimal(n, val);
2408 bc_num_parseBase(n, val, base);
2410 return BC_STATUS_SUCCESS;
2413 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2414 size_t *nchars, size_t line_len)
2416 BcStatus s = BC_STATUS_SUCCESS;
2418 bc_num_printNewline(nchars, line_len);
2424 else if (base_t == 10)
2425 bc_num_printDecimal(n, nchars, line_len);
2427 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2437 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2442 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2444 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2446 unsigned long prev = *result, powprev = pow;
2448 *result += ((unsigned long) n->num[i]) * pow;
2451 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2454 return BC_STATUS_SUCCESS;
2457 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2465 if (val == 0) return;
2467 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2468 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2471 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2473 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2475 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2478 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2480 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2482 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2485 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2487 size_t req = BC_NUM_MREQ(a, b, scale);
2488 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2491 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2493 size_t req = BC_NUM_MREQ(a, b, scale);
2494 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2497 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2499 size_t req = BC_NUM_MREQ(a, b, scale);
2500 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2503 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2505 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2508 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2511 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2512 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2513 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2515 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2516 bc_num_expand(b, req);
2519 bc_num_setToZero(b, scale);
2520 return BC_STATUS_SUCCESS;
2523 return BC_STATUS_MATH_NEGATIVE;
2524 else if (BC_NUM_ONE(a)) {
2526 bc_num_extend(b, scale);
2527 return BC_STATUS_SUCCESS;
2530 scale = BC_MAX(scale, a->rdx) + 1;
2531 len = a->len + scale;
2533 bc_num_init(&num1, len);
2534 bc_num_init(&num2, len);
2535 bc_num_init(&half, BC_NUM_DEF_SIZE);
2541 bc_num_init(&f, len);
2542 bc_num_init(&fprime, len);
2548 pow = BC_NUM_INT(a);
2557 pow -= 2 - (pow & 1);
2559 bc_num_extend(x0, pow);
2561 // Make sure to move the radix back.
2565 x0->rdx = digs = digs1 = 0;
2567 len = BC_NUM_INT(x0) + resrdx - 1;
2569 while (cmp != 0 || digs < len) {
2571 s = bc_num_div(a, x0, &f, resrdx);
2573 s = bc_num_add(x0, &f, &fprime, resrdx);
2575 s = bc_num_mul(&fprime, &half, x1, resrdx);
2578 cmp = bc_num_cmp(x1, x0);
2579 digs = x1->len - (unsigned long long) llabs(cmp);
2581 if (cmp == cmp2 && digs == digs1)
2586 resrdx += times > 4;
2599 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2602 bc_num_free(&fprime);
2610 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2616 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2619 memcpy(&num2, c, sizeof(BcNum));
2621 bc_num_init(c, len);
2626 bc_num_expand(c, len);
2629 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2631 if (init) bc_num_free(&num2);
2637 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2640 BcNum base, exp, two, temp;
2642 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2643 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2644 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2646 bc_num_expand(d, c->len);
2647 bc_num_init(&base, c->len);
2648 bc_num_init(&exp, b->len);
2649 bc_num_init(&two, BC_NUM_DEF_SIZE);
2650 bc_num_init(&temp, b->len);
2656 s = bc_num_rem(a, c, &base, 0);
2658 bc_num_copy(&exp, b);
2660 while (exp.len != 0) {
2662 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2665 if (BC_NUM_ONE(&temp)) {
2666 s = bc_num_mul(d, &base, &temp, 0);
2668 s = bc_num_rem(&temp, c, d, 0);
2672 s = bc_num_mul(&base, &base, &temp, 0);
2674 s = bc_num_rem(&temp, c, &base, 0);
2687 static int bc_id_cmp(const void *e1, const void *e2)
2689 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2692 static void bc_id_free(void *id)
2694 free(((BcId *) id)->name);
2697 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2702 for (i = 0; i < f->autos.len; ++i) {
2703 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2704 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2710 bc_vec_push(&f->autos, &a);
2712 return BC_STATUS_SUCCESS;
2715 static void bc_func_init(BcFunc *f)
2717 bc_vec_init(&f->code, sizeof(char), NULL);
2718 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2719 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2723 static void bc_func_free(void *func)
2725 BcFunc *f = (BcFunc *) func;
2726 bc_vec_free(&f->code);
2727 bc_vec_free(&f->autos);
2728 bc_vec_free(&f->labels);
2731 static void bc_array_init(BcVec *a, bool nums)
2734 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2736 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2737 bc_array_expand(a, 1);
2740 static void bc_array_copy(BcVec *d, const BcVec *s)
2744 bc_vec_npop(d, d->len);
2745 bc_vec_expand(d, s->cap);
2748 for (i = 0; i < s->len; ++i) {
2749 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2750 bc_num_init(dnum, snum->len);
2751 bc_num_copy(dnum, snum);
2755 static void bc_array_expand(BcVec *a, size_t len)
2759 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2760 while (len > a->len) {
2761 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2762 bc_vec_push(a, &data.n);
2766 while (len > a->len) {
2767 bc_array_init(&data.v, true);
2768 bc_vec_push(a, &data.v);
2773 static void bc_string_free(void *string)
2775 free(*((char **) string));
2779 static void bc_result_copy(BcResult *d, BcResult *src)
2785 case BC_RESULT_TEMP:
2786 case BC_RESULT_IBASE:
2787 case BC_RESULT_SCALE:
2788 case BC_RESULT_OBASE:
2790 bc_num_init(&d->d.n, src->d.n.len);
2791 bc_num_copy(&d->d.n, &src->d.n);
2796 case BC_RESULT_ARRAY:
2797 case BC_RESULT_ARRAY_ELEM:
2799 d->d.id.name = xstrdup(src->d.id.name);
2803 case BC_RESULT_CONSTANT:
2804 case BC_RESULT_LAST:
2808 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2815 static void bc_result_free(void *result)
2817 BcResult *r = (BcResult *) result;
2821 case BC_RESULT_TEMP:
2822 case BC_RESULT_IBASE:
2823 case BC_RESULT_SCALE:
2824 case BC_RESULT_OBASE:
2826 bc_num_free(&r->d.n);
2831 case BC_RESULT_ARRAY:
2832 case BC_RESULT_ARRAY_ELEM:
2846 static void bc_lex_lineComment(BcLex *l)
2848 l->t.t = BC_LEX_WHITESPACE;
2849 while (l->i < l->len && l->buf[l->i++] != '\n');
2853 static void bc_lex_whitespace(BcLex *l)
2856 l->t.t = BC_LEX_WHITESPACE;
2857 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2860 static BcStatus bc_lex_number(BcLex *l, char start)
2862 const char *buf = l->buf + l->i;
2863 size_t len, hits = 0, bslashes = 0, i = 0, j;
2865 bool last_pt, pt = start == '.';
2868 l->t.t = BC_LEX_NUMBER;
2870 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2871 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2885 len = i + 1 * !last_pt - bslashes * 2;
2886 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2888 bc_vec_npop(&l->t.v, l->t.v.len);
2889 bc_vec_expand(&l->t.v, len + 1);
2890 bc_vec_push(&l->t.v, &start);
2892 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2896 // If we have hit a backslash, skip it. We don't have
2897 // to check for a newline because it's guaranteed.
2898 if (hits < bslashes && c == '\\') {
2904 bc_vec_push(&l->t.v, &c);
2907 bc_vec_pushByte(&l->t.v, '\0');
2910 return BC_STATUS_SUCCESS;
2913 static BcStatus bc_lex_name(BcLex *l)
2916 const char *buf = l->buf + l->i - 1;
2919 l->t.t = BC_LEX_NAME;
2921 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2923 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2924 bc_vec_string(&l->t.v, i, buf);
2926 // Increment the index. We minus 1 because it has already been incremented.
2929 return BC_STATUS_SUCCESS;
2932 static void bc_lex_init(BcLex *l, BcLexNext next)
2935 bc_vec_init(&l->t.v, sizeof(char), NULL);
2938 static void bc_lex_free(BcLex *l)
2940 bc_vec_free(&l->t.v);
2943 static void bc_lex_file(BcLex *l, const char *file)
2950 static BcStatus bc_lex_next(BcLex *l)
2955 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2957 l->line += l->newline;
2958 l->t.t = BC_LEX_EOF;
2960 l->newline = (l->i == l->len);
2961 if (l->newline) return BC_STATUS_SUCCESS;
2963 // Loop until failure or we don't have whitespace. This
2964 // is so the parser doesn't get inundated with whitespace.
2967 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2972 static BcStatus bc_lex_text(BcLex *l, const char *text)
2976 l->len = strlen(text);
2977 l->t.t = l->t.last = BC_LEX_INVALID;
2978 return bc_lex_next(l);
2982 static BcStatus bc_lex_identifier(BcLex *l)
2986 const char *buf = l->buf + l->i - 1;
2988 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2990 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2992 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2994 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2996 if (!bc_lex_kws[i].posix) {
2997 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
2998 bc_lex_kws[i].name);
3002 // We minus 1 because the index has already been incremented.
3004 return BC_STATUS_SUCCESS;
3011 if (l->t.v.len - 1 > 1)
3012 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3017 static BcStatus bc_lex_string(BcLex *l)
3019 size_t len, nls = 0, i = l->i;
3022 l->t.t = BC_LEX_STR;
3024 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3028 return BC_STATUS_LEX_NO_STRING_END;
3032 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3033 bc_vec_string(&l->t.v, len, l->buf + l->i);
3038 return BC_STATUS_SUCCESS;
3041 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3043 if (l->buf[l->i] == '=') {
3051 static BcStatus bc_lex_comment(BcLex *l)
3054 const char *buf = l->buf;
3058 l->t.t = BC_LEX_WHITESPACE;
3060 for (i = ++l->i; !end; i += !end) {
3062 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3064 if (c == 0 || buf[i + 1] == '\0') {
3066 return BC_STATUS_LEX_NO_COMMENT_END;
3069 end = buf[i + 1] == '/';
3075 return BC_STATUS_SUCCESS;
3078 static BcStatus bc_lex_token(BcLex *l)
3080 BcStatus s = BC_STATUS_SUCCESS;
3081 char c = l->buf[l->i++], c2;
3083 // This is the workhorse of the lexer.
3090 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3100 bc_lex_whitespace(l);
3106 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3108 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3109 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3118 s = bc_lex_string(l);
3124 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3127 bc_lex_lineComment(l);
3134 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3143 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3147 l->t.t = BC_LEX_OP_BOOL_AND;
3150 l->t.t = BC_LEX_INVALID;
3151 s = BC_STATUS_LEX_BAD_CHAR;
3160 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3166 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3175 l->t.t = BC_LEX_OP_INC;
3178 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3184 l->t.t = BC_LEX_COMMA;
3193 l->t.t = BC_LEX_OP_DEC;
3196 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3202 if (isdigit(l->buf[l->i]))
3203 s = bc_lex_number(l, c);
3205 l->t.t = BC_LEX_KEY_LAST;
3206 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3215 s = bc_lex_comment(l);
3217 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3238 s = bc_lex_number(l, c);
3244 l->t.t = BC_LEX_SCOLON;
3250 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3256 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3262 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3269 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3275 if (l->buf[l->i] == '\n') {
3276 l->t.t = BC_LEX_WHITESPACE;
3280 s = BC_STATUS_LEX_BAD_CHAR;
3286 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3317 s = bc_lex_identifier(l);
3324 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3334 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3338 l->t.t = BC_LEX_OP_BOOL_OR;
3341 l->t.t = BC_LEX_INVALID;
3342 s = BC_STATUS_LEX_BAD_CHAR;
3350 l->t.t = BC_LEX_INVALID;
3351 s = BC_STATUS_LEX_BAD_CHAR;
3361 static BcStatus dc_lex_register(BcLex *l)
3363 BcStatus s = BC_STATUS_SUCCESS;
3365 if (isspace(l->buf[l->i - 1])) {
3366 bc_lex_whitespace(l);
3369 s = BC_STATUS_LEX_EXTENDED_REG;
3374 bc_vec_npop(&l->t.v, l->t.v.len);
3375 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3376 bc_vec_pushByte(&l->t.v, '\0');
3377 l->t.t = BC_LEX_NAME;
3383 static BcStatus dc_lex_string(BcLex *l)
3385 size_t depth = 1, nls = 0, i = l->i;
3388 l->t.t = BC_LEX_STR;
3389 bc_vec_npop(&l->t.v, l->t.v.len);
3391 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3393 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3394 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3397 if (depth) bc_vec_push(&l->t.v, &c);
3402 return BC_STATUS_LEX_NO_STRING_END;
3405 bc_vec_pushByte(&l->t.v, '\0');
3406 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3411 return BC_STATUS_SUCCESS;
3414 static BcStatus dc_lex_token(BcLex *l)
3416 BcStatus s = BC_STATUS_SUCCESS;
3417 char c = l->buf[l->i++], c2;
3420 for (i = 0; i < dc_lex_regs_len; ++i) {
3421 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3424 if (c >= '%' && c <= '~' &&
3425 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3430 // This is the workhorse of the lexer.
3435 l->t.t = BC_LEX_EOF;
3446 l->newline = (c == '\n');
3447 bc_lex_whitespace(l);
3456 l->t.t = BC_LEX_OP_REL_NE;
3458 l->t.t = BC_LEX_OP_REL_LE;
3460 l->t.t = BC_LEX_OP_REL_GE;
3462 return BC_STATUS_LEX_BAD_CHAR;
3470 bc_lex_lineComment(l);
3476 if (isdigit(l->buf[l->i]))
3477 s = bc_lex_number(l, c);
3479 s = BC_STATUS_LEX_BAD_CHAR;
3500 s = bc_lex_number(l, c);
3506 s = dc_lex_string(l);
3512 l->t.t = BC_LEX_INVALID;
3513 s = BC_STATUS_LEX_BAD_CHAR;
3522 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3524 bc_program_addFunc(name, idx);
3525 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3528 static void bc_parse_pushName(BcParse *p, char *name)
3530 size_t i = 0, len = strlen(name);
3532 for (; i < len; ++i) bc_parse_push(p, name[i]);
3533 bc_parse_push(p, BC_PARSE_STREND);
3538 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3540 unsigned char amt, i, nums[sizeof(size_t)];
3542 for (amt = 0; idx; ++amt) {
3543 nums[amt] = (char) idx;
3544 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3547 bc_parse_push(p, amt);
3548 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3551 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3553 char *num = xstrdup(p->l.t.v.v);
3554 size_t idx = G.prog.consts.len;
3556 bc_vec_push(&G.prog.consts, &num);
3558 bc_parse_push(p, BC_INST_NUM);
3559 bc_parse_pushIndex(p, idx);
3562 (*prev) = BC_INST_NUM;
3565 static BcStatus bc_parse_text(BcParse *p, const char *text)
3569 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3571 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3572 p->l.t.t = BC_LEX_INVALID;
3575 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3578 return bc_lex_text(&p->l, text);
3581 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3583 if (p->fidx != BC_PROG_MAIN) {
3585 p->func->nparams = 0;
3586 bc_vec_npop(&p->func->code, p->func->code.len);
3587 bc_vec_npop(&p->func->autos, p->func->autos.len);
3588 bc_vec_npop(&p->func->labels, p->func->labels.len);
3590 bc_parse_updateFunc(p, BC_PROG_MAIN);
3594 p->l.t.t = BC_LEX_EOF;
3595 p->auto_part = (p->nbraces = 0);
3597 bc_vec_npop(&p->flags, p->flags.len - 1);
3598 bc_vec_npop(&p->exits, p->exits.len);
3599 bc_vec_npop(&p->conds, p->conds.len);
3600 bc_vec_npop(&p->ops, p->ops.len);
3602 return bc_program_reset(s);
3605 static void bc_parse_free(BcParse *p)
3607 bc_vec_free(&p->flags);
3608 bc_vec_free(&p->exits);
3609 bc_vec_free(&p->conds);
3610 bc_vec_free(&p->ops);
3614 static void bc_parse_create(BcParse *p, size_t func,
3615 BcParseParse parse, BcLexNext next)
3617 memset(p, 0, sizeof(BcParse));
3619 bc_lex_init(&p->l, next);
3620 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3621 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3622 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3623 bc_vec_pushByte(&p->flags, 0);
3624 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3627 p->auto_part = (p->nbraces = 0);
3628 bc_parse_updateFunc(p, func);
3632 static BcStatus bc_parse_else(BcParse *p);
3633 static BcStatus bc_parse_stmt(BcParse *p);
3635 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3636 size_t *nexprs, bool next)
3638 BcStatus s = BC_STATUS_SUCCESS;
3640 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3641 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3643 while (p->ops.len > start) {
3645 t = BC_PARSE_TOP_OP(p);
3646 if (t == BC_LEX_LPAREN) break;
3648 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3649 if (l >= r && (l != r || !left)) break;
3651 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3652 bc_vec_pop(&p->ops);
3653 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3656 bc_vec_push(&p->ops, &type);
3657 if (next) s = bc_lex_next(&p->l);
3662 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3666 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3667 top = BC_PARSE_TOP_OP(p);
3669 while (top != BC_LEX_LPAREN) {
3671 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3673 bc_vec_pop(&p->ops);
3674 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3676 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3677 top = BC_PARSE_TOP_OP(p);
3680 bc_vec_pop(&p->ops);
3682 return bc_lex_next(&p->l);
3685 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3691 s = bc_lex_next(&p->l);
3694 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3696 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3697 s = bc_parse_expr(p, flags, bc_parse_next_param);
3700 comma = p->l.t.t == BC_LEX_COMMA;
3702 s = bc_lex_next(&p->l);
3707 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3708 bc_parse_push(p, BC_INST_CALL);
3709 bc_parse_pushIndex(p, nparams);
3711 return BC_STATUS_SUCCESS;
3714 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3717 BcId entry, *entry_ptr;
3722 s = bc_parse_params(p, flags);
3725 if (p->l.t.t != BC_LEX_RPAREN) {
3726 s = BC_STATUS_PARSE_BAD_TOKEN;
3730 idx = bc_map_index(&G.prog.fn_map, &entry);
3732 if (idx == BC_VEC_INVALID_IDX) {
3733 name = xstrdup(entry.name);
3734 bc_parse_addFunc(p, name, &idx);
3735 idx = bc_map_index(&G.prog.fn_map, &entry);
3741 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3742 bc_parse_pushIndex(p, entry_ptr->idx);
3744 return bc_lex_next(&p->l);
3751 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3756 name = xstrdup(p->l.t.v.v);
3757 s = bc_lex_next(&p->l);
3760 if (p->l.t.t == BC_LEX_LBRACKET) {
3762 s = bc_lex_next(&p->l);
3765 if (p->l.t.t == BC_LEX_RBRACKET) {
3767 if (!(flags & BC_PARSE_ARRAY)) {
3768 s = BC_STATUS_PARSE_BAD_EXP;
3772 *type = BC_INST_ARRAY;
3776 *type = BC_INST_ARRAY_ELEM;
3778 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3779 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3783 s = bc_lex_next(&p->l);
3785 bc_parse_push(p, *type);
3786 bc_parse_pushName(p, name);
3788 else if (p->l.t.t == BC_LEX_LPAREN) {
3790 if (flags & BC_PARSE_NOCALL) {
3791 s = BC_STATUS_PARSE_BAD_TOKEN;
3795 *type = BC_INST_CALL;
3796 s = bc_parse_call(p, name, flags);
3799 *type = BC_INST_VAR;
3800 bc_parse_push(p, BC_INST_VAR);
3801 bc_parse_pushName(p, name);
3811 static BcStatus bc_parse_read(BcParse *p)
3815 s = bc_lex_next(&p->l);
3817 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3819 s = bc_lex_next(&p->l);
3821 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3823 bc_parse_push(p, BC_INST_READ);
3825 return bc_lex_next(&p->l);
3828 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3833 s = bc_lex_next(&p->l);
3835 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3837 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3839 s = bc_lex_next(&p->l);
3842 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3845 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3847 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3848 bc_parse_push(p, *prev);
3850 return bc_lex_next(&p->l);
3853 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3857 s = bc_lex_next(&p->l);
3860 if (p->l.t.t != BC_LEX_LPAREN) {
3861 *type = BC_INST_SCALE;
3862 bc_parse_push(p, BC_INST_SCALE);
3863 return BC_STATUS_SUCCESS;
3866 *type = BC_INST_SCALE_FUNC;
3867 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3869 s = bc_lex_next(&p->l);
3872 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3874 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3875 bc_parse_push(p, BC_INST_SCALE_FUNC);
3877 return bc_lex_next(&p->l);
3880 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3881 size_t *nexprs, uint8_t flags)
3886 BcInst etype = *prev;
3888 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3889 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3890 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3892 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3893 bc_parse_push(p, inst);
3894 s = bc_lex_next(&p->l);
3898 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3901 s = bc_lex_next(&p->l);
3905 // Because we parse the next part of the expression
3906 // right here, we need to increment this.
3907 *nexprs = *nexprs + 1;
3913 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3917 case BC_LEX_KEY_IBASE:
3918 case BC_LEX_KEY_LAST:
3919 case BC_LEX_KEY_OBASE:
3921 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3922 s = bc_lex_next(&p->l);
3926 case BC_LEX_KEY_SCALE:
3928 s = bc_lex_next(&p->l);
3930 if (p->l.t.t == BC_LEX_LPAREN)
3931 s = BC_STATUS_PARSE_BAD_TOKEN;
3933 bc_parse_push(p, BC_INST_SCALE);
3939 s = BC_STATUS_PARSE_BAD_TOKEN;
3944 if (!s) bc_parse_push(p, inst);
3950 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3951 bool rparen, size_t *nexprs)
3955 BcInst etype = *prev;
3957 s = bc_lex_next(&p->l);
3960 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3961 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3964 *prev = BC_PARSE_TOKEN_INST(type);
3966 // We can just push onto the op stack because this is the largest
3967 // precedence operator that gets pushed. Inc/dec does not.
3968 if (type != BC_LEX_OP_MINUS)
3969 bc_vec_push(&p->ops, &type);
3971 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3976 static BcStatus bc_parse_string(BcParse *p, char inst)
3978 char *str = xstrdup(p->l.t.v.v);
3980 bc_parse_push(p, BC_INST_STR);
3981 bc_parse_pushIndex(p, G.prog.strs.len);
3982 bc_vec_push(&G.prog.strs, &str);
3983 bc_parse_push(p, inst);
3985 return bc_lex_next(&p->l);
3988 static BcStatus bc_parse_print(BcParse *p)
3994 s = bc_lex_next(&p->l);
3999 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4000 return BC_STATUS_PARSE_BAD_PRINT;
4002 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4004 if (type == BC_LEX_STR)
4005 s = bc_parse_string(p, BC_INST_PRINT_POP);
4007 s = bc_parse_expr(p, 0, bc_parse_next_print);
4009 bc_parse_push(p, BC_INST_PRINT_POP);
4014 comma = p->l.t.t == BC_LEX_COMMA;
4015 if (comma) s = bc_lex_next(&p->l);
4020 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4022 return bc_lex_next(&p->l);
4025 static BcStatus bc_parse_return(BcParse *p)
4031 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4033 s = bc_lex_next(&p->l);
4037 paren = t == BC_LEX_LPAREN;
4039 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4040 bc_parse_push(p, BC_INST_RET0);
4043 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4044 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4046 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4047 bc_parse_push(p, BC_INST_RET0);
4048 s = bc_lex_next(&p->l);
4052 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4053 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4057 bc_parse_push(p, BC_INST_RET);
4063 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4065 BcStatus s = BC_STATUS_SUCCESS;
4067 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4068 return BC_STATUS_PARSE_BAD_TOKEN;
4072 if (p->l.t.t == BC_LEX_RBRACE) {
4073 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4075 s = bc_lex_next(&p->l);
4079 return BC_STATUS_PARSE_BAD_TOKEN;
4082 if (BC_PARSE_IF(p)) {
4086 while (p->l.t.t == BC_LEX_NLINE) {
4087 s = bc_lex_next(&p->l);
4091 bc_vec_pop(&p->flags);
4093 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4094 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4096 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4098 else if (BC_PARSE_ELSE(p)) {
4103 bc_vec_pop(&p->flags);
4105 ip = bc_vec_top(&p->exits);
4106 label = bc_vec_item(&p->func->labels, ip->idx);
4107 *label = p->func->code.len;
4109 bc_vec_pop(&p->exits);
4111 else if (BC_PARSE_FUNC_INNER(p)) {
4112 bc_parse_push(p, BC_INST_RET0);
4113 bc_parse_updateFunc(p, BC_PROG_MAIN);
4114 bc_vec_pop(&p->flags);
4118 BcInstPtr *ip = bc_vec_top(&p->exits);
4119 size_t *label = bc_vec_top(&p->conds);
4121 bc_parse_push(p, BC_INST_JUMP);
4122 bc_parse_pushIndex(p, *label);
4124 label = bc_vec_item(&p->func->labels, ip->idx);
4125 *label = p->func->code.len;
4127 bc_vec_pop(&p->flags);
4128 bc_vec_pop(&p->exits);
4129 bc_vec_pop(&p->conds);
4135 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4137 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4138 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4139 flags |= BC_PARSE_FLAG_BODY;
4140 bc_vec_push(&p->flags, &flags);
4143 static void bc_parse_noElse(BcParse *p)
4147 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4149 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4151 ip = bc_vec_top(&p->exits);
4152 label = bc_vec_item(&p->func->labels, ip->idx);
4153 *label = p->func->code.len;
4155 bc_vec_pop(&p->exits);
4158 static BcStatus bc_parse_if(BcParse *p)
4163 s = bc_lex_next(&p->l);
4165 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4167 s = bc_lex_next(&p->l);
4169 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4171 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4173 s = bc_lex_next(&p->l);
4175 bc_parse_push(p, BC_INST_JUMP_ZERO);
4177 ip.idx = p->func->labels.len;
4178 ip.func = ip.len = 0;
4180 bc_parse_pushIndex(p, ip.idx);
4181 bc_vec_push(&p->exits, &ip);
4182 bc_vec_push(&p->func->labels, &ip.idx);
4183 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4185 return BC_STATUS_SUCCESS;
4188 static BcStatus bc_parse_else(BcParse *p)
4192 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4194 ip.idx = p->func->labels.len;
4195 ip.func = ip.len = 0;
4197 bc_parse_push(p, BC_INST_JUMP);
4198 bc_parse_pushIndex(p, ip.idx);
4202 bc_vec_push(&p->exits, &ip);
4203 bc_vec_push(&p->func->labels, &ip.idx);
4204 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4206 return bc_lex_next(&p->l);
4209 static BcStatus bc_parse_while(BcParse *p)
4214 s = bc_lex_next(&p->l);
4216 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4217 s = bc_lex_next(&p->l);
4220 ip.idx = p->func->labels.len;
4222 bc_vec_push(&p->func->labels, &p->func->code.len);
4223 bc_vec_push(&p->conds, &ip.idx);
4225 ip.idx = p->func->labels.len;
4229 bc_vec_push(&p->exits, &ip);
4230 bc_vec_push(&p->func->labels, &ip.idx);
4232 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4234 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4235 s = bc_lex_next(&p->l);
4238 bc_parse_push(p, BC_INST_JUMP_ZERO);
4239 bc_parse_pushIndex(p, ip.idx);
4240 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4242 return BC_STATUS_SUCCESS;
4245 static BcStatus bc_parse_for(BcParse *p)
4249 size_t cond_idx, exit_idx, body_idx, update_idx;
4251 s = bc_lex_next(&p->l);
4253 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4254 s = bc_lex_next(&p->l);
4257 if (p->l.t.t != BC_LEX_SCOLON)
4258 s = bc_parse_expr(p, 0, bc_parse_next_for);
4260 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4263 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4264 s = bc_lex_next(&p->l);
4267 cond_idx = p->func->labels.len;
4268 update_idx = cond_idx + 1;
4269 body_idx = update_idx + 1;
4270 exit_idx = body_idx + 1;
4272 bc_vec_push(&p->func->labels, &p->func->code.len);
4274 if (p->l.t.t != BC_LEX_SCOLON)
4275 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4277 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4280 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4282 s = bc_lex_next(&p->l);
4285 bc_parse_push(p, BC_INST_JUMP_ZERO);
4286 bc_parse_pushIndex(p, exit_idx);
4287 bc_parse_push(p, BC_INST_JUMP);
4288 bc_parse_pushIndex(p, body_idx);
4290 ip.idx = p->func->labels.len;
4292 bc_vec_push(&p->conds, &update_idx);
4293 bc_vec_push(&p->func->labels, &p->func->code.len);
4295 if (p->l.t.t != BC_LEX_RPAREN)
4296 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4298 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4302 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4303 bc_parse_push(p, BC_INST_JUMP);
4304 bc_parse_pushIndex(p, cond_idx);
4305 bc_vec_push(&p->func->labels, &p->func->code.len);
4311 bc_vec_push(&p->exits, &ip);
4312 bc_vec_push(&p->func->labels, &ip.idx);
4314 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4316 return BC_STATUS_SUCCESS;
4319 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4325 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4327 if (type == BC_LEX_KEY_BREAK) {
4329 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4331 i = p->exits.len - 1;
4332 ip = bc_vec_item(&p->exits, i);
4334 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4335 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4340 i = *((size_t *) bc_vec_top(&p->conds));
4342 bc_parse_push(p, BC_INST_JUMP);
4343 bc_parse_pushIndex(p, i);
4345 s = bc_lex_next(&p->l);
4348 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4349 return BC_STATUS_PARSE_BAD_TOKEN;
4351 return bc_lex_next(&p->l);
4354 static BcStatus bc_parse_func(BcParse *p)
4357 bool var, comma = false;
4361 s = bc_lex_next(&p->l);
4363 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4365 name = xstrdup(p->l.t.v.v);
4366 bc_parse_addFunc(p, name, &p->fidx);
4368 s = bc_lex_next(&p->l);
4370 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4371 s = bc_lex_next(&p->l);
4374 while (p->l.t.t != BC_LEX_RPAREN) {
4376 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4380 name = xstrdup(p->l.t.v.v);
4381 s = bc_lex_next(&p->l);
4384 var = p->l.t.t != BC_LEX_LBRACKET;
4388 s = bc_lex_next(&p->l);
4391 if (p->l.t.t != BC_LEX_RBRACKET) {
4392 s = BC_STATUS_PARSE_BAD_FUNC;
4396 s = bc_lex_next(&p->l);
4400 comma = p->l.t.t == BC_LEX_COMMA;
4402 s = bc_lex_next(&p->l);
4406 s = bc_func_insert(p->func, name, var);
4410 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4412 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4413 bc_parse_startBody(p, flags);
4415 s = bc_lex_next(&p->l);
4418 if (p->l.t.t != BC_LEX_LBRACE)
4419 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4428 static BcStatus bc_parse_auto(BcParse *p)
4431 bool comma, var, one;
4434 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4435 s = bc_lex_next(&p->l);
4438 p->auto_part = comma = false;
4439 one = p->l.t.t == BC_LEX_NAME;
4441 while (p->l.t.t == BC_LEX_NAME) {
4443 name = xstrdup(p->l.t.v.v);
4444 s = bc_lex_next(&p->l);
4447 var = p->l.t.t != BC_LEX_LBRACKET;
4450 s = bc_lex_next(&p->l);
4453 if (p->l.t.t != BC_LEX_RBRACKET) {
4454 s = BC_STATUS_PARSE_BAD_FUNC;
4458 s = bc_lex_next(&p->l);
4462 comma = p->l.t.t == BC_LEX_COMMA;
4464 s = bc_lex_next(&p->l);
4468 s = bc_func_insert(p->func, name, var);
4472 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4473 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4475 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4476 return BC_STATUS_PARSE_BAD_TOKEN;
4478 return bc_lex_next(&p->l);
4485 static BcStatus bc_parse_body(BcParse *p, bool brace)
4487 BcStatus s = BC_STATUS_SUCCESS;
4488 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4490 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4492 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4494 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4495 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4497 if (!p->auto_part) {
4498 s = bc_parse_auto(p);
4502 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4505 s = bc_parse_stmt(p);
4506 if (!s && !brace) s = bc_parse_endBody(p, false);
4512 static BcStatus bc_parse_stmt(BcParse *p)
4514 BcStatus s = BC_STATUS_SUCCESS;
4520 return bc_lex_next(&p->l);
4523 case BC_LEX_KEY_ELSE:
4525 p->auto_part = false;
4531 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4534 s = bc_lex_next(&p->l);
4537 return bc_parse_body(p, true);
4540 case BC_LEX_KEY_AUTO:
4542 return bc_parse_auto(p);
4547 p->auto_part = false;
4549 if (BC_PARSE_IF_END(p)) {
4551 return BC_STATUS_SUCCESS;
4553 else if (BC_PARSE_BODY(p))
4554 return bc_parse_body(p, false);
4564 case BC_LEX_OP_MINUS:
4565 case BC_LEX_OP_BOOL_NOT:
4569 case BC_LEX_KEY_IBASE:
4570 case BC_LEX_KEY_LAST:
4571 case BC_LEX_KEY_LENGTH:
4572 case BC_LEX_KEY_OBASE:
4573 case BC_LEX_KEY_READ:
4574 case BC_LEX_KEY_SCALE:
4575 case BC_LEX_KEY_SQRT:
4577 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4581 case BC_LEX_KEY_ELSE:
4583 s = bc_parse_else(p);
4589 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4595 s = bc_parse_endBody(p, true);
4601 s = bc_parse_string(p, BC_INST_PRINT_STR);
4605 case BC_LEX_KEY_BREAK:
4606 case BC_LEX_KEY_CONTINUE:
4608 s = bc_parse_loopExit(p, p->l.t.t);
4612 case BC_LEX_KEY_FOR:
4614 s = bc_parse_for(p);
4618 case BC_LEX_KEY_HALT:
4620 bc_parse_push(p, BC_INST_HALT);
4621 s = bc_lex_next(&p->l);
4631 case BC_LEX_KEY_LIMITS:
4633 s = bc_lex_next(&p->l);
4635 s = BC_STATUS_LIMITS;
4639 case BC_LEX_KEY_PRINT:
4641 s = bc_parse_print(p);
4645 case BC_LEX_KEY_QUIT:
4647 // Quit is a compile-time command. We don't exit directly,
4648 // so the vm can clean up. Limits do the same thing.
4653 case BC_LEX_KEY_RETURN:
4655 s = bc_parse_return(p);
4659 case BC_LEX_KEY_WHILE:
4661 s = bc_parse_while(p);
4667 s = BC_STATUS_PARSE_BAD_TOKEN;
4675 static BcStatus bc_parse_parse(BcParse *p)
4679 if (p->l.t.t == BC_LEX_EOF)
4680 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4681 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4682 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4683 s = bc_parse_func(p);
4686 s = bc_parse_stmt(p);
4688 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
4689 s = bc_parse_reset(p, s);
4694 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4696 BcStatus s = BC_STATUS_SUCCESS;
4697 BcInst prev = BC_INST_PRINT;
4698 BcLexType top, t = p->l.t.t;
4699 size_t nexprs = 0, ops_bgn = p->ops.len;
4700 uint32_t i, nparens, nrelops;
4701 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4703 paren_first = p->l.t.t == BC_LEX_LPAREN;
4704 nparens = nrelops = 0;
4705 paren_expr = rprn = done = get_token = assign = false;
4708 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4714 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4715 rprn = get_token = bin_last = false;
4719 case BC_LEX_OP_MINUS:
4721 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4722 rprn = get_token = false;
4723 bin_last = prev == BC_INST_MINUS;
4727 case BC_LEX_OP_ASSIGN_POWER:
4728 case BC_LEX_OP_ASSIGN_MULTIPLY:
4729 case BC_LEX_OP_ASSIGN_DIVIDE:
4730 case BC_LEX_OP_ASSIGN_MODULUS:
4731 case BC_LEX_OP_ASSIGN_PLUS:
4732 case BC_LEX_OP_ASSIGN_MINUS:
4733 case BC_LEX_OP_ASSIGN:
4735 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4736 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4737 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4739 s = BC_STATUS_PARSE_BAD_ASSIGN;
4744 case BC_LEX_OP_POWER:
4745 case BC_LEX_OP_MULTIPLY:
4746 case BC_LEX_OP_DIVIDE:
4747 case BC_LEX_OP_MODULUS:
4748 case BC_LEX_OP_PLUS:
4749 case BC_LEX_OP_REL_EQ:
4750 case BC_LEX_OP_REL_LE:
4751 case BC_LEX_OP_REL_GE:
4752 case BC_LEX_OP_REL_NE:
4753 case BC_LEX_OP_REL_LT:
4754 case BC_LEX_OP_REL_GT:
4755 case BC_LEX_OP_BOOL_NOT:
4756 case BC_LEX_OP_BOOL_OR:
4757 case BC_LEX_OP_BOOL_AND:
4759 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4760 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4762 return BC_STATUS_PARSE_BAD_EXP;
4765 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4766 prev = BC_PARSE_TOKEN_INST(t);
4767 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4768 rprn = get_token = false;
4769 bin_last = t != BC_LEX_OP_BOOL_NOT;
4776 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4779 paren_expr = rprn = bin_last = false;
4781 bc_vec_push(&p->ops, &t);
4788 if (bin_last || prev == BC_INST_BOOL_NOT)
4789 return BC_STATUS_PARSE_BAD_EXP;
4792 s = BC_STATUS_SUCCESS;
4797 else if (!paren_expr)
4798 return BC_STATUS_PARSE_EMPTY_EXP;
4801 paren_expr = rprn = true;
4802 get_token = bin_last = false;
4804 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4811 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4814 rprn = get_token = bin_last = false;
4815 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4823 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4825 bc_parse_number(p, &prev, &nexprs);
4826 paren_expr = get_token = true;
4827 rprn = bin_last = false;
4832 case BC_LEX_KEY_IBASE:
4833 case BC_LEX_KEY_LAST:
4834 case BC_LEX_KEY_OBASE:
4836 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4838 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4839 bc_parse_push(p, (char) prev);
4841 paren_expr = get_token = true;
4842 rprn = bin_last = false;
4848 case BC_LEX_KEY_LENGTH:
4849 case BC_LEX_KEY_SQRT:
4851 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4853 s = bc_parse_builtin(p, t, flags, &prev);
4855 rprn = get_token = bin_last = false;
4861 case BC_LEX_KEY_READ:
4863 if (BC_PARSE_LEAF(prev, rprn))
4864 return BC_STATUS_PARSE_BAD_EXP;
4865 else if (flags & BC_PARSE_NOREAD)
4866 s = BC_STATUS_EXEC_REC_READ;
4868 s = bc_parse_read(p);
4871 rprn = get_token = bin_last = false;
4873 prev = BC_INST_READ;
4878 case BC_LEX_KEY_SCALE:
4880 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4882 s = bc_parse_scale(p, &prev, flags);
4884 rprn = get_token = bin_last = false;
4886 prev = BC_INST_SCALE;
4893 s = BC_STATUS_PARSE_BAD_TOKEN;
4898 if (!s && get_token) s = bc_lex_next(&p->l);
4902 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4904 while (p->ops.len > ops_bgn) {
4906 top = BC_PARSE_TOP_OP(p);
4907 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4909 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4910 return BC_STATUS_PARSE_BAD_EXP;
4912 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4914 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4915 bc_vec_pop(&p->ops);
4918 s = BC_STATUS_PARSE_BAD_EXP;
4919 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4921 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4924 if (!(flags & BC_PARSE_REL) && nrelops) {
4925 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4928 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4929 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4933 if (flags & BC_PARSE_PRINT) {
4934 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4935 bc_parse_push(p, BC_INST_POP);
4941 static void bc_parse_init(BcParse *p, size_t func)
4943 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4946 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4948 return bc_parse_expr(p, flags, bc_parse_next_read);
4953 static BcStatus dc_parse_register(BcParse *p)
4958 s = bc_lex_next(&p->l);
4960 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
4962 name = xstrdup(p->l.t.v.v);
4963 bc_parse_pushName(p, name);
4968 static BcStatus dc_parse_string(BcParse *p)
4970 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4971 size_t idx, len = G.prog.strs.len;
4973 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4976 str = xstrdup(p->l.t.v.v);
4977 bc_parse_push(p, BC_INST_STR);
4978 bc_parse_pushIndex(p, len);
4979 bc_vec_push(&G.prog.strs, &str);
4980 bc_parse_addFunc(p, name, &idx);
4982 return bc_lex_next(&p->l);
4985 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4989 bc_parse_push(p, inst);
4991 s = dc_parse_register(p);
4996 bc_parse_push(p, BC_INST_SWAP);
4997 bc_parse_push(p, BC_INST_ASSIGN);
4998 bc_parse_push(p, BC_INST_POP);
5001 return bc_lex_next(&p->l);
5004 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5008 bc_parse_push(p, inst);
5009 bc_parse_push(p, BC_INST_EXEC_COND);
5011 s = dc_parse_register(p);
5014 s = bc_lex_next(&p->l);
5017 if (p->l.t.t == BC_LEX_ELSE) {
5018 s = dc_parse_register(p);
5020 s = bc_lex_next(&p->l);
5023 bc_parse_push(p, BC_PARSE_STREND);
5028 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5030 BcStatus s = BC_STATUS_SUCCESS;
5033 bool assign, get_token = false;
5037 case BC_LEX_OP_REL_EQ:
5038 case BC_LEX_OP_REL_LE:
5039 case BC_LEX_OP_REL_GE:
5040 case BC_LEX_OP_REL_NE:
5041 case BC_LEX_OP_REL_LT:
5042 case BC_LEX_OP_REL_GT:
5044 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5051 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5057 s = dc_parse_string(p);
5064 if (t == BC_LEX_NEG) {
5065 s = bc_lex_next(&p->l);
5067 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5070 bc_parse_number(p, &prev, &p->nbraces);
5072 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5078 case BC_LEX_KEY_READ:
5080 if (flags & BC_PARSE_NOREAD)
5081 s = BC_STATUS_EXEC_REC_READ;
5083 bc_parse_push(p, BC_INST_READ);
5088 case BC_LEX_OP_ASSIGN:
5089 case BC_LEX_STORE_PUSH:
5091 assign = t == BC_LEX_OP_ASSIGN;
5092 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5093 s = dc_parse_mem(p, inst, true, assign);
5098 case BC_LEX_LOAD_POP:
5100 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5101 s = dc_parse_mem(p, inst, true, false);
5105 case BC_LEX_STORE_IBASE:
5106 case BC_LEX_STORE_SCALE:
5107 case BC_LEX_STORE_OBASE:
5109 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5110 s = dc_parse_mem(p, inst, false, true);
5116 s = BC_STATUS_PARSE_BAD_TOKEN;
5122 if (!s && get_token) s = bc_lex_next(&p->l);
5127 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5129 BcStatus s = BC_STATUS_SUCCESS;
5133 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5135 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5137 inst = dc_parse_insts[t];
5139 if (inst != BC_INST_INVALID) {
5140 bc_parse_push(p, inst);
5141 s = bc_lex_next(&p->l);
5144 s = dc_parse_token(p, t, flags);
5147 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5148 bc_parse_push(p, BC_INST_POP_EXEC);
5153 static BcStatus dc_parse_parse(BcParse *p)
5157 if (p->l.t.t == BC_LEX_EOF)
5158 s = BC_STATUS_LEX_EOF;
5160 s = dc_parse_expr(p, 0);
5162 if (s || G_interrupt) s = bc_parse_reset(p, s);
5167 static void dc_parse_init(BcParse *p, size_t func)
5169 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5173 static void common_parse_init(BcParse *p, size_t func)
5176 bc_parse_init(p, func);
5178 dc_parse_init(p, func);
5182 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5185 return bc_parse_expression(p, flags);
5187 return dc_parse_expr(p, flags);
5191 static BcVec* bc_program_search(char *id, bool var)
5200 v = var ? &G.prog.vars : &G.prog.arrs;
5201 map = var ? &G.prog.var_map : &G.prog.arr_map;
5205 s = bc_map_insert(map, &e, &i);
5206 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5209 bc_array_init(&data.v, var);
5210 bc_vec_push(v, &data.v);
5213 ptr = bc_vec_item(map, i);
5214 if (new) ptr->name = xstrdup(e.name);
5215 return bc_vec_item(v, ptr->idx);
5218 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5220 BcStatus s = BC_STATUS_SUCCESS;
5225 case BC_RESULT_TEMP:
5226 case BC_RESULT_IBASE:
5227 case BC_RESULT_SCALE:
5228 case BC_RESULT_OBASE:
5234 case BC_RESULT_CONSTANT:
5236 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5237 size_t base_t, len = strlen(*str);
5240 bc_num_init(&r->d.n, len);
5242 hex = hex && len == 1;
5243 base = hex ? &G.prog.hexb : &G.prog.ib;
5244 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5245 s = bc_num_parse(&r->d.n, *str, base, base_t);
5248 bc_num_free(&r->d.n);
5253 r->t = BC_RESULT_TEMP;
5259 case BC_RESULT_ARRAY:
5260 case BC_RESULT_ARRAY_ELEM:
5264 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5266 if (r->t == BC_RESULT_ARRAY_ELEM) {
5268 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5269 *num = bc_vec_item(v, r->d.id.idx);
5272 *num = bc_vec_top(v);
5277 case BC_RESULT_LAST:
5279 *num = &G.prog.last;
5293 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5294 BcResult **r, BcNum **rn, bool assign)
5298 BcResultType lt, rt;
5300 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5302 *r = bc_vec_item_rev(&G.prog.results, 0);
5303 *l = bc_vec_item_rev(&G.prog.results, 1);
5307 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5309 s = bc_program_num(*l, ln, false);
5311 s = bc_program_num(*r, rn, hex);
5314 // We run this again under these conditions in case any vector has been
5315 // reallocated out from under the BcNums or arrays we had.
5316 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5317 s = bc_program_num(*l, ln, false);
5321 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5322 return BC_STATUS_EXEC_BAD_TYPE;
5323 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5328 static void bc_program_binOpRetire(BcResult *r)
5330 r->t = BC_RESULT_TEMP;
5331 bc_vec_pop(&G.prog.results);
5332 bc_vec_pop(&G.prog.results);
5333 bc_vec_push(&G.prog.results, r);
5336 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5340 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5341 *r = bc_vec_top(&G.prog.results);
5343 s = bc_program_num(*r, n, false);
5346 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5351 static void bc_program_retire(BcResult *r, BcResultType t)
5354 bc_vec_pop(&G.prog.results);
5355 bc_vec_push(&G.prog.results, r);
5358 static BcStatus bc_program_op(char inst)
5361 BcResult *opd1, *opd2, res;
5362 BcNum *n1, *n2 = NULL;
5364 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5366 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5368 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5370 bc_program_binOpRetire(&res);
5375 bc_num_free(&res.d.n);
5379 static BcStatus bc_program_read(void)
5386 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5388 for (i = 0; i < G.prog.stack.len; ++i) {
5389 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5390 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5393 bc_vec_npop(&f->code, f->code.len);
5394 bc_vec_init(&buf, sizeof(char), NULL);
5396 s = bc_read_line(&buf, "read> ");
5399 common_parse_init(&parse, BC_PROG_READ);
5400 bc_lex_file(&parse.l, bc_program_stdin_name);
5402 s = bc_parse_text(&parse, buf.v);
5403 if (s) goto exec_err;
5404 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5405 if (s) goto exec_err;
5407 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5408 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5412 ip.func = BC_PROG_READ;
5414 ip.len = G.prog.results.len;
5416 // Update this pointer, just in case.
5417 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5419 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5420 bc_vec_push(&G.prog.stack, &ip);
5423 bc_parse_free(&parse);
5429 static size_t bc_program_index(char *code, size_t *bgn)
5431 char amt = code[(*bgn)++], i = 0;
5434 for (; i < amt; ++i, ++(*bgn))
5435 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5440 static char *bc_program_name(char *code, size_t *bgn)
5443 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5445 s = xmalloc(ptr - str + 1);
5448 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5456 static void bc_program_printString(const char *str, size_t *nchars)
5458 size_t i, len = strlen(str);
5467 for (i = 0; i < len; ++i, ++(*nchars)) {
5471 if (c != '\\' || i == len - 1)
5531 // Just print the backslash and following character.
5542 static BcStatus bc_program_print(char inst, size_t idx)
5544 BcStatus s = BC_STATUS_SUCCESS;
5549 bool pop = inst != BC_INST_PRINT;
5551 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5553 r = bc_vec_item_rev(&G.prog.results, idx);
5554 s = bc_program_num(r, &num, false);
5557 if (BC_PROG_NUM(r, num)) {
5558 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5559 if (!s) bc_num_copy(&G.prog.last, num);
5563 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5564 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5566 if (inst == BC_INST_PRINT_STR) {
5567 for (i = 0, len = strlen(str); i < len; ++i) {
5570 if (c == '\n') G.prog.nchars = SIZE_MAX;
5575 bc_program_printString(str, &G.prog.nchars);
5576 if (inst == BC_INST_PRINT) bb_putchar('\n');
5580 if (!s && pop) bc_vec_pop(&G.prog.results);
5585 static BcStatus bc_program_negate(void)
5591 s = bc_program_prep(&ptr, &num);
5594 bc_num_init(&res.d.n, num->len);
5595 bc_num_copy(&res.d.n, num);
5596 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5598 bc_program_retire(&res, BC_RESULT_TEMP);
5603 static BcStatus bc_program_logical(char inst)
5606 BcResult *opd1, *opd2, res;
5611 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5613 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5615 if (inst == BC_INST_BOOL_AND)
5616 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5617 else if (inst == BC_INST_BOOL_OR)
5618 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5621 cmp = bc_num_cmp(n1, n2);
5625 case BC_INST_REL_EQ:
5631 case BC_INST_REL_LE:
5637 case BC_INST_REL_GE:
5643 case BC_INST_REL_NE:
5649 case BC_INST_REL_LT:
5655 case BC_INST_REL_GT:
5663 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5665 bc_program_binOpRetire(&res);
5671 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5677 memset(&n2, 0, sizeof(BcNum));
5678 n2.rdx = res.d.id.idx = r->d.id.idx;
5679 res.t = BC_RESULT_STR;
5682 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5684 bc_vec_pop(&G.prog.results);
5687 bc_vec_pop(&G.prog.results);
5689 bc_vec_push(&G.prog.results, &res);
5690 bc_vec_push(v, &n2);
5692 return BC_STATUS_SUCCESS;
5696 static BcStatus bc_program_copyToVar(char *name, bool var)
5703 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5705 ptr = bc_vec_top(&G.prog.results);
5706 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5707 v = bc_program_search(name, var);
5710 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5711 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5714 s = bc_program_num(ptr, &n, false);
5717 // Do this once more to make sure that pointers were not invalidated.
5718 v = bc_program_search(name, var);
5721 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5722 bc_num_copy(&r.d.n, n);
5725 bc_array_init(&r.d.v, true);
5726 bc_array_copy(&r.d.v, (BcVec *) n);
5729 bc_vec_push(v, &r.d);
5730 bc_vec_pop(&G.prog.results);
5735 static BcStatus bc_program_assign(char inst)
5738 BcResult *left, *right, res;
5739 BcNum *l = NULL, *r = NULL;
5740 unsigned long val, max;
5741 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5743 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5746 ib = left->t == BC_RESULT_IBASE;
5747 sc = left->t == BC_RESULT_SCALE;
5751 if (right->t == BC_RESULT_STR) {
5755 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5756 v = bc_program_search(left->d.id.name, true);
5758 return bc_program_assignStr(right, v, false);
5762 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5763 return BC_STATUS_PARSE_BAD_ASSIGN;
5766 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5767 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5772 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5779 if (ib || sc || left->t == BC_RESULT_OBASE) {
5783 s = bc_num_ulong(l, &val);
5785 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5789 ptr = &G.prog.scale;
5792 if (val < BC_NUM_MIN_BASE) return s;
5793 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5794 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5797 if (val > max) return s;
5798 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5800 *ptr = (size_t) val;
5801 s = BC_STATUS_SUCCESS;
5804 bc_num_init(&res.d.n, l->len);
5805 bc_num_copy(&res.d.n, l);
5806 bc_program_binOpRetire(&res);
5812 #define bc_program_pushVar(code, bgn, pop, copy) \
5813 bc_program_pushVar(code, bgn)
5814 // for bc, 'pop' and 'copy' are always false
5816 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5817 bool pop, bool copy)
5819 BcStatus s = BC_STATUS_SUCCESS;
5821 char *name = bc_program_name(code, bgn);
5823 r.t = BC_RESULT_VAR;
5828 BcVec *v = bc_program_search(name, true);
5829 BcNum *num = bc_vec_top(v);
5833 if (!BC_PROG_STACK(v, 2 - copy)) {
5835 return BC_STATUS_EXEC_STACK;
5841 if (!BC_PROG_STR(num)) {
5843 r.t = BC_RESULT_TEMP;
5845 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5846 bc_num_copy(&r.d.n, num);
5849 r.t = BC_RESULT_STR;
5850 r.d.id.idx = num->rdx;
5853 if (!copy) bc_vec_pop(v);
5858 bc_vec_push(&G.prog.results, &r);
5863 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5866 BcStatus s = BC_STATUS_SUCCESS;
5870 r.d.id.name = bc_program_name(code, bgn);
5872 if (inst == BC_INST_ARRAY) {
5873 r.t = BC_RESULT_ARRAY;
5874 bc_vec_push(&G.prog.results, &r);
5881 s = bc_program_prep(&operand, &num);
5883 s = bc_num_ulong(num, &temp);
5886 if (temp > BC_MAX_DIM) {
5887 s = BC_STATUS_EXEC_ARRAY_LEN;
5891 r.d.id.idx = (size_t) temp;
5892 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5896 if (s) free(r.d.id.name);
5901 static BcStatus bc_program_incdec(char inst)
5904 BcResult *ptr, res, copy;
5908 s = bc_program_prep(&ptr, &num);
5911 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5912 copy.t = BC_RESULT_TEMP;
5913 bc_num_init(©.d.n, num->len);
5914 bc_num_copy(©.d.n, num);
5917 res.t = BC_RESULT_ONE;
5918 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5919 BC_INST_ASSIGN_PLUS :
5920 BC_INST_ASSIGN_MINUS;
5922 bc_vec_push(&G.prog.results, &res);
5923 bc_program_assign(inst);
5925 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5926 bc_vec_pop(&G.prog.results);
5927 bc_vec_push(&G.prog.results, ©);
5933 static BcStatus bc_program_call(char *code, size_t *idx)
5935 BcStatus s = BC_STATUS_SUCCESS;
5937 size_t i, nparams = bc_program_index(code, idx);
5944 ip.func = bc_program_index(code, idx);
5945 func = bc_vec_item(&G.prog.fns, ip.func);
5947 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
5948 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
5949 ip.len = G.prog.results.len - nparams;
5951 for (i = 0; i < nparams; ++i) {
5953 a = bc_vec_item(&func->autos, nparams - 1 - i);
5954 arg = bc_vec_top(&G.prog.results);
5956 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5957 return BC_STATUS_EXEC_BAD_TYPE;
5959 s = bc_program_copyToVar(a->name, a->idx);
5963 for (; i < func->autos.len; ++i) {
5966 a = bc_vec_item(&func->autos, i);
5967 v = bc_program_search(a->name, a->idx);
5970 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5971 bc_vec_push(v, ¶m.n);
5974 bc_array_init(¶m.v, true);
5975 bc_vec_push(v, ¶m.v);
5979 bc_vec_push(&G.prog.stack, &ip);
5981 return BC_STATUS_SUCCESS;
5984 static BcStatus bc_program_return(char inst)
5990 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5992 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5993 return BC_STATUS_EXEC_STACK;
5995 f = bc_vec_item(&G.prog.fns, ip->func);
5996 res.t = BC_RESULT_TEMP;
5998 if (inst == BC_INST_RET) {
6001 BcResult *operand = bc_vec_top(&G.prog.results);
6003 s = bc_program_num(operand, &num, false);
6005 bc_num_init(&res.d.n, num->len);
6006 bc_num_copy(&res.d.n, num);
6009 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6010 bc_num_zero(&res.d.n);
6013 // We need to pop arguments as well, so this takes that into account.
6014 for (i = 0; i < f->autos.len; ++i) {
6017 BcId *a = bc_vec_item(&f->autos, i);
6019 v = bc_program_search(a->name, a->idx);
6023 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6024 bc_vec_push(&G.prog.results, &res);
6025 bc_vec_pop(&G.prog.stack);
6027 return BC_STATUS_SUCCESS;
6031 static unsigned long bc_program_scale(BcNum *n)
6033 return (unsigned long) n->rdx;
6036 static unsigned long bc_program_len(BcNum *n)
6038 unsigned long len = n->len;
6041 if (n->rdx != n->len) return len;
6042 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6047 static BcStatus bc_program_builtin(char inst)
6053 bool len = inst == BC_INST_LENGTH;
6055 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6056 opnd = bc_vec_top(&G.prog.results);
6058 s = bc_program_num(opnd, &num, false);
6062 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6065 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6067 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6069 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6070 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6074 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6077 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6079 str = bc_vec_item(&G.prog.strs, idx);
6080 bc_num_ulong2num(&res.d.n, strlen(*str));
6084 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6085 bc_num_ulong2num(&res.d.n, f(num));
6088 bc_program_retire(&res, BC_RESULT_TEMP);
6094 static BcStatus bc_program_divmod(void)
6097 BcResult *opd1, *opd2, res, res2;
6098 BcNum *n1, *n2 = NULL;
6100 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6103 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6104 bc_num_init(&res2.d.n, n2->len);
6106 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6109 bc_program_binOpRetire(&res2);
6110 res.t = BC_RESULT_TEMP;
6111 bc_vec_push(&G.prog.results, &res);
6116 bc_num_free(&res2.d.n);
6117 bc_num_free(&res.d.n);
6121 static BcStatus bc_program_modexp(void)
6124 BcResult *r1, *r2, *r3, res;
6125 BcNum *n1, *n2, *n3;
6127 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6128 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6131 r1 = bc_vec_item_rev(&G.prog.results, 2);
6132 s = bc_program_num(r1, &n1, false);
6134 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6136 // Make sure that the values have their pointers updated, if necessary.
6137 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6139 if (r1->t == r2->t) {
6140 s = bc_program_num(r2, &n2, false);
6144 if (r1->t == r3->t) {
6145 s = bc_program_num(r3, &n3, false);
6150 bc_num_init(&res.d.n, n3->len);
6151 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6154 bc_vec_pop(&G.prog.results);
6155 bc_program_binOpRetire(&res);
6160 bc_num_free(&res.d.n);
6164 static void bc_program_stackLen(void)
6167 size_t len = G.prog.results.len;
6169 res.t = BC_RESULT_TEMP;
6171 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6172 bc_num_ulong2num(&res.d.n, len);
6173 bc_vec_push(&G.prog.results, &res);
6176 static BcStatus bc_program_asciify(void)
6180 BcNum *num = NULL, n;
6181 char *str, *str2, c;
6182 size_t len = G.prog.strs.len, idx;
6185 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6186 r = bc_vec_top(&G.prog.results);
6188 s = bc_program_num(r, &num, false);
6191 if (BC_PROG_NUM(r, num)) {
6193 bc_num_init(&n, BC_NUM_DEF_SIZE);
6194 bc_num_copy(&n, num);
6195 bc_num_truncate(&n, n.rdx);
6197 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6198 if (s) goto num_err;
6199 s = bc_num_ulong(&n, &val);
6200 if (s) goto num_err;
6207 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6208 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6216 str2 = xstrdup(str);
6217 bc_program_addFunc(str2, &idx);
6219 if (idx != len + BC_PROG_REQ_FUNCS) {
6221 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6222 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6231 bc_vec_push(&G.prog.strs, &str);
6233 res.t = BC_RESULT_STR;
6235 bc_vec_pop(&G.prog.results);
6236 bc_vec_push(&G.prog.results, &res);
6238 return BC_STATUS_SUCCESS;
6245 static BcStatus bc_program_printStream(void)
6253 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6254 r = bc_vec_top(&G.prog.results);
6256 s = bc_program_num(r, &n, false);
6259 if (BC_PROG_NUM(r, n))
6260 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6262 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6263 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6270 static BcStatus bc_program_nquit(void)
6277 s = bc_program_prep(&opnd, &num);
6279 s = bc_num_ulong(num, &val);
6282 bc_vec_pop(&G.prog.results);
6284 if (G.prog.stack.len < val)
6285 return BC_STATUS_EXEC_STACK;
6286 else if (G.prog.stack.len == val)
6287 return BC_STATUS_QUIT;
6289 bc_vec_npop(&G.prog.stack, val);
6294 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6297 BcStatus s = BC_STATUS_SUCCESS;
6307 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6309 r = bc_vec_top(&G.prog.results);
6313 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6315 if (code[*bgn] == BC_PARSE_STREND)
6318 else_name = bc_program_name(code, bgn);
6320 exec = r->d.n.len != 0;
6324 else if (else_name != NULL) {
6331 v = bc_program_search(name, true);
6338 if (!exec) goto exit;
6339 if (!BC_PROG_STR(n)) {
6340 s = BC_STATUS_EXEC_BAD_TYPE;
6348 if (r->t == BC_RESULT_STR)
6350 else if (r->t == BC_RESULT_VAR) {
6351 s = bc_program_num(r, &n, false);
6352 if (s || !BC_PROG_STR(n)) goto exit;
6359 fidx = sidx + BC_PROG_REQ_FUNCS;
6361 str = bc_vec_item(&G.prog.strs, sidx);
6362 f = bc_vec_item(&G.prog.fns, fidx);
6364 if (f->code.len == 0) {
6365 common_parse_init(&prs, fidx);
6366 s = bc_parse_text(&prs, *str);
6368 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6371 if (prs.l.t.t != BC_LEX_EOF) {
6372 s = BC_STATUS_PARSE_BAD_EXP;
6376 bc_parse_free(&prs);
6380 ip.len = G.prog.results.len;
6383 bc_vec_pop(&G.prog.results);
6384 bc_vec_push(&G.prog.stack, &ip);
6386 return BC_STATUS_SUCCESS;
6389 bc_parse_free(&prs);
6390 f = bc_vec_item(&G.prog.fns, fidx);
6391 bc_vec_npop(&f->code, f->code.len);
6393 bc_vec_pop(&G.prog.results);
6398 static void bc_program_pushGlobal(char inst)
6403 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6404 if (inst == BC_INST_IBASE)
6405 val = (unsigned long) G.prog.ib_t;
6406 else if (inst == BC_INST_SCALE)
6407 val = (unsigned long) G.prog.scale;
6409 val = (unsigned long) G.prog.ob_t;
6411 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6412 bc_num_ulong2num(&res.d.n, val);
6413 bc_vec_push(&G.prog.results, &res);
6416 static void bc_program_addFunc(char *name, size_t *idx)
6419 BcId entry, *entry_ptr;
6423 entry.idx = G.prog.fns.len;
6425 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6428 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6429 *idx = entry_ptr->idx;
6431 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6433 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6435 // We need to reset these, so the function can be repopulated.
6437 bc_vec_npop(&func->autos, func->autos.len);
6438 bc_vec_npop(&func->code, func->code.len);
6439 bc_vec_npop(&func->labels, func->labels.len);
6443 bc_vec_push(&G.prog.fns, &f);
6447 static BcStatus bc_program_reset(BcStatus s)
6452 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6453 bc_vec_npop(&G.prog.results, G.prog.results.len);
6455 f = bc_vec_item(&G.prog.fns, 0);
6456 ip = bc_vec_top(&G.prog.stack);
6457 ip->idx = f->code.len;
6459 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
6461 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6464 fputs(bc_program_ready_msg, stderr);
6466 s = BC_STATUS_SUCCESS;
6475 static BcStatus bc_program_exec(void)
6477 BcStatus s = BC_STATUS_SUCCESS;
6481 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6482 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6483 char *code = func->code.v;
6486 while (!s && ip->idx < func->code.len) {
6488 char inst = code[(ip->idx)++];
6493 case BC_INST_JUMP_ZERO:
6495 s = bc_program_prep(&ptr, &num);
6497 cond = !bc_num_cmp(num, &G.prog.zero);
6498 bc_vec_pop(&G.prog.results);
6504 idx = bc_program_index(code, &ip->idx);
6505 addr = bc_vec_item(&func->labels, idx);
6506 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6512 s = bc_program_call(code, &ip->idx);
6516 case BC_INST_INC_PRE:
6517 case BC_INST_DEC_PRE:
6518 case BC_INST_INC_POST:
6519 case BC_INST_DEC_POST:
6521 s = bc_program_incdec(inst);
6534 s = bc_program_return(inst);
6538 case BC_INST_BOOL_OR:
6539 case BC_INST_BOOL_AND:
6541 case BC_INST_REL_EQ:
6542 case BC_INST_REL_LE:
6543 case BC_INST_REL_GE:
6544 case BC_INST_REL_NE:
6545 case BC_INST_REL_LT:
6546 case BC_INST_REL_GT:
6548 s = bc_program_logical(inst);
6554 s = bc_program_read();
6560 s = bc_program_pushVar(code, &ip->idx, false, false);
6564 case BC_INST_ARRAY_ELEM:
6567 s = bc_program_pushArray(code, &ip->idx, inst);
6573 r.t = BC_RESULT_LAST;
6574 bc_vec_push(&G.prog.results, &r);
6582 bc_program_pushGlobal(inst);
6586 case BC_INST_SCALE_FUNC:
6587 case BC_INST_LENGTH:
6590 s = bc_program_builtin(inst);
6596 r.t = BC_RESULT_CONSTANT;
6597 r.d.id.idx = bc_program_index(code, &ip->idx);
6598 bc_vec_push(&G.prog.results, &r);
6604 if (!BC_PROG_STACK(&G.prog.results, 1))
6605 s = BC_STATUS_EXEC_STACK;
6607 bc_vec_pop(&G.prog.results);
6611 case BC_INST_POP_EXEC:
6613 bc_vec_pop(&G.prog.stack);
6618 case BC_INST_PRINT_POP:
6619 case BC_INST_PRINT_STR:
6621 s = bc_program_print(inst, 0);
6627 r.t = BC_RESULT_STR;
6628 r.d.id.idx = bc_program_index(code, &ip->idx);
6629 bc_vec_push(&G.prog.results, &r);
6634 case BC_INST_MULTIPLY:
6635 case BC_INST_DIVIDE:
6636 case BC_INST_MODULUS:
6640 s = bc_program_op(inst);
6644 case BC_INST_BOOL_NOT:
6646 s = bc_program_prep(&ptr, &num);
6649 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6650 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6651 bc_program_retire(&r, BC_RESULT_TEMP);
6658 s = bc_program_negate();
6663 case BC_INST_ASSIGN_POWER:
6664 case BC_INST_ASSIGN_MULTIPLY:
6665 case BC_INST_ASSIGN_DIVIDE:
6666 case BC_INST_ASSIGN_MODULUS:
6667 case BC_INST_ASSIGN_PLUS:
6668 case BC_INST_ASSIGN_MINUS:
6670 case BC_INST_ASSIGN:
6672 s = bc_program_assign(inst);
6676 case BC_INST_MODEXP:
6678 s = bc_program_modexp();
6682 case BC_INST_DIVMOD:
6684 s = bc_program_divmod();
6688 case BC_INST_EXECUTE:
6689 case BC_INST_EXEC_COND:
6691 cond = inst == BC_INST_EXEC_COND;
6692 s = bc_program_execStr(code, &ip->idx, cond);
6696 case BC_INST_PRINT_STACK:
6698 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6699 s = bc_program_print(BC_INST_PRINT, idx);
6703 case BC_INST_CLEAR_STACK:
6705 bc_vec_npop(&G.prog.results, G.prog.results.len);
6709 case BC_INST_STACK_LEN:
6711 bc_program_stackLen();
6715 case BC_INST_DUPLICATE:
6717 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6718 ptr = bc_vec_top(&G.prog.results);
6719 bc_result_copy(&r, ptr);
6720 bc_vec_push(&G.prog.results, &r);
6728 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6730 ptr = bc_vec_item_rev(&G.prog.results, 0);
6731 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6732 memcpy(&r, ptr, sizeof(BcResult));
6733 memcpy(ptr, ptr2, sizeof(BcResult));
6734 memcpy(ptr2, &r, sizeof(BcResult));
6739 case BC_INST_ASCIIFY:
6741 s = bc_program_asciify();
6745 case BC_INST_PRINT_STREAM:
6747 s = bc_program_printStream();
6752 case BC_INST_PUSH_VAR:
6754 bool copy = inst == BC_INST_LOAD;
6755 s = bc_program_pushVar(code, &ip->idx, true, copy);
6759 case BC_INST_PUSH_TO_VAR:
6761 char *name = bc_program_name(code, &ip->idx);
6762 s = bc_program_copyToVar(name, true);
6769 if (G.prog.stack.len <= 2)
6772 bc_vec_npop(&G.prog.stack, 2);
6778 s = bc_program_nquit();
6784 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
6786 // If the stack has changed, pointers may be invalid.
6787 ip = bc_vec_top(&G.prog.stack);
6788 func = bc_vec_item(&G.prog.fns, ip->func);
6789 code = func->code.v;
6795 static void bc_vm_info(void)
6797 printf("%s "BB_VER"\n"
6798 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6799 "Report bugs at: https://github.com/gavinhoward/bc\n"
6800 "This is free software with ABSOLUTELY NO WARRANTY\n"
6804 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6806 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6808 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6809 fprintf(stderr, " %s", file);
6810 fprintf(stderr, bc_err_line + 4 * !line, line);
6812 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6816 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6821 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6822 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6824 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6825 fprintf(stderr, fmt, bc_err_msgs[s]);
6826 if (msg) fprintf(stderr, " %s\n", msg);
6827 fprintf(stderr, " %s", file);
6828 fprintf(stderr, bc_err_line + 4 * !line, line);
6830 if (G.ttyin || !G_posix)
6831 s = BC_STATUS_SUCCESS;
6835 static void bc_vm_envArgs(void)
6837 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6840 char *env_args = getenv(bc_args_env_name), *buf;
6842 if (!env_args) return;
6844 G.env_args = xstrdup(env_args);
6847 bc_vec_init(&v, sizeof(char *), NULL);
6848 bc_vec_push(&v, &bc_args_env_name);
6851 if (!isspace(*buf)) {
6852 bc_vec_push(&v, &buf);
6853 while (*buf != 0 && !isspace(*buf)) ++buf;
6854 if (*buf != 0) (*(buf++)) = '\0';
6860 bc_args((int) v.len, (char **) v.v);
6866 static size_t bc_vm_envLen(const char *var)
6868 char *lenv = getenv(var);
6869 size_t i, len = BC_NUM_PRINT_WIDTH;
6872 if (!lenv) return len;
6876 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6878 len = (size_t) atoi(lenv) - 1;
6879 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6882 len = BC_NUM_PRINT_WIDTH;
6887 static BcStatus bc_vm_process(const char *text)
6889 BcStatus s = bc_parse_text(&G.prs, text);
6891 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6894 while (G.prs.l.t.t != BC_LEX_EOF) {
6896 s = G.prs.parse(&G.prs);
6898 if (s == BC_STATUS_LIMITS) {
6900 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
6901 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
6902 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
6903 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
6904 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
6905 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
6906 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
6907 printf("Number of vars = %lu\n", BC_MAX_VARS);
6909 s = BC_STATUS_SUCCESS;
6912 if (s == BC_STATUS_QUIT) return s;
6913 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6918 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6919 s = bc_program_exec();
6920 if (!s && G.tty) fflush(stdout);
6921 if (s && s != BC_STATUS_QUIT)
6922 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6928 static BcStatus bc_vm_file(const char *file)
6936 data = bc_read_file(file);
6937 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
6939 bc_lex_file(&G.prs.l, file);
6940 s = bc_vm_process(data);
6943 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6944 ip = bc_vec_item(&G.prog.stack, 0);
6946 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6953 static BcStatus bc_vm_stdin(void)
6957 size_t len, i, str = 0;
6958 bool comment = false;
6960 G.prog.file = bc_program_stdin_name;
6961 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6963 bc_vec_init(&buffer, sizeof(char), NULL);
6964 bc_vec_init(&buf, sizeof(char), NULL);
6965 bc_vec_pushByte(&buffer, '\0');
6967 // This loop is complex because the vm tries not to send any lines that end
6968 // with a backslash to the parser. The reason for that is because the parser
6969 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6970 // case, and for strings and comments, the parser will expect more stuff.
6971 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6973 char *string = buf.v;
6978 if (str && buf.v[0] == G.send)
6980 else if (buf.v[0] == G.sbgn)
6983 else if (len > 1 || comment) {
6985 for (i = 0; i < len; ++i) {
6987 bool notend = len > i + 1;
6990 if (i - 1 > len || string[i - 1] != '\\') {
6991 if (G.sbgn == G.send)
6993 else if (c == G.send)
6995 else if (c == G.sbgn)
6999 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7003 else if (c == '*' && notend && comment && string[i + 1] == '/')
7007 if (str || comment || string[len - 2] == '\\') {
7008 bc_vec_concat(&buffer, buf.v);
7013 bc_vec_concat(&buffer, buf.v);
7014 s = bc_vm_process(buffer.v);
7017 bc_vec_npop(&buffer, buffer.len);
7020 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7022 // INPUT_EOF will always happen when stdin is
7023 // closed. It's not a problem in that case.
7024 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7025 s = BC_STATUS_SUCCESS;
7028 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7031 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7036 bc_vec_free(&buffer);
7040 static BcStatus bc_vm_exec(void)
7042 BcStatus s = BC_STATUS_SUCCESS;
7046 if (G.flags & BC_FLAG_L) {
7048 bc_lex_file(&G.prs.l, bc_lib_name);
7049 s = bc_parse_text(&G.prs, bc_lib);
7051 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7054 s = bc_program_exec();
7059 for (i = 0; !s && i < G.files.len; ++i)
7060 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7061 if (s && s != BC_STATUS_QUIT) return s;
7063 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7064 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7066 if (s == BC_STATUS_QUIT)
7067 s = BC_STATUS_SUCCESS;
7071 #if ENABLE_FEATURE_CLEAN_UP
7072 static void bc_program_free()
7074 bc_num_free(&G.prog.ib);
7075 bc_num_free(&G.prog.ob);
7076 bc_num_free(&G.prog.hexb);
7078 bc_num_free(&G.prog.strmb);
7080 bc_vec_free(&G.prog.fns);
7081 bc_vec_free(&G.prog.fn_map);
7082 bc_vec_free(&G.prog.vars);
7083 bc_vec_free(&G.prog.var_map);
7084 bc_vec_free(&G.prog.arrs);
7085 bc_vec_free(&G.prog.arr_map);
7086 bc_vec_free(&G.prog.strs);
7087 bc_vec_free(&G.prog.consts);
7088 bc_vec_free(&G.prog.results);
7089 bc_vec_free(&G.prog.stack);
7090 bc_num_free(&G.prog.last);
7091 bc_num_free(&G.prog.zero);
7092 bc_num_free(&G.prog.one);
7095 static void bc_vm_free(void)
7097 bc_vec_free(&G.files);
7099 bc_parse_free(&G.prs);
7104 static void bc_program_init(size_t line_len)
7109 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7110 memset(&ip, 0, sizeof(BcInstPtr));
7112 /* G.prog.nchars = G.prog.scale = 0; - already is */
7113 G.prog.len = line_len;
7115 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7116 bc_num_ten(&G.prog.ib);
7119 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7120 bc_num_ten(&G.prog.ob);
7123 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7124 bc_num_ten(&G.prog.hexb);
7125 G.prog.hexb.num[0] = 6;
7128 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7129 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7132 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7133 bc_num_zero(&G.prog.last);
7135 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7136 bc_num_zero(&G.prog.zero);
7138 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7139 bc_num_one(&G.prog.one);
7141 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7142 bc_map_init(&G.prog.fn_map);
7144 bc_program_addFunc(xstrdup("(main)"), &idx);
7145 bc_program_addFunc(xstrdup("(read)"), &idx);
7147 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7148 bc_map_init(&G.prog.var_map);
7150 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7151 bc_map_init(&G.prog.arr_map);
7153 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7154 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7155 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7156 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7157 bc_vec_push(&G.prog.stack, &ip);
7160 static void bc_vm_init(const char *env_len)
7162 size_t len = bc_vm_envLen(env_len);
7164 #if ENABLE_FEATURE_BC_SIGNALS
7165 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7168 bc_vec_init(&G.files, sizeof(char *), NULL);
7171 if (getenv("POSIXLY_CORRECT"))
7172 G.flags |= BC_FLAG_S;
7176 bc_program_init(len);
7178 bc_parse_init(&G.prs, BC_PROG_MAIN);
7180 dc_parse_init(&G.prs, BC_PROG_MAIN);
7184 static BcStatus bc_vm_run(int argc, char *argv[],
7185 const char *env_len)
7189 bc_vm_init(env_len);
7190 bc_args(argc, argv);
7192 G.ttyin = isatty(0);
7193 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7195 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7198 #if ENABLE_FEATURE_CLEAN_UP
7205 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7206 int bc_main(int argc, char **argv)
7209 G.sbgn = G.send = '"';
7211 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7216 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7217 int dc_main(int argc, char **argv)
7223 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");