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_char_vec_init(BcVec *v)
1046 bc_vec_init(v, sizeof(char), NULL);
1049 static void bc_vec_expand(BcVec *v, size_t req)
1052 v->v = xrealloc(v->v, v->size * req);
1057 static void bc_vec_npop(BcVec *v, size_t n)
1062 size_t len = v->len - n;
1063 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1067 static void bc_vec_pop_all(BcVec *v)
1069 bc_vec_npop(v, v->len);
1072 static void bc_vec_push(BcVec *v, const void *data)
1074 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1075 memmove(v->v + (v->size * v->len), data, v->size);
1079 static void bc_vec_pushByte(BcVec *v, char data)
1081 bc_vec_push(v, &data);
1084 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1087 bc_vec_push(v, data);
1092 if (v->len == v->cap) bc_vec_grow(v, 1);
1094 ptr = v->v + v->size * idx;
1096 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1097 memmove(ptr, data, v->size);
1101 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1104 bc_vec_expand(v, len + 1);
1105 memcpy(v->v, str, len);
1108 bc_vec_pushByte(v, '\0');
1111 static void bc_vec_concat(BcVec *v, const char *str)
1115 if (v->len == 0) bc_vec_pushByte(v, '\0');
1117 len = v->len + strlen(str);
1119 if (v->cap < len) bc_vec_grow(v, len - v->len);
1125 static void *bc_vec_item(const BcVec *v, size_t idx)
1127 return v->v + v->size * idx;
1130 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1132 return v->v + v->size * (v->len - idx - 1);
1135 static void bc_vec_free(void *vec)
1137 BcVec *v = (BcVec *) vec;
1142 static size_t bc_map_find(const BcVec *v, const void *ptr)
1144 size_t low = 0, high = v->len;
1146 while (low < high) {
1148 size_t mid = (low + high) / 2;
1149 BcId *id = bc_vec_item(v, mid);
1150 int result = bc_id_cmp(ptr, id);
1154 else if (result < 0)
1163 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1165 size_t n = *i = bc_map_find(v, ptr);
1168 bc_vec_push(v, ptr);
1169 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1170 return 0; // "was not inserted"
1172 bc_vec_pushAt(v, ptr, n);
1173 return 1; // "was inserted"
1176 static size_t bc_map_index(const BcVec *v, const void *ptr)
1178 size_t i = bc_map_find(v, ptr);
1179 if (i >= v->len) return BC_VEC_INVALID_IDX;
1180 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1183 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1192 bc_vec_pop_all(vec);
1195 #if ENABLE_FEATURE_BC_SIGNALS
1196 if (bb_got_signal) { // ^C was pressed
1198 bb_got_signal = 0; // resets G_interrupt to zero
1200 ? "\ninterrupt (type \"quit\" to exit)\n"
1201 : "\ninterrupt (type \"q\" to exit)\n"
1205 if (G.ttyin && !G_posix)
1206 fputs(prompt, stderr);
1208 #if ENABLE_FEATURE_BC_SIGNALS
1214 #if ENABLE_FEATURE_BC_SIGNALS
1215 // Both conditions appear simultaneously, check both just in case
1216 if (errno == EINTR || bb_got_signal) {
1223 quit(); // this emits error message
1225 // Note: EOF does not append '\n', therefore:
1226 // printf 'print 123\n' | bc - works
1227 // printf 'print 123' | bc - fails (syntax error)
1231 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1234 // Bad chars on this line, ignore entire line
1235 bc_error("illegal character 0x%02x", i);
1239 bc_vec_push(vec, &c);
1240 } while (i != '\n');
1241 } while (bad_chars);
1243 bc_vec_pushByte(vec, '\0');
1245 return BC_STATUS_SUCCESS;
1248 static char* bc_read_file(const char *path)
1251 size_t size = ((size_t) -1);
1254 buf = xmalloc_open_read_close(path, &size);
1256 for (i = 0; i < size; ++i) {
1258 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1270 static void bc_args(int argc, char **argv)
1276 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1277 opts = getopt32long(argv, "xwvsqli",
1278 "extended-register\0" No_argument "x"
1279 "warn\0" No_argument "w"
1280 "version\0" No_argument "v"
1281 "standard\0" No_argument "s"
1282 "quiet\0" No_argument "q"
1283 "mathlib\0" No_argument "l"
1284 "interactive\0" No_argument "i"
1287 opts = getopt32(argv, "xwvsqli");
1289 if (getenv("POSIXLY_CORRECT"))
1290 option_mask32 |= BC_FLAG_S;
1292 if (opts & BC_FLAG_V) bc_vm_info();
1293 // should not be necessary, getopt32() handles this??
1294 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1296 for (i = optind; i < argc; ++i)
1297 bc_vec_push(&G.files, argv + i);
1300 static void bc_num_setToZero(BcNum *n, size_t scale)
1307 static void bc_num_zero(BcNum *n)
1309 bc_num_setToZero(n, 0);
1312 static void bc_num_one(BcNum *n)
1314 bc_num_setToZero(n, 0);
1319 static void bc_num_ten(BcNum *n)
1321 bc_num_setToZero(n, 0);
1327 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1331 for (i = 0; i < len; ++i) {
1332 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1339 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1343 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1344 return BC_NUM_NEG(i + 1, c < 0);
1347 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1349 size_t i, min, a_int, b_int, diff;
1350 BcDig *max_num, *min_num;
1351 bool a_max, neg = false;
1354 if (a == b) return 0;
1355 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1356 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1366 a_int = BC_NUM_INT(a);
1367 b_int = BC_NUM_INT(b);
1369 a_max = (a->rdx > b->rdx);
1371 if (a_int != 0) return (ssize_t) a_int;
1375 diff = a->rdx - b->rdx;
1376 max_num = a->num + diff;
1381 diff = b->rdx - a->rdx;
1382 max_num = b->num + diff;
1386 cmp = bc_num_compare(max_num, min_num, b_int + min);
1387 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1389 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1390 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1396 static void bc_num_truncate(BcNum *n, size_t places)
1398 if (places == 0) return;
1404 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1408 static void bc_num_extend(BcNum *n, size_t places)
1410 size_t len = n->len + places;
1414 if (n->cap < len) bc_num_expand(n, len);
1416 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1417 memset(n->num, 0, sizeof(BcDig) * places);
1424 static void bc_num_clean(BcNum *n)
1426 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1429 else if (n->len < n->rdx)
1433 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1436 bc_num_extend(n, scale - n->rdx);
1438 bc_num_truncate(n, n->rdx - scale);
1441 if (n->len != 0) n->neg = !neg1 != !neg2;
1444 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1449 b->len = n->len - idx;
1451 a->rdx = b->rdx = 0;
1453 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1454 memcpy(a->num, n->num, idx * sizeof(BcDig));
1465 static BcStatus bc_num_shift(BcNum *n, size_t places)
1467 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1468 if (places + n->len > BC_MAX_NUM)
1469 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1471 if (n->rdx >= places)
1474 bc_num_extend(n, places - n->rdx);
1480 return BC_STATUS_SUCCESS;
1483 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1492 return bc_num_div(&one, a, b, scale);
1495 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1497 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1498 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1501 // Because this function doesn't need to use scale (per the bc spec),
1502 // I am hijacking it to say whether it's doing an add or a subtract.
1506 if (sub && c->len) c->neg = !c->neg;
1507 return BC_STATUS_SUCCESS;
1509 else if (b->len == 0) {
1511 return BC_STATUS_SUCCESS;
1515 c->rdx = BC_MAX(a->rdx, b->rdx);
1516 min_rdx = BC_MIN(a->rdx, b->rdx);
1519 if (a->rdx > b->rdx) {
1520 diff = a->rdx - b->rdx;
1522 ptr_a = a->num + diff;
1526 diff = b->rdx - a->rdx;
1529 ptr_b = b->num + diff;
1532 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1535 a_int = BC_NUM_INT(a);
1536 b_int = BC_NUM_INT(b);
1538 if (a_int > b_int) {
1549 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1550 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1552 ptr_c[i] = (BcDig)(in % 10);
1555 for (; i < max + min_rdx; ++i, ++c->len) {
1556 in = ((int) ptr[i]) + carry;
1558 ptr_c[i] = (BcDig)(in % 10);
1561 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1563 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1566 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1569 BcNum *minuend, *subtrahend;
1571 bool aneg, bneg, neg;
1573 // Because this function doesn't need to use scale (per the bc spec),
1574 // I am hijacking it to say whether it's doing an add or a subtract.
1578 if (sub && c->len) c->neg = !c->neg;
1579 return BC_STATUS_SUCCESS;
1581 else if (b->len == 0) {
1583 return BC_STATUS_SUCCESS;
1588 a->neg = b->neg = false;
1590 cmp = bc_num_cmp(a, b);
1596 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1597 return BC_STATUS_SUCCESS;
1606 if (sub) neg = !neg;
1611 bc_num_copy(c, minuend);
1614 if (c->rdx < subtrahend->rdx) {
1615 bc_num_extend(c, subtrahend->rdx - c->rdx);
1619 start = c->rdx - subtrahend->rdx;
1621 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1625 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1628 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1633 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1634 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1635 bool aone = BC_NUM_ONE(a);
1637 if (a->len == 0 || b->len == 0) {
1639 return BC_STATUS_SUCCESS;
1641 else if (aone || BC_NUM_ONE(b)) {
1642 bc_num_copy(c, aone ? b : a);
1643 return BC_STATUS_SUCCESS;
1646 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1647 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1649 bc_num_expand(c, a->len + b->len + 1);
1651 memset(c->num, 0, sizeof(BcDig) * c->cap);
1652 c->len = carry = len = 0;
1654 for (i = 0; i < b->len; ++i) {
1656 for (j = 0; j < a->len; ++j) {
1657 int in = (int) c->num[i + j];
1658 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1660 c->num[i + j] = (BcDig)(in % 10);
1663 c->num[i + j] += (BcDig) carry;
1664 len = BC_MAX(len, i + j + !!carry);
1670 return BC_STATUS_SUCCESS;
1673 bc_num_init(&l1, max);
1674 bc_num_init(&h1, max);
1675 bc_num_init(&l2, max);
1676 bc_num_init(&h2, max);
1677 bc_num_init(&m1, max);
1678 bc_num_init(&m2, max);
1679 bc_num_init(&z0, max);
1680 bc_num_init(&z1, max);
1681 bc_num_init(&z2, max);
1682 bc_num_init(&temp, max + max);
1684 bc_num_split(a, max2, &l1, &h1);
1685 bc_num_split(b, max2, &l2, &h2);
1687 s = bc_num_add(&h1, &l1, &m1, 0);
1689 s = bc_num_add(&h2, &l2, &m2, 0);
1692 s = bc_num_k(&h1, &h2, &z0);
1694 s = bc_num_k(&m1, &m2, &z1);
1696 s = bc_num_k(&l1, &l2, &z2);
1699 s = bc_num_sub(&z1, &z0, &temp, 0);
1701 s = bc_num_sub(&temp, &z2, &z1, 0);
1704 s = bc_num_shift(&z0, max2 * 2);
1706 s = bc_num_shift(&z1, max2);
1708 s = bc_num_add(&z0, &z1, &temp, 0);
1710 s = bc_num_add(&temp, &z2, c, 0);
1726 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1730 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1732 scale = BC_MAX(scale, a->rdx);
1733 scale = BC_MAX(scale, b->rdx);
1734 scale = BC_MIN(a->rdx + b->rdx, scale);
1735 maxrdx = BC_MAX(maxrdx, scale);
1737 bc_num_init(&cpa, a->len);
1738 bc_num_init(&cpb, b->len);
1740 bc_num_copy(&cpa, a);
1741 bc_num_copy(&cpb, b);
1742 cpa.neg = cpb.neg = false;
1744 s = bc_num_shift(&cpa, maxrdx);
1746 s = bc_num_shift(&cpb, maxrdx);
1748 s = bc_num_k(&cpa, &cpb, c);
1752 bc_num_expand(c, c->len + maxrdx);
1754 if (c->len < maxrdx) {
1755 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1760 bc_num_retireMul(c, scale, a->neg, b->neg);
1768 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1770 BcStatus s = BC_STATUS_SUCCESS;
1777 return bc_error("divide by zero");
1778 else if (a->len == 0) {
1779 bc_num_setToZero(c, scale);
1780 return BC_STATUS_SUCCESS;
1782 else if (BC_NUM_ONE(b)) {
1784 bc_num_retireMul(c, scale, a->neg, b->neg);
1785 return BC_STATUS_SUCCESS;
1788 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1789 bc_num_copy(&cp, a);
1793 bc_num_expand(&cp, len + 2);
1794 bc_num_extend(&cp, len - cp.len);
1797 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1799 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1801 if (b->rdx == b->len) {
1802 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1806 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1808 // We want an extra zero in front to make things simpler.
1809 cp.num[cp.len++] = 0;
1812 bc_num_expand(c, cp.len);
1815 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1820 for (i = end - 1; !s && i < end; --i) {
1822 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1823 bc_num_subArrays(n, p, len);
1827 bc_num_retireMul(c, scale, a->neg, b->neg);
1830 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1833 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1834 BcNum *restrict d, size_t scale, size_t ts)
1841 return bc_error("divide by zero");
1844 bc_num_setToZero(d, ts);
1845 return BC_STATUS_SUCCESS;
1848 bc_num_init(&temp, d->cap);
1849 bc_num_d(a, b, c, scale);
1851 if (scale != 0) scale = ts;
1853 s = bc_num_m(c, b, &temp, scale);
1855 s = bc_num_sub(a, &temp, d, scale);
1858 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1861 bc_num_retireMul(d, ts, a->neg, b->neg);
1869 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1873 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1875 bc_num_init(&c1, len);
1876 s = bc_num_r(a, b, &c1, c, scale, ts);
1882 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1884 BcStatus s = BC_STATUS_SUCCESS;
1887 size_t i, powrdx, resrdx;
1890 if (b->rdx) return bc_error("non integer number");
1894 return BC_STATUS_SUCCESS;
1896 else if (a->len == 0) {
1897 bc_num_setToZero(c, scale);
1898 return BC_STATUS_SUCCESS;
1900 else if (BC_NUM_ONE(b)) {
1904 s = bc_num_inv(a, c, scale);
1911 s = bc_num_ulong(b, &pow);
1914 bc_num_init(©, a->len);
1915 bc_num_copy(©, a);
1917 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1921 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1923 s = bc_num_mul(©, ©, ©, powrdx);
1927 bc_num_copy(c, ©);
1929 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1932 s = bc_num_mul(©, ©, ©, powrdx);
1937 s = bc_num_mul(c, ©, c, resrdx);
1943 s = bc_num_inv(c, c, scale);
1947 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1949 // We can't use bc_num_clean() here.
1950 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1951 if (zero) bc_num_setToZero(c, scale);
1958 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1959 BcNumBinaryOp op, size_t req)
1962 BcNum num2, *ptr_a, *ptr_b;
1967 memcpy(ptr_a, c, sizeof(BcNum));
1976 memcpy(ptr_b, c, sizeof(BcNum));
1984 bc_num_init(c, req);
1986 bc_num_expand(c, req);
1988 s = op(ptr_a, ptr_b, c, scale);
1990 if (init) bc_num_free(&num2);
1995 static bool bc_num_strValid(const char *val, size_t base)
1998 bool small, radix = false;
1999 size_t i, len = strlen(val);
2001 if (!len) return true;
2004 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2006 for (i = 0; i < len; ++i) {
2012 if (radix) return false;
2018 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2025 static void bc_num_parseDecimal(BcNum *n, const char *val)
2031 for (i = 0; val[i] == '0'; ++i);
2038 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2039 bc_num_expand(n, len);
2042 ptr = strchr(val, '.');
2046 n->rdx = (size_t)((val + len) - (ptr + 1));
2049 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2050 n->num[n->len] = val[i] - '0';
2054 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2057 BcNum temp, mult, result;
2061 size_t i, digits, len = strlen(val);
2065 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2068 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2069 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2071 for (i = 0; i < len; ++i) {
2074 if (c == '.') break;
2076 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2078 s = bc_num_mul(n, base, &mult, 0);
2079 if (s) goto int_err;
2080 bc_num_ulong2num(&temp, v);
2081 s = bc_num_add(&mult, &temp, n, 0);
2082 if (s) goto int_err;
2087 if (c == 0) goto int_err;
2090 bc_num_init(&result, base->len);
2091 bc_num_zero(&result);
2094 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2099 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2101 s = bc_num_mul(&result, base, &result, 0);
2103 bc_num_ulong2num(&temp, v);
2104 s = bc_num_add(&result, &temp, &result, 0);
2106 s = bc_num_mul(&mult, base, &mult, 0);
2110 s = bc_num_div(&result, &mult, &result, digits);
2112 s = bc_num_add(n, &result, n, digits);
2116 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2122 bc_num_free(&result);
2128 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2130 if (*nchars == line_len - 1) {
2138 static void bc_num_printChar(size_t num, size_t width, bool radix,
2139 size_t *nchars, size_t line_len)
2141 (void) radix, (void) line_len;
2142 bb_putchar((char) num);
2143 *nchars = *nchars + width;
2147 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2148 size_t *nchars, size_t line_len)
2152 bc_num_printNewline(nchars, line_len);
2153 bb_putchar(radix ? '.' : ' ');
2156 bc_num_printNewline(nchars, line_len);
2157 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2160 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2162 bc_num_printNewline(nchars, line_len);
2165 bb_putchar(((char) dig) + '0');
2169 static void bc_num_printHex(size_t num, size_t width, bool radix,
2170 size_t *nchars, size_t line_len)
2173 bc_num_printNewline(nchars, line_len);
2178 bc_num_printNewline(nchars, line_len);
2179 bb_putchar(bb_hexdigits_upcase[num]);
2180 *nchars = *nchars + width;
2183 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2185 size_t i, rdx = n->rdx - 1;
2187 if (n->neg) bb_putchar('-');
2188 (*nchars) += n->neg;
2190 for (i = n->len - 1; i < n->len; --i)
2191 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2194 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2195 size_t *nchars, size_t len, BcNumDigitOp print)
2199 BcNum intp, fracp, digit, frac_len;
2200 unsigned long dig, *ptr;
2205 print(0, width, false, nchars, len);
2206 return BC_STATUS_SUCCESS;
2209 bc_vec_init(&stack, sizeof(long), NULL);
2210 bc_num_init(&intp, n->len);
2211 bc_num_init(&fracp, n->rdx);
2212 bc_num_init(&digit, width);
2213 bc_num_init(&frac_len, BC_NUM_INT(n));
2214 bc_num_copy(&intp, n);
2215 bc_num_one(&frac_len);
2217 bc_num_truncate(&intp, intp.rdx);
2218 s = bc_num_sub(n, &intp, &fracp, 0);
2221 while (intp.len != 0) {
2222 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2224 s = bc_num_ulong(&digit, &dig);
2226 bc_vec_push(&stack, &dig);
2229 for (i = 0; i < stack.len; ++i) {
2230 ptr = bc_vec_item_rev(&stack, i);
2231 print(*ptr, width, false, nchars, len);
2234 if (!n->rdx) goto err;
2236 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2237 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2239 s = bc_num_ulong(&fracp, &dig);
2241 bc_num_ulong2num(&intp, dig);
2242 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2244 print(dig, width, radix, nchars, len);
2245 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2250 bc_num_free(&frac_len);
2251 bc_num_free(&digit);
2252 bc_num_free(&fracp);
2254 bc_vec_free(&stack);
2258 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2259 size_t *nchars, size_t line_len)
2266 if (neg) bb_putchar('-');
2271 if (base_t <= BC_NUM_MAX_IBASE) {
2273 print = bc_num_printHex;
2276 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2277 print = bc_num_printDigits;
2280 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2287 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2289 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2293 static void bc_num_init(BcNum *n, size_t req)
2295 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2296 memset(n, 0, sizeof(BcNum));
2297 n->num = xmalloc(req);
2301 static void bc_num_expand(BcNum *n, size_t req)
2303 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2305 n->num = xrealloc(n->num, req);
2310 static void bc_num_free(void *num)
2312 free(((BcNum *) num)->num);
2315 static void bc_num_copy(BcNum *d, BcNum *s)
2318 bc_num_expand(d, s->cap);
2322 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2326 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2329 if (!bc_num_strValid(val, base_t))
2330 return bc_error("bad number string");
2333 bc_num_parseDecimal(n, val);
2335 bc_num_parseBase(n, val, base);
2337 return BC_STATUS_SUCCESS;
2340 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2341 size_t *nchars, size_t line_len)
2343 BcStatus s = BC_STATUS_SUCCESS;
2345 bc_num_printNewline(nchars, line_len);
2351 else if (base_t == 10)
2352 bc_num_printDecimal(n, nchars, line_len);
2354 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2364 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2369 if (n->neg) return bc_error("negative number");
2371 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2373 unsigned long prev = *result, powprev = pow;
2375 *result += ((unsigned long) n->num[i]) * pow;
2378 if (*result < prev || pow < powprev)
2379 return bc_error("overflow");
2382 return BC_STATUS_SUCCESS;
2385 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2393 if (val == 0) return;
2395 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2396 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2399 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2401 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2403 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2406 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2408 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2410 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2413 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2415 size_t req = BC_NUM_MREQ(a, b, scale);
2416 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2419 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2421 size_t req = BC_NUM_MREQ(a, b, scale);
2422 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2425 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2427 size_t req = BC_NUM_MREQ(a, b, scale);
2428 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2431 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2433 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2436 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2439 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2440 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2441 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2443 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2444 bc_num_expand(b, req);
2447 bc_num_setToZero(b, scale);
2448 return BC_STATUS_SUCCESS;
2451 return bc_error("negative number");
2452 else if (BC_NUM_ONE(a)) {
2454 bc_num_extend(b, scale);
2455 return BC_STATUS_SUCCESS;
2458 scale = BC_MAX(scale, a->rdx) + 1;
2459 len = a->len + scale;
2461 bc_num_init(&num1, len);
2462 bc_num_init(&num2, len);
2463 bc_num_init(&half, BC_NUM_DEF_SIZE);
2469 bc_num_init(&f, len);
2470 bc_num_init(&fprime, len);
2476 pow = BC_NUM_INT(a);
2485 pow -= 2 - (pow & 1);
2487 bc_num_extend(x0, pow);
2489 // Make sure to move the radix back.
2493 x0->rdx = digs = digs1 = 0;
2495 len = BC_NUM_INT(x0) + resrdx - 1;
2497 while (cmp != 0 || digs < len) {
2499 s = bc_num_div(a, x0, &f, resrdx);
2501 s = bc_num_add(x0, &f, &fprime, resrdx);
2503 s = bc_num_mul(&fprime, &half, x1, resrdx);
2506 cmp = bc_num_cmp(x1, x0);
2507 digs = x1->len - (unsigned long long) llabs(cmp);
2509 if (cmp == cmp2 && digs == digs1)
2514 resrdx += times > 4;
2527 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2530 bc_num_free(&fprime);
2538 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2544 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2547 memcpy(&num2, c, sizeof(BcNum));
2549 bc_num_init(c, len);
2554 bc_num_expand(c, len);
2557 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2559 if (init) bc_num_free(&num2);
2565 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2568 BcNum base, exp, two, temp;
2571 return bc_error("divide by zero");
2572 if (a->rdx || b->rdx || c->rdx)
2573 return bc_error("non integer number");
2575 return bc_error("negative number");
2577 bc_num_expand(d, c->len);
2578 bc_num_init(&base, c->len);
2579 bc_num_init(&exp, b->len);
2580 bc_num_init(&two, BC_NUM_DEF_SIZE);
2581 bc_num_init(&temp, b->len);
2587 s = bc_num_rem(a, c, &base, 0);
2589 bc_num_copy(&exp, b);
2591 while (exp.len != 0) {
2593 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2596 if (BC_NUM_ONE(&temp)) {
2597 s = bc_num_mul(d, &base, &temp, 0);
2599 s = bc_num_rem(&temp, c, d, 0);
2603 s = bc_num_mul(&base, &base, &temp, 0);
2605 s = bc_num_rem(&temp, c, &base, 0);
2618 static int bc_id_cmp(const void *e1, const void *e2)
2620 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2623 static void bc_id_free(void *id)
2625 free(((BcId *) id)->name);
2628 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2633 for (i = 0; i < f->autos.len; ++i) {
2634 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2635 return bc_error("function parameter or auto var has the same name as another");
2641 bc_vec_push(&f->autos, &a);
2643 return BC_STATUS_SUCCESS;
2646 static void bc_func_init(BcFunc *f)
2648 bc_char_vec_init(&f->code);
2649 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2650 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2654 static void bc_func_free(void *func)
2656 BcFunc *f = (BcFunc *) func;
2657 bc_vec_free(&f->code);
2658 bc_vec_free(&f->autos);
2659 bc_vec_free(&f->labels);
2662 static void bc_array_init(BcVec *a, bool nums)
2665 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2667 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2668 bc_array_expand(a, 1);
2671 static void bc_array_copy(BcVec *d, const BcVec *s)
2676 bc_vec_expand(d, s->cap);
2679 for (i = 0; i < s->len; ++i) {
2680 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2681 bc_num_init(dnum, snum->len);
2682 bc_num_copy(dnum, snum);
2686 static void bc_array_expand(BcVec *a, size_t len)
2690 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2691 while (len > a->len) {
2692 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2693 bc_vec_push(a, &data.n);
2697 while (len > a->len) {
2698 bc_array_init(&data.v, true);
2699 bc_vec_push(a, &data.v);
2704 static void bc_string_free(void *string)
2706 free(*((char **) string));
2710 static void bc_result_copy(BcResult *d, BcResult *src)
2716 case BC_RESULT_TEMP:
2717 case BC_RESULT_IBASE:
2718 case BC_RESULT_SCALE:
2719 case BC_RESULT_OBASE:
2721 bc_num_init(&d->d.n, src->d.n.len);
2722 bc_num_copy(&d->d.n, &src->d.n);
2727 case BC_RESULT_ARRAY:
2728 case BC_RESULT_ARRAY_ELEM:
2730 d->d.id.name = xstrdup(src->d.id.name);
2734 case BC_RESULT_CONSTANT:
2735 case BC_RESULT_LAST:
2739 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2746 static void bc_result_free(void *result)
2748 BcResult *r = (BcResult *) result;
2752 case BC_RESULT_TEMP:
2753 case BC_RESULT_IBASE:
2754 case BC_RESULT_SCALE:
2755 case BC_RESULT_OBASE:
2757 bc_num_free(&r->d.n);
2762 case BC_RESULT_ARRAY:
2763 case BC_RESULT_ARRAY_ELEM:
2777 static void bc_lex_lineComment(BcLex *l)
2779 l->t.t = BC_LEX_WHITESPACE;
2780 while (l->i < l->len && l->buf[l->i++] != '\n');
2784 static void bc_lex_whitespace(BcLex *l)
2787 l->t.t = BC_LEX_WHITESPACE;
2788 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2791 static BcStatus bc_lex_number(BcLex *l, char start)
2793 const char *buf = l->buf + l->i;
2794 size_t len, hits = 0, bslashes = 0, i = 0, j;
2796 bool last_pt, pt = start == '.';
2799 l->t.t = BC_LEX_NUMBER;
2801 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2802 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2816 len = i + !last_pt - bslashes * 2;
2817 if (len > BC_MAX_NUM)
2818 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2820 bc_vec_pop_all(&l->t.v);
2821 bc_vec_expand(&l->t.v, len + 1);
2822 bc_vec_push(&l->t.v, &start);
2824 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2828 // If we have hit a backslash, skip it. We don't have
2829 // to check for a newline because it's guaranteed.
2830 if (hits < bslashes && c == '\\') {
2836 bc_vec_push(&l->t.v, &c);
2839 bc_vec_pushByte(&l->t.v, '\0');
2842 return BC_STATUS_SUCCESS;
2845 static BcStatus bc_lex_name(BcLex *l)
2848 const char *buf = l->buf + l->i - 1;
2851 l->t.t = BC_LEX_NAME;
2853 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2855 if (i > BC_MAX_STRING)
2856 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2857 bc_vec_string(&l->t.v, i, buf);
2859 // Increment the index. We minus 1 because it has already been incremented.
2862 return BC_STATUS_SUCCESS;
2865 static void bc_lex_init(BcLex *l, BcLexNext next)
2868 bc_char_vec_init(&l->t.v);
2871 static void bc_lex_free(BcLex *l)
2873 bc_vec_free(&l->t.v);
2876 static void bc_lex_file(BcLex *l, const char *file)
2883 static BcStatus bc_lex_next(BcLex *l)
2888 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2890 l->line += l->newline;
2891 l->t.t = BC_LEX_EOF;
2893 l->newline = (l->i == l->len);
2894 if (l->newline) return BC_STATUS_SUCCESS;
2896 // Loop until failure or we don't have whitespace. This
2897 // is so the parser doesn't get inundated with whitespace.
2900 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2905 static BcStatus bc_lex_text(BcLex *l, const char *text)
2909 l->len = strlen(text);
2910 l->t.t = l->t.last = BC_LEX_INVALID;
2911 return bc_lex_next(l);
2915 static BcStatus bc_lex_identifier(BcLex *l)
2919 const char *buf = l->buf + l->i - 1;
2921 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2923 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2925 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2927 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2929 if (!bc_lex_kws[i].posix) {
2930 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
2934 // We minus 1 because the index has already been incremented.
2936 return BC_STATUS_SUCCESS;
2943 if (l->t.v.len - 1 > 1)
2944 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2949 static BcStatus bc_lex_string(BcLex *l)
2951 size_t len, nls = 0, i = l->i;
2954 l->t.t = BC_LEX_STR;
2956 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2960 return bc_error("string end could not be found");
2964 if (len > BC_MAX_STRING)
2965 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2966 bc_vec_string(&l->t.v, len, l->buf + l->i);
2971 return BC_STATUS_SUCCESS;
2974 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2976 if (l->buf[l->i] == '=') {
2984 static BcStatus bc_lex_comment(BcLex *l)
2987 const char *buf = l->buf;
2989 l->t.t = BC_LEX_WHITESPACE;
3002 return bc_error("comment end could not be found");
3011 return BC_STATUS_SUCCESS;
3014 static BcStatus bc_lex_token(BcLex *l)
3016 BcStatus s = BC_STATUS_SUCCESS;
3017 char c = l->buf[l->i++], c2;
3019 // This is the workhorse of the lexer.
3026 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3036 bc_lex_whitespace(l);
3042 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3044 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3045 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3054 s = bc_lex_string(l);
3060 s = bc_posix_error("POSIX does not allow '#' script comments");
3063 bc_lex_lineComment(l);
3070 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3079 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3083 l->t.t = BC_LEX_OP_BOOL_AND;
3086 l->t.t = BC_LEX_INVALID;
3087 s = bc_error("bad character '%c'", '&');
3096 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3102 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3111 l->t.t = BC_LEX_OP_INC;
3114 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3120 l->t.t = BC_LEX_COMMA;
3129 l->t.t = BC_LEX_OP_DEC;
3132 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3138 if (isdigit(l->buf[l->i]))
3139 s = bc_lex_number(l, c);
3141 l->t.t = BC_LEX_KEY_LAST;
3142 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3151 s = bc_lex_comment(l);
3153 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3174 s = bc_lex_number(l, c);
3180 l->t.t = BC_LEX_SCOLON;
3186 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3192 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3198 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3205 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3211 if (l->buf[l->i] == '\n') {
3212 l->t.t = BC_LEX_WHITESPACE;
3216 s = bc_error("bad character '%c'", c);
3222 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3253 s = bc_lex_identifier(l);
3260 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3269 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3273 l->t.t = BC_LEX_OP_BOOL_OR;
3276 l->t.t = BC_LEX_INVALID;
3277 s = bc_error("bad character '%c'", c);
3285 l->t.t = BC_LEX_INVALID;
3286 s = bc_error("bad character '%c'", c);
3296 static BcStatus dc_lex_register(BcLex *l)
3298 BcStatus s = BC_STATUS_SUCCESS;
3300 if (isspace(l->buf[l->i - 1])) {
3301 bc_lex_whitespace(l);
3304 s = bc_error("extended register");
3309 bc_vec_pop_all(&l->t.v);
3310 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3311 bc_vec_pushByte(&l->t.v, '\0');
3312 l->t.t = BC_LEX_NAME;
3318 static BcStatus dc_lex_string(BcLex *l)
3320 size_t depth = 1, nls = 0, i = l->i;
3323 l->t.t = BC_LEX_STR;
3324 bc_vec_pop_all(&l->t.v);
3326 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3328 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3329 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3332 if (depth) bc_vec_push(&l->t.v, &c);
3337 return bc_error("string end could not be found");
3340 bc_vec_pushByte(&l->t.v, '\0');
3341 if (i - l->i > BC_MAX_STRING)
3342 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3347 return BC_STATUS_SUCCESS;
3350 static BcStatus dc_lex_token(BcLex *l)
3352 BcStatus s = BC_STATUS_SUCCESS;
3353 char c = l->buf[l->i++], c2;
3356 for (i = 0; i < dc_lex_regs_len; ++i) {
3357 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3360 if (c >= '%' && c <= '~' &&
3361 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3366 // This is the workhorse of the lexer.
3371 l->t.t = BC_LEX_EOF;
3382 l->newline = (c == '\n');
3383 bc_lex_whitespace(l);
3392 l->t.t = BC_LEX_OP_REL_NE;
3394 l->t.t = BC_LEX_OP_REL_LE;
3396 l->t.t = BC_LEX_OP_REL_GE;
3398 return bc_error("bad character '%c'", c);
3406 bc_lex_lineComment(l);
3412 if (isdigit(l->buf[l->i]))
3413 s = bc_lex_number(l, c);
3415 s = bc_error("bad character '%c'", c);
3436 s = bc_lex_number(l, c);
3442 s = dc_lex_string(l);
3448 l->t.t = BC_LEX_INVALID;
3449 s = bc_error("bad character '%c'", c);
3458 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3460 bc_program_addFunc(name, idx);
3461 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3464 static void bc_parse_pushName(BcParse *p, char *name)
3466 size_t i = 0, len = strlen(name);
3468 for (; i < len; ++i) bc_parse_push(p, name[i]);
3469 bc_parse_push(p, BC_PARSE_STREND);
3474 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3476 unsigned char amt, i, nums[sizeof(size_t)];
3478 for (amt = 0; idx; ++amt) {
3479 nums[amt] = (char) idx;
3480 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3483 bc_parse_push(p, amt);
3484 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3487 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3489 char *num = xstrdup(p->l.t.v.v);
3490 size_t idx = G.prog.consts.len;
3492 bc_vec_push(&G.prog.consts, &num);
3494 bc_parse_push(p, BC_INST_NUM);
3495 bc_parse_pushIndex(p, idx);
3498 (*prev) = BC_INST_NUM;
3501 static BcStatus bc_parse_text(BcParse *p, const char *text)
3505 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3507 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3508 p->l.t.t = BC_LEX_INVALID;
3511 if (!BC_PARSE_CAN_EXEC(p))
3512 return bc_error("file is not executable");
3515 return bc_lex_text(&p->l, text);
3518 // Called when bc/dc_parse_parse() detects a failure,
3519 // resets parsing structures.
3520 static void bc_parse_reset(BcParse *p)
3522 if (p->fidx != BC_PROG_MAIN) {
3523 p->func->nparams = 0;
3524 bc_vec_pop_all(&p->func->code);
3525 bc_vec_pop_all(&p->func->autos);
3526 bc_vec_pop_all(&p->func->labels);
3528 bc_parse_updateFunc(p, BC_PROG_MAIN);
3532 p->l.t.t = BC_LEX_EOF;
3533 p->auto_part = (p->nbraces = 0);
3535 bc_vec_npop(&p->flags, p->flags.len - 1);
3536 bc_vec_pop_all(&p->exits);
3537 bc_vec_pop_all(&p->conds);
3538 bc_vec_pop_all(&p->ops);
3543 static void bc_parse_free(BcParse *p)
3545 bc_vec_free(&p->flags);
3546 bc_vec_free(&p->exits);
3547 bc_vec_free(&p->conds);
3548 bc_vec_free(&p->ops);
3552 static void bc_parse_create(BcParse *p, size_t func,
3553 BcParseParse parse, BcLexNext next)
3555 memset(p, 0, sizeof(BcParse));
3557 bc_lex_init(&p->l, next);
3558 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3559 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3560 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3561 bc_vec_pushByte(&p->flags, 0);
3562 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3565 // p->auto_part = p->nbraces = 0; - already is
3566 bc_parse_updateFunc(p, func);
3570 static BcStatus bc_parse_else(BcParse *p);
3571 static BcStatus bc_parse_stmt(BcParse *p);
3573 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3574 size_t *nexprs, bool next)
3576 BcStatus s = BC_STATUS_SUCCESS;
3578 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3579 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3581 while (p->ops.len > start) {
3583 t = BC_PARSE_TOP_OP(p);
3584 if (t == BC_LEX_LPAREN) break;
3586 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3587 if (l >= r && (l != r || !left)) break;
3589 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3590 bc_vec_pop(&p->ops);
3591 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3594 bc_vec_push(&p->ops, &type);
3595 if (next) s = bc_lex_next(&p->l);
3600 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3604 if (p->ops.len <= ops_bgn)
3605 return bc_error("bad expression");
3606 top = BC_PARSE_TOP_OP(p);
3608 while (top != BC_LEX_LPAREN) {
3610 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3612 bc_vec_pop(&p->ops);
3613 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3615 if (p->ops.len <= ops_bgn)
3616 return bc_error("bad expression");
3617 top = BC_PARSE_TOP_OP(p);
3620 bc_vec_pop(&p->ops);
3622 return bc_lex_next(&p->l);
3625 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3631 s = bc_lex_next(&p->l);
3634 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3636 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3637 s = bc_parse_expr(p, flags, bc_parse_next_param);
3640 comma = p->l.t.t == BC_LEX_COMMA;
3642 s = bc_lex_next(&p->l);
3647 if (comma) return bc_error("bad token");
3648 bc_parse_push(p, BC_INST_CALL);
3649 bc_parse_pushIndex(p, nparams);
3651 return BC_STATUS_SUCCESS;
3654 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3657 BcId entry, *entry_ptr;
3662 s = bc_parse_params(p, flags);
3665 if (p->l.t.t != BC_LEX_RPAREN) {
3666 s = bc_error("bad token");
3670 idx = bc_map_index(&G.prog.fn_map, &entry);
3672 if (idx == BC_VEC_INVALID_IDX) {
3673 name = xstrdup(entry.name);
3674 bc_parse_addFunc(p, name, &idx);
3675 idx = bc_map_index(&G.prog.fn_map, &entry);
3681 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3682 bc_parse_pushIndex(p, entry_ptr->idx);
3684 return bc_lex_next(&p->l);
3691 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3696 name = xstrdup(p->l.t.v.v);
3697 s = bc_lex_next(&p->l);
3700 if (p->l.t.t == BC_LEX_LBRACKET) {
3702 s = bc_lex_next(&p->l);
3705 if (p->l.t.t == BC_LEX_RBRACKET) {
3707 if (!(flags & BC_PARSE_ARRAY)) {
3708 s = bc_error("bad expression");
3712 *type = BC_INST_ARRAY;
3716 *type = BC_INST_ARRAY_ELEM;
3718 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3719 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3723 s = bc_lex_next(&p->l);
3725 bc_parse_push(p, *type);
3726 bc_parse_pushName(p, name);
3728 else if (p->l.t.t == BC_LEX_LPAREN) {
3730 if (flags & BC_PARSE_NOCALL) {
3731 s = bc_error("bad token");
3735 *type = BC_INST_CALL;
3736 s = bc_parse_call(p, name, flags);
3739 *type = BC_INST_VAR;
3740 bc_parse_push(p, BC_INST_VAR);
3741 bc_parse_pushName(p, name);
3751 static BcStatus bc_parse_read(BcParse *p)
3755 s = bc_lex_next(&p->l);
3757 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3759 s = bc_lex_next(&p->l);
3761 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3763 bc_parse_push(p, BC_INST_READ);
3765 return bc_lex_next(&p->l);
3768 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3773 s = bc_lex_next(&p->l);
3775 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3777 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3779 s = bc_lex_next(&p->l);
3782 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3785 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3787 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3788 bc_parse_push(p, *prev);
3790 return bc_lex_next(&p->l);
3793 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3797 s = bc_lex_next(&p->l);
3800 if (p->l.t.t != BC_LEX_LPAREN) {
3801 *type = BC_INST_SCALE;
3802 bc_parse_push(p, BC_INST_SCALE);
3803 return BC_STATUS_SUCCESS;
3806 *type = BC_INST_SCALE_FUNC;
3807 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3809 s = bc_lex_next(&p->l);
3812 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3814 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3815 bc_parse_push(p, BC_INST_SCALE_FUNC);
3817 return bc_lex_next(&p->l);
3820 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3821 size_t *nexprs, uint8_t flags)
3826 BcInst etype = *prev;
3828 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3829 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3830 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3832 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3833 bc_parse_push(p, inst);
3834 s = bc_lex_next(&p->l);
3838 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3841 s = bc_lex_next(&p->l);
3845 // Because we parse the next part of the expression
3846 // right here, we need to increment this.
3847 *nexprs = *nexprs + 1;
3853 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3857 case BC_LEX_KEY_IBASE:
3858 case BC_LEX_KEY_LAST:
3859 case BC_LEX_KEY_OBASE:
3861 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3862 s = bc_lex_next(&p->l);
3866 case BC_LEX_KEY_SCALE:
3868 s = bc_lex_next(&p->l);
3870 if (p->l.t.t == BC_LEX_LPAREN)
3871 s = bc_error("bad token");
3873 bc_parse_push(p, BC_INST_SCALE);
3879 s = bc_error("bad token");
3884 if (!s) bc_parse_push(p, inst);
3890 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3891 bool rparen, size_t *nexprs)
3895 BcInst etype = *prev;
3897 s = bc_lex_next(&p->l);
3900 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3901 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3904 *prev = BC_PARSE_TOKEN_INST(type);
3906 // We can just push onto the op stack because this is the largest
3907 // precedence operator that gets pushed. Inc/dec does not.
3908 if (type != BC_LEX_OP_MINUS)
3909 bc_vec_push(&p->ops, &type);
3911 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3916 static BcStatus bc_parse_string(BcParse *p, char inst)
3918 char *str = xstrdup(p->l.t.v.v);
3920 bc_parse_push(p, BC_INST_STR);
3921 bc_parse_pushIndex(p, G.prog.strs.len);
3922 bc_vec_push(&G.prog.strs, &str);
3923 bc_parse_push(p, inst);
3925 return bc_lex_next(&p->l);
3928 static BcStatus bc_parse_print(BcParse *p)
3934 s = bc_lex_next(&p->l);
3939 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3940 return bc_error("bad print statement");
3942 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3944 if (type == BC_LEX_STR)
3945 s = bc_parse_string(p, BC_INST_PRINT_POP);
3947 s = bc_parse_expr(p, 0, bc_parse_next_print);
3949 bc_parse_push(p, BC_INST_PRINT_POP);
3954 comma = p->l.t.t == BC_LEX_COMMA;
3955 if (comma) s = bc_lex_next(&p->l);
3960 if (comma) return bc_error("bad token");
3962 return bc_lex_next(&p->l);
3965 static BcStatus bc_parse_return(BcParse *p)
3971 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
3973 s = bc_lex_next(&p->l);
3977 paren = t == BC_LEX_LPAREN;
3979 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3980 bc_parse_push(p, BC_INST_RET0);
3983 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3984 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3987 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3988 bc_parse_push(p, BC_INST_RET0);
3989 s = bc_lex_next(&p->l);
3993 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3994 s = bc_posix_error("POSIX requires parentheses around return expressions");
3998 bc_parse_push(p, BC_INST_RET);
4004 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4006 BcStatus s = BC_STATUS_SUCCESS;
4008 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4009 return bc_error("bad token");
4013 if (p->l.t.t == BC_LEX_RBRACE) {
4014 if (!p->nbraces) return bc_error("bad token");
4016 s = bc_lex_next(&p->l);
4020 return bc_error("bad token");
4023 if (BC_PARSE_IF(p)) {
4027 while (p->l.t.t == BC_LEX_NLINE) {
4028 s = bc_lex_next(&p->l);
4032 bc_vec_pop(&p->flags);
4034 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4035 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4037 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4039 else if (BC_PARSE_ELSE(p)) {
4044 bc_vec_pop(&p->flags);
4046 ip = bc_vec_top(&p->exits);
4047 label = bc_vec_item(&p->func->labels, ip->idx);
4048 *label = p->func->code.len;
4050 bc_vec_pop(&p->exits);
4052 else if (BC_PARSE_FUNC_INNER(p)) {
4053 bc_parse_push(p, BC_INST_RET0);
4054 bc_parse_updateFunc(p, BC_PROG_MAIN);
4055 bc_vec_pop(&p->flags);
4059 BcInstPtr *ip = bc_vec_top(&p->exits);
4060 size_t *label = bc_vec_top(&p->conds);
4062 bc_parse_push(p, BC_INST_JUMP);
4063 bc_parse_pushIndex(p, *label);
4065 label = bc_vec_item(&p->func->labels, ip->idx);
4066 *label = p->func->code.len;
4068 bc_vec_pop(&p->flags);
4069 bc_vec_pop(&p->exits);
4070 bc_vec_pop(&p->conds);
4076 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4078 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4079 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4080 flags |= BC_PARSE_FLAG_BODY;
4081 bc_vec_push(&p->flags, &flags);
4084 static void bc_parse_noElse(BcParse *p)
4088 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4090 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4092 ip = bc_vec_top(&p->exits);
4093 label = bc_vec_item(&p->func->labels, ip->idx);
4094 *label = p->func->code.len;
4096 bc_vec_pop(&p->exits);
4099 static BcStatus bc_parse_if(BcParse *p)
4104 s = bc_lex_next(&p->l);
4106 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4108 s = bc_lex_next(&p->l);
4110 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4112 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4114 s = bc_lex_next(&p->l);
4116 bc_parse_push(p, BC_INST_JUMP_ZERO);
4118 ip.idx = p->func->labels.len;
4119 ip.func = ip.len = 0;
4121 bc_parse_pushIndex(p, ip.idx);
4122 bc_vec_push(&p->exits, &ip);
4123 bc_vec_push(&p->func->labels, &ip.idx);
4124 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4126 return BC_STATUS_SUCCESS;
4129 static BcStatus bc_parse_else(BcParse *p)
4133 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4135 ip.idx = p->func->labels.len;
4136 ip.func = ip.len = 0;
4138 bc_parse_push(p, BC_INST_JUMP);
4139 bc_parse_pushIndex(p, ip.idx);
4143 bc_vec_push(&p->exits, &ip);
4144 bc_vec_push(&p->func->labels, &ip.idx);
4145 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4147 return bc_lex_next(&p->l);
4150 static BcStatus bc_parse_while(BcParse *p)
4155 s = bc_lex_next(&p->l);
4157 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4158 s = bc_lex_next(&p->l);
4161 ip.idx = p->func->labels.len;
4163 bc_vec_push(&p->func->labels, &p->func->code.len);
4164 bc_vec_push(&p->conds, &ip.idx);
4166 ip.idx = p->func->labels.len;
4170 bc_vec_push(&p->exits, &ip);
4171 bc_vec_push(&p->func->labels, &ip.idx);
4173 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4175 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4176 s = bc_lex_next(&p->l);
4179 bc_parse_push(p, BC_INST_JUMP_ZERO);
4180 bc_parse_pushIndex(p, ip.idx);
4181 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4183 return BC_STATUS_SUCCESS;
4186 static BcStatus bc_parse_for(BcParse *p)
4190 size_t cond_idx, exit_idx, body_idx, update_idx;
4192 s = bc_lex_next(&p->l);
4194 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4195 s = bc_lex_next(&p->l);
4198 if (p->l.t.t != BC_LEX_SCOLON)
4199 s = bc_parse_expr(p, 0, bc_parse_next_for);
4201 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4204 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4205 s = bc_lex_next(&p->l);
4208 cond_idx = p->func->labels.len;
4209 update_idx = cond_idx + 1;
4210 body_idx = update_idx + 1;
4211 exit_idx = body_idx + 1;
4213 bc_vec_push(&p->func->labels, &p->func->code.len);
4215 if (p->l.t.t != BC_LEX_SCOLON)
4216 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4218 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4221 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4223 s = bc_lex_next(&p->l);
4226 bc_parse_push(p, BC_INST_JUMP_ZERO);
4227 bc_parse_pushIndex(p, exit_idx);
4228 bc_parse_push(p, BC_INST_JUMP);
4229 bc_parse_pushIndex(p, body_idx);
4231 ip.idx = p->func->labels.len;
4233 bc_vec_push(&p->conds, &update_idx);
4234 bc_vec_push(&p->func->labels, &p->func->code.len);
4236 if (p->l.t.t != BC_LEX_RPAREN)
4237 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4239 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4243 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4244 bc_parse_push(p, BC_INST_JUMP);
4245 bc_parse_pushIndex(p, cond_idx);
4246 bc_vec_push(&p->func->labels, &p->func->code.len);
4252 bc_vec_push(&p->exits, &ip);
4253 bc_vec_push(&p->func->labels, &ip.idx);
4255 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4257 return BC_STATUS_SUCCESS;
4260 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4266 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4268 if (type == BC_LEX_KEY_BREAK) {
4270 if (p->exits.len == 0) return bc_error("bad token");
4272 i = p->exits.len - 1;
4273 ip = bc_vec_item(&p->exits, i);
4275 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4276 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4281 i = *((size_t *) bc_vec_top(&p->conds));
4283 bc_parse_push(p, BC_INST_JUMP);
4284 bc_parse_pushIndex(p, i);
4286 s = bc_lex_next(&p->l);
4289 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4290 return bc_error("bad token");
4292 return bc_lex_next(&p->l);
4295 static BcStatus bc_parse_func(BcParse *p)
4298 bool var, comma = false;
4302 s = bc_lex_next(&p->l);
4304 if (p->l.t.t != BC_LEX_NAME)
4305 return bc_error("bad function definition");
4307 name = xstrdup(p->l.t.v.v);
4308 bc_parse_addFunc(p, name, &p->fidx);
4310 s = bc_lex_next(&p->l);
4312 if (p->l.t.t != BC_LEX_LPAREN)
4313 return bc_error("bad function definition");
4314 s = bc_lex_next(&p->l);
4317 while (p->l.t.t != BC_LEX_RPAREN) {
4319 if (p->l.t.t != BC_LEX_NAME)
4320 return bc_error("bad function definition");
4324 name = xstrdup(p->l.t.v.v);
4325 s = bc_lex_next(&p->l);
4328 var = p->l.t.t != BC_LEX_LBRACKET;
4332 s = bc_lex_next(&p->l);
4335 if (p->l.t.t != BC_LEX_RBRACKET) {
4336 s = bc_error("bad function definition");
4340 s = bc_lex_next(&p->l);
4344 comma = p->l.t.t == BC_LEX_COMMA;
4346 s = bc_lex_next(&p->l);
4350 s = bc_func_insert(p->func, name, var);
4354 if (comma) return bc_error("bad function definition");
4356 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4357 bc_parse_startBody(p, flags);
4359 s = bc_lex_next(&p->l);
4362 if (p->l.t.t != BC_LEX_LBRACE)
4363 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4372 static BcStatus bc_parse_auto(BcParse *p)
4375 bool comma, var, one;
4378 if (!p->auto_part) return bc_error("bad token");
4379 s = bc_lex_next(&p->l);
4382 p->auto_part = comma = false;
4383 one = p->l.t.t == BC_LEX_NAME;
4385 while (p->l.t.t == BC_LEX_NAME) {
4387 name = xstrdup(p->l.t.v.v);
4388 s = bc_lex_next(&p->l);
4391 var = p->l.t.t != BC_LEX_LBRACKET;
4394 s = bc_lex_next(&p->l);
4397 if (p->l.t.t != BC_LEX_RBRACKET) {
4398 s = bc_error("bad function definition");
4402 s = bc_lex_next(&p->l);
4406 comma = p->l.t.t == BC_LEX_COMMA;
4408 s = bc_lex_next(&p->l);
4412 s = bc_func_insert(p->func, name, var);
4416 if (comma) return bc_error("bad function definition");
4417 if (!one) return bc_error("no auto variable found");
4419 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4420 return bc_error("bad token");
4422 return bc_lex_next(&p->l);
4429 static BcStatus bc_parse_body(BcParse *p, bool brace)
4431 BcStatus s = BC_STATUS_SUCCESS;
4432 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4434 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4436 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4438 if (!brace) return bc_error("bad token");
4439 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4441 if (!p->auto_part) {
4442 s = bc_parse_auto(p);
4446 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4449 s = bc_parse_stmt(p);
4450 if (!s && !brace) s = bc_parse_endBody(p, false);
4456 static BcStatus bc_parse_stmt(BcParse *p)
4458 BcStatus s = BC_STATUS_SUCCESS;
4464 return bc_lex_next(&p->l);
4467 case BC_LEX_KEY_ELSE:
4469 p->auto_part = false;
4475 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4478 s = bc_lex_next(&p->l);
4481 return bc_parse_body(p, true);
4484 case BC_LEX_KEY_AUTO:
4486 return bc_parse_auto(p);
4491 p->auto_part = false;
4493 if (BC_PARSE_IF_END(p)) {
4495 return BC_STATUS_SUCCESS;
4497 else if (BC_PARSE_BODY(p))
4498 return bc_parse_body(p, false);
4508 case BC_LEX_OP_MINUS:
4509 case BC_LEX_OP_BOOL_NOT:
4513 case BC_LEX_KEY_IBASE:
4514 case BC_LEX_KEY_LAST:
4515 case BC_LEX_KEY_LENGTH:
4516 case BC_LEX_KEY_OBASE:
4517 case BC_LEX_KEY_READ:
4518 case BC_LEX_KEY_SCALE:
4519 case BC_LEX_KEY_SQRT:
4521 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4525 case BC_LEX_KEY_ELSE:
4527 s = bc_parse_else(p);
4533 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4539 s = bc_parse_endBody(p, true);
4545 s = bc_parse_string(p, BC_INST_PRINT_STR);
4549 case BC_LEX_KEY_BREAK:
4550 case BC_LEX_KEY_CONTINUE:
4552 s = bc_parse_loopExit(p, p->l.t.t);
4556 case BC_LEX_KEY_FOR:
4558 s = bc_parse_for(p);
4562 case BC_LEX_KEY_HALT:
4564 bc_parse_push(p, BC_INST_HALT);
4565 s = bc_lex_next(&p->l);
4575 case BC_LEX_KEY_LIMITS:
4577 // "limits" is a compile-time command,
4578 // the output is produced at _parse time_.
4579 s = bc_lex_next(&p->l);
4581 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4582 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4583 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4584 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4585 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4586 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4587 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4588 printf("Number of vars = %lu\n", BC_MAX_VARS);
4592 case BC_LEX_KEY_PRINT:
4594 s = bc_parse_print(p);
4598 case BC_LEX_KEY_QUIT:
4600 // "quit" is a compile-time command. For example,
4601 // "if (0 == 1) quit" terminates when parsing the statement,
4602 // not when it is executed
4606 case BC_LEX_KEY_RETURN:
4608 s = bc_parse_return(p);
4612 case BC_LEX_KEY_WHILE:
4614 s = bc_parse_while(p);
4620 s = bc_error("bad token");
4628 static BcStatus bc_parse_parse(BcParse *p)
4632 if (p->l.t.t == BC_LEX_EOF)
4633 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4634 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4635 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4636 s = bc_parse_func(p);
4639 s = bc_parse_stmt(p);
4641 if (s || G_interrupt) {
4643 s = BC_STATUS_FAILURE;
4649 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4651 BcStatus s = BC_STATUS_SUCCESS;
4652 BcInst prev = BC_INST_PRINT;
4653 BcLexType top, t = p->l.t.t;
4654 size_t nexprs = 0, ops_bgn = p->ops.len;
4655 uint32_t i, nparens, nrelops;
4656 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4658 paren_first = p->l.t.t == BC_LEX_LPAREN;
4659 nparens = nrelops = 0;
4660 paren_expr = rprn = done = get_token = assign = false;
4663 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4669 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4670 rprn = get_token = bin_last = false;
4674 case BC_LEX_OP_MINUS:
4676 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4677 rprn = get_token = false;
4678 bin_last = prev == BC_INST_MINUS;
4682 case BC_LEX_OP_ASSIGN_POWER:
4683 case BC_LEX_OP_ASSIGN_MULTIPLY:
4684 case BC_LEX_OP_ASSIGN_DIVIDE:
4685 case BC_LEX_OP_ASSIGN_MODULUS:
4686 case BC_LEX_OP_ASSIGN_PLUS:
4687 case BC_LEX_OP_ASSIGN_MINUS:
4688 case BC_LEX_OP_ASSIGN:
4690 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4691 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4692 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4694 s = bc_error("bad assignment:"
4695 " left side must be scale,"
4696 " ibase, obase, last, var,"
4703 case BC_LEX_OP_POWER:
4704 case BC_LEX_OP_MULTIPLY:
4705 case BC_LEX_OP_DIVIDE:
4706 case BC_LEX_OP_MODULUS:
4707 case BC_LEX_OP_PLUS:
4708 case BC_LEX_OP_REL_EQ:
4709 case BC_LEX_OP_REL_LE:
4710 case BC_LEX_OP_REL_GE:
4711 case BC_LEX_OP_REL_NE:
4712 case BC_LEX_OP_REL_LT:
4713 case BC_LEX_OP_REL_GT:
4714 case BC_LEX_OP_BOOL_NOT:
4715 case BC_LEX_OP_BOOL_OR:
4716 case BC_LEX_OP_BOOL_AND:
4718 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4719 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4721 return bc_error("bad expression");
4724 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4725 prev = BC_PARSE_TOKEN_INST(t);
4726 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4727 rprn = get_token = false;
4728 bin_last = t != BC_LEX_OP_BOOL_NOT;
4735 if (BC_PARSE_LEAF(prev, rprn))
4736 return bc_error("bad expression");
4738 paren_expr = rprn = bin_last = false;
4740 bc_vec_push(&p->ops, &t);
4747 if (bin_last || prev == BC_INST_BOOL_NOT)
4748 return bc_error("bad expression");
4751 s = BC_STATUS_SUCCESS;
4756 else if (!paren_expr)
4757 return BC_STATUS_PARSE_EMPTY_EXP;
4760 paren_expr = rprn = true;
4761 get_token = bin_last = false;
4763 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4770 if (BC_PARSE_LEAF(prev, rprn))
4771 return bc_error("bad expression");
4773 rprn = get_token = bin_last = false;
4774 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4782 if (BC_PARSE_LEAF(prev, rprn))
4783 return bc_error("bad expression");
4784 bc_parse_number(p, &prev, &nexprs);
4785 paren_expr = get_token = true;
4786 rprn = bin_last = false;
4791 case BC_LEX_KEY_IBASE:
4792 case BC_LEX_KEY_LAST:
4793 case BC_LEX_KEY_OBASE:
4795 if (BC_PARSE_LEAF(prev, rprn))
4796 return bc_error("bad expression");
4797 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4798 bc_parse_push(p, (char) prev);
4800 paren_expr = get_token = true;
4801 rprn = bin_last = false;
4807 case BC_LEX_KEY_LENGTH:
4808 case BC_LEX_KEY_SQRT:
4810 if (BC_PARSE_LEAF(prev, rprn))
4811 return bc_error("bad expression");
4812 s = bc_parse_builtin(p, t, flags, &prev);
4814 rprn = get_token = bin_last = false;
4820 case BC_LEX_KEY_READ:
4822 if (BC_PARSE_LEAF(prev, rprn))
4823 return bc_error("bad expression");
4824 else if (flags & BC_PARSE_NOREAD)
4825 s = bc_error("read() call inside of a read() call");
4827 s = bc_parse_read(p);
4830 rprn = get_token = bin_last = false;
4832 prev = BC_INST_READ;
4837 case BC_LEX_KEY_SCALE:
4839 if (BC_PARSE_LEAF(prev, rprn))
4840 return bc_error("bad expression");
4841 s = bc_parse_scale(p, &prev, flags);
4843 rprn = get_token = bin_last = false;
4845 prev = BC_INST_SCALE;
4852 s = bc_error("bad token");
4857 if (!s && get_token) s = bc_lex_next(&p->l);
4861 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4863 while (p->ops.len > ops_bgn) {
4865 top = BC_PARSE_TOP_OP(p);
4866 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4868 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4869 return bc_error("bad expression");
4871 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4873 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4874 bc_vec_pop(&p->ops);
4877 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4878 return bc_error("bad expression");
4880 for (i = 0; i < next.len; ++i)
4881 if (t == next.tokens[i])
4883 return bc_error("bad expression");
4886 if (!(flags & BC_PARSE_REL) && nrelops) {
4887 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4890 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4891 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4895 if (flags & BC_PARSE_PRINT) {
4896 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4897 bc_parse_push(p, BC_INST_POP);
4903 static void bc_parse_init(BcParse *p, size_t func)
4905 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4908 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4910 return bc_parse_expr(p, flags, bc_parse_next_read);
4915 static BcStatus dc_parse_register(BcParse *p)
4920 s = bc_lex_next(&p->l);
4922 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
4924 name = xstrdup(p->l.t.v.v);
4925 bc_parse_pushName(p, name);
4930 static BcStatus dc_parse_string(BcParse *p)
4932 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4933 size_t idx, len = G.prog.strs.len;
4935 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4938 str = xstrdup(p->l.t.v.v);
4939 bc_parse_push(p, BC_INST_STR);
4940 bc_parse_pushIndex(p, len);
4941 bc_vec_push(&G.prog.strs, &str);
4942 bc_parse_addFunc(p, name, &idx);
4944 return bc_lex_next(&p->l);
4947 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4951 bc_parse_push(p, inst);
4953 s = dc_parse_register(p);
4958 bc_parse_push(p, BC_INST_SWAP);
4959 bc_parse_push(p, BC_INST_ASSIGN);
4960 bc_parse_push(p, BC_INST_POP);
4963 return bc_lex_next(&p->l);
4966 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4970 bc_parse_push(p, inst);
4971 bc_parse_push(p, BC_INST_EXEC_COND);
4973 s = dc_parse_register(p);
4976 s = bc_lex_next(&p->l);
4979 if (p->l.t.t == BC_LEX_ELSE) {
4980 s = dc_parse_register(p);
4982 s = bc_lex_next(&p->l);
4985 bc_parse_push(p, BC_PARSE_STREND);
4990 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4992 BcStatus s = BC_STATUS_SUCCESS;
4995 bool assign, get_token = false;
4999 case BC_LEX_OP_REL_EQ:
5000 case BC_LEX_OP_REL_LE:
5001 case BC_LEX_OP_REL_GE:
5002 case BC_LEX_OP_REL_NE:
5003 case BC_LEX_OP_REL_LT:
5004 case BC_LEX_OP_REL_GT:
5006 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5013 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5019 s = dc_parse_string(p);
5026 if (t == BC_LEX_NEG) {
5027 s = bc_lex_next(&p->l);
5029 if (p->l.t.t != BC_LEX_NUMBER)
5030 return bc_error("bad token");
5033 bc_parse_number(p, &prev, &p->nbraces);
5035 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5041 case BC_LEX_KEY_READ:
5043 if (flags & BC_PARSE_NOREAD)
5044 s = bc_error("read() call inside of a read() call");
5046 bc_parse_push(p, BC_INST_READ);
5051 case BC_LEX_OP_ASSIGN:
5052 case BC_LEX_STORE_PUSH:
5054 assign = t == BC_LEX_OP_ASSIGN;
5055 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5056 s = dc_parse_mem(p, inst, true, assign);
5061 case BC_LEX_LOAD_POP:
5063 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5064 s = dc_parse_mem(p, inst, true, false);
5068 case BC_LEX_STORE_IBASE:
5069 case BC_LEX_STORE_SCALE:
5070 case BC_LEX_STORE_OBASE:
5072 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5073 s = dc_parse_mem(p, inst, false, true);
5079 s = bc_error("bad token");
5085 if (!s && get_token) s = bc_lex_next(&p->l);
5090 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5092 BcStatus s = BC_STATUS_SUCCESS;
5096 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5098 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5100 inst = dc_parse_insts[t];
5102 if (inst != BC_INST_INVALID) {
5103 bc_parse_push(p, inst);
5104 s = bc_lex_next(&p->l);
5107 s = dc_parse_token(p, t, flags);
5110 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5111 bc_parse_push(p, BC_INST_POP_EXEC);
5116 static BcStatus dc_parse_parse(BcParse *p)
5120 if (p->l.t.t == BC_LEX_EOF)
5121 s = bc_error("end of file");
5123 s = dc_parse_expr(p, 0);
5125 if (s || G_interrupt) {
5127 s = BC_STATUS_FAILURE;
5133 static void dc_parse_init(BcParse *p, size_t func)
5135 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5139 static void common_parse_init(BcParse *p, size_t func)
5142 bc_parse_init(p, func);
5144 dc_parse_init(p, func);
5148 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5151 return bc_parse_expression(p, flags);
5153 return dc_parse_expr(p, flags);
5157 static BcVec* bc_program_search(char *id, bool var)
5165 v = var ? &G.prog.vars : &G.prog.arrs;
5166 map = var ? &G.prog.var_map : &G.prog.arr_map;
5170 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5173 bc_array_init(&data.v, var);
5174 bc_vec_push(v, &data.v);
5177 ptr = bc_vec_item(map, i);
5178 if (new) ptr->name = xstrdup(e.name);
5179 return bc_vec_item(v, ptr->idx);
5182 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5184 BcStatus s = BC_STATUS_SUCCESS;
5189 case BC_RESULT_TEMP:
5190 case BC_RESULT_IBASE:
5191 case BC_RESULT_SCALE:
5192 case BC_RESULT_OBASE:
5198 case BC_RESULT_CONSTANT:
5200 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5201 size_t base_t, len = strlen(*str);
5204 bc_num_init(&r->d.n, len);
5206 hex = hex && len == 1;
5207 base = hex ? &G.prog.hexb : &G.prog.ib;
5208 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5209 s = bc_num_parse(&r->d.n, *str, base, base_t);
5212 bc_num_free(&r->d.n);
5217 r->t = BC_RESULT_TEMP;
5223 case BC_RESULT_ARRAY:
5224 case BC_RESULT_ARRAY_ELEM:
5228 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5230 if (r->t == BC_RESULT_ARRAY_ELEM) {
5232 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5233 *num = bc_vec_item(v, r->d.id.idx);
5236 *num = bc_vec_top(v);
5241 case BC_RESULT_LAST:
5243 *num = &G.prog.last;
5257 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5258 BcResult **r, BcNum **rn, bool assign)
5262 BcResultType lt, rt;
5264 if (!BC_PROG_STACK(&G.prog.results, 2))
5265 return bc_error("stack has too few elements");
5267 *r = bc_vec_item_rev(&G.prog.results, 0);
5268 *l = bc_vec_item_rev(&G.prog.results, 1);
5272 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5274 s = bc_program_num(*l, ln, false);
5276 s = bc_program_num(*r, rn, hex);
5279 // We run this again under these conditions in case any vector has been
5280 // reallocated out from under the BcNums or arrays we had.
5281 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5282 s = bc_program_num(*l, ln, false);
5286 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5287 return bc_error("variable is wrong type");
5288 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5289 return bc_error("variable is wrong type");
5294 static void bc_program_binOpRetire(BcResult *r)
5296 r->t = BC_RESULT_TEMP;
5297 bc_vec_pop(&G.prog.results);
5298 bc_vec_pop(&G.prog.results);
5299 bc_vec_push(&G.prog.results, r);
5302 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5306 if (!BC_PROG_STACK(&G.prog.results, 1))
5307 return bc_error("stack has too few elements");
5308 *r = bc_vec_top(&G.prog.results);
5310 s = bc_program_num(*r, n, false);
5313 if (!BC_PROG_NUM((*r), (*n)))
5314 return bc_error("variable is wrong type");
5319 static void bc_program_retire(BcResult *r, BcResultType t)
5322 bc_vec_pop(&G.prog.results);
5323 bc_vec_push(&G.prog.results, r);
5326 static BcStatus bc_program_op(char inst)
5329 BcResult *opd1, *opd2, res;
5330 BcNum *n1, *n2 = NULL;
5332 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5334 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5336 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5338 bc_program_binOpRetire(&res);
5343 bc_num_free(&res.d.n);
5347 static BcStatus bc_program_read(void)
5354 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5356 for (i = 0; i < G.prog.stack.len; ++i) {
5357 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5358 if (ip_ptr->func == BC_PROG_READ)
5359 return bc_error("read() call inside of a read() call");
5362 bc_vec_pop_all(&f->code);
5363 bc_char_vec_init(&buf);
5365 s = bc_read_line(&buf, "read> ");
5368 common_parse_init(&parse, BC_PROG_READ);
5369 bc_lex_file(&parse.l, bc_program_stdin_name);
5371 s = bc_parse_text(&parse, buf.v);
5372 if (s) goto exec_err;
5373 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5374 if (s) goto exec_err;
5376 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5377 s = bc_error("bad read() expression");
5381 ip.func = BC_PROG_READ;
5383 ip.len = G.prog.results.len;
5385 // Update this pointer, just in case.
5386 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5388 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5389 bc_vec_push(&G.prog.stack, &ip);
5392 bc_parse_free(&parse);
5398 static size_t bc_program_index(char *code, size_t *bgn)
5400 char amt = code[(*bgn)++], i = 0;
5403 for (; i < amt; ++i, ++(*bgn))
5404 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5409 static char *bc_program_name(char *code, size_t *bgn)
5412 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5414 s = xmalloc(ptr - str + 1);
5417 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5425 static void bc_program_printString(const char *str, size_t *nchars)
5427 size_t i, len = strlen(str);
5436 for (i = 0; i < len; ++i, ++(*nchars)) {
5440 if (c != '\\' || i == len - 1)
5500 // Just print the backslash and following character.
5511 static BcStatus bc_program_print(char inst, size_t idx)
5513 BcStatus s = BC_STATUS_SUCCESS;
5518 bool pop = inst != BC_INST_PRINT;
5520 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5521 return bc_error("stack has too few elements");
5523 r = bc_vec_item_rev(&G.prog.results, idx);
5524 s = bc_program_num(r, &num, false);
5527 if (BC_PROG_NUM(r, num)) {
5528 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5529 if (!s) bc_num_copy(&G.prog.last, num);
5533 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5534 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5536 if (inst == BC_INST_PRINT_STR) {
5537 for (i = 0, len = strlen(str); i < len; ++i) {
5540 if (c == '\n') G.prog.nchars = SIZE_MAX;
5545 bc_program_printString(str, &G.prog.nchars);
5546 if (inst == BC_INST_PRINT) bb_putchar('\n');
5550 if (!s && pop) bc_vec_pop(&G.prog.results);
5555 static BcStatus bc_program_negate(void)
5561 s = bc_program_prep(&ptr, &num);
5564 bc_num_init(&res.d.n, num->len);
5565 bc_num_copy(&res.d.n, num);
5566 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5568 bc_program_retire(&res, BC_RESULT_TEMP);
5573 static BcStatus bc_program_logical(char inst)
5576 BcResult *opd1, *opd2, res;
5581 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5583 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5585 if (inst == BC_INST_BOOL_AND)
5586 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5587 else if (inst == BC_INST_BOOL_OR)
5588 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5591 cmp = bc_num_cmp(n1, n2);
5595 case BC_INST_REL_EQ:
5601 case BC_INST_REL_LE:
5607 case BC_INST_REL_GE:
5613 case BC_INST_REL_NE:
5619 case BC_INST_REL_LT:
5625 case BC_INST_REL_GT:
5633 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5635 bc_program_binOpRetire(&res);
5641 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5647 memset(&n2, 0, sizeof(BcNum));
5648 n2.rdx = res.d.id.idx = r->d.id.idx;
5649 res.t = BC_RESULT_STR;
5652 if (!BC_PROG_STACK(&G.prog.results, 2))
5653 return bc_error("stack has too few elements");
5655 bc_vec_pop(&G.prog.results);
5658 bc_vec_pop(&G.prog.results);
5660 bc_vec_push(&G.prog.results, &res);
5661 bc_vec_push(v, &n2);
5663 return BC_STATUS_SUCCESS;
5667 static BcStatus bc_program_copyToVar(char *name, bool var)
5674 if (!BC_PROG_STACK(&G.prog.results, 1))
5675 return bc_error("stack has too few elements");
5677 ptr = bc_vec_top(&G.prog.results);
5678 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5679 return bc_error("variable is wrong type");
5680 v = bc_program_search(name, var);
5683 if (ptr->t == BC_RESULT_STR && !var)
5684 return bc_error("variable is wrong type");
5685 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5688 s = bc_program_num(ptr, &n, false);
5691 // Do this once more to make sure that pointers were not invalidated.
5692 v = bc_program_search(name, var);
5695 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5696 bc_num_copy(&r.d.n, n);
5699 bc_array_init(&r.d.v, true);
5700 bc_array_copy(&r.d.v, (BcVec *) n);
5703 bc_vec_push(v, &r.d);
5704 bc_vec_pop(&G.prog.results);
5709 static BcStatus bc_program_assign(char inst)
5712 BcResult *left, *right, res;
5713 BcNum *l = NULL, *r = NULL;
5714 unsigned long val, max;
5715 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5717 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5720 ib = left->t == BC_RESULT_IBASE;
5721 sc = left->t == BC_RESULT_SCALE;
5725 if (right->t == BC_RESULT_STR) {
5729 if (left->t != BC_RESULT_VAR)
5730 return bc_error("variable is wrong type");
5731 v = bc_program_search(left->d.id.name, true);
5733 return bc_program_assignStr(right, v, false);
5737 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5738 return bc_error("bad assignment:"
5739 " left side must be scale,"
5740 " ibase, obase, last, var,"
5745 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5746 return bc_error("divide by zero");
5751 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5758 if (ib || sc || left->t == BC_RESULT_OBASE) {
5759 static const char *const msg[] = {
5760 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5761 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5762 "?1", //BC_RESULT_LAST
5763 "?2", //BC_RESULT_CONSTANT
5764 "?3", //BC_RESULT_ONE
5765 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5769 s = bc_num_ulong(l, &val);
5772 s = left->t - BC_RESULT_IBASE;
5775 ptr = &G.prog.scale;
5778 if (val < BC_NUM_MIN_BASE)
5779 return bc_error(msg[s]);
5780 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5781 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5785 return bc_error(msg[s]);
5787 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5789 *ptr = (size_t) val;
5790 s = BC_STATUS_SUCCESS;
5793 bc_num_init(&res.d.n, l->len);
5794 bc_num_copy(&res.d.n, l);
5795 bc_program_binOpRetire(&res);
5801 #define bc_program_pushVar(code, bgn, pop, copy) \
5802 bc_program_pushVar(code, bgn)
5803 // for bc, 'pop' and 'copy' are always false
5805 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5806 bool pop, bool copy)
5808 BcStatus s = BC_STATUS_SUCCESS;
5810 char *name = bc_program_name(code, bgn);
5812 r.t = BC_RESULT_VAR;
5817 BcVec *v = bc_program_search(name, true);
5818 BcNum *num = bc_vec_top(v);
5822 if (!BC_PROG_STACK(v, 2 - copy)) {
5824 return bc_error("stack has too few elements");
5830 if (!BC_PROG_STR(num)) {
5832 r.t = BC_RESULT_TEMP;
5834 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5835 bc_num_copy(&r.d.n, num);
5838 r.t = BC_RESULT_STR;
5839 r.d.id.idx = num->rdx;
5842 if (!copy) bc_vec_pop(v);
5847 bc_vec_push(&G.prog.results, &r);
5852 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5855 BcStatus s = BC_STATUS_SUCCESS;
5859 r.d.id.name = bc_program_name(code, bgn);
5861 if (inst == BC_INST_ARRAY) {
5862 r.t = BC_RESULT_ARRAY;
5863 bc_vec_push(&G.prog.results, &r);
5870 s = bc_program_prep(&operand, &num);
5872 s = bc_num_ulong(num, &temp);
5875 if (temp > BC_MAX_DIM) {
5876 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5880 r.d.id.idx = (size_t) temp;
5881 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5885 if (s) free(r.d.id.name);
5890 static BcStatus bc_program_incdec(char inst)
5893 BcResult *ptr, res, copy;
5897 s = bc_program_prep(&ptr, &num);
5900 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5901 copy.t = BC_RESULT_TEMP;
5902 bc_num_init(©.d.n, num->len);
5903 bc_num_copy(©.d.n, num);
5906 res.t = BC_RESULT_ONE;
5907 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5908 BC_INST_ASSIGN_PLUS :
5909 BC_INST_ASSIGN_MINUS;
5911 bc_vec_push(&G.prog.results, &res);
5912 bc_program_assign(inst);
5914 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5915 bc_vec_pop(&G.prog.results);
5916 bc_vec_push(&G.prog.results, ©);
5922 static BcStatus bc_program_call(char *code, size_t *idx)
5924 BcStatus s = BC_STATUS_SUCCESS;
5926 size_t i, nparams = bc_program_index(code, idx);
5933 ip.func = bc_program_index(code, idx);
5934 func = bc_vec_item(&G.prog.fns, ip.func);
5936 if (func->code.len == 0) {
5937 return bc_error("undefined function");
5939 if (nparams != func->nparams) {
5940 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5942 ip.len = G.prog.results.len - nparams;
5944 for (i = 0; i < nparams; ++i) {
5946 a = bc_vec_item(&func->autos, nparams - 1 - i);
5947 arg = bc_vec_top(&G.prog.results);
5949 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5950 return bc_error("variable is wrong type");
5952 s = bc_program_copyToVar(a->name, a->idx);
5956 for (; i < func->autos.len; ++i) {
5959 a = bc_vec_item(&func->autos, i);
5960 v = bc_program_search(a->name, a->idx);
5963 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5964 bc_vec_push(v, ¶m.n);
5967 bc_array_init(¶m.v, true);
5968 bc_vec_push(v, ¶m.v);
5972 bc_vec_push(&G.prog.stack, &ip);
5974 return BC_STATUS_SUCCESS;
5977 static BcStatus bc_program_return(char inst)
5983 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5985 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5986 return bc_error("stack has too few elements");
5988 f = bc_vec_item(&G.prog.fns, ip->func);
5989 res.t = BC_RESULT_TEMP;
5991 if (inst == BC_INST_RET) {
5994 BcResult *operand = bc_vec_top(&G.prog.results);
5996 s = bc_program_num(operand, &num, false);
5998 bc_num_init(&res.d.n, num->len);
5999 bc_num_copy(&res.d.n, num);
6002 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6003 bc_num_zero(&res.d.n);
6006 // We need to pop arguments as well, so this takes that into account.
6007 for (i = 0; i < f->autos.len; ++i) {
6010 BcId *a = bc_vec_item(&f->autos, i);
6012 v = bc_program_search(a->name, a->idx);
6016 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6017 bc_vec_push(&G.prog.results, &res);
6018 bc_vec_pop(&G.prog.stack);
6020 return BC_STATUS_SUCCESS;
6024 static unsigned long bc_program_scale(BcNum *n)
6026 return (unsigned long) n->rdx;
6029 static unsigned long bc_program_len(BcNum *n)
6031 unsigned long len = n->len;
6034 if (n->rdx != n->len) return len;
6035 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6040 static BcStatus bc_program_builtin(char inst)
6046 bool len = inst == BC_INST_LENGTH;
6048 if (!BC_PROG_STACK(&G.prog.results, 1))
6049 return bc_error("stack has too few elements");
6050 opnd = bc_vec_top(&G.prog.results);
6052 s = bc_program_num(opnd, &num, false);
6056 if (!BC_PROG_NUM(opnd, num) && !len)
6057 return bc_error("variable is wrong type");
6060 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6062 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6064 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6065 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6069 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6072 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6074 str = bc_vec_item(&G.prog.strs, idx);
6075 bc_num_ulong2num(&res.d.n, strlen(*str));
6079 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6080 bc_num_ulong2num(&res.d.n, f(num));
6083 bc_program_retire(&res, BC_RESULT_TEMP);
6089 static BcStatus bc_program_divmod(void)
6092 BcResult *opd1, *opd2, res, res2;
6093 BcNum *n1, *n2 = NULL;
6095 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6098 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6099 bc_num_init(&res2.d.n, n2->len);
6101 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6104 bc_program_binOpRetire(&res2);
6105 res.t = BC_RESULT_TEMP;
6106 bc_vec_push(&G.prog.results, &res);
6111 bc_num_free(&res2.d.n);
6112 bc_num_free(&res.d.n);
6116 static BcStatus bc_program_modexp(void)
6119 BcResult *r1, *r2, *r3, res;
6120 BcNum *n1, *n2, *n3;
6122 if (!BC_PROG_STACK(&G.prog.results, 3))
6123 return bc_error("stack has too few elements");
6124 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6127 r1 = bc_vec_item_rev(&G.prog.results, 2);
6128 s = bc_program_num(r1, &n1, false);
6130 if (!BC_PROG_NUM(r1, n1))
6131 return bc_error("variable is wrong type");
6133 // Make sure that the values have their pointers updated, if necessary.
6134 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6136 if (r1->t == r2->t) {
6137 s = bc_program_num(r2, &n2, false);
6141 if (r1->t == r3->t) {
6142 s = bc_program_num(r3, &n3, false);
6147 bc_num_init(&res.d.n, n3->len);
6148 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6151 bc_vec_pop(&G.prog.results);
6152 bc_program_binOpRetire(&res);
6157 bc_num_free(&res.d.n);
6161 static void bc_program_stackLen(void)
6164 size_t len = G.prog.results.len;
6166 res.t = BC_RESULT_TEMP;
6168 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6169 bc_num_ulong2num(&res.d.n, len);
6170 bc_vec_push(&G.prog.results, &res);
6173 static BcStatus bc_program_asciify(void)
6177 BcNum *num = NULL, n;
6178 char *str, *str2, c;
6179 size_t len = G.prog.strs.len, idx;
6182 if (!BC_PROG_STACK(&G.prog.results, 1))
6183 return bc_error("stack has too few elements");
6184 r = bc_vec_top(&G.prog.results);
6186 s = bc_program_num(r, &num, false);
6189 if (BC_PROG_NUM(r, num)) {
6191 bc_num_init(&n, BC_NUM_DEF_SIZE);
6192 bc_num_copy(&n, num);
6193 bc_num_truncate(&n, n.rdx);
6195 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6196 if (s) goto num_err;
6197 s = bc_num_ulong(&n, &val);
6198 if (s) goto num_err;
6205 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6206 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6214 str2 = xstrdup(str);
6215 bc_program_addFunc(str2, &idx);
6217 if (idx != len + BC_PROG_REQ_FUNCS) {
6219 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6220 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6229 bc_vec_push(&G.prog.strs, &str);
6231 res.t = BC_RESULT_STR;
6233 bc_vec_pop(&G.prog.results);
6234 bc_vec_push(&G.prog.results, &res);
6236 return BC_STATUS_SUCCESS;
6243 static BcStatus bc_program_printStream(void)
6251 if (!BC_PROG_STACK(&G.prog.results, 1))
6252 return bc_error("stack has too few elements");
6253 r = bc_vec_top(&G.prog.results);
6255 s = bc_program_num(r, &n, false);
6258 if (BC_PROG_NUM(r, n))
6259 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6261 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6262 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6269 static BcStatus bc_program_nquit(void)
6276 s = bc_program_prep(&opnd, &num);
6278 s = bc_num_ulong(num, &val);
6281 bc_vec_pop(&G.prog.results);
6283 if (G.prog.stack.len < val)
6284 return bc_error("stack has too few elements");
6285 if (G.prog.stack.len == val)
6288 bc_vec_npop(&G.prog.stack, val);
6293 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6296 BcStatus s = BC_STATUS_SUCCESS;
6306 if (!BC_PROG_STACK(&G.prog.results, 1))
6307 return bc_error("stack has too few elements");
6309 r = bc_vec_top(&G.prog.results);
6313 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6315 if (code[*bgn] == BC_PARSE_STREND)
6318 else_name = bc_program_name(code, bgn);
6320 exec = r->d.n.len != 0;
6324 else if (else_name != NULL) {
6331 v = bc_program_search(name, true);
6338 if (!exec) goto exit;
6339 if (!BC_PROG_STR(n)) {
6340 s = bc_error("variable is wrong type");
6348 if (r->t == BC_RESULT_STR)
6350 else if (r->t == BC_RESULT_VAR) {
6351 s = bc_program_num(r, &n, false);
6352 if (s || !BC_PROG_STR(n)) goto exit;
6359 fidx = sidx + BC_PROG_REQ_FUNCS;
6361 str = bc_vec_item(&G.prog.strs, sidx);
6362 f = bc_vec_item(&G.prog.fns, fidx);
6364 if (f->code.len == 0) {
6365 common_parse_init(&prs, fidx);
6366 s = bc_parse_text(&prs, *str);
6368 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6371 if (prs.l.t.t != BC_LEX_EOF) {
6372 s = bc_error("bad expression");
6376 bc_parse_free(&prs);
6380 ip.len = G.prog.results.len;
6383 bc_vec_pop(&G.prog.results);
6384 bc_vec_push(&G.prog.stack, &ip);
6386 return BC_STATUS_SUCCESS;
6389 bc_parse_free(&prs);
6390 f = bc_vec_item(&G.prog.fns, fidx);
6391 bc_vec_pop_all(&f->code);
6393 bc_vec_pop(&G.prog.results);
6398 static void bc_program_pushGlobal(char inst)
6403 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6404 if (inst == BC_INST_IBASE)
6405 val = (unsigned long) G.prog.ib_t;
6406 else if (inst == BC_INST_SCALE)
6407 val = (unsigned long) G.prog.scale;
6409 val = (unsigned long) G.prog.ob_t;
6411 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6412 bc_num_ulong2num(&res.d.n, val);
6413 bc_vec_push(&G.prog.results, &res);
6416 static void bc_program_addFunc(char *name, size_t *idx)
6418 BcId entry, *entry_ptr;
6423 entry.idx = G.prog.fns.len;
6425 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6426 if (!inserted) free(name);
6428 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6429 *idx = entry_ptr->idx;
6433 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6435 // We need to reset these, so the function can be repopulated.
6437 bc_vec_pop_all(&func->autos);
6438 bc_vec_pop_all(&func->code);
6439 bc_vec_pop_all(&func->labels);
6443 bc_vec_push(&G.prog.fns, &f);
6447 // Called when parsing or execution detects a failure,
6448 // resets execution structures.
6449 static void bc_program_reset(void)
6454 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6455 bc_vec_pop_all(&G.prog.results);
6457 f = bc_vec_item(&G.prog.fns, 0);
6458 ip = bc_vec_top(&G.prog.stack);
6459 ip->idx = f->code.len;
6461 // If !tty, no need to check for ^C: we don't have ^C handler,
6462 // we would be killed by a signal and won't reach this place
6465 static BcStatus bc_program_exec(void)
6467 BcStatus s = BC_STATUS_SUCCESS;
6471 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6472 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6473 char *code = func->code.v;
6476 while (!s && ip->idx < func->code.len) {
6478 char inst = code[(ip->idx)++];
6483 case BC_INST_JUMP_ZERO:
6485 s = bc_program_prep(&ptr, &num);
6487 cond = !bc_num_cmp(num, &G.prog.zero);
6488 bc_vec_pop(&G.prog.results);
6494 idx = bc_program_index(code, &ip->idx);
6495 addr = bc_vec_item(&func->labels, idx);
6496 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6502 s = bc_program_call(code, &ip->idx);
6506 case BC_INST_INC_PRE:
6507 case BC_INST_DEC_PRE:
6508 case BC_INST_INC_POST:
6509 case BC_INST_DEC_POST:
6511 s = bc_program_incdec(inst);
6524 s = bc_program_return(inst);
6528 case BC_INST_BOOL_OR:
6529 case BC_INST_BOOL_AND:
6531 case BC_INST_REL_EQ:
6532 case BC_INST_REL_LE:
6533 case BC_INST_REL_GE:
6534 case BC_INST_REL_NE:
6535 case BC_INST_REL_LT:
6536 case BC_INST_REL_GT:
6538 s = bc_program_logical(inst);
6544 s = bc_program_read();
6550 s = bc_program_pushVar(code, &ip->idx, false, false);
6554 case BC_INST_ARRAY_ELEM:
6557 s = bc_program_pushArray(code, &ip->idx, inst);
6563 r.t = BC_RESULT_LAST;
6564 bc_vec_push(&G.prog.results, &r);
6572 bc_program_pushGlobal(inst);
6576 case BC_INST_SCALE_FUNC:
6577 case BC_INST_LENGTH:
6580 s = bc_program_builtin(inst);
6586 r.t = BC_RESULT_CONSTANT;
6587 r.d.id.idx = bc_program_index(code, &ip->idx);
6588 bc_vec_push(&G.prog.results, &r);
6594 if (!BC_PROG_STACK(&G.prog.results, 1))
6595 s = bc_error("stack has too few elements");
6597 bc_vec_pop(&G.prog.results);
6601 case BC_INST_POP_EXEC:
6603 bc_vec_pop(&G.prog.stack);
6608 case BC_INST_PRINT_POP:
6609 case BC_INST_PRINT_STR:
6611 s = bc_program_print(inst, 0);
6617 r.t = BC_RESULT_STR;
6618 r.d.id.idx = bc_program_index(code, &ip->idx);
6619 bc_vec_push(&G.prog.results, &r);
6624 case BC_INST_MULTIPLY:
6625 case BC_INST_DIVIDE:
6626 case BC_INST_MODULUS:
6630 s = bc_program_op(inst);
6634 case BC_INST_BOOL_NOT:
6636 s = bc_program_prep(&ptr, &num);
6639 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6640 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6641 bc_program_retire(&r, BC_RESULT_TEMP);
6648 s = bc_program_negate();
6653 case BC_INST_ASSIGN_POWER:
6654 case BC_INST_ASSIGN_MULTIPLY:
6655 case BC_INST_ASSIGN_DIVIDE:
6656 case BC_INST_ASSIGN_MODULUS:
6657 case BC_INST_ASSIGN_PLUS:
6658 case BC_INST_ASSIGN_MINUS:
6660 case BC_INST_ASSIGN:
6662 s = bc_program_assign(inst);
6666 case BC_INST_MODEXP:
6668 s = bc_program_modexp();
6672 case BC_INST_DIVMOD:
6674 s = bc_program_divmod();
6678 case BC_INST_EXECUTE:
6679 case BC_INST_EXEC_COND:
6681 cond = inst == BC_INST_EXEC_COND;
6682 s = bc_program_execStr(code, &ip->idx, cond);
6686 case BC_INST_PRINT_STACK:
6688 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6689 s = bc_program_print(BC_INST_PRINT, idx);
6693 case BC_INST_CLEAR_STACK:
6695 bc_vec_pop_all(&G.prog.results);
6699 case BC_INST_STACK_LEN:
6701 bc_program_stackLen();
6705 case BC_INST_DUPLICATE:
6707 if (!BC_PROG_STACK(&G.prog.results, 1))
6708 return bc_error("stack has too few elements");
6709 ptr = bc_vec_top(&G.prog.results);
6710 bc_result_copy(&r, ptr);
6711 bc_vec_push(&G.prog.results, &r);
6719 if (!BC_PROG_STACK(&G.prog.results, 2))
6720 return bc_error("stack has too few elements");
6722 ptr = bc_vec_item_rev(&G.prog.results, 0);
6723 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6724 memcpy(&r, ptr, sizeof(BcResult));
6725 memcpy(ptr, ptr2, sizeof(BcResult));
6726 memcpy(ptr2, &r, sizeof(BcResult));
6731 case BC_INST_ASCIIFY:
6733 s = bc_program_asciify();
6737 case BC_INST_PRINT_STREAM:
6739 s = bc_program_printStream();
6744 case BC_INST_PUSH_VAR:
6746 bool copy = inst == BC_INST_LOAD;
6747 s = bc_program_pushVar(code, &ip->idx, true, copy);
6751 case BC_INST_PUSH_TO_VAR:
6753 char *name = bc_program_name(code, &ip->idx);
6754 s = bc_program_copyToVar(name, true);
6761 if (G.prog.stack.len <= 2)
6763 bc_vec_npop(&G.prog.stack, 2);
6769 s = bc_program_nquit();
6775 if (s || G_interrupt) {
6780 // If the stack has changed, pointers may be invalid.
6781 ip = bc_vec_top(&G.prog.stack);
6782 func = bc_vec_item(&G.prog.fns, ip->func);
6783 code = func->code.v;
6789 static void bc_vm_info(void)
6791 printf("%s "BB_VER"\n"
6792 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6793 "Report bugs at: https://github.com/gavinhoward/bc\n"
6794 "This is free software with ABSOLUTELY NO WARRANTY\n"
6799 static void bc_vm_envArgs(void)
6801 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6804 char *env_args = getenv(bc_args_env_name), *buf;
6806 if (!env_args) return;
6808 G.env_args = xstrdup(env_args);
6811 bc_vec_init(&v, sizeof(char *), NULL);
6812 bc_vec_push(&v, &bc_args_env_name);
6815 if (!isspace(*buf)) {
6816 bc_vec_push(&v, &buf);
6817 while (*buf != 0 && !isspace(*buf)) ++buf;
6818 if (*buf != 0) (*(buf++)) = '\0';
6824 bc_args((int) v.len, (char **) v.v);
6830 static size_t bc_vm_envLen(const char *var)
6832 char *lenv = getenv(var);
6833 size_t i, len = BC_NUM_PRINT_WIDTH;
6836 if (!lenv) return len;
6840 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6842 len = (size_t) atoi(lenv) - 1;
6843 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6846 len = BC_NUM_PRINT_WIDTH;
6851 static BcStatus bc_vm_process(const char *text)
6853 BcStatus s = bc_parse_text(&G.prs, text);
6857 while (G.prs.l.t.t != BC_LEX_EOF) {
6858 s = G.prs.parse(&G.prs);
6862 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6863 s = bc_program_exec();
6872 static BcStatus bc_vm_file(const char *file)
6880 data = bc_read_file(file);
6881 if (!data) return bc_error("file '%s' is not text", file);
6883 bc_lex_file(&G.prs.l, file);
6884 s = bc_vm_process(data);
6887 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6888 ip = bc_vec_item(&G.prog.stack, 0);
6890 if (main_func->code.len < ip->idx)
6891 s = bc_error("file '%s' is not executable", file);
6898 static BcStatus bc_vm_stdin(void)
6902 size_t len, i, str = 0;
6903 bool comment = false;
6905 G.prog.file = bc_program_stdin_name;
6906 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6908 bc_char_vec_init(&buffer);
6909 bc_char_vec_init(&buf);
6910 bc_vec_pushByte(&buffer, '\0');
6912 // This loop is complex because the vm tries not to send any lines that end
6913 // with a backslash to the parser. The reason for that is because the parser
6914 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6915 // case, and for strings and comments, the parser will expect more stuff.
6916 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6918 char *string = buf.v;
6923 if (str && buf.v[0] == G.send)
6925 else if (buf.v[0] == G.sbgn)
6928 else if (len > 1 || comment) {
6930 for (i = 0; i < len; ++i) {
6932 bool notend = len > i + 1;
6935 if (i - 1 > len || string[i - 1] != '\\') {
6936 if (G.sbgn == G.send)
6938 else if (c == G.send)
6940 else if (c == G.sbgn)
6944 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6948 else if (c == '*' && notend && comment && string[i + 1] == '/')
6952 if (str || comment || string[len - 2] == '\\') {
6953 bc_vec_concat(&buffer, buf.v);
6958 bc_vec_concat(&buffer, buf.v);
6959 s = bc_vm_process(buffer.v);
6962 fputs("ready for more input\n", stderr);
6965 bc_vec_pop_all(&buffer);
6969 s = bc_error("string end could not be found");
6972 s = bc_error("comment end could not be found");
6976 bc_vec_free(&buffer);
6980 static BcStatus bc_vm_exec(void)
6982 BcStatus s = BC_STATUS_SUCCESS;
6986 if (option_mask32 & BC_FLAG_L) {
6988 bc_lex_file(&G.prs.l, bc_lib_name);
6989 s = bc_parse_text(&G.prs, bc_lib);
6991 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6992 s = G.prs.parse(&G.prs);
6995 s = bc_program_exec();
7000 for (i = 0; !s && i < G.files.len; ++i)
7001 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7004 fputs("ready for more input\n", stderr);
7007 if (IS_BC || !G.files.len)
7009 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7010 s = bc_vm_process("");
7015 #if ENABLE_FEATURE_CLEAN_UP
7016 static void bc_program_free()
7018 bc_num_free(&G.prog.ib);
7019 bc_num_free(&G.prog.ob);
7020 bc_num_free(&G.prog.hexb);
7022 bc_num_free(&G.prog.strmb);
7024 bc_vec_free(&G.prog.fns);
7025 bc_vec_free(&G.prog.fn_map);
7026 bc_vec_free(&G.prog.vars);
7027 bc_vec_free(&G.prog.var_map);
7028 bc_vec_free(&G.prog.arrs);
7029 bc_vec_free(&G.prog.arr_map);
7030 bc_vec_free(&G.prog.strs);
7031 bc_vec_free(&G.prog.consts);
7032 bc_vec_free(&G.prog.results);
7033 bc_vec_free(&G.prog.stack);
7034 bc_num_free(&G.prog.last);
7035 bc_num_free(&G.prog.zero);
7036 bc_num_free(&G.prog.one);
7039 static void bc_vm_free(void)
7041 bc_vec_free(&G.files);
7043 bc_parse_free(&G.prs);
7048 static void bc_program_init(size_t line_len)
7053 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7054 memset(&ip, 0, sizeof(BcInstPtr));
7056 /* G.prog.nchars = G.prog.scale = 0; - already is */
7057 G.prog.len = line_len;
7059 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7060 bc_num_ten(&G.prog.ib);
7063 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7064 bc_num_ten(&G.prog.ob);
7067 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7068 bc_num_ten(&G.prog.hexb);
7069 G.prog.hexb.num[0] = 6;
7072 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7073 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7076 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7077 bc_num_zero(&G.prog.last);
7079 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7080 bc_num_zero(&G.prog.zero);
7082 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7083 bc_num_one(&G.prog.one);
7085 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7086 bc_map_init(&G.prog.fn_map);
7088 bc_program_addFunc(xstrdup("(main)"), &idx);
7089 bc_program_addFunc(xstrdup("(read)"), &idx);
7091 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7092 bc_map_init(&G.prog.var_map);
7094 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7095 bc_map_init(&G.prog.arr_map);
7097 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7098 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7099 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7100 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7101 bc_vec_push(&G.prog.stack, &ip);
7104 static void bc_vm_init(const char *env_len)
7106 size_t len = bc_vm_envLen(env_len);
7108 bc_vec_init(&G.files, sizeof(char *), NULL);
7114 bc_program_init(len);
7116 bc_parse_init(&G.prs, BC_PROG_MAIN);
7118 dc_parse_init(&G.prs, BC_PROG_MAIN);
7122 static BcStatus bc_vm_run(int argc, char *argv[],
7123 const char *env_len)
7127 bc_vm_init(env_len);
7128 bc_args(argc, argv);
7130 G.ttyin = isatty(0);
7133 #if ENABLE_FEATURE_BC_SIGNALS
7134 // With SA_RESTART, most system calls will restart
7135 // (IOW: they won't fail with EINTR).
7136 // In particular, this means ^C won't cause
7137 // stdout to get into "error state" if SIGINT hits
7138 // within write() syscall.
7139 // The downside is that ^C while line input is taken
7140 // will only be handled after [Enter] since read()
7141 // from stdin is not interrupted by ^C either,
7142 // it restarts, thus fgetc() does not return on ^C.
7143 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7145 // Without SA_RESTART, this exhibits a bug:
7146 // "while (1) print 1" and try ^C-ing it.
7147 // Intermittently, instead of returning to input line,
7148 // you'll get "output error: Interrupted system call"
7150 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7152 if (!(option_mask32 & BC_FLAG_Q))
7157 #if ENABLE_FEATURE_CLEAN_UP
7164 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7165 int bc_main(int argc, char **argv)
7168 G.sbgn = G.send = '"';
7170 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7175 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7176 int dc_main(int argc, char **argv)
7182 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");