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 {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
194 typedef signed char BcDig;
196 typedef struct BcNum {
204 #define BC_NUM_MIN_BASE ((unsigned long) 2)
205 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
206 #define BC_NUM_DEF_SIZE (16)
207 #define BC_NUM_PRINT_WIDTH (69)
209 #define BC_NUM_KARATSUBA_LEN (32)
211 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
212 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
213 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
214 #define BC_NUM_AREQ(a, b) \
215 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
216 #define BC_NUM_MREQ(a, b, scale) \
217 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
219 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
220 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
222 static void bc_num_init(BcNum *n, size_t req);
223 static void bc_num_expand(BcNum *n, size_t req);
224 static void bc_num_copy(BcNum *d, BcNum *s);
225 static void bc_num_free(void *num);
227 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
228 static void bc_num_ulong2num(BcNum *n, unsigned long val);
230 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
235 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
236 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
237 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
240 typedef enum BcInst {
270 BC_INST_ASSIGN_POWER,
271 BC_INST_ASSIGN_MULTIPLY,
272 BC_INST_ASSIGN_DIVIDE,
273 BC_INST_ASSIGN_MODULUS,
275 BC_INST_ASSIGN_MINUS,
321 BC_INST_PRINT_STREAM,
336 BC_INST_INVALID = -1,
341 typedef struct BcId {
346 typedef struct BcFunc {
353 typedef enum BcResultType {
358 BC_RESULT_ARRAY_ELEM,
367 // These are between to calculate ibase, obase, and last from instructions.
375 typedef union BcResultData {
381 typedef struct BcResult {
386 typedef struct BcInstPtr {
392 static void bc_array_expand(BcVec *a, size_t len);
393 static int bc_id_cmp(const void *e1, const void *e2);
395 // BC_LEX_NEG is not used in lexing; it is only for parsing.
396 typedef enum BcLexType {
424 BC_LEX_OP_ASSIGN_POWER,
425 BC_LEX_OP_ASSIGN_MULTIPLY,
426 BC_LEX_OP_ASSIGN_DIVIDE,
427 BC_LEX_OP_ASSIGN_MODULUS,
428 BC_LEX_OP_ASSIGN_PLUS,
429 BC_LEX_OP_ASSIGN_MINUS,
503 typedef BcStatus (*BcLexNext)(struct BcLex *);
505 typedef struct BcLex {
524 #define BC_PARSE_STREND ((char) UCHAR_MAX)
526 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
527 #define bc_parse_updateFunc(p, f) \
528 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
530 #define BC_PARSE_REL (1 << 0)
531 #define BC_PARSE_PRINT (1 << 1)
532 #define BC_PARSE_NOCALL (1 << 2)
533 #define BC_PARSE_NOREAD (1 << 3)
534 #define BC_PARSE_ARRAY (1 << 4)
536 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
537 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
539 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
540 #define BC_PARSE_FUNC_INNER(parse) \
541 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
543 #define BC_PARSE_FLAG_FUNC (1 << 1)
544 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
546 #define BC_PARSE_FLAG_BODY (1 << 2)
547 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
549 #define BC_PARSE_FLAG_LOOP (1 << 3)
550 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
552 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
553 #define BC_PARSE_LOOP_INNER(parse) \
554 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
556 #define BC_PARSE_FLAG_IF (1 << 5)
557 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
559 #define BC_PARSE_FLAG_ELSE (1 << 6)
560 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
562 #define BC_PARSE_FLAG_IF_END (1 << 7)
563 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
565 #define BC_PARSE_CAN_EXEC(parse) \
566 (!(BC_PARSE_TOP_FLAG(parse) & \
567 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
568 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
569 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
571 typedef struct BcOp {
576 typedef struct BcParseNext {
581 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
582 #define BC_PARSE_NEXT(a, ...) \
584 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
591 typedef BcStatus (*BcParseParse)(struct BcParse *);
593 typedef struct BcParse {
616 typedef struct BcLexKeyword {
622 #define BC_LEX_KW_ENTRY(a, b, c) \
624 .name = a, .len = (b), .posix = (c) \
627 static BcStatus bc_lex_token(BcLex *l);
629 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
630 #define BC_PARSE_LEAF(p, rparen) \
631 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
632 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
634 // We can calculate the conversion between tokens and exprs by subtracting the
635 // position of the first operator in the lex enum and adding the position of the
636 // first in the expr enum. Note: This only works for binary operators.
637 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
639 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
645 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
647 static BcStatus dc_lex_token(BcLex *l);
649 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
653 typedef struct BcProgram {
694 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
696 #define BC_PROG_MAIN (0)
697 #define BC_PROG_READ (1)
700 #define BC_PROG_REQ_FUNCS (2)
703 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
704 #define BC_PROG_NUM(r, n) \
705 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
707 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
709 static void bc_program_addFunc(char *name, size_t *idx);
710 static void bc_program_reset(void);
712 #define BC_FLAG_X (1 << 0)
713 #define BC_FLAG_W (1 << 1)
714 #define BC_FLAG_V (1 << 2)
715 #define BC_FLAG_S (1 << 3)
716 #define BC_FLAG_Q (1 << 4)
717 #define BC_FLAG_L (1 << 5)
718 #define BC_FLAG_I (1 << 6)
720 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
721 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
723 #define BC_MAX_OBASE ((unsigned) 999)
724 #define BC_MAX_DIM ((unsigned) INT_MAX)
725 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
726 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
727 #define BC_MAX_NAME BC_MAX_STRING
728 #define BC_MAX_NUM BC_MAX_STRING
729 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
730 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
745 #define G (*ptr_to_globals)
746 #define INIT_G() do { \
747 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
749 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
750 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
751 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
752 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
755 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
757 static void bc_vm_info(void);
760 static const BcLexKeyword bc_lex_kws[20] = {
761 BC_LEX_KW_ENTRY("auto", 4, true),
762 BC_LEX_KW_ENTRY("break", 5, true),
763 BC_LEX_KW_ENTRY("continue", 8, false),
764 BC_LEX_KW_ENTRY("define", 6, true),
765 BC_LEX_KW_ENTRY("else", 4, false),
766 BC_LEX_KW_ENTRY("for", 3, true),
767 BC_LEX_KW_ENTRY("halt", 4, false),
768 BC_LEX_KW_ENTRY("ibase", 5, true),
769 BC_LEX_KW_ENTRY("if", 2, true),
770 BC_LEX_KW_ENTRY("last", 4, false),
771 BC_LEX_KW_ENTRY("length", 6, true),
772 BC_LEX_KW_ENTRY("limits", 6, false),
773 BC_LEX_KW_ENTRY("obase", 5, true),
774 BC_LEX_KW_ENTRY("print", 5, false),
775 BC_LEX_KW_ENTRY("quit", 4, true),
776 BC_LEX_KW_ENTRY("read", 4, false),
777 BC_LEX_KW_ENTRY("return", 6, true),
778 BC_LEX_KW_ENTRY("scale", 5, true),
779 BC_LEX_KW_ENTRY("sqrt", 4, true),
780 BC_LEX_KW_ENTRY("while", 5, true),
783 // This is an array that corresponds to token types. An entry is
784 // true if the token is valid in an expression, false otherwise.
785 static const bool bc_parse_exprs[] = {
786 false, false, true, true, true, true, true, true, true, true, true, true,
787 true, true, true, true, true, true, true, true, true, true, true, true,
788 true, true, true, false, false, true, true, false, false, false, false,
789 false, false, false, true, true, false, false, false, false, false, false,
790 false, true, false, true, true, true, true, false, false, true, false, true,
794 // This is an array of data for operators that correspond to token types.
795 static const BcOp bc_parse_ops[] = {
796 { 0, false }, { 0, false },
799 { 3, true }, { 3, true }, { 3, true },
800 { 4, true }, { 4, true },
801 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
803 { 7, true }, { 7, true },
804 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
805 { 5, false }, { 5, false },
808 // These identify what tokens can come after expressions in certain cases.
809 static const BcParseNext bc_parse_next_expr =
810 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
811 static const BcParseNext bc_parse_next_param =
812 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
813 static const BcParseNext bc_parse_next_print =
814 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
815 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
816 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
817 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
818 static const BcParseNext bc_parse_next_read =
819 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
823 static const BcLexType dc_lex_regs[] = {
824 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
825 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
826 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
830 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
832 static const BcLexType dc_lex_tokens[] = {
833 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
834 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
835 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
836 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
838 BC_LEX_INVALID, BC_LEX_INVALID,
839 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
840 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
843 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
844 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
845 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
847 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
848 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
849 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
850 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
852 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
853 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
854 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
855 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
856 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
860 static const BcInst dc_parse_insts[] = {
861 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
862 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
863 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
871 BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
874 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
876 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
878 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
879 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
880 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
881 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
883 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
887 static const BcNumBinaryOp bc_program_ops[] = {
888 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
891 static const char bc_program_stdin_name[] = "<stdin>";
894 static const char *bc_lib_name = "gen/lib.bc";
896 static const char bc_lib[] = {
897 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
898 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
899 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
900 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,
901 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
902 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
903 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,
904 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
905 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
906 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,
907 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
908 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
909 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
910 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
911 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
912 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
913 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
914 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
915 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
916 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
917 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
918 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
919 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
920 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,
921 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
922 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,
923 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
924 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
925 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
926 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
927 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
928 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,
929 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
930 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
931 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
932 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
933 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,
934 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
935 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
936 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
937 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
938 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
939 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
940 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
941 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
942 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
943 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
944 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,
945 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,
946 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
947 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,
948 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,
949 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,
950 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
951 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
952 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,
953 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,
954 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,
955 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
956 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,
957 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
958 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
959 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
960 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,
961 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
962 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
963 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
964 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
965 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
966 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
967 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
968 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
969 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
970 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
971 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
972 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
973 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
974 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
975 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
976 117,114,110,40,97,42,114,47,49,41,10,125,10,0
980 static void fflush_and_check(void)
983 if (ferror(stdout) || ferror(stderr))
984 bb_perror_msg_and_die("output error");
987 static void quit(void) NORETURN;
988 static void quit(void)
991 bb_perror_msg_and_die("input error");
996 static int bc_error(const char *fmt, ...)
1001 bb_verror_msg(fmt, p, NULL);
1005 return BC_STATUS_FAILURE;
1008 static int bc_posix_error(const char *fmt, ...)
1012 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
1013 return BC_STATUS_SUCCESS;
1016 bb_verror_msg(fmt, p, NULL);
1019 // Do we treat non-POSIX constructs as errors?
1020 if (!(option_mask32 & BC_FLAG_S))
1021 return BC_STATUS_SUCCESS; // no, it's a warning
1024 return BC_STATUS_FAILURE;
1027 static void bc_vec_grow(BcVec *v, size_t n)
1029 size_t cap = v->cap * 2;
1030 while (cap < v->len + n) cap *= 2;
1031 v->v = xrealloc(v->v, v->size * cap);
1035 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1038 v->cap = BC_VEC_START_CAP;
1041 v->v = xmalloc(esize * BC_VEC_START_CAP);
1044 static void bc_vec_expand(BcVec *v, size_t req)
1047 v->v = xrealloc(v->v, v->size * req);
1052 static void bc_vec_npop(BcVec *v, size_t n)
1057 size_t len = v->len - n;
1058 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1062 static void bc_vec_push(BcVec *v, const void *data)
1064 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1065 memmove(v->v + (v->size * v->len), data, v->size);
1069 static void bc_vec_pushByte(BcVec *v, char data)
1071 bc_vec_push(v, &data);
1074 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1077 bc_vec_push(v, data);
1082 if (v->len == v->cap) bc_vec_grow(v, 1);
1084 ptr = v->v + v->size * idx;
1086 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1087 memmove(ptr, data, v->size);
1091 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1093 bc_vec_npop(v, v->len);
1094 bc_vec_expand(v, len + 1);
1095 memcpy(v->v, str, len);
1098 bc_vec_pushByte(v, '\0');
1101 static void bc_vec_concat(BcVec *v, const char *str)
1105 if (v->len == 0) bc_vec_pushByte(v, '\0');
1107 len = v->len + strlen(str);
1109 if (v->cap < len) bc_vec_grow(v, len - v->len);
1115 static void *bc_vec_item(const BcVec *v, size_t idx)
1117 return v->v + v->size * idx;
1120 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1122 return v->v + v->size * (v->len - idx - 1);
1125 static void bc_vec_free(void *vec)
1127 BcVec *v = (BcVec *) vec;
1128 bc_vec_npop(v, v->len);
1132 static size_t bc_map_find(const BcVec *v, const void *ptr)
1134 size_t low = 0, high = v->len;
1136 while (low < high) {
1138 size_t mid = (low + high) / 2;
1139 BcId *id = bc_vec_item(v, mid);
1140 int result = bc_id_cmp(ptr, id);
1144 else if (result < 0)
1153 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1155 size_t n = *i = bc_map_find(v, ptr);
1158 bc_vec_push(v, ptr);
1159 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1160 return 0; // "was not inserted"
1162 bc_vec_pushAt(v, ptr, n);
1163 return 1; // "was inserted"
1166 static size_t bc_map_index(const BcVec *v, const void *ptr)
1168 size_t i = bc_map_find(v, ptr);
1169 if (i >= v->len) return BC_VEC_INVALID_IDX;
1170 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1173 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1182 bc_vec_npop(vec, vec->len);
1185 #if ENABLE_FEATURE_BC_SIGNALS
1186 if (bb_got_signal) { // ^C was pressed
1188 bb_got_signal = 0; // resets G_interrupt to zero
1190 ? "\ninterrupt (type \"quit\" to exit)\n"
1191 : "\ninterrupt (type \"q\" to exit)\n"
1195 if (G.ttyin && !G_posix)
1196 fputs(prompt, stderr);
1198 #if ENABLE_FEATURE_BC_SIGNALS
1204 #if ENABLE_FEATURE_BC_SIGNALS
1205 // Both conditions appear simultaneously, check both just in case
1206 if (errno == EINTR || bb_got_signal) {
1213 quit(); // this emits error message
1215 // Note: EOF does not append '\n', therefore:
1216 // printf 'print 123\n' | bc - works
1217 // printf 'print 123' | bc - fails (syntax error)
1221 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1224 // Bad chars on this line, ignore entire line
1225 bc_error("illegal character 0x%02x", i);
1229 bc_vec_push(vec, &c);
1230 } while (i != '\n');
1231 } while (bad_chars);
1233 bc_vec_pushByte(vec, '\0');
1235 return BC_STATUS_SUCCESS;
1238 static char* bc_read_file(const char *path)
1241 size_t size = ((size_t) -1);
1244 buf = xmalloc_open_read_close(path, &size);
1246 for (i = 0; i < size; ++i) {
1248 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1260 static void bc_args(int argc, char **argv)
1266 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1267 opts = getopt32long(argv, "xwvsqli",
1268 "extended-register\0" No_argument "x"
1269 "warn\0" No_argument "w"
1270 "version\0" No_argument "v"
1271 "standard\0" No_argument "s"
1272 "quiet\0" No_argument "q"
1273 "mathlib\0" No_argument "l"
1274 "interactive\0" No_argument "i"
1277 opts = getopt32(argv, "xwvsqli");
1279 if (getenv("POSIXLY_CORRECT"))
1280 option_mask32 |= BC_FLAG_S;
1282 if (opts & BC_FLAG_V) bc_vm_info();
1283 // should not be necessary, getopt32() handles this??
1284 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1286 for (i = optind; i < argc; ++i)
1287 bc_vec_push(&G.files, argv + i);
1290 static void bc_num_setToZero(BcNum *n, size_t scale)
1297 static void bc_num_zero(BcNum *n)
1299 bc_num_setToZero(n, 0);
1302 static void bc_num_one(BcNum *n)
1304 bc_num_setToZero(n, 0);
1309 static void bc_num_ten(BcNum *n)
1311 bc_num_setToZero(n, 0);
1317 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1321 for (i = 0; i < len; ++i) {
1322 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1329 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1333 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1334 return BC_NUM_NEG(i + 1, c < 0);
1337 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1339 size_t i, min, a_int, b_int, diff;
1340 BcDig *max_num, *min_num;
1341 bool a_max, neg = false;
1344 if (a == b) return 0;
1345 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1346 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1356 a_int = BC_NUM_INT(a);
1357 b_int = BC_NUM_INT(b);
1359 a_max = (a->rdx > b->rdx);
1361 if (a_int != 0) return (ssize_t) a_int;
1365 diff = a->rdx - b->rdx;
1366 max_num = a->num + diff;
1371 diff = b->rdx - a->rdx;
1372 max_num = b->num + diff;
1376 cmp = bc_num_compare(max_num, min_num, b_int + min);
1377 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1379 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1380 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1386 static void bc_num_truncate(BcNum *n, size_t places)
1388 if (places == 0) return;
1394 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1398 static void bc_num_extend(BcNum *n, size_t places)
1400 size_t len = n->len + places;
1404 if (n->cap < len) bc_num_expand(n, len);
1406 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1407 memset(n->num, 0, sizeof(BcDig) * places);
1414 static void bc_num_clean(BcNum *n)
1416 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1419 else if (n->len < n->rdx)
1423 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1426 bc_num_extend(n, scale - n->rdx);
1428 bc_num_truncate(n, n->rdx - scale);
1431 if (n->len != 0) n->neg = !neg1 != !neg2;
1434 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1439 b->len = n->len - idx;
1441 a->rdx = b->rdx = 0;
1443 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1444 memcpy(a->num, n->num, idx * sizeof(BcDig));
1455 static BcStatus bc_num_shift(BcNum *n, size_t places)
1457 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1458 if (places + n->len > BC_MAX_NUM)
1459 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1461 if (n->rdx >= places)
1464 bc_num_extend(n, places - n->rdx);
1470 return BC_STATUS_SUCCESS;
1473 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1482 return bc_num_div(&one, a, b, scale);
1485 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1487 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1488 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1491 // Because this function doesn't need to use scale (per the bc spec),
1492 // I am hijacking it to say whether it's doing an add or a subtract.
1496 if (sub && c->len) c->neg = !c->neg;
1497 return BC_STATUS_SUCCESS;
1499 else if (b->len == 0) {
1501 return BC_STATUS_SUCCESS;
1505 c->rdx = BC_MAX(a->rdx, b->rdx);
1506 min_rdx = BC_MIN(a->rdx, b->rdx);
1509 if (a->rdx > b->rdx) {
1510 diff = a->rdx - b->rdx;
1512 ptr_a = a->num + diff;
1516 diff = b->rdx - a->rdx;
1519 ptr_b = b->num + diff;
1522 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1525 a_int = BC_NUM_INT(a);
1526 b_int = BC_NUM_INT(b);
1528 if (a_int > b_int) {
1539 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1540 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1542 ptr_c[i] = (BcDig)(in % 10);
1545 for (; i < max + min_rdx; ++i, ++c->len) {
1546 in = ((int) ptr[i]) + carry;
1548 ptr_c[i] = (BcDig)(in % 10);
1551 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1553 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1556 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1559 BcNum *minuend, *subtrahend;
1561 bool aneg, bneg, neg;
1563 // Because this function doesn't need to use scale (per the bc spec),
1564 // I am hijacking it to say whether it's doing an add or a subtract.
1568 if (sub && c->len) c->neg = !c->neg;
1569 return BC_STATUS_SUCCESS;
1571 else if (b->len == 0) {
1573 return BC_STATUS_SUCCESS;
1578 a->neg = b->neg = false;
1580 cmp = bc_num_cmp(a, b);
1586 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1587 return BC_STATUS_SUCCESS;
1596 if (sub) neg = !neg;
1601 bc_num_copy(c, minuend);
1604 if (c->rdx < subtrahend->rdx) {
1605 bc_num_extend(c, subtrahend->rdx - c->rdx);
1609 start = c->rdx - subtrahend->rdx;
1611 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1615 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1618 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1623 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1624 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1625 bool aone = BC_NUM_ONE(a);
1627 if (a->len == 0 || b->len == 0) {
1629 return BC_STATUS_SUCCESS;
1631 else if (aone || BC_NUM_ONE(b)) {
1632 bc_num_copy(c, aone ? b : a);
1633 return BC_STATUS_SUCCESS;
1636 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1637 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1639 bc_num_expand(c, a->len + b->len + 1);
1641 memset(c->num, 0, sizeof(BcDig) * c->cap);
1642 c->len = carry = len = 0;
1644 for (i = 0; i < b->len; ++i) {
1646 for (j = 0; j < a->len; ++j) {
1647 int in = (int) c->num[i + j];
1648 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1650 c->num[i + j] = (BcDig)(in % 10);
1653 c->num[i + j] += (BcDig) carry;
1654 len = BC_MAX(len, i + j + !!carry);
1660 return BC_STATUS_SUCCESS;
1663 bc_num_init(&l1, max);
1664 bc_num_init(&h1, max);
1665 bc_num_init(&l2, max);
1666 bc_num_init(&h2, max);
1667 bc_num_init(&m1, max);
1668 bc_num_init(&m2, max);
1669 bc_num_init(&z0, max);
1670 bc_num_init(&z1, max);
1671 bc_num_init(&z2, max);
1672 bc_num_init(&temp, max + max);
1674 bc_num_split(a, max2, &l1, &h1);
1675 bc_num_split(b, max2, &l2, &h2);
1677 s = bc_num_add(&h1, &l1, &m1, 0);
1679 s = bc_num_add(&h2, &l2, &m2, 0);
1682 s = bc_num_k(&h1, &h2, &z0);
1684 s = bc_num_k(&m1, &m2, &z1);
1686 s = bc_num_k(&l1, &l2, &z2);
1689 s = bc_num_sub(&z1, &z0, &temp, 0);
1691 s = bc_num_sub(&temp, &z2, &z1, 0);
1694 s = bc_num_shift(&z0, max2 * 2);
1696 s = bc_num_shift(&z1, max2);
1698 s = bc_num_add(&z0, &z1, &temp, 0);
1700 s = bc_num_add(&temp, &z2, c, 0);
1716 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1720 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1722 scale = BC_MAX(scale, a->rdx);
1723 scale = BC_MAX(scale, b->rdx);
1724 scale = BC_MIN(a->rdx + b->rdx, scale);
1725 maxrdx = BC_MAX(maxrdx, scale);
1727 bc_num_init(&cpa, a->len);
1728 bc_num_init(&cpb, b->len);
1730 bc_num_copy(&cpa, a);
1731 bc_num_copy(&cpb, b);
1732 cpa.neg = cpb.neg = false;
1734 s = bc_num_shift(&cpa, maxrdx);
1736 s = bc_num_shift(&cpb, maxrdx);
1738 s = bc_num_k(&cpa, &cpb, c);
1742 bc_num_expand(c, c->len + maxrdx);
1744 if (c->len < maxrdx) {
1745 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1750 bc_num_retireMul(c, scale, a->neg, b->neg);
1758 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1760 BcStatus s = BC_STATUS_SUCCESS;
1767 return bc_error("divide by zero");
1768 else if (a->len == 0) {
1769 bc_num_setToZero(c, scale);
1770 return BC_STATUS_SUCCESS;
1772 else if (BC_NUM_ONE(b)) {
1774 bc_num_retireMul(c, scale, a->neg, b->neg);
1775 return BC_STATUS_SUCCESS;
1778 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1779 bc_num_copy(&cp, a);
1783 bc_num_expand(&cp, len + 2);
1784 bc_num_extend(&cp, len - cp.len);
1787 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1789 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1791 if (b->rdx == b->len) {
1792 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1796 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1798 // We want an extra zero in front to make things simpler.
1799 cp.num[cp.len++] = 0;
1802 bc_num_expand(c, cp.len);
1805 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1810 for (i = end - 1; !s && i < end; --i) {
1812 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1813 bc_num_subArrays(n, p, len);
1817 bc_num_retireMul(c, scale, a->neg, b->neg);
1820 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1823 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1824 BcNum *restrict d, size_t scale, size_t ts)
1831 return bc_error("divide by zero");
1834 bc_num_setToZero(d, ts);
1835 return BC_STATUS_SUCCESS;
1838 bc_num_init(&temp, d->cap);
1839 bc_num_d(a, b, c, scale);
1841 if (scale != 0) scale = ts;
1843 s = bc_num_m(c, b, &temp, scale);
1845 s = bc_num_sub(a, &temp, d, scale);
1848 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1851 bc_num_retireMul(d, ts, a->neg, b->neg);
1859 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1863 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1865 bc_num_init(&c1, len);
1866 s = bc_num_r(a, b, &c1, c, scale, ts);
1872 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1874 BcStatus s = BC_STATUS_SUCCESS;
1877 size_t i, powrdx, resrdx;
1880 if (b->rdx) return bc_error("non integer number");
1884 return BC_STATUS_SUCCESS;
1886 else if (a->len == 0) {
1887 bc_num_setToZero(c, scale);
1888 return BC_STATUS_SUCCESS;
1890 else if (BC_NUM_ONE(b)) {
1894 s = bc_num_inv(a, c, scale);
1901 s = bc_num_ulong(b, &pow);
1904 bc_num_init(©, a->len);
1905 bc_num_copy(©, a);
1907 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1911 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1913 s = bc_num_mul(©, ©, ©, powrdx);
1917 bc_num_copy(c, ©);
1919 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1922 s = bc_num_mul(©, ©, ©, powrdx);
1927 s = bc_num_mul(c, ©, c, resrdx);
1933 s = bc_num_inv(c, c, scale);
1937 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1939 // We can't use bc_num_clean() here.
1940 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1941 if (zero) bc_num_setToZero(c, scale);
1948 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1949 BcNumBinaryOp op, size_t req)
1952 BcNum num2, *ptr_a, *ptr_b;
1957 memcpy(ptr_a, c, sizeof(BcNum));
1966 memcpy(ptr_b, c, sizeof(BcNum));
1974 bc_num_init(c, req);
1976 bc_num_expand(c, req);
1978 s = op(ptr_a, ptr_b, c, scale);
1980 if (init) bc_num_free(&num2);
1985 static bool bc_num_strValid(const char *val, size_t base)
1988 bool small, radix = false;
1989 size_t i, len = strlen(val);
1991 if (!len) return true;
1994 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1996 for (i = 0; i < len; ++i) {
2002 if (radix) return false;
2008 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2015 static void bc_num_parseDecimal(BcNum *n, const char *val)
2021 for (i = 0; val[i] == '0'; ++i);
2028 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2029 bc_num_expand(n, len);
2032 ptr = strchr(val, '.');
2034 // Explicitly test for NULL here to produce either a 0 or 1.
2035 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2038 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2039 n->num[n->len] = val[i] - '0';
2043 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2046 BcNum temp, mult, result;
2050 size_t i, digits, len = strlen(val);
2054 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2057 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2058 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2060 for (i = 0; i < len; ++i) {
2063 if (c == '.') break;
2065 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2067 s = bc_num_mul(n, base, &mult, 0);
2068 if (s) goto int_err;
2069 bc_num_ulong2num(&temp, v);
2070 s = bc_num_add(&mult, &temp, n, 0);
2071 if (s) goto int_err;
2076 if (c == 0) goto int_err;
2079 bc_num_init(&result, base->len);
2080 bc_num_zero(&result);
2083 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2088 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2090 s = bc_num_mul(&result, base, &result, 0);
2092 bc_num_ulong2num(&temp, v);
2093 s = bc_num_add(&result, &temp, &result, 0);
2095 s = bc_num_mul(&mult, base, &mult, 0);
2099 s = bc_num_div(&result, &mult, &result, digits);
2101 s = bc_num_add(n, &result, n, digits);
2105 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2111 bc_num_free(&result);
2117 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2119 if (*nchars == line_len - 1) {
2127 static void bc_num_printChar(size_t num, size_t width, bool radix,
2128 size_t *nchars, size_t line_len)
2130 (void) radix, (void) line_len;
2131 bb_putchar((char) num);
2132 *nchars = *nchars + width;
2136 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2137 size_t *nchars, size_t line_len)
2141 bc_num_printNewline(nchars, line_len);
2142 bb_putchar(radix ? '.' : ' ');
2145 bc_num_printNewline(nchars, line_len);
2146 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2149 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2151 bc_num_printNewline(nchars, line_len);
2154 bb_putchar(((char) dig) + '0');
2158 static void bc_num_printHex(size_t num, size_t width, bool radix,
2159 size_t *nchars, size_t line_len)
2162 bc_num_printNewline(nchars, line_len);
2167 bc_num_printNewline(nchars, line_len);
2168 bb_putchar(bb_hexdigits_upcase[num]);
2169 *nchars = *nchars + width;
2172 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2174 size_t i, rdx = n->rdx - 1;
2176 if (n->neg) bb_putchar('-');
2177 (*nchars) += n->neg;
2179 for (i = n->len - 1; i < n->len; --i)
2180 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2183 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2184 size_t *nchars, size_t len, BcNumDigitOp print)
2188 BcNum intp, fracp, digit, frac_len;
2189 unsigned long dig, *ptr;
2194 print(0, width, false, nchars, len);
2195 return BC_STATUS_SUCCESS;
2198 bc_vec_init(&stack, sizeof(long), NULL);
2199 bc_num_init(&intp, n->len);
2200 bc_num_init(&fracp, n->rdx);
2201 bc_num_init(&digit, width);
2202 bc_num_init(&frac_len, BC_NUM_INT(n));
2203 bc_num_copy(&intp, n);
2204 bc_num_one(&frac_len);
2206 bc_num_truncate(&intp, intp.rdx);
2207 s = bc_num_sub(n, &intp, &fracp, 0);
2210 while (intp.len != 0) {
2211 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2213 s = bc_num_ulong(&digit, &dig);
2215 bc_vec_push(&stack, &dig);
2218 for (i = 0; i < stack.len; ++i) {
2219 ptr = bc_vec_item_rev(&stack, i);
2220 print(*ptr, width, false, nchars, len);
2223 if (!n->rdx) goto err;
2225 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2226 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2228 s = bc_num_ulong(&fracp, &dig);
2230 bc_num_ulong2num(&intp, dig);
2231 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2233 print(dig, width, radix, nchars, len);
2234 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2239 bc_num_free(&frac_len);
2240 bc_num_free(&digit);
2241 bc_num_free(&fracp);
2243 bc_vec_free(&stack);
2247 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2248 size_t *nchars, size_t line_len)
2255 if (neg) bb_putchar('-');
2260 if (base_t <= BC_NUM_MAX_IBASE) {
2262 print = bc_num_printHex;
2265 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2266 print = bc_num_printDigits;
2269 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2276 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2278 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2282 static void bc_num_init(BcNum *n, size_t req)
2284 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2285 memset(n, 0, sizeof(BcNum));
2286 n->num = xmalloc(req);
2290 static void bc_num_expand(BcNum *n, size_t req)
2292 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2294 n->num = xrealloc(n->num, req);
2299 static void bc_num_free(void *num)
2301 free(((BcNum *) num)->num);
2304 static void bc_num_copy(BcNum *d, BcNum *s)
2307 bc_num_expand(d, s->cap);
2311 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2315 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2318 if (!bc_num_strValid(val, base_t))
2319 return bc_error("bad number string");
2322 bc_num_parseDecimal(n, val);
2324 bc_num_parseBase(n, val, base);
2326 return BC_STATUS_SUCCESS;
2329 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2330 size_t *nchars, size_t line_len)
2332 BcStatus s = BC_STATUS_SUCCESS;
2334 bc_num_printNewline(nchars, line_len);
2340 else if (base_t == 10)
2341 bc_num_printDecimal(n, nchars, line_len);
2343 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2353 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2358 if (n->neg) return bc_error("negative number");
2360 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2362 unsigned long prev = *result, powprev = pow;
2364 *result += ((unsigned long) n->num[i]) * pow;
2367 if (*result < prev || pow < powprev)
2368 return bc_error("overflow");
2371 return BC_STATUS_SUCCESS;
2374 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2382 if (val == 0) return;
2384 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2385 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2388 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2390 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2392 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2395 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2397 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2399 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2402 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2404 size_t req = BC_NUM_MREQ(a, b, scale);
2405 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2408 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2410 size_t req = BC_NUM_MREQ(a, b, scale);
2411 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2414 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2416 size_t req = BC_NUM_MREQ(a, b, scale);
2417 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2420 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2422 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2425 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2428 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2429 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2430 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2432 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2433 bc_num_expand(b, req);
2436 bc_num_setToZero(b, scale);
2437 return BC_STATUS_SUCCESS;
2440 return bc_error("negative number");
2441 else if (BC_NUM_ONE(a)) {
2443 bc_num_extend(b, scale);
2444 return BC_STATUS_SUCCESS;
2447 scale = BC_MAX(scale, a->rdx) + 1;
2448 len = a->len + scale;
2450 bc_num_init(&num1, len);
2451 bc_num_init(&num2, len);
2452 bc_num_init(&half, BC_NUM_DEF_SIZE);
2458 bc_num_init(&f, len);
2459 bc_num_init(&fprime, len);
2465 pow = BC_NUM_INT(a);
2474 pow -= 2 - (pow & 1);
2476 bc_num_extend(x0, pow);
2478 // Make sure to move the radix back.
2482 x0->rdx = digs = digs1 = 0;
2484 len = BC_NUM_INT(x0) + resrdx - 1;
2486 while (cmp != 0 || digs < len) {
2488 s = bc_num_div(a, x0, &f, resrdx);
2490 s = bc_num_add(x0, &f, &fprime, resrdx);
2492 s = bc_num_mul(&fprime, &half, x1, resrdx);
2495 cmp = bc_num_cmp(x1, x0);
2496 digs = x1->len - (unsigned long long) llabs(cmp);
2498 if (cmp == cmp2 && digs == digs1)
2503 resrdx += times > 4;
2516 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2519 bc_num_free(&fprime);
2527 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2533 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2536 memcpy(&num2, c, sizeof(BcNum));
2538 bc_num_init(c, len);
2543 bc_num_expand(c, len);
2546 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2548 if (init) bc_num_free(&num2);
2554 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2557 BcNum base, exp, two, temp;
2560 return bc_error("divide by zero");
2561 if (a->rdx || b->rdx || c->rdx)
2562 return bc_error("non integer number");
2564 return bc_error("negative number");
2566 bc_num_expand(d, c->len);
2567 bc_num_init(&base, c->len);
2568 bc_num_init(&exp, b->len);
2569 bc_num_init(&two, BC_NUM_DEF_SIZE);
2570 bc_num_init(&temp, b->len);
2576 s = bc_num_rem(a, c, &base, 0);
2578 bc_num_copy(&exp, b);
2580 while (exp.len != 0) {
2582 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2585 if (BC_NUM_ONE(&temp)) {
2586 s = bc_num_mul(d, &base, &temp, 0);
2588 s = bc_num_rem(&temp, c, d, 0);
2592 s = bc_num_mul(&base, &base, &temp, 0);
2594 s = bc_num_rem(&temp, c, &base, 0);
2607 static int bc_id_cmp(const void *e1, const void *e2)
2609 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2612 static void bc_id_free(void *id)
2614 free(((BcId *) id)->name);
2617 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2622 for (i = 0; i < f->autos.len; ++i) {
2623 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2624 return bc_error("function parameter or auto var has the same name as another");
2630 bc_vec_push(&f->autos, &a);
2632 return BC_STATUS_SUCCESS;
2635 static void bc_func_init(BcFunc *f)
2637 bc_vec_init(&f->code, sizeof(char), NULL);
2638 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2639 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2643 static void bc_func_free(void *func)
2645 BcFunc *f = (BcFunc *) func;
2646 bc_vec_free(&f->code);
2647 bc_vec_free(&f->autos);
2648 bc_vec_free(&f->labels);
2651 static void bc_array_init(BcVec *a, bool nums)
2654 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2656 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2657 bc_array_expand(a, 1);
2660 static void bc_array_copy(BcVec *d, const BcVec *s)
2664 bc_vec_npop(d, d->len);
2665 bc_vec_expand(d, s->cap);
2668 for (i = 0; i < s->len; ++i) {
2669 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2670 bc_num_init(dnum, snum->len);
2671 bc_num_copy(dnum, snum);
2675 static void bc_array_expand(BcVec *a, size_t len)
2679 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2680 while (len > a->len) {
2681 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2682 bc_vec_push(a, &data.n);
2686 while (len > a->len) {
2687 bc_array_init(&data.v, true);
2688 bc_vec_push(a, &data.v);
2693 static void bc_string_free(void *string)
2695 free(*((char **) string));
2699 static void bc_result_copy(BcResult *d, BcResult *src)
2705 case BC_RESULT_TEMP:
2706 case BC_RESULT_IBASE:
2707 case BC_RESULT_SCALE:
2708 case BC_RESULT_OBASE:
2710 bc_num_init(&d->d.n, src->d.n.len);
2711 bc_num_copy(&d->d.n, &src->d.n);
2716 case BC_RESULT_ARRAY:
2717 case BC_RESULT_ARRAY_ELEM:
2719 d->d.id.name = xstrdup(src->d.id.name);
2723 case BC_RESULT_CONSTANT:
2724 case BC_RESULT_LAST:
2728 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2735 static void bc_result_free(void *result)
2737 BcResult *r = (BcResult *) result;
2741 case BC_RESULT_TEMP:
2742 case BC_RESULT_IBASE:
2743 case BC_RESULT_SCALE:
2744 case BC_RESULT_OBASE:
2746 bc_num_free(&r->d.n);
2751 case BC_RESULT_ARRAY:
2752 case BC_RESULT_ARRAY_ELEM:
2766 static void bc_lex_lineComment(BcLex *l)
2768 l->t.t = BC_LEX_WHITESPACE;
2769 while (l->i < l->len && l->buf[l->i++] != '\n');
2773 static void bc_lex_whitespace(BcLex *l)
2776 l->t.t = BC_LEX_WHITESPACE;
2777 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2780 static BcStatus bc_lex_number(BcLex *l, char start)
2782 const char *buf = l->buf + l->i;
2783 size_t len, hits = 0, bslashes = 0, i = 0, j;
2785 bool last_pt, pt = start == '.';
2788 l->t.t = BC_LEX_NUMBER;
2790 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2791 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2805 len = i + 1 * !last_pt - bslashes * 2;
2806 if (len > BC_MAX_NUM)
2807 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2809 bc_vec_npop(&l->t.v, l->t.v.len);
2810 bc_vec_expand(&l->t.v, len + 1);
2811 bc_vec_push(&l->t.v, &start);
2813 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2817 // If we have hit a backslash, skip it. We don't have
2818 // to check for a newline because it's guaranteed.
2819 if (hits < bslashes && c == '\\') {
2825 bc_vec_push(&l->t.v, &c);
2828 bc_vec_pushByte(&l->t.v, '\0');
2831 return BC_STATUS_SUCCESS;
2834 static BcStatus bc_lex_name(BcLex *l)
2837 const char *buf = l->buf + l->i - 1;
2840 l->t.t = BC_LEX_NAME;
2842 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2844 if (i > BC_MAX_STRING)
2845 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2846 bc_vec_string(&l->t.v, i, buf);
2848 // Increment the index. We minus 1 because it has already been incremented.
2851 return BC_STATUS_SUCCESS;
2854 static void bc_lex_init(BcLex *l, BcLexNext next)
2857 bc_vec_init(&l->t.v, sizeof(char), NULL);
2860 static void bc_lex_free(BcLex *l)
2862 bc_vec_free(&l->t.v);
2865 static void bc_lex_file(BcLex *l, const char *file)
2872 static BcStatus bc_lex_next(BcLex *l)
2877 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2879 l->line += l->newline;
2880 l->t.t = BC_LEX_EOF;
2882 l->newline = (l->i == l->len);
2883 if (l->newline) return BC_STATUS_SUCCESS;
2885 // Loop until failure or we don't have whitespace. This
2886 // is so the parser doesn't get inundated with whitespace.
2889 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2894 static BcStatus bc_lex_text(BcLex *l, const char *text)
2898 l->len = strlen(text);
2899 l->t.t = l->t.last = BC_LEX_INVALID;
2900 return bc_lex_next(l);
2904 static BcStatus bc_lex_identifier(BcLex *l)
2908 const char *buf = l->buf + l->i - 1;
2910 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2912 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2914 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2916 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2918 if (!bc_lex_kws[i].posix) {
2919 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
2923 // We minus 1 because the index has already been incremented.
2925 return BC_STATUS_SUCCESS;
2932 if (l->t.v.len - 1 > 1)
2933 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2938 static BcStatus bc_lex_string(BcLex *l)
2940 size_t len, nls = 0, i = l->i;
2943 l->t.t = BC_LEX_STR;
2945 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2949 return bc_error("string end could not be found");
2953 if (len > BC_MAX_STRING)
2954 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2955 bc_vec_string(&l->t.v, len, l->buf + l->i);
2960 return BC_STATUS_SUCCESS;
2963 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2965 if (l->buf[l->i] == '=') {
2973 static BcStatus bc_lex_comment(BcLex *l)
2976 const char *buf = l->buf;
2978 l->t.t = BC_LEX_WHITESPACE;
2991 return bc_error("comment end could not be found");
3000 return BC_STATUS_SUCCESS;
3003 static BcStatus bc_lex_token(BcLex *l)
3005 BcStatus s = BC_STATUS_SUCCESS;
3006 char c = l->buf[l->i++], c2;
3008 // This is the workhorse of the lexer.
3015 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3025 bc_lex_whitespace(l);
3031 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3033 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3034 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3043 s = bc_lex_string(l);
3049 s = bc_posix_error("POSIX does not allow '#' script comments");
3052 bc_lex_lineComment(l);
3059 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3068 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3072 l->t.t = BC_LEX_OP_BOOL_AND;
3075 l->t.t = BC_LEX_INVALID;
3076 s = bc_error("bad character '%c'", '&');
3085 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3091 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3100 l->t.t = BC_LEX_OP_INC;
3103 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3109 l->t.t = BC_LEX_COMMA;
3118 l->t.t = BC_LEX_OP_DEC;
3121 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3127 if (isdigit(l->buf[l->i]))
3128 s = bc_lex_number(l, c);
3130 l->t.t = BC_LEX_KEY_LAST;
3131 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3140 s = bc_lex_comment(l);
3142 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3163 s = bc_lex_number(l, c);
3169 l->t.t = BC_LEX_SCOLON;
3175 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3181 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3187 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3194 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3200 if (l->buf[l->i] == '\n') {
3201 l->t.t = BC_LEX_WHITESPACE;
3205 s = bc_error("bad character '%c'", c);
3211 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3242 s = bc_lex_identifier(l);
3249 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3258 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3262 l->t.t = BC_LEX_OP_BOOL_OR;
3265 l->t.t = BC_LEX_INVALID;
3266 s = bc_error("bad character '%c'", c);
3274 l->t.t = BC_LEX_INVALID;
3275 s = bc_error("bad character '%c'", c);
3285 static BcStatus dc_lex_register(BcLex *l)
3287 BcStatus s = BC_STATUS_SUCCESS;
3289 if (isspace(l->buf[l->i - 1])) {
3290 bc_lex_whitespace(l);
3293 s = bc_error("extended register");
3298 bc_vec_npop(&l->t.v, l->t.v.len);
3299 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3300 bc_vec_pushByte(&l->t.v, '\0');
3301 l->t.t = BC_LEX_NAME;
3307 static BcStatus dc_lex_string(BcLex *l)
3309 size_t depth = 1, nls = 0, i = l->i;
3312 l->t.t = BC_LEX_STR;
3313 bc_vec_npop(&l->t.v, l->t.v.len);
3315 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3317 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3318 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3321 if (depth) bc_vec_push(&l->t.v, &c);
3326 return bc_error("string end could not be found");
3329 bc_vec_pushByte(&l->t.v, '\0');
3330 if (i - l->i > BC_MAX_STRING)
3331 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3336 return BC_STATUS_SUCCESS;
3339 static BcStatus dc_lex_token(BcLex *l)
3341 BcStatus s = BC_STATUS_SUCCESS;
3342 char c = l->buf[l->i++], c2;
3345 for (i = 0; i < dc_lex_regs_len; ++i) {
3346 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3349 if (c >= '%' && c <= '~' &&
3350 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3355 // This is the workhorse of the lexer.
3360 l->t.t = BC_LEX_EOF;
3371 l->newline = (c == '\n');
3372 bc_lex_whitespace(l);
3381 l->t.t = BC_LEX_OP_REL_NE;
3383 l->t.t = BC_LEX_OP_REL_LE;
3385 l->t.t = BC_LEX_OP_REL_GE;
3387 return bc_error("bad character '%c'", c);
3395 bc_lex_lineComment(l);
3401 if (isdigit(l->buf[l->i]))
3402 s = bc_lex_number(l, c);
3404 s = bc_error("bad character '%c'", c);
3425 s = bc_lex_number(l, c);
3431 s = dc_lex_string(l);
3437 l->t.t = BC_LEX_INVALID;
3438 s = bc_error("bad character '%c'", c);
3447 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3449 bc_program_addFunc(name, idx);
3450 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3453 static void bc_parse_pushName(BcParse *p, char *name)
3455 size_t i = 0, len = strlen(name);
3457 for (; i < len; ++i) bc_parse_push(p, name[i]);
3458 bc_parse_push(p, BC_PARSE_STREND);
3463 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3465 unsigned char amt, i, nums[sizeof(size_t)];
3467 for (amt = 0; idx; ++amt) {
3468 nums[amt] = (char) idx;
3469 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3472 bc_parse_push(p, amt);
3473 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3476 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3478 char *num = xstrdup(p->l.t.v.v);
3479 size_t idx = G.prog.consts.len;
3481 bc_vec_push(&G.prog.consts, &num);
3483 bc_parse_push(p, BC_INST_NUM);
3484 bc_parse_pushIndex(p, idx);
3487 (*prev) = BC_INST_NUM;
3490 static BcStatus bc_parse_text(BcParse *p, const char *text)
3494 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3496 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3497 p->l.t.t = BC_LEX_INVALID;
3500 if (!BC_PARSE_CAN_EXEC(p))
3501 return bc_error("file is not executable");
3504 return bc_lex_text(&p->l, text);
3507 // Called when bc/dc_parse_parse() detects a failure,
3508 // resets parsing structures.
3509 static void bc_parse_reset(BcParse *p)
3511 if (p->fidx != BC_PROG_MAIN) {
3513 p->func->nparams = 0;
3514 bc_vec_npop(&p->func->code, p->func->code.len);
3515 bc_vec_npop(&p->func->autos, p->func->autos.len);
3516 bc_vec_npop(&p->func->labels, p->func->labels.len);
3518 bc_parse_updateFunc(p, BC_PROG_MAIN);
3522 p->l.t.t = BC_LEX_EOF;
3523 p->auto_part = (p->nbraces = 0);
3525 bc_vec_npop(&p->flags, p->flags.len - 1);
3526 bc_vec_npop(&p->exits, p->exits.len);
3527 bc_vec_npop(&p->conds, p->conds.len);
3528 bc_vec_npop(&p->ops, p->ops.len);
3533 static void bc_parse_free(BcParse *p)
3535 bc_vec_free(&p->flags);
3536 bc_vec_free(&p->exits);
3537 bc_vec_free(&p->conds);
3538 bc_vec_free(&p->ops);
3542 static void bc_parse_create(BcParse *p, size_t func,
3543 BcParseParse parse, BcLexNext next)
3545 memset(p, 0, sizeof(BcParse));
3547 bc_lex_init(&p->l, next);
3548 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3549 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3550 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3551 bc_vec_pushByte(&p->flags, 0);
3552 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3555 // p->auto_part = p->nbraces = 0; - already is
3556 bc_parse_updateFunc(p, func);
3560 static BcStatus bc_parse_else(BcParse *p);
3561 static BcStatus bc_parse_stmt(BcParse *p);
3563 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3564 size_t *nexprs, bool next)
3566 BcStatus s = BC_STATUS_SUCCESS;
3568 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3569 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3571 while (p->ops.len > start) {
3573 t = BC_PARSE_TOP_OP(p);
3574 if (t == BC_LEX_LPAREN) break;
3576 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3577 if (l >= r && (l != r || !left)) break;
3579 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3580 bc_vec_pop(&p->ops);
3581 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3584 bc_vec_push(&p->ops, &type);
3585 if (next) s = bc_lex_next(&p->l);
3590 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3594 if (p->ops.len <= ops_bgn)
3595 return bc_error("bad expression");
3596 top = BC_PARSE_TOP_OP(p);
3598 while (top != BC_LEX_LPAREN) {
3600 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3602 bc_vec_pop(&p->ops);
3603 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3605 if (p->ops.len <= ops_bgn)
3606 return bc_error("bad expression");
3607 top = BC_PARSE_TOP_OP(p);
3610 bc_vec_pop(&p->ops);
3612 return bc_lex_next(&p->l);
3615 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3621 s = bc_lex_next(&p->l);
3624 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3626 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3627 s = bc_parse_expr(p, flags, bc_parse_next_param);
3630 comma = p->l.t.t == BC_LEX_COMMA;
3632 s = bc_lex_next(&p->l);
3637 if (comma) return bc_error("bad token");
3638 bc_parse_push(p, BC_INST_CALL);
3639 bc_parse_pushIndex(p, nparams);
3641 return BC_STATUS_SUCCESS;
3644 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3647 BcId entry, *entry_ptr;
3652 s = bc_parse_params(p, flags);
3655 if (p->l.t.t != BC_LEX_RPAREN) {
3656 s = bc_error("bad token");
3660 idx = bc_map_index(&G.prog.fn_map, &entry);
3662 if (idx == BC_VEC_INVALID_IDX) {
3663 name = xstrdup(entry.name);
3664 bc_parse_addFunc(p, name, &idx);
3665 idx = bc_map_index(&G.prog.fn_map, &entry);
3671 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3672 bc_parse_pushIndex(p, entry_ptr->idx);
3674 return bc_lex_next(&p->l);
3681 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3686 name = xstrdup(p->l.t.v.v);
3687 s = bc_lex_next(&p->l);
3690 if (p->l.t.t == BC_LEX_LBRACKET) {
3692 s = bc_lex_next(&p->l);
3695 if (p->l.t.t == BC_LEX_RBRACKET) {
3697 if (!(flags & BC_PARSE_ARRAY)) {
3698 s = bc_error("bad expression");
3702 *type = BC_INST_ARRAY;
3706 *type = BC_INST_ARRAY_ELEM;
3708 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3709 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3713 s = bc_lex_next(&p->l);
3715 bc_parse_push(p, *type);
3716 bc_parse_pushName(p, name);
3718 else if (p->l.t.t == BC_LEX_LPAREN) {
3720 if (flags & BC_PARSE_NOCALL) {
3721 s = bc_error("bad token");
3725 *type = BC_INST_CALL;
3726 s = bc_parse_call(p, name, flags);
3729 *type = BC_INST_VAR;
3730 bc_parse_push(p, BC_INST_VAR);
3731 bc_parse_pushName(p, name);
3741 static BcStatus bc_parse_read(BcParse *p)
3745 s = bc_lex_next(&p->l);
3747 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3749 s = bc_lex_next(&p->l);
3751 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3753 bc_parse_push(p, BC_INST_READ);
3755 return bc_lex_next(&p->l);
3758 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3763 s = bc_lex_next(&p->l);
3765 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3767 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3769 s = bc_lex_next(&p->l);
3772 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3775 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3777 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3778 bc_parse_push(p, *prev);
3780 return bc_lex_next(&p->l);
3783 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3787 s = bc_lex_next(&p->l);
3790 if (p->l.t.t != BC_LEX_LPAREN) {
3791 *type = BC_INST_SCALE;
3792 bc_parse_push(p, BC_INST_SCALE);
3793 return BC_STATUS_SUCCESS;
3796 *type = BC_INST_SCALE_FUNC;
3797 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3799 s = bc_lex_next(&p->l);
3802 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3804 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3805 bc_parse_push(p, BC_INST_SCALE_FUNC);
3807 return bc_lex_next(&p->l);
3810 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3811 size_t *nexprs, uint8_t flags)
3816 BcInst etype = *prev;
3818 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3819 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3820 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3822 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3823 bc_parse_push(p, inst);
3824 s = bc_lex_next(&p->l);
3828 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3831 s = bc_lex_next(&p->l);
3835 // Because we parse the next part of the expression
3836 // right here, we need to increment this.
3837 *nexprs = *nexprs + 1;
3843 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3847 case BC_LEX_KEY_IBASE:
3848 case BC_LEX_KEY_LAST:
3849 case BC_LEX_KEY_OBASE:
3851 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3852 s = bc_lex_next(&p->l);
3856 case BC_LEX_KEY_SCALE:
3858 s = bc_lex_next(&p->l);
3860 if (p->l.t.t == BC_LEX_LPAREN)
3861 s = bc_error("bad token");
3863 bc_parse_push(p, BC_INST_SCALE);
3869 s = bc_error("bad token");
3874 if (!s) bc_parse_push(p, inst);
3880 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3881 bool rparen, size_t *nexprs)
3885 BcInst etype = *prev;
3887 s = bc_lex_next(&p->l);
3890 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3891 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3894 *prev = BC_PARSE_TOKEN_INST(type);
3896 // We can just push onto the op stack because this is the largest
3897 // precedence operator that gets pushed. Inc/dec does not.
3898 if (type != BC_LEX_OP_MINUS)
3899 bc_vec_push(&p->ops, &type);
3901 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3906 static BcStatus bc_parse_string(BcParse *p, char inst)
3908 char *str = xstrdup(p->l.t.v.v);
3910 bc_parse_push(p, BC_INST_STR);
3911 bc_parse_pushIndex(p, G.prog.strs.len);
3912 bc_vec_push(&G.prog.strs, &str);
3913 bc_parse_push(p, inst);
3915 return bc_lex_next(&p->l);
3918 static BcStatus bc_parse_print(BcParse *p)
3924 s = bc_lex_next(&p->l);
3929 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3930 return bc_error("bad print statement");
3932 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3934 if (type == BC_LEX_STR)
3935 s = bc_parse_string(p, BC_INST_PRINT_POP);
3937 s = bc_parse_expr(p, 0, bc_parse_next_print);
3939 bc_parse_push(p, BC_INST_PRINT_POP);
3944 comma = p->l.t.t == BC_LEX_COMMA;
3945 if (comma) s = bc_lex_next(&p->l);
3950 if (comma) return bc_error("bad token");
3952 return bc_lex_next(&p->l);
3955 static BcStatus bc_parse_return(BcParse *p)
3961 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
3963 s = bc_lex_next(&p->l);
3967 paren = t == BC_LEX_LPAREN;
3969 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3970 bc_parse_push(p, BC_INST_RET0);
3973 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3974 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3977 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3978 bc_parse_push(p, BC_INST_RET0);
3979 s = bc_lex_next(&p->l);
3983 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3984 s = bc_posix_error("POSIX requires parentheses around return expressions");
3988 bc_parse_push(p, BC_INST_RET);
3994 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3996 BcStatus s = BC_STATUS_SUCCESS;
3998 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
3999 return bc_error("bad token");
4003 if (p->l.t.t == BC_LEX_RBRACE) {
4004 if (!p->nbraces) return bc_error("bad token");
4006 s = bc_lex_next(&p->l);
4010 return bc_error("bad token");
4013 if (BC_PARSE_IF(p)) {
4017 while (p->l.t.t == BC_LEX_NLINE) {
4018 s = bc_lex_next(&p->l);
4022 bc_vec_pop(&p->flags);
4024 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4025 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4027 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4029 else if (BC_PARSE_ELSE(p)) {
4034 bc_vec_pop(&p->flags);
4036 ip = bc_vec_top(&p->exits);
4037 label = bc_vec_item(&p->func->labels, ip->idx);
4038 *label = p->func->code.len;
4040 bc_vec_pop(&p->exits);
4042 else if (BC_PARSE_FUNC_INNER(p)) {
4043 bc_parse_push(p, BC_INST_RET0);
4044 bc_parse_updateFunc(p, BC_PROG_MAIN);
4045 bc_vec_pop(&p->flags);
4049 BcInstPtr *ip = bc_vec_top(&p->exits);
4050 size_t *label = bc_vec_top(&p->conds);
4052 bc_parse_push(p, BC_INST_JUMP);
4053 bc_parse_pushIndex(p, *label);
4055 label = bc_vec_item(&p->func->labels, ip->idx);
4056 *label = p->func->code.len;
4058 bc_vec_pop(&p->flags);
4059 bc_vec_pop(&p->exits);
4060 bc_vec_pop(&p->conds);
4066 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4068 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4069 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4070 flags |= BC_PARSE_FLAG_BODY;
4071 bc_vec_push(&p->flags, &flags);
4074 static void bc_parse_noElse(BcParse *p)
4078 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4080 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4082 ip = bc_vec_top(&p->exits);
4083 label = bc_vec_item(&p->func->labels, ip->idx);
4084 *label = p->func->code.len;
4086 bc_vec_pop(&p->exits);
4089 static BcStatus bc_parse_if(BcParse *p)
4094 s = bc_lex_next(&p->l);
4096 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4098 s = bc_lex_next(&p->l);
4100 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4102 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4104 s = bc_lex_next(&p->l);
4106 bc_parse_push(p, BC_INST_JUMP_ZERO);
4108 ip.idx = p->func->labels.len;
4109 ip.func = ip.len = 0;
4111 bc_parse_pushIndex(p, ip.idx);
4112 bc_vec_push(&p->exits, &ip);
4113 bc_vec_push(&p->func->labels, &ip.idx);
4114 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4116 return BC_STATUS_SUCCESS;
4119 static BcStatus bc_parse_else(BcParse *p)
4123 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4125 ip.idx = p->func->labels.len;
4126 ip.func = ip.len = 0;
4128 bc_parse_push(p, BC_INST_JUMP);
4129 bc_parse_pushIndex(p, ip.idx);
4133 bc_vec_push(&p->exits, &ip);
4134 bc_vec_push(&p->func->labels, &ip.idx);
4135 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4137 return bc_lex_next(&p->l);
4140 static BcStatus bc_parse_while(BcParse *p)
4145 s = bc_lex_next(&p->l);
4147 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4148 s = bc_lex_next(&p->l);
4151 ip.idx = p->func->labels.len;
4153 bc_vec_push(&p->func->labels, &p->func->code.len);
4154 bc_vec_push(&p->conds, &ip.idx);
4156 ip.idx = p->func->labels.len;
4160 bc_vec_push(&p->exits, &ip);
4161 bc_vec_push(&p->func->labels, &ip.idx);
4163 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4165 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4166 s = bc_lex_next(&p->l);
4169 bc_parse_push(p, BC_INST_JUMP_ZERO);
4170 bc_parse_pushIndex(p, ip.idx);
4171 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4173 return BC_STATUS_SUCCESS;
4176 static BcStatus bc_parse_for(BcParse *p)
4180 size_t cond_idx, exit_idx, body_idx, update_idx;
4182 s = bc_lex_next(&p->l);
4184 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4185 s = bc_lex_next(&p->l);
4188 if (p->l.t.t != BC_LEX_SCOLON)
4189 s = bc_parse_expr(p, 0, bc_parse_next_for);
4191 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4194 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4195 s = bc_lex_next(&p->l);
4198 cond_idx = p->func->labels.len;
4199 update_idx = cond_idx + 1;
4200 body_idx = update_idx + 1;
4201 exit_idx = body_idx + 1;
4203 bc_vec_push(&p->func->labels, &p->func->code.len);
4205 if (p->l.t.t != BC_LEX_SCOLON)
4206 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4208 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4211 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4213 s = bc_lex_next(&p->l);
4216 bc_parse_push(p, BC_INST_JUMP_ZERO);
4217 bc_parse_pushIndex(p, exit_idx);
4218 bc_parse_push(p, BC_INST_JUMP);
4219 bc_parse_pushIndex(p, body_idx);
4221 ip.idx = p->func->labels.len;
4223 bc_vec_push(&p->conds, &update_idx);
4224 bc_vec_push(&p->func->labels, &p->func->code.len);
4226 if (p->l.t.t != BC_LEX_RPAREN)
4227 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4229 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4233 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4234 bc_parse_push(p, BC_INST_JUMP);
4235 bc_parse_pushIndex(p, cond_idx);
4236 bc_vec_push(&p->func->labels, &p->func->code.len);
4242 bc_vec_push(&p->exits, &ip);
4243 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4247 return BC_STATUS_SUCCESS;
4250 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4256 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4258 if (type == BC_LEX_KEY_BREAK) {
4260 if (p->exits.len == 0) return bc_error("bad token");
4262 i = p->exits.len - 1;
4263 ip = bc_vec_item(&p->exits, i);
4265 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4266 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4271 i = *((size_t *) bc_vec_top(&p->conds));
4273 bc_parse_push(p, BC_INST_JUMP);
4274 bc_parse_pushIndex(p, i);
4276 s = bc_lex_next(&p->l);
4279 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4280 return bc_error("bad token");
4282 return bc_lex_next(&p->l);
4285 static BcStatus bc_parse_func(BcParse *p)
4288 bool var, comma = false;
4292 s = bc_lex_next(&p->l);
4294 if (p->l.t.t != BC_LEX_NAME)
4295 return bc_error("bad function definition");
4297 name = xstrdup(p->l.t.v.v);
4298 bc_parse_addFunc(p, name, &p->fidx);
4300 s = bc_lex_next(&p->l);
4302 if (p->l.t.t != BC_LEX_LPAREN)
4303 return bc_error("bad function definition");
4304 s = bc_lex_next(&p->l);
4307 while (p->l.t.t != BC_LEX_RPAREN) {
4309 if (p->l.t.t != BC_LEX_NAME)
4310 return bc_error("bad function definition");
4314 name = xstrdup(p->l.t.v.v);
4315 s = bc_lex_next(&p->l);
4318 var = p->l.t.t != BC_LEX_LBRACKET;
4322 s = bc_lex_next(&p->l);
4325 if (p->l.t.t != BC_LEX_RBRACKET) {
4326 s = bc_error("bad function definition");
4330 s = bc_lex_next(&p->l);
4334 comma = p->l.t.t == BC_LEX_COMMA;
4336 s = bc_lex_next(&p->l);
4340 s = bc_func_insert(p->func, name, var);
4344 if (comma) return bc_error("bad function definition");
4346 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4347 bc_parse_startBody(p, flags);
4349 s = bc_lex_next(&p->l);
4352 if (p->l.t.t != BC_LEX_LBRACE)
4353 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4362 static BcStatus bc_parse_auto(BcParse *p)
4365 bool comma, var, one;
4368 if (!p->auto_part) return bc_error("bad token");
4369 s = bc_lex_next(&p->l);
4372 p->auto_part = comma = false;
4373 one = p->l.t.t == BC_LEX_NAME;
4375 while (p->l.t.t == BC_LEX_NAME) {
4377 name = xstrdup(p->l.t.v.v);
4378 s = bc_lex_next(&p->l);
4381 var = p->l.t.t != BC_LEX_LBRACKET;
4384 s = bc_lex_next(&p->l);
4387 if (p->l.t.t != BC_LEX_RBRACKET) {
4388 s = bc_error("bad function definition");
4392 s = bc_lex_next(&p->l);
4396 comma = p->l.t.t == BC_LEX_COMMA;
4398 s = bc_lex_next(&p->l);
4402 s = bc_func_insert(p->func, name, var);
4406 if (comma) return bc_error("bad function definition");
4407 if (!one) return bc_error("no auto variable found");
4409 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4410 return bc_error("bad token");
4412 return bc_lex_next(&p->l);
4419 static BcStatus bc_parse_body(BcParse *p, bool brace)
4421 BcStatus s = BC_STATUS_SUCCESS;
4422 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4424 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4426 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4428 if (!brace) return bc_error("bad token");
4429 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4431 if (!p->auto_part) {
4432 s = bc_parse_auto(p);
4436 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4439 s = bc_parse_stmt(p);
4440 if (!s && !brace) s = bc_parse_endBody(p, false);
4446 static BcStatus bc_parse_stmt(BcParse *p)
4448 BcStatus s = BC_STATUS_SUCCESS;
4454 return bc_lex_next(&p->l);
4457 case BC_LEX_KEY_ELSE:
4459 p->auto_part = false;
4465 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4468 s = bc_lex_next(&p->l);
4471 return bc_parse_body(p, true);
4474 case BC_LEX_KEY_AUTO:
4476 return bc_parse_auto(p);
4481 p->auto_part = false;
4483 if (BC_PARSE_IF_END(p)) {
4485 return BC_STATUS_SUCCESS;
4487 else if (BC_PARSE_BODY(p))
4488 return bc_parse_body(p, false);
4498 case BC_LEX_OP_MINUS:
4499 case BC_LEX_OP_BOOL_NOT:
4503 case BC_LEX_KEY_IBASE:
4504 case BC_LEX_KEY_LAST:
4505 case BC_LEX_KEY_LENGTH:
4506 case BC_LEX_KEY_OBASE:
4507 case BC_LEX_KEY_READ:
4508 case BC_LEX_KEY_SCALE:
4509 case BC_LEX_KEY_SQRT:
4511 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4515 case BC_LEX_KEY_ELSE:
4517 s = bc_parse_else(p);
4523 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4529 s = bc_parse_endBody(p, true);
4535 s = bc_parse_string(p, BC_INST_PRINT_STR);
4539 case BC_LEX_KEY_BREAK:
4540 case BC_LEX_KEY_CONTINUE:
4542 s = bc_parse_loopExit(p, p->l.t.t);
4546 case BC_LEX_KEY_FOR:
4548 s = bc_parse_for(p);
4552 case BC_LEX_KEY_HALT:
4554 bc_parse_push(p, BC_INST_HALT);
4555 s = bc_lex_next(&p->l);
4565 case BC_LEX_KEY_LIMITS:
4567 // "limits" is a compile-time command,
4568 // the output is produced at _parse time_.
4569 s = bc_lex_next(&p->l);
4571 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4572 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4573 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4574 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4575 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4576 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4577 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4578 printf("Number of vars = %lu\n", BC_MAX_VARS);
4582 case BC_LEX_KEY_PRINT:
4584 s = bc_parse_print(p);
4588 case BC_LEX_KEY_QUIT:
4590 // "quit" is a compile-time command. For example,
4591 // "if (0 == 1) quit" terminates when parsing the statement,
4592 // not when it is executed
4596 case BC_LEX_KEY_RETURN:
4598 s = bc_parse_return(p);
4602 case BC_LEX_KEY_WHILE:
4604 s = bc_parse_while(p);
4610 s = bc_error("bad token");
4618 static BcStatus bc_parse_parse(BcParse *p)
4622 if (p->l.t.t == BC_LEX_EOF)
4623 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4624 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4625 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4626 s = bc_parse_func(p);
4629 s = bc_parse_stmt(p);
4631 if (s || G_interrupt) {
4633 s = BC_STATUS_FAILURE;
4639 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4641 BcStatus s = BC_STATUS_SUCCESS;
4642 BcInst prev = BC_INST_PRINT;
4643 BcLexType top, t = p->l.t.t;
4644 size_t nexprs = 0, ops_bgn = p->ops.len;
4645 uint32_t i, nparens, nrelops;
4646 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4648 paren_first = p->l.t.t == BC_LEX_LPAREN;
4649 nparens = nrelops = 0;
4650 paren_expr = rprn = done = get_token = assign = false;
4653 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4659 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4660 rprn = get_token = bin_last = false;
4664 case BC_LEX_OP_MINUS:
4666 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4667 rprn = get_token = false;
4668 bin_last = prev == BC_INST_MINUS;
4672 case BC_LEX_OP_ASSIGN_POWER:
4673 case BC_LEX_OP_ASSIGN_MULTIPLY:
4674 case BC_LEX_OP_ASSIGN_DIVIDE:
4675 case BC_LEX_OP_ASSIGN_MODULUS:
4676 case BC_LEX_OP_ASSIGN_PLUS:
4677 case BC_LEX_OP_ASSIGN_MINUS:
4678 case BC_LEX_OP_ASSIGN:
4680 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4681 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4682 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4684 s = bc_error("bad assignment:"
4685 " left side must be scale,"
4686 " ibase, obase, last, var,"
4693 case BC_LEX_OP_POWER:
4694 case BC_LEX_OP_MULTIPLY:
4695 case BC_LEX_OP_DIVIDE:
4696 case BC_LEX_OP_MODULUS:
4697 case BC_LEX_OP_PLUS:
4698 case BC_LEX_OP_REL_EQ:
4699 case BC_LEX_OP_REL_LE:
4700 case BC_LEX_OP_REL_GE:
4701 case BC_LEX_OP_REL_NE:
4702 case BC_LEX_OP_REL_LT:
4703 case BC_LEX_OP_REL_GT:
4704 case BC_LEX_OP_BOOL_NOT:
4705 case BC_LEX_OP_BOOL_OR:
4706 case BC_LEX_OP_BOOL_AND:
4708 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4709 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4711 return bc_error("bad expression");
4714 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4715 prev = BC_PARSE_TOKEN_INST(t);
4716 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4717 rprn = get_token = false;
4718 bin_last = t != BC_LEX_OP_BOOL_NOT;
4725 if (BC_PARSE_LEAF(prev, rprn))
4726 return bc_error("bad expression");
4728 paren_expr = rprn = bin_last = false;
4730 bc_vec_push(&p->ops, &t);
4737 if (bin_last || prev == BC_INST_BOOL_NOT)
4738 return bc_error("bad expression");
4741 s = BC_STATUS_SUCCESS;
4746 else if (!paren_expr)
4747 return BC_STATUS_PARSE_EMPTY_EXP;
4750 paren_expr = rprn = true;
4751 get_token = bin_last = false;
4753 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4760 if (BC_PARSE_LEAF(prev, rprn))
4761 return bc_error("bad expression");
4763 rprn = get_token = bin_last = false;
4764 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4772 if (BC_PARSE_LEAF(prev, rprn))
4773 return bc_error("bad expression");
4774 bc_parse_number(p, &prev, &nexprs);
4775 paren_expr = get_token = true;
4776 rprn = bin_last = false;
4781 case BC_LEX_KEY_IBASE:
4782 case BC_LEX_KEY_LAST:
4783 case BC_LEX_KEY_OBASE:
4785 if (BC_PARSE_LEAF(prev, rprn))
4786 return bc_error("bad expression");
4787 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4788 bc_parse_push(p, (char) prev);
4790 paren_expr = get_token = true;
4791 rprn = bin_last = false;
4797 case BC_LEX_KEY_LENGTH:
4798 case BC_LEX_KEY_SQRT:
4800 if (BC_PARSE_LEAF(prev, rprn))
4801 return bc_error("bad expression");
4802 s = bc_parse_builtin(p, t, flags, &prev);
4804 rprn = get_token = bin_last = false;
4810 case BC_LEX_KEY_READ:
4812 if (BC_PARSE_LEAF(prev, rprn))
4813 return bc_error("bad expression");
4814 else if (flags & BC_PARSE_NOREAD)
4815 s = bc_error("read() call inside of a read() call");
4817 s = bc_parse_read(p);
4820 rprn = get_token = bin_last = false;
4822 prev = BC_INST_READ;
4827 case BC_LEX_KEY_SCALE:
4829 if (BC_PARSE_LEAF(prev, rprn))
4830 return bc_error("bad expression");
4831 s = bc_parse_scale(p, &prev, flags);
4833 rprn = get_token = bin_last = false;
4835 prev = BC_INST_SCALE;
4842 s = bc_error("bad token");
4847 if (!s && get_token) s = bc_lex_next(&p->l);
4851 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4853 while (p->ops.len > ops_bgn) {
4855 top = BC_PARSE_TOP_OP(p);
4856 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4858 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4859 return bc_error("bad expression");
4861 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4863 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4864 bc_vec_pop(&p->ops);
4867 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4868 return bc_error("bad expression");
4870 for (i = 0; i < next.len; ++i)
4871 if (t == next.tokens[i])
4873 return bc_error("bad expression");
4876 if (!(flags & BC_PARSE_REL) && nrelops) {
4877 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4880 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4881 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4885 if (flags & BC_PARSE_PRINT) {
4886 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4887 bc_parse_push(p, BC_INST_POP);
4893 static void bc_parse_init(BcParse *p, size_t func)
4895 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4898 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4900 return bc_parse_expr(p, flags, bc_parse_next_read);
4905 static BcStatus dc_parse_register(BcParse *p)
4910 s = bc_lex_next(&p->l);
4912 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
4914 name = xstrdup(p->l.t.v.v);
4915 bc_parse_pushName(p, name);
4920 static BcStatus dc_parse_string(BcParse *p)
4922 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4923 size_t idx, len = G.prog.strs.len;
4925 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4928 str = xstrdup(p->l.t.v.v);
4929 bc_parse_push(p, BC_INST_STR);
4930 bc_parse_pushIndex(p, len);
4931 bc_vec_push(&G.prog.strs, &str);
4932 bc_parse_addFunc(p, name, &idx);
4934 return bc_lex_next(&p->l);
4937 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4941 bc_parse_push(p, inst);
4943 s = dc_parse_register(p);
4948 bc_parse_push(p, BC_INST_SWAP);
4949 bc_parse_push(p, BC_INST_ASSIGN);
4950 bc_parse_push(p, BC_INST_POP);
4953 return bc_lex_next(&p->l);
4956 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4960 bc_parse_push(p, inst);
4961 bc_parse_push(p, BC_INST_EXEC_COND);
4963 s = dc_parse_register(p);
4966 s = bc_lex_next(&p->l);
4969 if (p->l.t.t == BC_LEX_ELSE) {
4970 s = dc_parse_register(p);
4972 s = bc_lex_next(&p->l);
4975 bc_parse_push(p, BC_PARSE_STREND);
4980 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4982 BcStatus s = BC_STATUS_SUCCESS;
4985 bool assign, get_token = false;
4989 case BC_LEX_OP_REL_EQ:
4990 case BC_LEX_OP_REL_LE:
4991 case BC_LEX_OP_REL_GE:
4992 case BC_LEX_OP_REL_NE:
4993 case BC_LEX_OP_REL_LT:
4994 case BC_LEX_OP_REL_GT:
4996 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5003 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5009 s = dc_parse_string(p);
5016 if (t == BC_LEX_NEG) {
5017 s = bc_lex_next(&p->l);
5019 if (p->l.t.t != BC_LEX_NUMBER)
5020 return bc_error("bad token");
5023 bc_parse_number(p, &prev, &p->nbraces);
5025 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5031 case BC_LEX_KEY_READ:
5033 if (flags & BC_PARSE_NOREAD)
5034 s = bc_error("read() call inside of a read() call");
5036 bc_parse_push(p, BC_INST_READ);
5041 case BC_LEX_OP_ASSIGN:
5042 case BC_LEX_STORE_PUSH:
5044 assign = t == BC_LEX_OP_ASSIGN;
5045 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5046 s = dc_parse_mem(p, inst, true, assign);
5051 case BC_LEX_LOAD_POP:
5053 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5054 s = dc_parse_mem(p, inst, true, false);
5058 case BC_LEX_STORE_IBASE:
5059 case BC_LEX_STORE_SCALE:
5060 case BC_LEX_STORE_OBASE:
5062 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5063 s = dc_parse_mem(p, inst, false, true);
5069 s = bc_error("bad token");
5075 if (!s && get_token) s = bc_lex_next(&p->l);
5080 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5082 BcStatus s = BC_STATUS_SUCCESS;
5086 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5088 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5090 inst = dc_parse_insts[t];
5092 if (inst != BC_INST_INVALID) {
5093 bc_parse_push(p, inst);
5094 s = bc_lex_next(&p->l);
5097 s = dc_parse_token(p, t, flags);
5100 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5101 bc_parse_push(p, BC_INST_POP_EXEC);
5106 static BcStatus dc_parse_parse(BcParse *p)
5110 if (p->l.t.t == BC_LEX_EOF)
5111 s = bc_error("end of file");
5113 s = dc_parse_expr(p, 0);
5115 if (s || G_interrupt) {
5117 s = BC_STATUS_FAILURE;
5123 static void dc_parse_init(BcParse *p, size_t func)
5125 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5129 static void common_parse_init(BcParse *p, size_t func)
5132 bc_parse_init(p, func);
5134 dc_parse_init(p, func);
5138 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5141 return bc_parse_expression(p, flags);
5143 return dc_parse_expr(p, flags);
5147 static BcVec* bc_program_search(char *id, bool var)
5155 v = var ? &G.prog.vars : &G.prog.arrs;
5156 map = var ? &G.prog.var_map : &G.prog.arr_map;
5160 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5163 bc_array_init(&data.v, var);
5164 bc_vec_push(v, &data.v);
5167 ptr = bc_vec_item(map, i);
5168 if (new) ptr->name = xstrdup(e.name);
5169 return bc_vec_item(v, ptr->idx);
5172 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5174 BcStatus s = BC_STATUS_SUCCESS;
5179 case BC_RESULT_TEMP:
5180 case BC_RESULT_IBASE:
5181 case BC_RESULT_SCALE:
5182 case BC_RESULT_OBASE:
5188 case BC_RESULT_CONSTANT:
5190 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5191 size_t base_t, len = strlen(*str);
5194 bc_num_init(&r->d.n, len);
5196 hex = hex && len == 1;
5197 base = hex ? &G.prog.hexb : &G.prog.ib;
5198 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5199 s = bc_num_parse(&r->d.n, *str, base, base_t);
5202 bc_num_free(&r->d.n);
5207 r->t = BC_RESULT_TEMP;
5213 case BC_RESULT_ARRAY:
5214 case BC_RESULT_ARRAY_ELEM:
5218 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5220 if (r->t == BC_RESULT_ARRAY_ELEM) {
5222 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5223 *num = bc_vec_item(v, r->d.id.idx);
5226 *num = bc_vec_top(v);
5231 case BC_RESULT_LAST:
5233 *num = &G.prog.last;
5247 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5248 BcResult **r, BcNum **rn, bool assign)
5252 BcResultType lt, rt;
5254 if (!BC_PROG_STACK(&G.prog.results, 2))
5255 return bc_error("stack has too few elements");
5257 *r = bc_vec_item_rev(&G.prog.results, 0);
5258 *l = bc_vec_item_rev(&G.prog.results, 1);
5262 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5264 s = bc_program_num(*l, ln, false);
5266 s = bc_program_num(*r, rn, hex);
5269 // We run this again under these conditions in case any vector has been
5270 // reallocated out from under the BcNums or arrays we had.
5271 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5272 s = bc_program_num(*l, ln, false);
5276 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5277 return bc_error("variable is wrong type");
5278 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5279 return bc_error("variable is wrong type");
5284 static void bc_program_binOpRetire(BcResult *r)
5286 r->t = BC_RESULT_TEMP;
5287 bc_vec_pop(&G.prog.results);
5288 bc_vec_pop(&G.prog.results);
5289 bc_vec_push(&G.prog.results, r);
5292 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5296 if (!BC_PROG_STACK(&G.prog.results, 1))
5297 return bc_error("stack has too few elements");
5298 *r = bc_vec_top(&G.prog.results);
5300 s = bc_program_num(*r, n, false);
5303 if (!BC_PROG_NUM((*r), (*n)))
5304 return bc_error("variable is wrong type");
5309 static void bc_program_retire(BcResult *r, BcResultType t)
5312 bc_vec_pop(&G.prog.results);
5313 bc_vec_push(&G.prog.results, r);
5316 static BcStatus bc_program_op(char inst)
5319 BcResult *opd1, *opd2, res;
5320 BcNum *n1, *n2 = NULL;
5322 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5324 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5326 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5328 bc_program_binOpRetire(&res);
5333 bc_num_free(&res.d.n);
5337 static BcStatus bc_program_read(void)
5344 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5346 for (i = 0; i < G.prog.stack.len; ++i) {
5347 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5348 if (ip_ptr->func == BC_PROG_READ)
5349 return bc_error("read() call inside of a read() call");
5352 bc_vec_npop(&f->code, f->code.len);
5353 bc_vec_init(&buf, sizeof(char), NULL);
5355 s = bc_read_line(&buf, "read> ");
5358 common_parse_init(&parse, BC_PROG_READ);
5359 bc_lex_file(&parse.l, bc_program_stdin_name);
5361 s = bc_parse_text(&parse, buf.v);
5362 if (s) goto exec_err;
5363 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5364 if (s) goto exec_err;
5366 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5367 s = bc_error("bad read() expression");
5371 ip.func = BC_PROG_READ;
5373 ip.len = G.prog.results.len;
5375 // Update this pointer, just in case.
5376 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5378 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5379 bc_vec_push(&G.prog.stack, &ip);
5382 bc_parse_free(&parse);
5388 static size_t bc_program_index(char *code, size_t *bgn)
5390 char amt = code[(*bgn)++], i = 0;
5393 for (; i < amt; ++i, ++(*bgn))
5394 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5399 static char *bc_program_name(char *code, size_t *bgn)
5402 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5404 s = xmalloc(ptr - str + 1);
5407 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5415 static void bc_program_printString(const char *str, size_t *nchars)
5417 size_t i, len = strlen(str);
5426 for (i = 0; i < len; ++i, ++(*nchars)) {
5430 if (c != '\\' || i == len - 1)
5490 // Just print the backslash and following character.
5501 static BcStatus bc_program_print(char inst, size_t idx)
5503 BcStatus s = BC_STATUS_SUCCESS;
5508 bool pop = inst != BC_INST_PRINT;
5510 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5511 return bc_error("stack has too few elements");
5513 r = bc_vec_item_rev(&G.prog.results, idx);
5514 s = bc_program_num(r, &num, false);
5517 if (BC_PROG_NUM(r, num)) {
5518 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5519 if (!s) bc_num_copy(&G.prog.last, num);
5523 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5524 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5526 if (inst == BC_INST_PRINT_STR) {
5527 for (i = 0, len = strlen(str); i < len; ++i) {
5530 if (c == '\n') G.prog.nchars = SIZE_MAX;
5535 bc_program_printString(str, &G.prog.nchars);
5536 if (inst == BC_INST_PRINT) bb_putchar('\n');
5540 if (!s && pop) bc_vec_pop(&G.prog.results);
5545 static BcStatus bc_program_negate(void)
5551 s = bc_program_prep(&ptr, &num);
5554 bc_num_init(&res.d.n, num->len);
5555 bc_num_copy(&res.d.n, num);
5556 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5558 bc_program_retire(&res, BC_RESULT_TEMP);
5563 static BcStatus bc_program_logical(char inst)
5566 BcResult *opd1, *opd2, res;
5571 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5573 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5575 if (inst == BC_INST_BOOL_AND)
5576 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5577 else if (inst == BC_INST_BOOL_OR)
5578 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5581 cmp = bc_num_cmp(n1, n2);
5585 case BC_INST_REL_EQ:
5591 case BC_INST_REL_LE:
5597 case BC_INST_REL_GE:
5603 case BC_INST_REL_NE:
5609 case BC_INST_REL_LT:
5615 case BC_INST_REL_GT:
5623 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5625 bc_program_binOpRetire(&res);
5631 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5637 memset(&n2, 0, sizeof(BcNum));
5638 n2.rdx = res.d.id.idx = r->d.id.idx;
5639 res.t = BC_RESULT_STR;
5642 if (!BC_PROG_STACK(&G.prog.results, 2))
5643 return bc_error("stack has too few elements");
5645 bc_vec_pop(&G.prog.results);
5648 bc_vec_pop(&G.prog.results);
5650 bc_vec_push(&G.prog.results, &res);
5651 bc_vec_push(v, &n2);
5653 return BC_STATUS_SUCCESS;
5657 static BcStatus bc_program_copyToVar(char *name, bool var)
5664 if (!BC_PROG_STACK(&G.prog.results, 1))
5665 return bc_error("stack has too few elements");
5667 ptr = bc_vec_top(&G.prog.results);
5668 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5669 return bc_error("variable is wrong type");
5670 v = bc_program_search(name, var);
5673 if (ptr->t == BC_RESULT_STR && !var)
5674 return bc_error("variable is wrong type");
5675 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5678 s = bc_program_num(ptr, &n, false);
5681 // Do this once more to make sure that pointers were not invalidated.
5682 v = bc_program_search(name, var);
5685 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5686 bc_num_copy(&r.d.n, n);
5689 bc_array_init(&r.d.v, true);
5690 bc_array_copy(&r.d.v, (BcVec *) n);
5693 bc_vec_push(v, &r.d);
5694 bc_vec_pop(&G.prog.results);
5699 static BcStatus bc_program_assign(char inst)
5702 BcResult *left, *right, res;
5703 BcNum *l = NULL, *r = NULL;
5704 unsigned long val, max;
5705 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5707 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5710 ib = left->t == BC_RESULT_IBASE;
5711 sc = left->t == BC_RESULT_SCALE;
5715 if (right->t == BC_RESULT_STR) {
5719 if (left->t != BC_RESULT_VAR)
5720 return bc_error("variable is wrong type");
5721 v = bc_program_search(left->d.id.name, true);
5723 return bc_program_assignStr(right, v, false);
5727 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5728 return bc_error("bad assignment:"
5729 " left side must be scale,"
5730 " ibase, obase, last, var,"
5735 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5736 return bc_error("divide by zero");
5741 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5748 if (ib || sc || left->t == BC_RESULT_OBASE) {
5749 static const char *const msg[] = {
5750 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5751 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5752 "?1", //BC_RESULT_LAST
5753 "?2", //BC_RESULT_CONSTANT
5754 "?3", //BC_RESULT_ONE
5755 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5759 s = bc_num_ulong(l, &val);
5762 s = left->t - BC_RESULT_IBASE;
5765 ptr = &G.prog.scale;
5768 if (val < BC_NUM_MIN_BASE)
5769 return bc_error(msg[s]);
5770 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5771 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5775 return bc_error(msg[s]);
5777 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5779 *ptr = (size_t) val;
5780 s = BC_STATUS_SUCCESS;
5783 bc_num_init(&res.d.n, l->len);
5784 bc_num_copy(&res.d.n, l);
5785 bc_program_binOpRetire(&res);
5791 #define bc_program_pushVar(code, bgn, pop, copy) \
5792 bc_program_pushVar(code, bgn)
5793 // for bc, 'pop' and 'copy' are always false
5795 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5796 bool pop, bool copy)
5798 BcStatus s = BC_STATUS_SUCCESS;
5800 char *name = bc_program_name(code, bgn);
5802 r.t = BC_RESULT_VAR;
5807 BcVec *v = bc_program_search(name, true);
5808 BcNum *num = bc_vec_top(v);
5812 if (!BC_PROG_STACK(v, 2 - copy)) {
5814 return bc_error("stack has too few elements");
5820 if (!BC_PROG_STR(num)) {
5822 r.t = BC_RESULT_TEMP;
5824 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5825 bc_num_copy(&r.d.n, num);
5828 r.t = BC_RESULT_STR;
5829 r.d.id.idx = num->rdx;
5832 if (!copy) bc_vec_pop(v);
5837 bc_vec_push(&G.prog.results, &r);
5842 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5845 BcStatus s = BC_STATUS_SUCCESS;
5849 r.d.id.name = bc_program_name(code, bgn);
5851 if (inst == BC_INST_ARRAY) {
5852 r.t = BC_RESULT_ARRAY;
5853 bc_vec_push(&G.prog.results, &r);
5860 s = bc_program_prep(&operand, &num);
5862 s = bc_num_ulong(num, &temp);
5865 if (temp > BC_MAX_DIM) {
5866 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5870 r.d.id.idx = (size_t) temp;
5871 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5875 if (s) free(r.d.id.name);
5880 static BcStatus bc_program_incdec(char inst)
5883 BcResult *ptr, res, copy;
5887 s = bc_program_prep(&ptr, &num);
5890 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5891 copy.t = BC_RESULT_TEMP;
5892 bc_num_init(©.d.n, num->len);
5893 bc_num_copy(©.d.n, num);
5896 res.t = BC_RESULT_ONE;
5897 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5898 BC_INST_ASSIGN_PLUS :
5899 BC_INST_ASSIGN_MINUS;
5901 bc_vec_push(&G.prog.results, &res);
5902 bc_program_assign(inst);
5904 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5905 bc_vec_pop(&G.prog.results);
5906 bc_vec_push(&G.prog.results, ©);
5912 static BcStatus bc_program_call(char *code, size_t *idx)
5914 BcStatus s = BC_STATUS_SUCCESS;
5916 size_t i, nparams = bc_program_index(code, idx);
5923 ip.func = bc_program_index(code, idx);
5924 func = bc_vec_item(&G.prog.fns, ip.func);
5926 if (func->code.len == 0) {
5927 return bc_error("undefined function");
5929 if (nparams != func->nparams) {
5930 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5932 ip.len = G.prog.results.len - nparams;
5934 for (i = 0; i < nparams; ++i) {
5936 a = bc_vec_item(&func->autos, nparams - 1 - i);
5937 arg = bc_vec_top(&G.prog.results);
5939 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5940 return bc_error("variable is wrong type");
5942 s = bc_program_copyToVar(a->name, a->idx);
5946 for (; i < func->autos.len; ++i) {
5949 a = bc_vec_item(&func->autos, i);
5950 v = bc_program_search(a->name, a->idx);
5953 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5954 bc_vec_push(v, ¶m.n);
5957 bc_array_init(¶m.v, true);
5958 bc_vec_push(v, ¶m.v);
5962 bc_vec_push(&G.prog.stack, &ip);
5964 return BC_STATUS_SUCCESS;
5967 static BcStatus bc_program_return(char inst)
5973 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5975 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5976 return bc_error("stack has too few elements");
5978 f = bc_vec_item(&G.prog.fns, ip->func);
5979 res.t = BC_RESULT_TEMP;
5981 if (inst == BC_INST_RET) {
5984 BcResult *operand = bc_vec_top(&G.prog.results);
5986 s = bc_program_num(operand, &num, false);
5988 bc_num_init(&res.d.n, num->len);
5989 bc_num_copy(&res.d.n, num);
5992 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5993 bc_num_zero(&res.d.n);
5996 // We need to pop arguments as well, so this takes that into account.
5997 for (i = 0; i < f->autos.len; ++i) {
6000 BcId *a = bc_vec_item(&f->autos, i);
6002 v = bc_program_search(a->name, a->idx);
6006 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6007 bc_vec_push(&G.prog.results, &res);
6008 bc_vec_pop(&G.prog.stack);
6010 return BC_STATUS_SUCCESS;
6014 static unsigned long bc_program_scale(BcNum *n)
6016 return (unsigned long) n->rdx;
6019 static unsigned long bc_program_len(BcNum *n)
6021 unsigned long len = n->len;
6024 if (n->rdx != n->len) return len;
6025 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6030 static BcStatus bc_program_builtin(char inst)
6036 bool len = inst == BC_INST_LENGTH;
6038 if (!BC_PROG_STACK(&G.prog.results, 1))
6039 return bc_error("stack has too few elements");
6040 opnd = bc_vec_top(&G.prog.results);
6042 s = bc_program_num(opnd, &num, false);
6046 if (!BC_PROG_NUM(opnd, num) && !len)
6047 return bc_error("variable is wrong type");
6050 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6052 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6054 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6055 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6059 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6062 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6064 str = bc_vec_item(&G.prog.strs, idx);
6065 bc_num_ulong2num(&res.d.n, strlen(*str));
6069 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6070 bc_num_ulong2num(&res.d.n, f(num));
6073 bc_program_retire(&res, BC_RESULT_TEMP);
6079 static BcStatus bc_program_divmod(void)
6082 BcResult *opd1, *opd2, res, res2;
6083 BcNum *n1, *n2 = NULL;
6085 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6088 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6089 bc_num_init(&res2.d.n, n2->len);
6091 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6094 bc_program_binOpRetire(&res2);
6095 res.t = BC_RESULT_TEMP;
6096 bc_vec_push(&G.prog.results, &res);
6101 bc_num_free(&res2.d.n);
6102 bc_num_free(&res.d.n);
6106 static BcStatus bc_program_modexp(void)
6109 BcResult *r1, *r2, *r3, res;
6110 BcNum *n1, *n2, *n3;
6112 if (!BC_PROG_STACK(&G.prog.results, 3))
6113 return bc_error("stack has too few elements");
6114 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6117 r1 = bc_vec_item_rev(&G.prog.results, 2);
6118 s = bc_program_num(r1, &n1, false);
6120 if (!BC_PROG_NUM(r1, n1))
6121 return bc_error("variable is wrong type");
6123 // Make sure that the values have their pointers updated, if necessary.
6124 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6126 if (r1->t == r2->t) {
6127 s = bc_program_num(r2, &n2, false);
6131 if (r1->t == r3->t) {
6132 s = bc_program_num(r3, &n3, false);
6137 bc_num_init(&res.d.n, n3->len);
6138 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6141 bc_vec_pop(&G.prog.results);
6142 bc_program_binOpRetire(&res);
6147 bc_num_free(&res.d.n);
6151 static void bc_program_stackLen(void)
6154 size_t len = G.prog.results.len;
6156 res.t = BC_RESULT_TEMP;
6158 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6159 bc_num_ulong2num(&res.d.n, len);
6160 bc_vec_push(&G.prog.results, &res);
6163 static BcStatus bc_program_asciify(void)
6167 BcNum *num = NULL, n;
6168 char *str, *str2, c;
6169 size_t len = G.prog.strs.len, idx;
6172 if (!BC_PROG_STACK(&G.prog.results, 1))
6173 return bc_error("stack has too few elements");
6174 r = bc_vec_top(&G.prog.results);
6176 s = bc_program_num(r, &num, false);
6179 if (BC_PROG_NUM(r, num)) {
6181 bc_num_init(&n, BC_NUM_DEF_SIZE);
6182 bc_num_copy(&n, num);
6183 bc_num_truncate(&n, n.rdx);
6185 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6186 if (s) goto num_err;
6187 s = bc_num_ulong(&n, &val);
6188 if (s) goto num_err;
6195 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6196 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6204 str2 = xstrdup(str);
6205 bc_program_addFunc(str2, &idx);
6207 if (idx != len + BC_PROG_REQ_FUNCS) {
6209 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6210 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6219 bc_vec_push(&G.prog.strs, &str);
6221 res.t = BC_RESULT_STR;
6223 bc_vec_pop(&G.prog.results);
6224 bc_vec_push(&G.prog.results, &res);
6226 return BC_STATUS_SUCCESS;
6233 static BcStatus bc_program_printStream(void)
6241 if (!BC_PROG_STACK(&G.prog.results, 1))
6242 return bc_error("stack has too few elements");
6243 r = bc_vec_top(&G.prog.results);
6245 s = bc_program_num(r, &n, false);
6248 if (BC_PROG_NUM(r, n))
6249 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6251 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6252 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6259 static BcStatus bc_program_nquit(void)
6266 s = bc_program_prep(&opnd, &num);
6268 s = bc_num_ulong(num, &val);
6271 bc_vec_pop(&G.prog.results);
6273 if (G.prog.stack.len < val)
6274 return bc_error("stack has too few elements");
6275 if (G.prog.stack.len == val)
6278 bc_vec_npop(&G.prog.stack, val);
6283 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6286 BcStatus s = BC_STATUS_SUCCESS;
6296 if (!BC_PROG_STACK(&G.prog.results, 1))
6297 return bc_error("stack has too few elements");
6299 r = bc_vec_top(&G.prog.results);
6303 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6305 if (code[*bgn] == BC_PARSE_STREND)
6308 else_name = bc_program_name(code, bgn);
6310 exec = r->d.n.len != 0;
6314 else if (else_name != NULL) {
6321 v = bc_program_search(name, true);
6328 if (!exec) goto exit;
6329 if (!BC_PROG_STR(n)) {
6330 s = bc_error("variable is wrong type");
6338 if (r->t == BC_RESULT_STR)
6340 else if (r->t == BC_RESULT_VAR) {
6341 s = bc_program_num(r, &n, false);
6342 if (s || !BC_PROG_STR(n)) goto exit;
6349 fidx = sidx + BC_PROG_REQ_FUNCS;
6351 str = bc_vec_item(&G.prog.strs, sidx);
6352 f = bc_vec_item(&G.prog.fns, fidx);
6354 if (f->code.len == 0) {
6355 common_parse_init(&prs, fidx);
6356 s = bc_parse_text(&prs, *str);
6358 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6361 if (prs.l.t.t != BC_LEX_EOF) {
6362 s = bc_error("bad expression");
6366 bc_parse_free(&prs);
6370 ip.len = G.prog.results.len;
6373 bc_vec_pop(&G.prog.results);
6374 bc_vec_push(&G.prog.stack, &ip);
6376 return BC_STATUS_SUCCESS;
6379 bc_parse_free(&prs);
6380 f = bc_vec_item(&G.prog.fns, fidx);
6381 bc_vec_npop(&f->code, f->code.len);
6383 bc_vec_pop(&G.prog.results);
6388 static void bc_program_pushGlobal(char inst)
6393 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6394 if (inst == BC_INST_IBASE)
6395 val = (unsigned long) G.prog.ib_t;
6396 else if (inst == BC_INST_SCALE)
6397 val = (unsigned long) G.prog.scale;
6399 val = (unsigned long) G.prog.ob_t;
6401 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6402 bc_num_ulong2num(&res.d.n, val);
6403 bc_vec_push(&G.prog.results, &res);
6406 static void bc_program_addFunc(char *name, size_t *idx)
6408 BcId entry, *entry_ptr;
6413 entry.idx = G.prog.fns.len;
6415 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6416 if (!inserted) free(name);
6418 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6419 *idx = entry_ptr->idx;
6423 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6425 // We need to reset these, so the function can be repopulated.
6427 bc_vec_npop(&func->autos, func->autos.len);
6428 bc_vec_npop(&func->code, func->code.len);
6429 bc_vec_npop(&func->labels, func->labels.len);
6433 bc_vec_push(&G.prog.fns, &f);
6437 // Called when parsing or execution detects a failure,
6438 // resets execution structures.
6439 static void bc_program_reset(void)
6444 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6445 bc_vec_npop(&G.prog.results, G.prog.results.len);
6447 f = bc_vec_item(&G.prog.fns, 0);
6448 ip = bc_vec_top(&G.prog.stack);
6449 ip->idx = f->code.len;
6451 // If !tty, no need to check for ^C: we don't have ^C handler,
6452 // we would be killed by a signal and won't reach this place
6455 static BcStatus bc_program_exec(void)
6457 BcStatus s = BC_STATUS_SUCCESS;
6461 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6462 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6463 char *code = func->code.v;
6466 while (!s && ip->idx < func->code.len) {
6468 char inst = code[(ip->idx)++];
6473 case BC_INST_JUMP_ZERO:
6475 s = bc_program_prep(&ptr, &num);
6477 cond = !bc_num_cmp(num, &G.prog.zero);
6478 bc_vec_pop(&G.prog.results);
6484 idx = bc_program_index(code, &ip->idx);
6485 addr = bc_vec_item(&func->labels, idx);
6486 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6492 s = bc_program_call(code, &ip->idx);
6496 case BC_INST_INC_PRE:
6497 case BC_INST_DEC_PRE:
6498 case BC_INST_INC_POST:
6499 case BC_INST_DEC_POST:
6501 s = bc_program_incdec(inst);
6514 s = bc_program_return(inst);
6518 case BC_INST_BOOL_OR:
6519 case BC_INST_BOOL_AND:
6521 case BC_INST_REL_EQ:
6522 case BC_INST_REL_LE:
6523 case BC_INST_REL_GE:
6524 case BC_INST_REL_NE:
6525 case BC_INST_REL_LT:
6526 case BC_INST_REL_GT:
6528 s = bc_program_logical(inst);
6534 s = bc_program_read();
6540 s = bc_program_pushVar(code, &ip->idx, false, false);
6544 case BC_INST_ARRAY_ELEM:
6547 s = bc_program_pushArray(code, &ip->idx, inst);
6553 r.t = BC_RESULT_LAST;
6554 bc_vec_push(&G.prog.results, &r);
6562 bc_program_pushGlobal(inst);
6566 case BC_INST_SCALE_FUNC:
6567 case BC_INST_LENGTH:
6570 s = bc_program_builtin(inst);
6576 r.t = BC_RESULT_CONSTANT;
6577 r.d.id.idx = bc_program_index(code, &ip->idx);
6578 bc_vec_push(&G.prog.results, &r);
6584 if (!BC_PROG_STACK(&G.prog.results, 1))
6585 s = bc_error("stack has too few elements");
6587 bc_vec_pop(&G.prog.results);
6591 case BC_INST_POP_EXEC:
6593 bc_vec_pop(&G.prog.stack);
6598 case BC_INST_PRINT_POP:
6599 case BC_INST_PRINT_STR:
6601 s = bc_program_print(inst, 0);
6607 r.t = BC_RESULT_STR;
6608 r.d.id.idx = bc_program_index(code, &ip->idx);
6609 bc_vec_push(&G.prog.results, &r);
6614 case BC_INST_MULTIPLY:
6615 case BC_INST_DIVIDE:
6616 case BC_INST_MODULUS:
6620 s = bc_program_op(inst);
6624 case BC_INST_BOOL_NOT:
6626 s = bc_program_prep(&ptr, &num);
6629 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6630 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6631 bc_program_retire(&r, BC_RESULT_TEMP);
6638 s = bc_program_negate();
6643 case BC_INST_ASSIGN_POWER:
6644 case BC_INST_ASSIGN_MULTIPLY:
6645 case BC_INST_ASSIGN_DIVIDE:
6646 case BC_INST_ASSIGN_MODULUS:
6647 case BC_INST_ASSIGN_PLUS:
6648 case BC_INST_ASSIGN_MINUS:
6650 case BC_INST_ASSIGN:
6652 s = bc_program_assign(inst);
6656 case BC_INST_MODEXP:
6658 s = bc_program_modexp();
6662 case BC_INST_DIVMOD:
6664 s = bc_program_divmod();
6668 case BC_INST_EXECUTE:
6669 case BC_INST_EXEC_COND:
6671 cond = inst == BC_INST_EXEC_COND;
6672 s = bc_program_execStr(code, &ip->idx, cond);
6676 case BC_INST_PRINT_STACK:
6678 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6679 s = bc_program_print(BC_INST_PRINT, idx);
6683 case BC_INST_CLEAR_STACK:
6685 bc_vec_npop(&G.prog.results, G.prog.results.len);
6689 case BC_INST_STACK_LEN:
6691 bc_program_stackLen();
6695 case BC_INST_DUPLICATE:
6697 if (!BC_PROG_STACK(&G.prog.results, 1))
6698 return bc_error("stack has too few elements");
6699 ptr = bc_vec_top(&G.prog.results);
6700 bc_result_copy(&r, ptr);
6701 bc_vec_push(&G.prog.results, &r);
6709 if (!BC_PROG_STACK(&G.prog.results, 2))
6710 return bc_error("stack has too few elements");
6712 ptr = bc_vec_item_rev(&G.prog.results, 0);
6713 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6714 memcpy(&r, ptr, sizeof(BcResult));
6715 memcpy(ptr, ptr2, sizeof(BcResult));
6716 memcpy(ptr2, &r, sizeof(BcResult));
6721 case BC_INST_ASCIIFY:
6723 s = bc_program_asciify();
6727 case BC_INST_PRINT_STREAM:
6729 s = bc_program_printStream();
6734 case BC_INST_PUSH_VAR:
6736 bool copy = inst == BC_INST_LOAD;
6737 s = bc_program_pushVar(code, &ip->idx, true, copy);
6741 case BC_INST_PUSH_TO_VAR:
6743 char *name = bc_program_name(code, &ip->idx);
6744 s = bc_program_copyToVar(name, true);
6751 if (G.prog.stack.len <= 2)
6753 bc_vec_npop(&G.prog.stack, 2);
6759 s = bc_program_nquit();
6765 if (s || G_interrupt) {
6770 // If the stack has changed, pointers may be invalid.
6771 ip = bc_vec_top(&G.prog.stack);
6772 func = bc_vec_item(&G.prog.fns, ip->func);
6773 code = func->code.v;
6779 static void bc_vm_info(void)
6781 printf("%s "BB_VER"\n"
6782 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6783 "Report bugs at: https://github.com/gavinhoward/bc\n"
6784 "This is free software with ABSOLUTELY NO WARRANTY\n"
6789 static void bc_vm_envArgs(void)
6791 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6794 char *env_args = getenv(bc_args_env_name), *buf;
6796 if (!env_args) return;
6798 G.env_args = xstrdup(env_args);
6801 bc_vec_init(&v, sizeof(char *), NULL);
6802 bc_vec_push(&v, &bc_args_env_name);
6805 if (!isspace(*buf)) {
6806 bc_vec_push(&v, &buf);
6807 while (*buf != 0 && !isspace(*buf)) ++buf;
6808 if (*buf != 0) (*(buf++)) = '\0';
6814 bc_args((int) v.len, (char **) v.v);
6820 static size_t bc_vm_envLen(const char *var)
6822 char *lenv = getenv(var);
6823 size_t i, len = BC_NUM_PRINT_WIDTH;
6826 if (!lenv) return len;
6830 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6832 len = (size_t) atoi(lenv) - 1;
6833 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6836 len = BC_NUM_PRINT_WIDTH;
6841 static BcStatus bc_vm_process(const char *text)
6843 BcStatus s = bc_parse_text(&G.prs, text);
6847 while (G.prs.l.t.t != BC_LEX_EOF) {
6848 s = G.prs.parse(&G.prs);
6852 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6853 s = bc_program_exec();
6862 static BcStatus bc_vm_file(const char *file)
6870 data = bc_read_file(file);
6871 if (!data) return bc_error("file '%s' is not text", file);
6873 bc_lex_file(&G.prs.l, file);
6874 s = bc_vm_process(data);
6877 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6878 ip = bc_vec_item(&G.prog.stack, 0);
6880 if (main_func->code.len < ip->idx)
6881 s = bc_error("file '%s' is not executable", file);
6888 static BcStatus bc_vm_stdin(void)
6892 size_t len, i, str = 0;
6893 bool comment = false;
6895 G.prog.file = bc_program_stdin_name;
6896 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6898 bc_vec_init(&buffer, sizeof(char), NULL);
6899 bc_vec_init(&buf, sizeof(char), NULL);
6900 bc_vec_pushByte(&buffer, '\0');
6902 // This loop is complex because the vm tries not to send any lines that end
6903 // with a backslash to the parser. The reason for that is because the parser
6904 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6905 // case, and for strings and comments, the parser will expect more stuff.
6906 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6908 char *string = buf.v;
6913 if (str && buf.v[0] == G.send)
6915 else if (buf.v[0] == G.sbgn)
6918 else if (len > 1 || comment) {
6920 for (i = 0; i < len; ++i) {
6922 bool notend = len > i + 1;
6925 if (i - 1 > len || string[i - 1] != '\\') {
6926 if (G.sbgn == G.send)
6928 else if (c == G.send)
6930 else if (c == G.sbgn)
6934 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6938 else if (c == '*' && notend && comment && string[i + 1] == '/')
6942 if (str || comment || string[len - 2] == '\\') {
6943 bc_vec_concat(&buffer, buf.v);
6948 bc_vec_concat(&buffer, buf.v);
6949 s = bc_vm_process(buffer.v);
6952 fputs("ready for more input\n", stderr);
6955 bc_vec_npop(&buffer, buffer.len);
6959 s = bc_error("string end could not be found");
6962 s = bc_error("comment end could not be found");
6966 bc_vec_free(&buffer);
6970 static BcStatus bc_vm_exec(void)
6972 BcStatus s = BC_STATUS_SUCCESS;
6976 if (option_mask32 & BC_FLAG_L) {
6978 bc_lex_file(&G.prs.l, bc_lib_name);
6979 s = bc_parse_text(&G.prs, bc_lib);
6981 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6982 s = G.prs.parse(&G.prs);
6985 s = bc_program_exec();
6990 for (i = 0; !s && i < G.files.len; ++i)
6991 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
6994 fputs("ready for more input\n", stderr);
6997 if (IS_BC || !G.files.len)
6999 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7000 s = bc_vm_process("");
7005 #if ENABLE_FEATURE_CLEAN_UP
7006 static void bc_program_free()
7008 bc_num_free(&G.prog.ib);
7009 bc_num_free(&G.prog.ob);
7010 bc_num_free(&G.prog.hexb);
7012 bc_num_free(&G.prog.strmb);
7014 bc_vec_free(&G.prog.fns);
7015 bc_vec_free(&G.prog.fn_map);
7016 bc_vec_free(&G.prog.vars);
7017 bc_vec_free(&G.prog.var_map);
7018 bc_vec_free(&G.prog.arrs);
7019 bc_vec_free(&G.prog.arr_map);
7020 bc_vec_free(&G.prog.strs);
7021 bc_vec_free(&G.prog.consts);
7022 bc_vec_free(&G.prog.results);
7023 bc_vec_free(&G.prog.stack);
7024 bc_num_free(&G.prog.last);
7025 bc_num_free(&G.prog.zero);
7026 bc_num_free(&G.prog.one);
7029 static void bc_vm_free(void)
7031 bc_vec_free(&G.files);
7033 bc_parse_free(&G.prs);
7038 static void bc_program_init(size_t line_len)
7043 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7044 memset(&ip, 0, sizeof(BcInstPtr));
7046 /* G.prog.nchars = G.prog.scale = 0; - already is */
7047 G.prog.len = line_len;
7049 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7050 bc_num_ten(&G.prog.ib);
7053 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7054 bc_num_ten(&G.prog.ob);
7057 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7058 bc_num_ten(&G.prog.hexb);
7059 G.prog.hexb.num[0] = 6;
7062 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7063 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7066 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7067 bc_num_zero(&G.prog.last);
7069 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7070 bc_num_zero(&G.prog.zero);
7072 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7073 bc_num_one(&G.prog.one);
7075 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7076 bc_map_init(&G.prog.fn_map);
7078 bc_program_addFunc(xstrdup("(main)"), &idx);
7079 bc_program_addFunc(xstrdup("(read)"), &idx);
7081 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7082 bc_map_init(&G.prog.var_map);
7084 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7085 bc_map_init(&G.prog.arr_map);
7087 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7088 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7089 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7090 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7091 bc_vec_push(&G.prog.stack, &ip);
7094 static void bc_vm_init(const char *env_len)
7096 size_t len = bc_vm_envLen(env_len);
7098 bc_vec_init(&G.files, sizeof(char *), NULL);
7104 bc_program_init(len);
7106 bc_parse_init(&G.prs, BC_PROG_MAIN);
7108 dc_parse_init(&G.prs, BC_PROG_MAIN);
7112 static BcStatus bc_vm_run(int argc, char *argv[],
7113 const char *env_len)
7117 bc_vm_init(env_len);
7118 bc_args(argc, argv);
7120 G.ttyin = isatty(0);
7123 #if ENABLE_FEATURE_BC_SIGNALS
7124 // With SA_RESTART, most system calls will restart
7125 // (IOW: they won't fail with EINTR).
7126 // In particular, this means ^C won't cause
7127 // stdout to get into "error state" if SIGINT hits
7128 // within write() syscall.
7129 // The downside is that ^C while line input is taken
7130 // will only be handled after [Enter] since read()
7131 // from stdin is not interrupted by ^C either,
7132 // it restarts, thus fgetc() does not return on ^C.
7133 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7135 // Without SA_RESTART, this exhibits a bug:
7136 // "while (1) print 1" and try ^C-ing it.
7137 // Intermittently, instead of returning to input line,
7138 // you'll get "output error: Interrupted system call"
7140 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7142 if (!(option_mask32 & BC_FLAG_Q))
7147 #if ENABLE_FEATURE_CLEAN_UP
7154 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7155 int bc_main(int argc, char **argv)
7158 G.sbgn = G.send = '"';
7160 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7165 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7166 int dc_main(int argc, char **argv)
7172 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");