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)
748 #define G (*ptr_to_globals)
749 #define INIT_G() do { \
750 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
752 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
753 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
754 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
755 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
758 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
760 static void bc_vm_info(void);
763 static const BcLexKeyword bc_lex_kws[20] = {
764 BC_LEX_KW_ENTRY("auto", 4, true),
765 BC_LEX_KW_ENTRY("break", 5, true),
766 BC_LEX_KW_ENTRY("continue", 8, false),
767 BC_LEX_KW_ENTRY("define", 6, true),
768 BC_LEX_KW_ENTRY("else", 4, false),
769 BC_LEX_KW_ENTRY("for", 3, true),
770 BC_LEX_KW_ENTRY("halt", 4, false),
771 BC_LEX_KW_ENTRY("ibase", 5, true),
772 BC_LEX_KW_ENTRY("if", 2, true),
773 BC_LEX_KW_ENTRY("last", 4, false),
774 BC_LEX_KW_ENTRY("length", 6, true),
775 BC_LEX_KW_ENTRY("limits", 6, false),
776 BC_LEX_KW_ENTRY("obase", 5, true),
777 BC_LEX_KW_ENTRY("print", 5, false),
778 BC_LEX_KW_ENTRY("quit", 4, true),
779 BC_LEX_KW_ENTRY("read", 4, false),
780 BC_LEX_KW_ENTRY("return", 6, true),
781 BC_LEX_KW_ENTRY("scale", 5, true),
782 BC_LEX_KW_ENTRY("sqrt", 4, true),
783 BC_LEX_KW_ENTRY("while", 5, true),
786 // This is an array that corresponds to token types. An entry is
787 // true if the token is valid in an expression, false otherwise.
788 static const bool bc_parse_exprs[] = {
789 false, false, true, true, true, true, true, true, true, true, true, true,
790 true, true, true, true, true, true, true, true, true, true, true, true,
791 true, true, true, false, false, true, true, false, false, false, false,
792 false, false, false, true, true, false, false, false, false, false, false,
793 false, true, false, true, true, true, true, false, false, true, false, true,
797 // This is an array of data for operators that correspond to token types.
798 static const BcOp bc_parse_ops[] = {
799 { 0, false }, { 0, false },
802 { 3, true }, { 3, true }, { 3, true },
803 { 4, true }, { 4, true },
804 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
806 { 7, true }, { 7, true },
807 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
808 { 5, false }, { 5, false },
811 // These identify what tokens can come after expressions in certain cases.
812 static const BcParseNext bc_parse_next_expr =
813 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
814 static const BcParseNext bc_parse_next_param =
815 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
816 static const BcParseNext bc_parse_next_print =
817 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
818 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
819 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
820 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
821 static const BcParseNext bc_parse_next_read =
822 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
826 static const BcLexType dc_lex_regs[] = {
827 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
828 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
829 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
833 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
835 static const BcLexType dc_lex_tokens[] = {
836 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
837 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
838 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
839 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
840 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
843 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
844 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
845 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
846 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
847 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
848 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
849 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
850 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
852 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
853 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
854 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
855 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
856 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
857 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
858 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
859 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
863 static const BcInst dc_parse_insts[] = {
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
865 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
866 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
871 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
874 BC_INST_INVALID, BC_INST_INVALID,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
876 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
878 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
879 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
880 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
881 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
883 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
884 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
885 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
886 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
890 static const BcNumBinaryOp bc_program_ops[] = {
891 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
894 static const char bc_program_stdin_name[] = "<stdin>";
897 static const char *bc_lib_name = "gen/lib.bc";
899 static const char bc_lib[] = {
900 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
901 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
902 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
903 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,
904 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
905 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
906 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,
907 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
908 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
909 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,
910 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
911 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
912 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
913 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
914 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
915 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
916 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
917 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
918 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
919 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
920 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
921 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
922 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
923 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,
924 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
925 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,
926 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
927 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
928 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
929 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
930 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
931 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,
932 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
933 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
934 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
935 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
936 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,
937 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
938 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
939 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
940 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
941 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
942 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
943 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
944 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
945 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
946 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
947 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,
948 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,
949 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
950 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,
951 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,
952 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,
953 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
954 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
955 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,
956 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,
957 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,
958 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
959 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,
960 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
961 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
962 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
963 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,
964 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
965 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
966 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
967 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
968 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
969 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
970 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
971 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
972 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
973 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
974 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
975 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
976 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
977 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
978 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
979 117,114,110,40,97,42,114,47,49,41,10,125,10,0
983 static void fflush_and_check(void)
986 if (ferror(stdout) || ferror(stderr))
987 bb_perror_msg_and_die("output error");
990 static void quit(void) NORETURN;
991 static void quit(void)
994 bb_perror_msg_and_die("input error");
999 static int bc_error(const char *fmt, ...)
1004 bb_verror_msg(fmt, p, NULL);
1008 return BC_STATUS_FAILURE;
1011 static int bc_posix_error(const char *fmt, ...)
1015 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W)))
1016 return BC_STATUS_SUCCESS;
1019 bb_verror_msg(fmt, p, NULL);
1022 // Do we treat non-POSIX constructs as errors?
1023 if (!(G.flags & BC_FLAG_S))
1024 return BC_STATUS_SUCCESS; // no, it's a warning
1027 return BC_STATUS_FAILURE;
1030 static void bc_vec_grow(BcVec *v, size_t n)
1032 size_t cap = v->cap * 2;
1033 while (cap < v->len + n) cap *= 2;
1034 v->v = xrealloc(v->v, v->size * cap);
1038 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1041 v->cap = BC_VEC_START_CAP;
1044 v->v = xmalloc(esize * BC_VEC_START_CAP);
1047 static void bc_vec_expand(BcVec *v, size_t req)
1050 v->v = xrealloc(v->v, v->size * req);
1055 static void bc_vec_npop(BcVec *v, size_t n)
1060 size_t len = v->len - n;
1061 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1065 static void bc_vec_push(BcVec *v, const void *data)
1067 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1068 memmove(v->v + (v->size * v->len), data, v->size);
1072 static void bc_vec_pushByte(BcVec *v, char data)
1074 bc_vec_push(v, &data);
1077 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1080 bc_vec_push(v, data);
1085 if (v->len == v->cap) bc_vec_grow(v, 1);
1087 ptr = v->v + v->size * idx;
1089 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1090 memmove(ptr, data, v->size);
1094 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1096 bc_vec_npop(v, v->len);
1097 bc_vec_expand(v, len + 1);
1098 memcpy(v->v, str, len);
1101 bc_vec_pushByte(v, '\0');
1104 static void bc_vec_concat(BcVec *v, const char *str)
1108 if (v->len == 0) bc_vec_pushByte(v, '\0');
1110 len = v->len + strlen(str);
1112 if (v->cap < len) bc_vec_grow(v, len - v->len);
1118 static void *bc_vec_item(const BcVec *v, size_t idx)
1120 return v->v + v->size * idx;
1123 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1125 return v->v + v->size * (v->len - idx - 1);
1128 static void bc_vec_free(void *vec)
1130 BcVec *v = (BcVec *) vec;
1131 bc_vec_npop(v, v->len);
1135 static size_t bc_map_find(const BcVec *v, const void *ptr)
1137 size_t low = 0, high = v->len;
1139 while (low < high) {
1141 size_t mid = (low + high) / 2;
1142 BcId *id = bc_vec_item(v, mid);
1143 int result = bc_id_cmp(ptr, id);
1147 else if (result < 0)
1156 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1158 size_t n = *i = bc_map_find(v, ptr);
1161 bc_vec_push(v, ptr);
1162 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1163 return 0; // "was not inserted"
1165 bc_vec_pushAt(v, ptr, n);
1166 return 1; // "was inserted"
1169 static size_t bc_map_index(const BcVec *v, const void *ptr)
1171 size_t i = bc_map_find(v, ptr);
1172 if (i >= v->len) return BC_VEC_INVALID_IDX;
1173 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1176 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1185 bc_vec_npop(vec, vec->len);
1188 #if ENABLE_FEATURE_BC_SIGNALS
1189 if (bb_got_signal) { // ^C was pressed
1191 bb_got_signal = 0; // resets G_interrupt to zero
1193 ? "\ninterrupt (type \"quit\" to exit)\n"
1194 : "\ninterrupt (type \"q\" to exit)\n"
1198 if (G.ttyin && !G_posix)
1199 fputs(prompt, stderr);
1201 #if ENABLE_FEATURE_BC_SIGNALS
1207 #if ENABLE_FEATURE_BC_SIGNALS
1208 // Both conditions appear simultaneously, check both just in case
1209 if (errno == EINTR || bb_got_signal) {
1216 quit(); // this emits error message
1218 // Note: EOF does not append '\n', therefore:
1219 // printf 'print 123\n' | bc - works
1220 // printf 'print 123' | bc - fails (syntax error)
1224 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1227 // Bad chars on this line, ignore entire line
1228 bc_error("illegal character 0x%02x", i);
1232 bc_vec_push(vec, &c);
1233 } while (i != '\n');
1234 } while (bad_chars);
1236 bc_vec_pushByte(vec, '\0');
1238 return BC_STATUS_SUCCESS;
1241 static char* bc_read_file(const char *path)
1244 size_t size = ((size_t) -1);
1247 buf = xmalloc_open_read_close(path, &size);
1249 for (i = 0; i < size; ++i) {
1251 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1263 static void bc_args(int argc, char **argv)
1268 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1269 G.flags = getopt32long(argv, "xwvsqli",
1270 "extended-register\0" No_argument "x"
1271 "warn\0" No_argument "w"
1272 "version\0" No_argument "v"
1273 "standard\0" No_argument "s"
1274 "quiet\0" No_argument "q"
1275 "mathlib\0" No_argument "l"
1276 "interactive\0" No_argument "i"
1279 G.flags = getopt32(argv, "xwvsqli");
1282 if (G.flags & BC_FLAG_V) bc_vm_info();
1283 // should not be necessary, getopt32() handles this??
1284 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1286 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1289 static void bc_num_setToZero(BcNum *n, size_t scale)
1296 static void bc_num_zero(BcNum *n)
1298 bc_num_setToZero(n, 0);
1301 static void bc_num_one(BcNum *n)
1303 bc_num_setToZero(n, 0);
1308 static void bc_num_ten(BcNum *n)
1310 bc_num_setToZero(n, 0);
1316 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1320 for (i = 0; i < len; ++i) {
1321 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1328 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1332 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1333 return BC_NUM_NEG(i + 1, c < 0);
1336 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1338 size_t i, min, a_int, b_int, diff;
1339 BcDig *max_num, *min_num;
1340 bool a_max, neg = false;
1343 if (a == b) return 0;
1344 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1345 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1355 a_int = BC_NUM_INT(a);
1356 b_int = BC_NUM_INT(b);
1358 a_max = (a->rdx > b->rdx);
1360 if (a_int != 0) return (ssize_t) a_int;
1364 diff = a->rdx - b->rdx;
1365 max_num = a->num + diff;
1370 diff = b->rdx - a->rdx;
1371 max_num = b->num + diff;
1375 cmp = bc_num_compare(max_num, min_num, b_int + min);
1376 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1378 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1379 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1385 static void bc_num_truncate(BcNum *n, size_t places)
1387 if (places == 0) return;
1393 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1397 static void bc_num_extend(BcNum *n, size_t places)
1399 size_t len = n->len + places;
1403 if (n->cap < len) bc_num_expand(n, len);
1405 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1406 memset(n->num, 0, sizeof(BcDig) * places);
1413 static void bc_num_clean(BcNum *n)
1415 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1418 else if (n->len < n->rdx)
1422 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1425 bc_num_extend(n, scale - n->rdx);
1427 bc_num_truncate(n, n->rdx - scale);
1430 if (n->len != 0) n->neg = !neg1 != !neg2;
1433 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1438 b->len = n->len - idx;
1440 a->rdx = b->rdx = 0;
1442 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1443 memcpy(a->num, n->num, idx * sizeof(BcDig));
1454 static BcStatus bc_num_shift(BcNum *n, size_t places)
1456 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1457 if (places + n->len > BC_MAX_NUM)
1458 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1460 if (n->rdx >= places)
1463 bc_num_extend(n, places - n->rdx);
1469 return BC_STATUS_SUCCESS;
1472 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1481 return bc_num_div(&one, a, b, scale);
1484 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1486 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1487 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1490 // Because this function doesn't need to use scale (per the bc spec),
1491 // I am hijacking it to say whether it's doing an add or a subtract.
1495 if (sub && c->len) c->neg = !c->neg;
1496 return BC_STATUS_SUCCESS;
1498 else if (b->len == 0) {
1500 return BC_STATUS_SUCCESS;
1504 c->rdx = BC_MAX(a->rdx, b->rdx);
1505 min_rdx = BC_MIN(a->rdx, b->rdx);
1508 if (a->rdx > b->rdx) {
1509 diff = a->rdx - b->rdx;
1511 ptr_a = a->num + diff;
1515 diff = b->rdx - a->rdx;
1518 ptr_b = b->num + diff;
1521 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1524 a_int = BC_NUM_INT(a);
1525 b_int = BC_NUM_INT(b);
1527 if (a_int > b_int) {
1538 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1539 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1541 ptr_c[i] = (BcDig)(in % 10);
1544 for (; i < max + min_rdx; ++i, ++c->len) {
1545 in = ((int) ptr[i]) + carry;
1547 ptr_c[i] = (BcDig)(in % 10);
1550 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1552 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1555 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1558 BcNum *minuend, *subtrahend;
1560 bool aneg, bneg, neg;
1562 // Because this function doesn't need to use scale (per the bc spec),
1563 // I am hijacking it to say whether it's doing an add or a subtract.
1567 if (sub && c->len) c->neg = !c->neg;
1568 return BC_STATUS_SUCCESS;
1570 else if (b->len == 0) {
1572 return BC_STATUS_SUCCESS;
1577 a->neg = b->neg = false;
1579 cmp = bc_num_cmp(a, b);
1585 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1586 return BC_STATUS_SUCCESS;
1595 if (sub) neg = !neg;
1600 bc_num_copy(c, minuend);
1603 if (c->rdx < subtrahend->rdx) {
1604 bc_num_extend(c, subtrahend->rdx - c->rdx);
1608 start = c->rdx - subtrahend->rdx;
1610 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1614 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1617 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1622 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1623 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1624 bool aone = BC_NUM_ONE(a);
1626 if (a->len == 0 || b->len == 0) {
1628 return BC_STATUS_SUCCESS;
1630 else if (aone || BC_NUM_ONE(b)) {
1631 bc_num_copy(c, aone ? b : a);
1632 return BC_STATUS_SUCCESS;
1635 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1636 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1638 bc_num_expand(c, a->len + b->len + 1);
1640 memset(c->num, 0, sizeof(BcDig) * c->cap);
1641 c->len = carry = len = 0;
1643 for (i = 0; i < b->len; ++i) {
1645 for (j = 0; j < a->len; ++j) {
1646 int in = (int) c->num[i + j];
1647 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1649 c->num[i + j] = (BcDig)(in % 10);
1652 c->num[i + j] += (BcDig) carry;
1653 len = BC_MAX(len, i + j + !!carry);
1659 return BC_STATUS_SUCCESS;
1662 bc_num_init(&l1, max);
1663 bc_num_init(&h1, max);
1664 bc_num_init(&l2, max);
1665 bc_num_init(&h2, max);
1666 bc_num_init(&m1, max);
1667 bc_num_init(&m2, max);
1668 bc_num_init(&z0, max);
1669 bc_num_init(&z1, max);
1670 bc_num_init(&z2, max);
1671 bc_num_init(&temp, max + max);
1673 bc_num_split(a, max2, &l1, &h1);
1674 bc_num_split(b, max2, &l2, &h2);
1676 s = bc_num_add(&h1, &l1, &m1, 0);
1678 s = bc_num_add(&h2, &l2, &m2, 0);
1681 s = bc_num_k(&h1, &h2, &z0);
1683 s = bc_num_k(&m1, &m2, &z1);
1685 s = bc_num_k(&l1, &l2, &z2);
1688 s = bc_num_sub(&z1, &z0, &temp, 0);
1690 s = bc_num_sub(&temp, &z2, &z1, 0);
1693 s = bc_num_shift(&z0, max2 * 2);
1695 s = bc_num_shift(&z1, max2);
1697 s = bc_num_add(&z0, &z1, &temp, 0);
1699 s = bc_num_add(&temp, &z2, c, 0);
1715 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1719 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1721 scale = BC_MAX(scale, a->rdx);
1722 scale = BC_MAX(scale, b->rdx);
1723 scale = BC_MIN(a->rdx + b->rdx, scale);
1724 maxrdx = BC_MAX(maxrdx, scale);
1726 bc_num_init(&cpa, a->len);
1727 bc_num_init(&cpb, b->len);
1729 bc_num_copy(&cpa, a);
1730 bc_num_copy(&cpb, b);
1731 cpa.neg = cpb.neg = false;
1733 s = bc_num_shift(&cpa, maxrdx);
1735 s = bc_num_shift(&cpb, maxrdx);
1737 s = bc_num_k(&cpa, &cpb, c);
1741 bc_num_expand(c, c->len + maxrdx);
1743 if (c->len < maxrdx) {
1744 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1749 bc_num_retireMul(c, scale, a->neg, b->neg);
1757 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1759 BcStatus s = BC_STATUS_SUCCESS;
1766 return bc_error("divide by zero");
1767 else if (a->len == 0) {
1768 bc_num_setToZero(c, scale);
1769 return BC_STATUS_SUCCESS;
1771 else if (BC_NUM_ONE(b)) {
1773 bc_num_retireMul(c, scale, a->neg, b->neg);
1774 return BC_STATUS_SUCCESS;
1777 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1778 bc_num_copy(&cp, a);
1782 bc_num_expand(&cp, len + 2);
1783 bc_num_extend(&cp, len - cp.len);
1786 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1788 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1790 if (b->rdx == b->len) {
1791 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1795 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1797 // We want an extra zero in front to make things simpler.
1798 cp.num[cp.len++] = 0;
1801 bc_num_expand(c, cp.len);
1804 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1809 for (i = end - 1; !s && i < end; --i) {
1811 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1812 bc_num_subArrays(n, p, len);
1816 bc_num_retireMul(c, scale, a->neg, b->neg);
1819 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1822 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1823 BcNum *restrict d, size_t scale, size_t ts)
1830 return bc_error("divide by zero");
1833 bc_num_setToZero(d, ts);
1834 return BC_STATUS_SUCCESS;
1837 bc_num_init(&temp, d->cap);
1838 bc_num_d(a, b, c, scale);
1840 if (scale != 0) scale = ts;
1842 s = bc_num_m(c, b, &temp, scale);
1844 s = bc_num_sub(a, &temp, d, scale);
1847 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1850 bc_num_retireMul(d, ts, a->neg, b->neg);
1858 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1862 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1864 bc_num_init(&c1, len);
1865 s = bc_num_r(a, b, &c1, c, scale, ts);
1871 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1873 BcStatus s = BC_STATUS_SUCCESS;
1876 size_t i, powrdx, resrdx;
1879 if (b->rdx) return bc_error("non integer number");
1883 return BC_STATUS_SUCCESS;
1885 else if (a->len == 0) {
1886 bc_num_setToZero(c, scale);
1887 return BC_STATUS_SUCCESS;
1889 else if (BC_NUM_ONE(b)) {
1893 s = bc_num_inv(a, c, scale);
1900 s = bc_num_ulong(b, &pow);
1903 bc_num_init(©, a->len);
1904 bc_num_copy(©, a);
1906 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1910 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1912 s = bc_num_mul(©, ©, ©, powrdx);
1916 bc_num_copy(c, ©);
1918 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1921 s = bc_num_mul(©, ©, ©, powrdx);
1926 s = bc_num_mul(c, ©, c, resrdx);
1932 s = bc_num_inv(c, c, scale);
1936 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1938 // We can't use bc_num_clean() here.
1939 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1940 if (zero) bc_num_setToZero(c, scale);
1947 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1948 BcNumBinaryOp op, size_t req)
1951 BcNum num2, *ptr_a, *ptr_b;
1956 memcpy(ptr_a, c, sizeof(BcNum));
1965 memcpy(ptr_b, c, sizeof(BcNum));
1973 bc_num_init(c, req);
1975 bc_num_expand(c, req);
1977 s = op(ptr_a, ptr_b, c, scale);
1979 if (init) bc_num_free(&num2);
1984 static bool bc_num_strValid(const char *val, size_t base)
1987 bool small, radix = false;
1988 size_t i, len = strlen(val);
1990 if (!len) return true;
1993 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1995 for (i = 0; i < len; ++i) {
2001 if (radix) return false;
2007 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2014 static void bc_num_parseDecimal(BcNum *n, const char *val)
2020 for (i = 0; val[i] == '0'; ++i);
2027 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2028 bc_num_expand(n, len);
2031 ptr = strchr(val, '.');
2033 // Explicitly test for NULL here to produce either a 0 or 1.
2034 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2037 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2038 n->num[n->len] = val[i] - '0';
2042 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2045 BcNum temp, mult, result;
2049 size_t i, digits, len = strlen(val);
2053 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2056 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2057 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2059 for (i = 0; i < len; ++i) {
2062 if (c == '.') break;
2064 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2066 s = bc_num_mul(n, base, &mult, 0);
2067 if (s) goto int_err;
2068 bc_num_ulong2num(&temp, v);
2069 s = bc_num_add(&mult, &temp, n, 0);
2070 if (s) goto int_err;
2075 if (c == 0) goto int_err;
2078 bc_num_init(&result, base->len);
2079 bc_num_zero(&result);
2082 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2087 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2089 s = bc_num_mul(&result, base, &result, 0);
2091 bc_num_ulong2num(&temp, v);
2092 s = bc_num_add(&result, &temp, &result, 0);
2094 s = bc_num_mul(&mult, base, &mult, 0);
2098 s = bc_num_div(&result, &mult, &result, digits);
2100 s = bc_num_add(n, &result, n, digits);
2104 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2110 bc_num_free(&result);
2116 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2118 if (*nchars == line_len - 1) {
2126 static void bc_num_printChar(size_t num, size_t width, bool radix,
2127 size_t *nchars, size_t line_len)
2129 (void) radix, (void) line_len;
2130 bb_putchar((char) num);
2131 *nchars = *nchars + width;
2135 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2136 size_t *nchars, size_t line_len)
2140 bc_num_printNewline(nchars, line_len);
2141 bb_putchar(radix ? '.' : ' ');
2144 bc_num_printNewline(nchars, line_len);
2145 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2148 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2150 bc_num_printNewline(nchars, line_len);
2153 bb_putchar(((char) dig) + '0');
2157 static void bc_num_printHex(size_t num, size_t width, bool radix,
2158 size_t *nchars, size_t line_len)
2161 bc_num_printNewline(nchars, line_len);
2166 bc_num_printNewline(nchars, line_len);
2167 bb_putchar(bb_hexdigits_upcase[num]);
2168 *nchars = *nchars + width;
2171 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2173 size_t i, rdx = n->rdx - 1;
2175 if (n->neg) bb_putchar('-');
2176 (*nchars) += n->neg;
2178 for (i = n->len - 1; i < n->len; --i)
2179 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2182 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2183 size_t *nchars, size_t len, BcNumDigitOp print)
2187 BcNum intp, fracp, digit, frac_len;
2188 unsigned long dig, *ptr;
2193 print(0, width, false, nchars, len);
2194 return BC_STATUS_SUCCESS;
2197 bc_vec_init(&stack, sizeof(long), NULL);
2198 bc_num_init(&intp, n->len);
2199 bc_num_init(&fracp, n->rdx);
2200 bc_num_init(&digit, width);
2201 bc_num_init(&frac_len, BC_NUM_INT(n));
2202 bc_num_copy(&intp, n);
2203 bc_num_one(&frac_len);
2205 bc_num_truncate(&intp, intp.rdx);
2206 s = bc_num_sub(n, &intp, &fracp, 0);
2209 while (intp.len != 0) {
2210 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2212 s = bc_num_ulong(&digit, &dig);
2214 bc_vec_push(&stack, &dig);
2217 for (i = 0; i < stack.len; ++i) {
2218 ptr = bc_vec_item_rev(&stack, i);
2219 print(*ptr, width, false, nchars, len);
2222 if (!n->rdx) goto err;
2224 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2225 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2227 s = bc_num_ulong(&fracp, &dig);
2229 bc_num_ulong2num(&intp, dig);
2230 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2232 print(dig, width, radix, nchars, len);
2233 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2238 bc_num_free(&frac_len);
2239 bc_num_free(&digit);
2240 bc_num_free(&fracp);
2242 bc_vec_free(&stack);
2246 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2247 size_t *nchars, size_t line_len)
2254 if (neg) bb_putchar('-');
2259 if (base_t <= BC_NUM_MAX_IBASE) {
2261 print = bc_num_printHex;
2264 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2265 print = bc_num_printDigits;
2268 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2275 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2277 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2281 static void bc_num_init(BcNum *n, size_t req)
2283 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2284 memset(n, 0, sizeof(BcNum));
2285 n->num = xmalloc(req);
2289 static void bc_num_expand(BcNum *n, size_t req)
2291 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2293 n->num = xrealloc(n->num, req);
2298 static void bc_num_free(void *num)
2300 free(((BcNum *) num)->num);
2303 static void bc_num_copy(BcNum *d, BcNum *s)
2306 bc_num_expand(d, s->cap);
2310 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2314 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2317 if (!bc_num_strValid(val, base_t))
2318 return bc_error("bad number string");
2321 bc_num_parseDecimal(n, val);
2323 bc_num_parseBase(n, val, base);
2325 return BC_STATUS_SUCCESS;
2328 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2329 size_t *nchars, size_t line_len)
2331 BcStatus s = BC_STATUS_SUCCESS;
2333 bc_num_printNewline(nchars, line_len);
2339 else if (base_t == 10)
2340 bc_num_printDecimal(n, nchars, line_len);
2342 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2352 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2357 if (n->neg) return bc_error("negative number");
2359 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2361 unsigned long prev = *result, powprev = pow;
2363 *result += ((unsigned long) n->num[i]) * pow;
2366 if (*result < prev || pow < powprev)
2367 return bc_error("overflow");
2370 return BC_STATUS_SUCCESS;
2373 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2381 if (val == 0) return;
2383 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2384 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2387 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2389 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2391 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2394 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2396 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2398 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2401 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2403 size_t req = BC_NUM_MREQ(a, b, scale);
2404 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2407 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2409 size_t req = BC_NUM_MREQ(a, b, scale);
2410 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2413 static BcStatus bc_num_mod(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_rem, req);
2419 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2421 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2424 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2427 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2428 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2429 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2431 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2432 bc_num_expand(b, req);
2435 bc_num_setToZero(b, scale);
2436 return BC_STATUS_SUCCESS;
2439 return bc_error("negative number");
2440 else if (BC_NUM_ONE(a)) {
2442 bc_num_extend(b, scale);
2443 return BC_STATUS_SUCCESS;
2446 scale = BC_MAX(scale, a->rdx) + 1;
2447 len = a->len + scale;
2449 bc_num_init(&num1, len);
2450 bc_num_init(&num2, len);
2451 bc_num_init(&half, BC_NUM_DEF_SIZE);
2457 bc_num_init(&f, len);
2458 bc_num_init(&fprime, len);
2464 pow = BC_NUM_INT(a);
2473 pow -= 2 - (pow & 1);
2475 bc_num_extend(x0, pow);
2477 // Make sure to move the radix back.
2481 x0->rdx = digs = digs1 = 0;
2483 len = BC_NUM_INT(x0) + resrdx - 1;
2485 while (cmp != 0 || digs < len) {
2487 s = bc_num_div(a, x0, &f, resrdx);
2489 s = bc_num_add(x0, &f, &fprime, resrdx);
2491 s = bc_num_mul(&fprime, &half, x1, resrdx);
2494 cmp = bc_num_cmp(x1, x0);
2495 digs = x1->len - (unsigned long long) llabs(cmp);
2497 if (cmp == cmp2 && digs == digs1)
2502 resrdx += times > 4;
2515 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2518 bc_num_free(&fprime);
2526 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2532 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2535 memcpy(&num2, c, sizeof(BcNum));
2537 bc_num_init(c, len);
2542 bc_num_expand(c, len);
2545 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2547 if (init) bc_num_free(&num2);
2553 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2556 BcNum base, exp, two, temp;
2559 return bc_error("divide by zero");
2560 if (a->rdx || b->rdx || c->rdx)
2561 return bc_error("non integer number");
2563 return bc_error("negative number");
2565 bc_num_expand(d, c->len);
2566 bc_num_init(&base, c->len);
2567 bc_num_init(&exp, b->len);
2568 bc_num_init(&two, BC_NUM_DEF_SIZE);
2569 bc_num_init(&temp, b->len);
2575 s = bc_num_rem(a, c, &base, 0);
2577 bc_num_copy(&exp, b);
2579 while (exp.len != 0) {
2581 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2584 if (BC_NUM_ONE(&temp)) {
2585 s = bc_num_mul(d, &base, &temp, 0);
2587 s = bc_num_rem(&temp, c, d, 0);
2591 s = bc_num_mul(&base, &base, &temp, 0);
2593 s = bc_num_rem(&temp, c, &base, 0);
2606 static int bc_id_cmp(const void *e1, const void *e2)
2608 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2611 static void bc_id_free(void *id)
2613 free(((BcId *) id)->name);
2616 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2621 for (i = 0; i < f->autos.len; ++i) {
2622 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2623 return bc_error("function parameter or auto var has the same name as another");
2629 bc_vec_push(&f->autos, &a);
2631 return BC_STATUS_SUCCESS;
2634 static void bc_func_init(BcFunc *f)
2636 bc_vec_init(&f->code, sizeof(char), NULL);
2637 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2638 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2642 static void bc_func_free(void *func)
2644 BcFunc *f = (BcFunc *) func;
2645 bc_vec_free(&f->code);
2646 bc_vec_free(&f->autos);
2647 bc_vec_free(&f->labels);
2650 static void bc_array_init(BcVec *a, bool nums)
2653 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2655 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2656 bc_array_expand(a, 1);
2659 static void bc_array_copy(BcVec *d, const BcVec *s)
2663 bc_vec_npop(d, d->len);
2664 bc_vec_expand(d, s->cap);
2667 for (i = 0; i < s->len; ++i) {
2668 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2669 bc_num_init(dnum, snum->len);
2670 bc_num_copy(dnum, snum);
2674 static void bc_array_expand(BcVec *a, size_t len)
2678 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2679 while (len > a->len) {
2680 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2681 bc_vec_push(a, &data.n);
2685 while (len > a->len) {
2686 bc_array_init(&data.v, true);
2687 bc_vec_push(a, &data.v);
2692 static void bc_string_free(void *string)
2694 free(*((char **) string));
2698 static void bc_result_copy(BcResult *d, BcResult *src)
2704 case BC_RESULT_TEMP:
2705 case BC_RESULT_IBASE:
2706 case BC_RESULT_SCALE:
2707 case BC_RESULT_OBASE:
2709 bc_num_init(&d->d.n, src->d.n.len);
2710 bc_num_copy(&d->d.n, &src->d.n);
2715 case BC_RESULT_ARRAY:
2716 case BC_RESULT_ARRAY_ELEM:
2718 d->d.id.name = xstrdup(src->d.id.name);
2722 case BC_RESULT_CONSTANT:
2723 case BC_RESULT_LAST:
2727 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2734 static void bc_result_free(void *result)
2736 BcResult *r = (BcResult *) result;
2740 case BC_RESULT_TEMP:
2741 case BC_RESULT_IBASE:
2742 case BC_RESULT_SCALE:
2743 case BC_RESULT_OBASE:
2745 bc_num_free(&r->d.n);
2750 case BC_RESULT_ARRAY:
2751 case BC_RESULT_ARRAY_ELEM:
2765 static void bc_lex_lineComment(BcLex *l)
2767 l->t.t = BC_LEX_WHITESPACE;
2768 while (l->i < l->len && l->buf[l->i++] != '\n');
2772 static void bc_lex_whitespace(BcLex *l)
2775 l->t.t = BC_LEX_WHITESPACE;
2776 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2779 static BcStatus bc_lex_number(BcLex *l, char start)
2781 const char *buf = l->buf + l->i;
2782 size_t len, hits = 0, bslashes = 0, i = 0, j;
2784 bool last_pt, pt = start == '.';
2787 l->t.t = BC_LEX_NUMBER;
2789 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2790 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2804 len = i + 1 * !last_pt - bslashes * 2;
2805 if (len > BC_MAX_NUM)
2806 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2808 bc_vec_npop(&l->t.v, l->t.v.len);
2809 bc_vec_expand(&l->t.v, len + 1);
2810 bc_vec_push(&l->t.v, &start);
2812 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2816 // If we have hit a backslash, skip it. We don't have
2817 // to check for a newline because it's guaranteed.
2818 if (hits < bslashes && c == '\\') {
2824 bc_vec_push(&l->t.v, &c);
2827 bc_vec_pushByte(&l->t.v, '\0');
2830 return BC_STATUS_SUCCESS;
2833 static BcStatus bc_lex_name(BcLex *l)
2836 const char *buf = l->buf + l->i - 1;
2839 l->t.t = BC_LEX_NAME;
2841 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2843 if (i > BC_MAX_STRING)
2844 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2845 bc_vec_string(&l->t.v, i, buf);
2847 // Increment the index. We minus 1 because it has already been incremented.
2850 return BC_STATUS_SUCCESS;
2853 static void bc_lex_init(BcLex *l, BcLexNext next)
2856 bc_vec_init(&l->t.v, sizeof(char), NULL);
2859 static void bc_lex_free(BcLex *l)
2861 bc_vec_free(&l->t.v);
2864 static void bc_lex_file(BcLex *l, const char *file)
2871 static BcStatus bc_lex_next(BcLex *l)
2876 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2878 l->line += l->newline;
2879 l->t.t = BC_LEX_EOF;
2881 l->newline = (l->i == l->len);
2882 if (l->newline) return BC_STATUS_SUCCESS;
2884 // Loop until failure or we don't have whitespace. This
2885 // is so the parser doesn't get inundated with whitespace.
2888 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2893 static BcStatus bc_lex_text(BcLex *l, const char *text)
2897 l->len = strlen(text);
2898 l->t.t = l->t.last = BC_LEX_INVALID;
2899 return bc_lex_next(l);
2903 static BcStatus bc_lex_identifier(BcLex *l)
2907 const char *buf = l->buf + l->i - 1;
2909 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2911 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2913 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2915 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2917 if (!bc_lex_kws[i].posix) {
2918 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
2922 // We minus 1 because the index has already been incremented.
2924 return BC_STATUS_SUCCESS;
2931 if (l->t.v.len - 1 > 1)
2932 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2937 static BcStatus bc_lex_string(BcLex *l)
2939 size_t len, nls = 0, i = l->i;
2942 l->t.t = BC_LEX_STR;
2944 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2948 return bc_error("string end could not be found");
2952 if (len > BC_MAX_STRING)
2953 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2954 bc_vec_string(&l->t.v, len, l->buf + l->i);
2959 return BC_STATUS_SUCCESS;
2962 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2964 if (l->buf[l->i] == '=') {
2972 static BcStatus bc_lex_comment(BcLex *l)
2975 const char *buf = l->buf;
2977 l->t.t = BC_LEX_WHITESPACE;
2990 return bc_error("comment end could not be found");
2999 return BC_STATUS_SUCCESS;
3002 static BcStatus bc_lex_token(BcLex *l)
3004 BcStatus s = BC_STATUS_SUCCESS;
3005 char c = l->buf[l->i++], c2;
3007 // This is the workhorse of the lexer.
3014 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3024 bc_lex_whitespace(l);
3030 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3032 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3033 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3042 s = bc_lex_string(l);
3048 s = bc_posix_error("POSIX does not allow '#' script comments");
3051 bc_lex_lineComment(l);
3058 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3067 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3071 l->t.t = BC_LEX_OP_BOOL_AND;
3074 l->t.t = BC_LEX_INVALID;
3075 s = bc_error("bad character '%c'", '&');
3084 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3090 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3099 l->t.t = BC_LEX_OP_INC;
3102 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3108 l->t.t = BC_LEX_COMMA;
3117 l->t.t = BC_LEX_OP_DEC;
3120 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3126 if (isdigit(l->buf[l->i]))
3127 s = bc_lex_number(l, c);
3129 l->t.t = BC_LEX_KEY_LAST;
3130 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3139 s = bc_lex_comment(l);
3141 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3162 s = bc_lex_number(l, c);
3168 l->t.t = BC_LEX_SCOLON;
3174 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3180 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3186 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3193 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3199 if (l->buf[l->i] == '\n') {
3200 l->t.t = BC_LEX_WHITESPACE;
3204 s = bc_error("bad character '%c'", c);
3210 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3241 s = bc_lex_identifier(l);
3248 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3257 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3261 l->t.t = BC_LEX_OP_BOOL_OR;
3264 l->t.t = BC_LEX_INVALID;
3265 s = bc_error("bad character '%c'", c);
3273 l->t.t = BC_LEX_INVALID;
3274 s = bc_error("bad character '%c'", c);
3284 static BcStatus dc_lex_register(BcLex *l)
3286 BcStatus s = BC_STATUS_SUCCESS;
3288 if (isspace(l->buf[l->i - 1])) {
3289 bc_lex_whitespace(l);
3292 s = bc_error("extended register");
3297 bc_vec_npop(&l->t.v, l->t.v.len);
3298 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3299 bc_vec_pushByte(&l->t.v, '\0');
3300 l->t.t = BC_LEX_NAME;
3306 static BcStatus dc_lex_string(BcLex *l)
3308 size_t depth = 1, nls = 0, i = l->i;
3311 l->t.t = BC_LEX_STR;
3312 bc_vec_npop(&l->t.v, l->t.v.len);
3314 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3316 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3317 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3320 if (depth) bc_vec_push(&l->t.v, &c);
3325 return bc_error("string end could not be found");
3328 bc_vec_pushByte(&l->t.v, '\0');
3329 if (i - l->i > BC_MAX_STRING)
3330 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3335 return BC_STATUS_SUCCESS;
3338 static BcStatus dc_lex_token(BcLex *l)
3340 BcStatus s = BC_STATUS_SUCCESS;
3341 char c = l->buf[l->i++], c2;
3344 for (i = 0; i < dc_lex_regs_len; ++i) {
3345 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3348 if (c >= '%' && c <= '~' &&
3349 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3354 // This is the workhorse of the lexer.
3359 l->t.t = BC_LEX_EOF;
3370 l->newline = (c == '\n');
3371 bc_lex_whitespace(l);
3380 l->t.t = BC_LEX_OP_REL_NE;
3382 l->t.t = BC_LEX_OP_REL_LE;
3384 l->t.t = BC_LEX_OP_REL_GE;
3386 return bc_error("bad character '%c'", c);
3394 bc_lex_lineComment(l);
3400 if (isdigit(l->buf[l->i]))
3401 s = bc_lex_number(l, c);
3403 s = bc_error("bad character '%c'", c);
3424 s = bc_lex_number(l, c);
3430 s = dc_lex_string(l);
3436 l->t.t = BC_LEX_INVALID;
3437 s = bc_error("bad character '%c'", c);
3446 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3448 bc_program_addFunc(name, idx);
3449 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3452 static void bc_parse_pushName(BcParse *p, char *name)
3454 size_t i = 0, len = strlen(name);
3456 for (; i < len; ++i) bc_parse_push(p, name[i]);
3457 bc_parse_push(p, BC_PARSE_STREND);
3462 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3464 unsigned char amt, i, nums[sizeof(size_t)];
3466 for (amt = 0; idx; ++amt) {
3467 nums[amt] = (char) idx;
3468 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3471 bc_parse_push(p, amt);
3472 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3475 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3477 char *num = xstrdup(p->l.t.v.v);
3478 size_t idx = G.prog.consts.len;
3480 bc_vec_push(&G.prog.consts, &num);
3482 bc_parse_push(p, BC_INST_NUM);
3483 bc_parse_pushIndex(p, idx);
3486 (*prev) = BC_INST_NUM;
3489 static BcStatus bc_parse_text(BcParse *p, const char *text)
3493 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3495 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3496 p->l.t.t = BC_LEX_INVALID;
3499 if (!BC_PARSE_CAN_EXEC(p))
3500 return bc_error("file is not executable");
3503 return bc_lex_text(&p->l, text);
3506 // Called when bc/dc_parse_parse() detects a failure,
3507 // resets parsing structures.
3508 static void bc_parse_reset(BcParse *p)
3510 if (p->fidx != BC_PROG_MAIN) {
3512 p->func->nparams = 0;
3513 bc_vec_npop(&p->func->code, p->func->code.len);
3514 bc_vec_npop(&p->func->autos, p->func->autos.len);
3515 bc_vec_npop(&p->func->labels, p->func->labels.len);
3517 bc_parse_updateFunc(p, BC_PROG_MAIN);
3521 p->l.t.t = BC_LEX_EOF;
3522 p->auto_part = (p->nbraces = 0);
3524 bc_vec_npop(&p->flags, p->flags.len - 1);
3525 bc_vec_npop(&p->exits, p->exits.len);
3526 bc_vec_npop(&p->conds, p->conds.len);
3527 bc_vec_npop(&p->ops, p->ops.len);
3532 static void bc_parse_free(BcParse *p)
3534 bc_vec_free(&p->flags);
3535 bc_vec_free(&p->exits);
3536 bc_vec_free(&p->conds);
3537 bc_vec_free(&p->ops);
3541 static void bc_parse_create(BcParse *p, size_t func,
3542 BcParseParse parse, BcLexNext next)
3544 memset(p, 0, sizeof(BcParse));
3546 bc_lex_init(&p->l, next);
3547 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3548 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3549 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3550 bc_vec_pushByte(&p->flags, 0);
3551 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3554 // p->auto_part = p->nbraces = 0; - already is
3555 bc_parse_updateFunc(p, func);
3559 static BcStatus bc_parse_else(BcParse *p);
3560 static BcStatus bc_parse_stmt(BcParse *p);
3562 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3563 size_t *nexprs, bool next)
3565 BcStatus s = BC_STATUS_SUCCESS;
3567 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3568 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3570 while (p->ops.len > start) {
3572 t = BC_PARSE_TOP_OP(p);
3573 if (t == BC_LEX_LPAREN) break;
3575 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3576 if (l >= r && (l != r || !left)) break;
3578 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3579 bc_vec_pop(&p->ops);
3580 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3583 bc_vec_push(&p->ops, &type);
3584 if (next) s = bc_lex_next(&p->l);
3589 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3593 if (p->ops.len <= ops_bgn)
3594 return bc_error("bad expression");
3595 top = BC_PARSE_TOP_OP(p);
3597 while (top != BC_LEX_LPAREN) {
3599 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3601 bc_vec_pop(&p->ops);
3602 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3604 if (p->ops.len <= ops_bgn)
3605 return bc_error("bad expression");
3606 top = BC_PARSE_TOP_OP(p);
3609 bc_vec_pop(&p->ops);
3611 return bc_lex_next(&p->l);
3614 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3620 s = bc_lex_next(&p->l);
3623 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3625 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3626 s = bc_parse_expr(p, flags, bc_parse_next_param);
3629 comma = p->l.t.t == BC_LEX_COMMA;
3631 s = bc_lex_next(&p->l);
3636 if (comma) return bc_error("bad token");
3637 bc_parse_push(p, BC_INST_CALL);
3638 bc_parse_pushIndex(p, nparams);
3640 return BC_STATUS_SUCCESS;
3643 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3646 BcId entry, *entry_ptr;
3651 s = bc_parse_params(p, flags);
3654 if (p->l.t.t != BC_LEX_RPAREN) {
3655 s = bc_error("bad token");
3659 idx = bc_map_index(&G.prog.fn_map, &entry);
3661 if (idx == BC_VEC_INVALID_IDX) {
3662 name = xstrdup(entry.name);
3663 bc_parse_addFunc(p, name, &idx);
3664 idx = bc_map_index(&G.prog.fn_map, &entry);
3670 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3671 bc_parse_pushIndex(p, entry_ptr->idx);
3673 return bc_lex_next(&p->l);
3680 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3685 name = xstrdup(p->l.t.v.v);
3686 s = bc_lex_next(&p->l);
3689 if (p->l.t.t == BC_LEX_LBRACKET) {
3691 s = bc_lex_next(&p->l);
3694 if (p->l.t.t == BC_LEX_RBRACKET) {
3696 if (!(flags & BC_PARSE_ARRAY)) {
3697 s = bc_error("bad expression");
3701 *type = BC_INST_ARRAY;
3705 *type = BC_INST_ARRAY_ELEM;
3707 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3708 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3712 s = bc_lex_next(&p->l);
3714 bc_parse_push(p, *type);
3715 bc_parse_pushName(p, name);
3717 else if (p->l.t.t == BC_LEX_LPAREN) {
3719 if (flags & BC_PARSE_NOCALL) {
3720 s = bc_error("bad token");
3724 *type = BC_INST_CALL;
3725 s = bc_parse_call(p, name, flags);
3728 *type = BC_INST_VAR;
3729 bc_parse_push(p, BC_INST_VAR);
3730 bc_parse_pushName(p, name);
3740 static BcStatus bc_parse_read(BcParse *p)
3744 s = bc_lex_next(&p->l);
3746 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3748 s = bc_lex_next(&p->l);
3750 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3752 bc_parse_push(p, BC_INST_READ);
3754 return bc_lex_next(&p->l);
3757 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3762 s = bc_lex_next(&p->l);
3764 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3766 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3768 s = bc_lex_next(&p->l);
3771 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3774 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3776 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3777 bc_parse_push(p, *prev);
3779 return bc_lex_next(&p->l);
3782 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3786 s = bc_lex_next(&p->l);
3789 if (p->l.t.t != BC_LEX_LPAREN) {
3790 *type = BC_INST_SCALE;
3791 bc_parse_push(p, BC_INST_SCALE);
3792 return BC_STATUS_SUCCESS;
3795 *type = BC_INST_SCALE_FUNC;
3796 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3798 s = bc_lex_next(&p->l);
3801 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3803 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3804 bc_parse_push(p, BC_INST_SCALE_FUNC);
3806 return bc_lex_next(&p->l);
3809 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3810 size_t *nexprs, uint8_t flags)
3815 BcInst etype = *prev;
3817 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3818 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3819 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3821 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3822 bc_parse_push(p, inst);
3823 s = bc_lex_next(&p->l);
3827 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3830 s = bc_lex_next(&p->l);
3834 // Because we parse the next part of the expression
3835 // right here, we need to increment this.
3836 *nexprs = *nexprs + 1;
3842 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3846 case BC_LEX_KEY_IBASE:
3847 case BC_LEX_KEY_LAST:
3848 case BC_LEX_KEY_OBASE:
3850 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3851 s = bc_lex_next(&p->l);
3855 case BC_LEX_KEY_SCALE:
3857 s = bc_lex_next(&p->l);
3859 if (p->l.t.t == BC_LEX_LPAREN)
3860 s = bc_error("bad token");
3862 bc_parse_push(p, BC_INST_SCALE);
3868 s = bc_error("bad token");
3873 if (!s) bc_parse_push(p, inst);
3879 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3880 bool rparen, size_t *nexprs)
3884 BcInst etype = *prev;
3886 s = bc_lex_next(&p->l);
3889 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3890 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3893 *prev = BC_PARSE_TOKEN_INST(type);
3895 // We can just push onto the op stack because this is the largest
3896 // precedence operator that gets pushed. Inc/dec does not.
3897 if (type != BC_LEX_OP_MINUS)
3898 bc_vec_push(&p->ops, &type);
3900 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3905 static BcStatus bc_parse_string(BcParse *p, char inst)
3907 char *str = xstrdup(p->l.t.v.v);
3909 bc_parse_push(p, BC_INST_STR);
3910 bc_parse_pushIndex(p, G.prog.strs.len);
3911 bc_vec_push(&G.prog.strs, &str);
3912 bc_parse_push(p, inst);
3914 return bc_lex_next(&p->l);
3917 static BcStatus bc_parse_print(BcParse *p)
3923 s = bc_lex_next(&p->l);
3928 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3929 return bc_error("bad print statement");
3931 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3933 if (type == BC_LEX_STR)
3934 s = bc_parse_string(p, BC_INST_PRINT_POP);
3936 s = bc_parse_expr(p, 0, bc_parse_next_print);
3938 bc_parse_push(p, BC_INST_PRINT_POP);
3943 comma = p->l.t.t == BC_LEX_COMMA;
3944 if (comma) s = bc_lex_next(&p->l);
3949 if (comma) return bc_error("bad token");
3951 return bc_lex_next(&p->l);
3954 static BcStatus bc_parse_return(BcParse *p)
3960 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
3962 s = bc_lex_next(&p->l);
3966 paren = t == BC_LEX_LPAREN;
3968 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3969 bc_parse_push(p, BC_INST_RET0);
3972 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3973 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3976 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3977 bc_parse_push(p, BC_INST_RET0);
3978 s = bc_lex_next(&p->l);
3982 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3983 s = bc_posix_error("POSIX requires parentheses around return expressions");
3987 bc_parse_push(p, BC_INST_RET);
3993 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3995 BcStatus s = BC_STATUS_SUCCESS;
3997 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
3998 return bc_error("bad token");
4002 if (p->l.t.t == BC_LEX_RBRACE) {
4003 if (!p->nbraces) return bc_error("bad token");
4005 s = bc_lex_next(&p->l);
4009 return bc_error("bad token");
4012 if (BC_PARSE_IF(p)) {
4016 while (p->l.t.t == BC_LEX_NLINE) {
4017 s = bc_lex_next(&p->l);
4021 bc_vec_pop(&p->flags);
4023 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4024 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4026 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4028 else if (BC_PARSE_ELSE(p)) {
4033 bc_vec_pop(&p->flags);
4035 ip = bc_vec_top(&p->exits);
4036 label = bc_vec_item(&p->func->labels, ip->idx);
4037 *label = p->func->code.len;
4039 bc_vec_pop(&p->exits);
4041 else if (BC_PARSE_FUNC_INNER(p)) {
4042 bc_parse_push(p, BC_INST_RET0);
4043 bc_parse_updateFunc(p, BC_PROG_MAIN);
4044 bc_vec_pop(&p->flags);
4048 BcInstPtr *ip = bc_vec_top(&p->exits);
4049 size_t *label = bc_vec_top(&p->conds);
4051 bc_parse_push(p, BC_INST_JUMP);
4052 bc_parse_pushIndex(p, *label);
4054 label = bc_vec_item(&p->func->labels, ip->idx);
4055 *label = p->func->code.len;
4057 bc_vec_pop(&p->flags);
4058 bc_vec_pop(&p->exits);
4059 bc_vec_pop(&p->conds);
4065 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4067 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4068 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4069 flags |= BC_PARSE_FLAG_BODY;
4070 bc_vec_push(&p->flags, &flags);
4073 static void bc_parse_noElse(BcParse *p)
4077 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4079 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4081 ip = bc_vec_top(&p->exits);
4082 label = bc_vec_item(&p->func->labels, ip->idx);
4083 *label = p->func->code.len;
4085 bc_vec_pop(&p->exits);
4088 static BcStatus bc_parse_if(BcParse *p)
4093 s = bc_lex_next(&p->l);
4095 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4097 s = bc_lex_next(&p->l);
4099 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4101 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4103 s = bc_lex_next(&p->l);
4105 bc_parse_push(p, BC_INST_JUMP_ZERO);
4107 ip.idx = p->func->labels.len;
4108 ip.func = ip.len = 0;
4110 bc_parse_pushIndex(p, ip.idx);
4111 bc_vec_push(&p->exits, &ip);
4112 bc_vec_push(&p->func->labels, &ip.idx);
4113 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4115 return BC_STATUS_SUCCESS;
4118 static BcStatus bc_parse_else(BcParse *p)
4122 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4124 ip.idx = p->func->labels.len;
4125 ip.func = ip.len = 0;
4127 bc_parse_push(p, BC_INST_JUMP);
4128 bc_parse_pushIndex(p, ip.idx);
4132 bc_vec_push(&p->exits, &ip);
4133 bc_vec_push(&p->func->labels, &ip.idx);
4134 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4136 return bc_lex_next(&p->l);
4139 static BcStatus bc_parse_while(BcParse *p)
4144 s = bc_lex_next(&p->l);
4146 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4147 s = bc_lex_next(&p->l);
4150 ip.idx = p->func->labels.len;
4152 bc_vec_push(&p->func->labels, &p->func->code.len);
4153 bc_vec_push(&p->conds, &ip.idx);
4155 ip.idx = p->func->labels.len;
4159 bc_vec_push(&p->exits, &ip);
4160 bc_vec_push(&p->func->labels, &ip.idx);
4162 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4164 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4165 s = bc_lex_next(&p->l);
4168 bc_parse_push(p, BC_INST_JUMP_ZERO);
4169 bc_parse_pushIndex(p, ip.idx);
4170 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4172 return BC_STATUS_SUCCESS;
4175 static BcStatus bc_parse_for(BcParse *p)
4179 size_t cond_idx, exit_idx, body_idx, update_idx;
4181 s = bc_lex_next(&p->l);
4183 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4184 s = bc_lex_next(&p->l);
4187 if (p->l.t.t != BC_LEX_SCOLON)
4188 s = bc_parse_expr(p, 0, bc_parse_next_for);
4190 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4193 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4194 s = bc_lex_next(&p->l);
4197 cond_idx = p->func->labels.len;
4198 update_idx = cond_idx + 1;
4199 body_idx = update_idx + 1;
4200 exit_idx = body_idx + 1;
4202 bc_vec_push(&p->func->labels, &p->func->code.len);
4204 if (p->l.t.t != BC_LEX_SCOLON)
4205 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4207 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4210 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4212 s = bc_lex_next(&p->l);
4215 bc_parse_push(p, BC_INST_JUMP_ZERO);
4216 bc_parse_pushIndex(p, exit_idx);
4217 bc_parse_push(p, BC_INST_JUMP);
4218 bc_parse_pushIndex(p, body_idx);
4220 ip.idx = p->func->labels.len;
4222 bc_vec_push(&p->conds, &update_idx);
4223 bc_vec_push(&p->func->labels, &p->func->code.len);
4225 if (p->l.t.t != BC_LEX_RPAREN)
4226 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4228 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4232 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4233 bc_parse_push(p, BC_INST_JUMP);
4234 bc_parse_pushIndex(p, cond_idx);
4235 bc_vec_push(&p->func->labels, &p->func->code.len);
4241 bc_vec_push(&p->exits, &ip);
4242 bc_vec_push(&p->func->labels, &ip.idx);
4244 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4246 return BC_STATUS_SUCCESS;
4249 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4255 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4257 if (type == BC_LEX_KEY_BREAK) {
4259 if (p->exits.len == 0) return bc_error("bad token");
4261 i = p->exits.len - 1;
4262 ip = bc_vec_item(&p->exits, i);
4264 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4265 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4270 i = *((size_t *) bc_vec_top(&p->conds));
4272 bc_parse_push(p, BC_INST_JUMP);
4273 bc_parse_pushIndex(p, i);
4275 s = bc_lex_next(&p->l);
4278 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4279 return bc_error("bad token");
4281 return bc_lex_next(&p->l);
4284 static BcStatus bc_parse_func(BcParse *p)
4287 bool var, comma = false;
4291 s = bc_lex_next(&p->l);
4293 if (p->l.t.t != BC_LEX_NAME)
4294 return bc_error("bad function definition");
4296 name = xstrdup(p->l.t.v.v);
4297 bc_parse_addFunc(p, name, &p->fidx);
4299 s = bc_lex_next(&p->l);
4301 if (p->l.t.t != BC_LEX_LPAREN)
4302 return bc_error("bad function definition");
4303 s = bc_lex_next(&p->l);
4306 while (p->l.t.t != BC_LEX_RPAREN) {
4308 if (p->l.t.t != BC_LEX_NAME)
4309 return bc_error("bad function definition");
4313 name = xstrdup(p->l.t.v.v);
4314 s = bc_lex_next(&p->l);
4317 var = p->l.t.t != BC_LEX_LBRACKET;
4321 s = bc_lex_next(&p->l);
4324 if (p->l.t.t != BC_LEX_RBRACKET) {
4325 s = bc_error("bad function definition");
4329 s = bc_lex_next(&p->l);
4333 comma = p->l.t.t == BC_LEX_COMMA;
4335 s = bc_lex_next(&p->l);
4339 s = bc_func_insert(p->func, name, var);
4343 if (comma) return bc_error("bad function definition");
4345 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4346 bc_parse_startBody(p, flags);
4348 s = bc_lex_next(&p->l);
4351 if (p->l.t.t != BC_LEX_LBRACE)
4352 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4361 static BcStatus bc_parse_auto(BcParse *p)
4364 bool comma, var, one;
4367 if (!p->auto_part) return bc_error("bad token");
4368 s = bc_lex_next(&p->l);
4371 p->auto_part = comma = false;
4372 one = p->l.t.t == BC_LEX_NAME;
4374 while (p->l.t.t == BC_LEX_NAME) {
4376 name = xstrdup(p->l.t.v.v);
4377 s = bc_lex_next(&p->l);
4380 var = p->l.t.t != BC_LEX_LBRACKET;
4383 s = bc_lex_next(&p->l);
4386 if (p->l.t.t != BC_LEX_RBRACKET) {
4387 s = bc_error("bad function definition");
4391 s = bc_lex_next(&p->l);
4395 comma = p->l.t.t == BC_LEX_COMMA;
4397 s = bc_lex_next(&p->l);
4401 s = bc_func_insert(p->func, name, var);
4405 if (comma) return bc_error("bad function definition");
4406 if (!one) return bc_error("no auto variable found");
4408 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4409 return bc_error("bad token");
4411 return bc_lex_next(&p->l);
4418 static BcStatus bc_parse_body(BcParse *p, bool brace)
4420 BcStatus s = BC_STATUS_SUCCESS;
4421 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4423 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4425 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4427 if (!brace) return bc_error("bad token");
4428 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4430 if (!p->auto_part) {
4431 s = bc_parse_auto(p);
4435 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4438 s = bc_parse_stmt(p);
4439 if (!s && !brace) s = bc_parse_endBody(p, false);
4445 static BcStatus bc_parse_stmt(BcParse *p)
4447 BcStatus s = BC_STATUS_SUCCESS;
4453 return bc_lex_next(&p->l);
4456 case BC_LEX_KEY_ELSE:
4458 p->auto_part = false;
4464 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4467 s = bc_lex_next(&p->l);
4470 return bc_parse_body(p, true);
4473 case BC_LEX_KEY_AUTO:
4475 return bc_parse_auto(p);
4480 p->auto_part = false;
4482 if (BC_PARSE_IF_END(p)) {
4484 return BC_STATUS_SUCCESS;
4486 else if (BC_PARSE_BODY(p))
4487 return bc_parse_body(p, false);
4497 case BC_LEX_OP_MINUS:
4498 case BC_LEX_OP_BOOL_NOT:
4502 case BC_LEX_KEY_IBASE:
4503 case BC_LEX_KEY_LAST:
4504 case BC_LEX_KEY_LENGTH:
4505 case BC_LEX_KEY_OBASE:
4506 case BC_LEX_KEY_READ:
4507 case BC_LEX_KEY_SCALE:
4508 case BC_LEX_KEY_SQRT:
4510 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4514 case BC_LEX_KEY_ELSE:
4516 s = bc_parse_else(p);
4522 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4528 s = bc_parse_endBody(p, true);
4534 s = bc_parse_string(p, BC_INST_PRINT_STR);
4538 case BC_LEX_KEY_BREAK:
4539 case BC_LEX_KEY_CONTINUE:
4541 s = bc_parse_loopExit(p, p->l.t.t);
4545 case BC_LEX_KEY_FOR:
4547 s = bc_parse_for(p);
4551 case BC_LEX_KEY_HALT:
4553 bc_parse_push(p, BC_INST_HALT);
4554 s = bc_lex_next(&p->l);
4564 case BC_LEX_KEY_LIMITS:
4566 // "limits" is a compile-time command,
4567 // the output is produced at _parse time_.
4568 s = bc_lex_next(&p->l);
4570 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4571 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4572 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4573 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4574 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4575 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4576 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4577 printf("Number of vars = %lu\n", BC_MAX_VARS);
4581 case BC_LEX_KEY_PRINT:
4583 s = bc_parse_print(p);
4587 case BC_LEX_KEY_QUIT:
4589 // "quit" is a compile-time command. For example,
4590 // "if (0 == 1) quit" terminates when parsing the statement,
4591 // not when it is executed
4595 case BC_LEX_KEY_RETURN:
4597 s = bc_parse_return(p);
4601 case BC_LEX_KEY_WHILE:
4603 s = bc_parse_while(p);
4609 s = bc_error("bad token");
4617 static BcStatus bc_parse_parse(BcParse *p)
4621 if (p->l.t.t == BC_LEX_EOF)
4622 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4623 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4624 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4625 s = bc_parse_func(p);
4628 s = bc_parse_stmt(p);
4630 if (s || G_interrupt) {
4632 s = BC_STATUS_FAILURE;
4638 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4640 BcStatus s = BC_STATUS_SUCCESS;
4641 BcInst prev = BC_INST_PRINT;
4642 BcLexType top, t = p->l.t.t;
4643 size_t nexprs = 0, ops_bgn = p->ops.len;
4644 uint32_t i, nparens, nrelops;
4645 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4647 paren_first = p->l.t.t == BC_LEX_LPAREN;
4648 nparens = nrelops = 0;
4649 paren_expr = rprn = done = get_token = assign = false;
4652 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4658 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4659 rprn = get_token = bin_last = false;
4663 case BC_LEX_OP_MINUS:
4665 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4666 rprn = get_token = false;
4667 bin_last = prev == BC_INST_MINUS;
4671 case BC_LEX_OP_ASSIGN_POWER:
4672 case BC_LEX_OP_ASSIGN_MULTIPLY:
4673 case BC_LEX_OP_ASSIGN_DIVIDE:
4674 case BC_LEX_OP_ASSIGN_MODULUS:
4675 case BC_LEX_OP_ASSIGN_PLUS:
4676 case BC_LEX_OP_ASSIGN_MINUS:
4677 case BC_LEX_OP_ASSIGN:
4679 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4680 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4681 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4683 s = bc_error("bad assignment:"
4684 " left side must be scale,"
4685 " ibase, obase, last, var,"
4692 case BC_LEX_OP_POWER:
4693 case BC_LEX_OP_MULTIPLY:
4694 case BC_LEX_OP_DIVIDE:
4695 case BC_LEX_OP_MODULUS:
4696 case BC_LEX_OP_PLUS:
4697 case BC_LEX_OP_REL_EQ:
4698 case BC_LEX_OP_REL_LE:
4699 case BC_LEX_OP_REL_GE:
4700 case BC_LEX_OP_REL_NE:
4701 case BC_LEX_OP_REL_LT:
4702 case BC_LEX_OP_REL_GT:
4703 case BC_LEX_OP_BOOL_NOT:
4704 case BC_LEX_OP_BOOL_OR:
4705 case BC_LEX_OP_BOOL_AND:
4707 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4708 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4710 return bc_error("bad expression");
4713 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4714 prev = BC_PARSE_TOKEN_INST(t);
4715 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4716 rprn = get_token = false;
4717 bin_last = t != BC_LEX_OP_BOOL_NOT;
4724 if (BC_PARSE_LEAF(prev, rprn))
4725 return bc_error("bad expression");
4727 paren_expr = rprn = bin_last = false;
4729 bc_vec_push(&p->ops, &t);
4736 if (bin_last || prev == BC_INST_BOOL_NOT)
4737 return bc_error("bad expression");
4740 s = BC_STATUS_SUCCESS;
4745 else if (!paren_expr)
4746 return BC_STATUS_PARSE_EMPTY_EXP;
4749 paren_expr = rprn = true;
4750 get_token = bin_last = false;
4752 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4759 if (BC_PARSE_LEAF(prev, rprn))
4760 return bc_error("bad expression");
4762 rprn = get_token = bin_last = false;
4763 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4771 if (BC_PARSE_LEAF(prev, rprn))
4772 return bc_error("bad expression");
4773 bc_parse_number(p, &prev, &nexprs);
4774 paren_expr = get_token = true;
4775 rprn = bin_last = false;
4780 case BC_LEX_KEY_IBASE:
4781 case BC_LEX_KEY_LAST:
4782 case BC_LEX_KEY_OBASE:
4784 if (BC_PARSE_LEAF(prev, rprn))
4785 return bc_error("bad expression");
4786 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4787 bc_parse_push(p, (char) prev);
4789 paren_expr = get_token = true;
4790 rprn = bin_last = false;
4796 case BC_LEX_KEY_LENGTH:
4797 case BC_LEX_KEY_SQRT:
4799 if (BC_PARSE_LEAF(prev, rprn))
4800 return bc_error("bad expression");
4801 s = bc_parse_builtin(p, t, flags, &prev);
4803 rprn = get_token = bin_last = false;
4809 case BC_LEX_KEY_READ:
4811 if (BC_PARSE_LEAF(prev, rprn))
4812 return bc_error("bad expression");
4813 else if (flags & BC_PARSE_NOREAD)
4814 s = bc_error("read() call inside of a read() call");
4816 s = bc_parse_read(p);
4819 rprn = get_token = bin_last = false;
4821 prev = BC_INST_READ;
4826 case BC_LEX_KEY_SCALE:
4828 if (BC_PARSE_LEAF(prev, rprn))
4829 return bc_error("bad expression");
4830 s = bc_parse_scale(p, &prev, flags);
4832 rprn = get_token = bin_last = false;
4834 prev = BC_INST_SCALE;
4841 s = bc_error("bad token");
4846 if (!s && get_token) s = bc_lex_next(&p->l);
4850 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4852 while (p->ops.len > ops_bgn) {
4854 top = BC_PARSE_TOP_OP(p);
4855 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4857 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4858 return bc_error("bad expression");
4860 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4862 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4863 bc_vec_pop(&p->ops);
4866 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4867 return bc_error("bad expression");
4869 for (i = 0; i < next.len; ++i)
4870 if (t == next.tokens[i])
4872 return bc_error("bad expression");
4875 if (!(flags & BC_PARSE_REL) && nrelops) {
4876 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4879 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4880 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4884 if (flags & BC_PARSE_PRINT) {
4885 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4886 bc_parse_push(p, BC_INST_POP);
4892 static void bc_parse_init(BcParse *p, size_t func)
4894 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4897 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4899 return bc_parse_expr(p, flags, bc_parse_next_read);
4904 static BcStatus dc_parse_register(BcParse *p)
4909 s = bc_lex_next(&p->l);
4911 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
4913 name = xstrdup(p->l.t.v.v);
4914 bc_parse_pushName(p, name);
4919 static BcStatus dc_parse_string(BcParse *p)
4921 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4922 size_t idx, len = G.prog.strs.len;
4924 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4927 str = xstrdup(p->l.t.v.v);
4928 bc_parse_push(p, BC_INST_STR);
4929 bc_parse_pushIndex(p, len);
4930 bc_vec_push(&G.prog.strs, &str);
4931 bc_parse_addFunc(p, name, &idx);
4933 return bc_lex_next(&p->l);
4936 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4940 bc_parse_push(p, inst);
4942 s = dc_parse_register(p);
4947 bc_parse_push(p, BC_INST_SWAP);
4948 bc_parse_push(p, BC_INST_ASSIGN);
4949 bc_parse_push(p, BC_INST_POP);
4952 return bc_lex_next(&p->l);
4955 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4959 bc_parse_push(p, inst);
4960 bc_parse_push(p, BC_INST_EXEC_COND);
4962 s = dc_parse_register(p);
4965 s = bc_lex_next(&p->l);
4968 if (p->l.t.t == BC_LEX_ELSE) {
4969 s = dc_parse_register(p);
4971 s = bc_lex_next(&p->l);
4974 bc_parse_push(p, BC_PARSE_STREND);
4979 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4981 BcStatus s = BC_STATUS_SUCCESS;
4984 bool assign, get_token = false;
4988 case BC_LEX_OP_REL_EQ:
4989 case BC_LEX_OP_REL_LE:
4990 case BC_LEX_OP_REL_GE:
4991 case BC_LEX_OP_REL_NE:
4992 case BC_LEX_OP_REL_LT:
4993 case BC_LEX_OP_REL_GT:
4995 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5002 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5008 s = dc_parse_string(p);
5015 if (t == BC_LEX_NEG) {
5016 s = bc_lex_next(&p->l);
5018 if (p->l.t.t != BC_LEX_NUMBER)
5019 return bc_error("bad token");
5022 bc_parse_number(p, &prev, &p->nbraces);
5024 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5030 case BC_LEX_KEY_READ:
5032 if (flags & BC_PARSE_NOREAD)
5033 s = bc_error("read() call inside of a read() call");
5035 bc_parse_push(p, BC_INST_READ);
5040 case BC_LEX_OP_ASSIGN:
5041 case BC_LEX_STORE_PUSH:
5043 assign = t == BC_LEX_OP_ASSIGN;
5044 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5045 s = dc_parse_mem(p, inst, true, assign);
5050 case BC_LEX_LOAD_POP:
5052 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5053 s = dc_parse_mem(p, inst, true, false);
5057 case BC_LEX_STORE_IBASE:
5058 case BC_LEX_STORE_SCALE:
5059 case BC_LEX_STORE_OBASE:
5061 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5062 s = dc_parse_mem(p, inst, false, true);
5068 s = bc_error("bad token");
5074 if (!s && get_token) s = bc_lex_next(&p->l);
5079 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5081 BcStatus s = BC_STATUS_SUCCESS;
5085 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5087 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5089 inst = dc_parse_insts[t];
5091 if (inst != BC_INST_INVALID) {
5092 bc_parse_push(p, inst);
5093 s = bc_lex_next(&p->l);
5096 s = dc_parse_token(p, t, flags);
5099 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5100 bc_parse_push(p, BC_INST_POP_EXEC);
5105 static BcStatus dc_parse_parse(BcParse *p)
5109 if (p->l.t.t == BC_LEX_EOF)
5110 s = bc_error("end of file");
5112 s = dc_parse_expr(p, 0);
5114 if (s || G_interrupt) {
5116 s = BC_STATUS_FAILURE;
5122 static void dc_parse_init(BcParse *p, size_t func)
5124 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5128 static void common_parse_init(BcParse *p, size_t func)
5131 bc_parse_init(p, func);
5133 dc_parse_init(p, func);
5137 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5140 return bc_parse_expression(p, flags);
5142 return dc_parse_expr(p, flags);
5146 static BcVec* bc_program_search(char *id, bool var)
5154 v = var ? &G.prog.vars : &G.prog.arrs;
5155 map = var ? &G.prog.var_map : &G.prog.arr_map;
5159 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5162 bc_array_init(&data.v, var);
5163 bc_vec_push(v, &data.v);
5166 ptr = bc_vec_item(map, i);
5167 if (new) ptr->name = xstrdup(e.name);
5168 return bc_vec_item(v, ptr->idx);
5171 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5173 BcStatus s = BC_STATUS_SUCCESS;
5178 case BC_RESULT_TEMP:
5179 case BC_RESULT_IBASE:
5180 case BC_RESULT_SCALE:
5181 case BC_RESULT_OBASE:
5187 case BC_RESULT_CONSTANT:
5189 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5190 size_t base_t, len = strlen(*str);
5193 bc_num_init(&r->d.n, len);
5195 hex = hex && len == 1;
5196 base = hex ? &G.prog.hexb : &G.prog.ib;
5197 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5198 s = bc_num_parse(&r->d.n, *str, base, base_t);
5201 bc_num_free(&r->d.n);
5206 r->t = BC_RESULT_TEMP;
5212 case BC_RESULT_ARRAY:
5213 case BC_RESULT_ARRAY_ELEM:
5217 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5219 if (r->t == BC_RESULT_ARRAY_ELEM) {
5221 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5222 *num = bc_vec_item(v, r->d.id.idx);
5225 *num = bc_vec_top(v);
5230 case BC_RESULT_LAST:
5232 *num = &G.prog.last;
5246 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5247 BcResult **r, BcNum **rn, bool assign)
5251 BcResultType lt, rt;
5253 if (!BC_PROG_STACK(&G.prog.results, 2))
5254 return bc_error("stack has too few elements");
5256 *r = bc_vec_item_rev(&G.prog.results, 0);
5257 *l = bc_vec_item_rev(&G.prog.results, 1);
5261 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5263 s = bc_program_num(*l, ln, false);
5265 s = bc_program_num(*r, rn, hex);
5268 // We run this again under these conditions in case any vector has been
5269 // reallocated out from under the BcNums or arrays we had.
5270 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5271 s = bc_program_num(*l, ln, false);
5275 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5276 return bc_error("variable is wrong type");
5277 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5278 return bc_error("variable is wrong type");
5283 static void bc_program_binOpRetire(BcResult *r)
5285 r->t = BC_RESULT_TEMP;
5286 bc_vec_pop(&G.prog.results);
5287 bc_vec_pop(&G.prog.results);
5288 bc_vec_push(&G.prog.results, r);
5291 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5295 if (!BC_PROG_STACK(&G.prog.results, 1))
5296 return bc_error("stack has too few elements");
5297 *r = bc_vec_top(&G.prog.results);
5299 s = bc_program_num(*r, n, false);
5302 if (!BC_PROG_NUM((*r), (*n)))
5303 return bc_error("variable is wrong type");
5308 static void bc_program_retire(BcResult *r, BcResultType t)
5311 bc_vec_pop(&G.prog.results);
5312 bc_vec_push(&G.prog.results, r);
5315 static BcStatus bc_program_op(char inst)
5318 BcResult *opd1, *opd2, res;
5319 BcNum *n1, *n2 = NULL;
5321 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5323 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5325 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5327 bc_program_binOpRetire(&res);
5332 bc_num_free(&res.d.n);
5336 static BcStatus bc_program_read(void)
5343 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5345 for (i = 0; i < G.prog.stack.len; ++i) {
5346 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5347 if (ip_ptr->func == BC_PROG_READ)
5348 return bc_error("read() call inside of a read() call");
5351 bc_vec_npop(&f->code, f->code.len);
5352 bc_vec_init(&buf, sizeof(char), NULL);
5354 s = bc_read_line(&buf, "read> ");
5357 common_parse_init(&parse, BC_PROG_READ);
5358 bc_lex_file(&parse.l, bc_program_stdin_name);
5360 s = bc_parse_text(&parse, buf.v);
5361 if (s) goto exec_err;
5362 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5363 if (s) goto exec_err;
5365 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5366 s = bc_error("bad read() expression");
5370 ip.func = BC_PROG_READ;
5372 ip.len = G.prog.results.len;
5374 // Update this pointer, just in case.
5375 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5377 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5378 bc_vec_push(&G.prog.stack, &ip);
5381 bc_parse_free(&parse);
5387 static size_t bc_program_index(char *code, size_t *bgn)
5389 char amt = code[(*bgn)++], i = 0;
5392 for (; i < amt; ++i, ++(*bgn))
5393 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5398 static char *bc_program_name(char *code, size_t *bgn)
5401 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5403 s = xmalloc(ptr - str + 1);
5406 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5414 static void bc_program_printString(const char *str, size_t *nchars)
5416 size_t i, len = strlen(str);
5425 for (i = 0; i < len; ++i, ++(*nchars)) {
5429 if (c != '\\' || i == len - 1)
5489 // Just print the backslash and following character.
5500 static BcStatus bc_program_print(char inst, size_t idx)
5502 BcStatus s = BC_STATUS_SUCCESS;
5507 bool pop = inst != BC_INST_PRINT;
5509 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5510 return bc_error("stack has too few elements");
5512 r = bc_vec_item_rev(&G.prog.results, idx);
5513 s = bc_program_num(r, &num, false);
5516 if (BC_PROG_NUM(r, num)) {
5517 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5518 if (!s) bc_num_copy(&G.prog.last, num);
5522 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5523 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5525 if (inst == BC_INST_PRINT_STR) {
5526 for (i = 0, len = strlen(str); i < len; ++i) {
5529 if (c == '\n') G.prog.nchars = SIZE_MAX;
5534 bc_program_printString(str, &G.prog.nchars);
5535 if (inst == BC_INST_PRINT) bb_putchar('\n');
5539 if (!s && pop) bc_vec_pop(&G.prog.results);
5544 static BcStatus bc_program_negate(void)
5550 s = bc_program_prep(&ptr, &num);
5553 bc_num_init(&res.d.n, num->len);
5554 bc_num_copy(&res.d.n, num);
5555 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5557 bc_program_retire(&res, BC_RESULT_TEMP);
5562 static BcStatus bc_program_logical(char inst)
5565 BcResult *opd1, *opd2, res;
5570 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5572 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5574 if (inst == BC_INST_BOOL_AND)
5575 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5576 else if (inst == BC_INST_BOOL_OR)
5577 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5580 cmp = bc_num_cmp(n1, n2);
5584 case BC_INST_REL_EQ:
5590 case BC_INST_REL_LE:
5596 case BC_INST_REL_GE:
5602 case BC_INST_REL_NE:
5608 case BC_INST_REL_LT:
5614 case BC_INST_REL_GT:
5622 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5624 bc_program_binOpRetire(&res);
5630 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5636 memset(&n2, 0, sizeof(BcNum));
5637 n2.rdx = res.d.id.idx = r->d.id.idx;
5638 res.t = BC_RESULT_STR;
5641 if (!BC_PROG_STACK(&G.prog.results, 2))
5642 return bc_error("stack has too few elements");
5644 bc_vec_pop(&G.prog.results);
5647 bc_vec_pop(&G.prog.results);
5649 bc_vec_push(&G.prog.results, &res);
5650 bc_vec_push(v, &n2);
5652 return BC_STATUS_SUCCESS;
5656 static BcStatus bc_program_copyToVar(char *name, bool var)
5663 if (!BC_PROG_STACK(&G.prog.results, 1))
5664 return bc_error("stack has too few elements");
5666 ptr = bc_vec_top(&G.prog.results);
5667 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5668 return bc_error("variable is wrong type");
5669 v = bc_program_search(name, var);
5672 if (ptr->t == BC_RESULT_STR && !var)
5673 return bc_error("variable is wrong type");
5674 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5677 s = bc_program_num(ptr, &n, false);
5680 // Do this once more to make sure that pointers were not invalidated.
5681 v = bc_program_search(name, var);
5684 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5685 bc_num_copy(&r.d.n, n);
5688 bc_array_init(&r.d.v, true);
5689 bc_array_copy(&r.d.v, (BcVec *) n);
5692 bc_vec_push(v, &r.d);
5693 bc_vec_pop(&G.prog.results);
5698 static BcStatus bc_program_assign(char inst)
5701 BcResult *left, *right, res;
5702 BcNum *l = NULL, *r = NULL;
5703 unsigned long val, max;
5704 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5706 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5709 ib = left->t == BC_RESULT_IBASE;
5710 sc = left->t == BC_RESULT_SCALE;
5714 if (right->t == BC_RESULT_STR) {
5718 if (left->t != BC_RESULT_VAR)
5719 return bc_error("variable is wrong type");
5720 v = bc_program_search(left->d.id.name, true);
5722 return bc_program_assignStr(right, v, false);
5726 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5727 return bc_error("bad assignment:"
5728 " left side must be scale,"
5729 " ibase, obase, last, var,"
5734 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5735 return bc_error("divide by zero");
5740 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5747 if (ib || sc || left->t == BC_RESULT_OBASE) {
5748 static const char *const msg[] = {
5749 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5750 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5751 "?1", //BC_RESULT_LAST
5752 "?2", //BC_RESULT_CONSTANT
5753 "?3", //BC_RESULT_ONE
5754 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5758 s = bc_num_ulong(l, &val);
5761 s = left->t - BC_RESULT_IBASE;
5764 ptr = &G.prog.scale;
5767 if (val < BC_NUM_MIN_BASE)
5768 return bc_error(msg[s]);
5769 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5770 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5774 return bc_error(msg[s]);
5776 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5778 *ptr = (size_t) val;
5779 s = BC_STATUS_SUCCESS;
5782 bc_num_init(&res.d.n, l->len);
5783 bc_num_copy(&res.d.n, l);
5784 bc_program_binOpRetire(&res);
5790 #define bc_program_pushVar(code, bgn, pop, copy) \
5791 bc_program_pushVar(code, bgn)
5792 // for bc, 'pop' and 'copy' are always false
5794 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5795 bool pop, bool copy)
5797 BcStatus s = BC_STATUS_SUCCESS;
5799 char *name = bc_program_name(code, bgn);
5801 r.t = BC_RESULT_VAR;
5806 BcVec *v = bc_program_search(name, true);
5807 BcNum *num = bc_vec_top(v);
5811 if (!BC_PROG_STACK(v, 2 - copy)) {
5813 return bc_error("stack has too few elements");
5819 if (!BC_PROG_STR(num)) {
5821 r.t = BC_RESULT_TEMP;
5823 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5824 bc_num_copy(&r.d.n, num);
5827 r.t = BC_RESULT_STR;
5828 r.d.id.idx = num->rdx;
5831 if (!copy) bc_vec_pop(v);
5836 bc_vec_push(&G.prog.results, &r);
5841 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5844 BcStatus s = BC_STATUS_SUCCESS;
5848 r.d.id.name = bc_program_name(code, bgn);
5850 if (inst == BC_INST_ARRAY) {
5851 r.t = BC_RESULT_ARRAY;
5852 bc_vec_push(&G.prog.results, &r);
5859 s = bc_program_prep(&operand, &num);
5861 s = bc_num_ulong(num, &temp);
5864 if (temp > BC_MAX_DIM) {
5865 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5869 r.d.id.idx = (size_t) temp;
5870 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5874 if (s) free(r.d.id.name);
5879 static BcStatus bc_program_incdec(char inst)
5882 BcResult *ptr, res, copy;
5886 s = bc_program_prep(&ptr, &num);
5889 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5890 copy.t = BC_RESULT_TEMP;
5891 bc_num_init(©.d.n, num->len);
5892 bc_num_copy(©.d.n, num);
5895 res.t = BC_RESULT_ONE;
5896 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5897 BC_INST_ASSIGN_PLUS :
5898 BC_INST_ASSIGN_MINUS;
5900 bc_vec_push(&G.prog.results, &res);
5901 bc_program_assign(inst);
5903 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5904 bc_vec_pop(&G.prog.results);
5905 bc_vec_push(&G.prog.results, ©);
5911 static BcStatus bc_program_call(char *code, size_t *idx)
5913 BcStatus s = BC_STATUS_SUCCESS;
5915 size_t i, nparams = bc_program_index(code, idx);
5922 ip.func = bc_program_index(code, idx);
5923 func = bc_vec_item(&G.prog.fns, ip.func);
5925 if (func->code.len == 0) {
5926 return bc_error("undefined function");
5928 if (nparams != func->nparams) {
5929 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5931 ip.len = G.prog.results.len - nparams;
5933 for (i = 0; i < nparams; ++i) {
5935 a = bc_vec_item(&func->autos, nparams - 1 - i);
5936 arg = bc_vec_top(&G.prog.results);
5938 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5939 return bc_error("variable is wrong type");
5941 s = bc_program_copyToVar(a->name, a->idx);
5945 for (; i < func->autos.len; ++i) {
5948 a = bc_vec_item(&func->autos, i);
5949 v = bc_program_search(a->name, a->idx);
5952 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5953 bc_vec_push(v, ¶m.n);
5956 bc_array_init(¶m.v, true);
5957 bc_vec_push(v, ¶m.v);
5961 bc_vec_push(&G.prog.stack, &ip);
5963 return BC_STATUS_SUCCESS;
5966 static BcStatus bc_program_return(char inst)
5972 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5974 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5975 return bc_error("stack has too few elements");
5977 f = bc_vec_item(&G.prog.fns, ip->func);
5978 res.t = BC_RESULT_TEMP;
5980 if (inst == BC_INST_RET) {
5983 BcResult *operand = bc_vec_top(&G.prog.results);
5985 s = bc_program_num(operand, &num, false);
5987 bc_num_init(&res.d.n, num->len);
5988 bc_num_copy(&res.d.n, num);
5991 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5992 bc_num_zero(&res.d.n);
5995 // We need to pop arguments as well, so this takes that into account.
5996 for (i = 0; i < f->autos.len; ++i) {
5999 BcId *a = bc_vec_item(&f->autos, i);
6001 v = bc_program_search(a->name, a->idx);
6005 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6006 bc_vec_push(&G.prog.results, &res);
6007 bc_vec_pop(&G.prog.stack);
6009 return BC_STATUS_SUCCESS;
6013 static unsigned long bc_program_scale(BcNum *n)
6015 return (unsigned long) n->rdx;
6018 static unsigned long bc_program_len(BcNum *n)
6020 unsigned long len = n->len;
6023 if (n->rdx != n->len) return len;
6024 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6029 static BcStatus bc_program_builtin(char inst)
6035 bool len = inst == BC_INST_LENGTH;
6037 if (!BC_PROG_STACK(&G.prog.results, 1))
6038 return bc_error("stack has too few elements");
6039 opnd = bc_vec_top(&G.prog.results);
6041 s = bc_program_num(opnd, &num, false);
6045 if (!BC_PROG_NUM(opnd, num) && !len)
6046 return bc_error("variable is wrong type");
6049 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6051 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6053 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6054 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6058 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6061 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6063 str = bc_vec_item(&G.prog.strs, idx);
6064 bc_num_ulong2num(&res.d.n, strlen(*str));
6068 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6069 bc_num_ulong2num(&res.d.n, f(num));
6072 bc_program_retire(&res, BC_RESULT_TEMP);
6078 static BcStatus bc_program_divmod(void)
6081 BcResult *opd1, *opd2, res, res2;
6082 BcNum *n1, *n2 = NULL;
6084 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6087 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6088 bc_num_init(&res2.d.n, n2->len);
6090 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6093 bc_program_binOpRetire(&res2);
6094 res.t = BC_RESULT_TEMP;
6095 bc_vec_push(&G.prog.results, &res);
6100 bc_num_free(&res2.d.n);
6101 bc_num_free(&res.d.n);
6105 static BcStatus bc_program_modexp(void)
6108 BcResult *r1, *r2, *r3, res;
6109 BcNum *n1, *n2, *n3;
6111 if (!BC_PROG_STACK(&G.prog.results, 3))
6112 return bc_error("stack has too few elements");
6113 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6116 r1 = bc_vec_item_rev(&G.prog.results, 2);
6117 s = bc_program_num(r1, &n1, false);
6119 if (!BC_PROG_NUM(r1, n1))
6120 return bc_error("variable is wrong type");
6122 // Make sure that the values have their pointers updated, if necessary.
6123 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6125 if (r1->t == r2->t) {
6126 s = bc_program_num(r2, &n2, false);
6130 if (r1->t == r3->t) {
6131 s = bc_program_num(r3, &n3, false);
6136 bc_num_init(&res.d.n, n3->len);
6137 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6140 bc_vec_pop(&G.prog.results);
6141 bc_program_binOpRetire(&res);
6146 bc_num_free(&res.d.n);
6150 static void bc_program_stackLen(void)
6153 size_t len = G.prog.results.len;
6155 res.t = BC_RESULT_TEMP;
6157 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6158 bc_num_ulong2num(&res.d.n, len);
6159 bc_vec_push(&G.prog.results, &res);
6162 static BcStatus bc_program_asciify(void)
6166 BcNum *num = NULL, n;
6167 char *str, *str2, c;
6168 size_t len = G.prog.strs.len, idx;
6171 if (!BC_PROG_STACK(&G.prog.results, 1))
6172 return bc_error("stack has too few elements");
6173 r = bc_vec_top(&G.prog.results);
6175 s = bc_program_num(r, &num, false);
6178 if (BC_PROG_NUM(r, num)) {
6180 bc_num_init(&n, BC_NUM_DEF_SIZE);
6181 bc_num_copy(&n, num);
6182 bc_num_truncate(&n, n.rdx);
6184 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6185 if (s) goto num_err;
6186 s = bc_num_ulong(&n, &val);
6187 if (s) goto num_err;
6194 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6195 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6203 str2 = xstrdup(str);
6204 bc_program_addFunc(str2, &idx);
6206 if (idx != len + BC_PROG_REQ_FUNCS) {
6208 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6209 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6218 bc_vec_push(&G.prog.strs, &str);
6220 res.t = BC_RESULT_STR;
6222 bc_vec_pop(&G.prog.results);
6223 bc_vec_push(&G.prog.results, &res);
6225 return BC_STATUS_SUCCESS;
6232 static BcStatus bc_program_printStream(void)
6240 if (!BC_PROG_STACK(&G.prog.results, 1))
6241 return bc_error("stack has too few elements");
6242 r = bc_vec_top(&G.prog.results);
6244 s = bc_program_num(r, &n, false);
6247 if (BC_PROG_NUM(r, n))
6248 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6250 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6251 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6258 static BcStatus bc_program_nquit(void)
6265 s = bc_program_prep(&opnd, &num);
6267 s = bc_num_ulong(num, &val);
6270 bc_vec_pop(&G.prog.results);
6272 if (G.prog.stack.len < val)
6273 return bc_error("stack has too few elements");
6274 if (G.prog.stack.len == val)
6277 bc_vec_npop(&G.prog.stack, val);
6282 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6285 BcStatus s = BC_STATUS_SUCCESS;
6295 if (!BC_PROG_STACK(&G.prog.results, 1))
6296 return bc_error("stack has too few elements");
6298 r = bc_vec_top(&G.prog.results);
6302 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6304 if (code[*bgn] == BC_PARSE_STREND)
6307 else_name = bc_program_name(code, bgn);
6309 exec = r->d.n.len != 0;
6313 else if (else_name != NULL) {
6320 v = bc_program_search(name, true);
6327 if (!exec) goto exit;
6328 if (!BC_PROG_STR(n)) {
6329 s = bc_error("variable is wrong type");
6337 if (r->t == BC_RESULT_STR)
6339 else if (r->t == BC_RESULT_VAR) {
6340 s = bc_program_num(r, &n, false);
6341 if (s || !BC_PROG_STR(n)) goto exit;
6348 fidx = sidx + BC_PROG_REQ_FUNCS;
6350 str = bc_vec_item(&G.prog.strs, sidx);
6351 f = bc_vec_item(&G.prog.fns, fidx);
6353 if (f->code.len == 0) {
6354 common_parse_init(&prs, fidx);
6355 s = bc_parse_text(&prs, *str);
6357 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6360 if (prs.l.t.t != BC_LEX_EOF) {
6361 s = bc_error("bad expression");
6365 bc_parse_free(&prs);
6369 ip.len = G.prog.results.len;
6372 bc_vec_pop(&G.prog.results);
6373 bc_vec_push(&G.prog.stack, &ip);
6375 return BC_STATUS_SUCCESS;
6378 bc_parse_free(&prs);
6379 f = bc_vec_item(&G.prog.fns, fidx);
6380 bc_vec_npop(&f->code, f->code.len);
6382 bc_vec_pop(&G.prog.results);
6387 static void bc_program_pushGlobal(char inst)
6392 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6393 if (inst == BC_INST_IBASE)
6394 val = (unsigned long) G.prog.ib_t;
6395 else if (inst == BC_INST_SCALE)
6396 val = (unsigned long) G.prog.scale;
6398 val = (unsigned long) G.prog.ob_t;
6400 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6401 bc_num_ulong2num(&res.d.n, val);
6402 bc_vec_push(&G.prog.results, &res);
6405 static void bc_program_addFunc(char *name, size_t *idx)
6407 BcId entry, *entry_ptr;
6412 entry.idx = G.prog.fns.len;
6414 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6415 if (!inserted) free(name);
6417 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6418 *idx = entry_ptr->idx;
6422 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6424 // We need to reset these, so the function can be repopulated.
6426 bc_vec_npop(&func->autos, func->autos.len);
6427 bc_vec_npop(&func->code, func->code.len);
6428 bc_vec_npop(&func->labels, func->labels.len);
6432 bc_vec_push(&G.prog.fns, &f);
6436 // Called when parsing or execution detects a failure,
6437 // resets execution structures.
6438 static void bc_program_reset(void)
6443 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6444 bc_vec_npop(&G.prog.results, G.prog.results.len);
6446 f = bc_vec_item(&G.prog.fns, 0);
6447 ip = bc_vec_top(&G.prog.stack);
6448 ip->idx = f->code.len;
6450 // If !tty, no need to check for ^C: we don't have ^C handler,
6451 // we would be killed by a signal and won't reach this place
6454 static BcStatus bc_program_exec(void)
6456 BcStatus s = BC_STATUS_SUCCESS;
6460 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6461 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6462 char *code = func->code.v;
6465 while (!s && ip->idx < func->code.len) {
6467 char inst = code[(ip->idx)++];
6472 case BC_INST_JUMP_ZERO:
6474 s = bc_program_prep(&ptr, &num);
6476 cond = !bc_num_cmp(num, &G.prog.zero);
6477 bc_vec_pop(&G.prog.results);
6483 idx = bc_program_index(code, &ip->idx);
6484 addr = bc_vec_item(&func->labels, idx);
6485 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6491 s = bc_program_call(code, &ip->idx);
6495 case BC_INST_INC_PRE:
6496 case BC_INST_DEC_PRE:
6497 case BC_INST_INC_POST:
6498 case BC_INST_DEC_POST:
6500 s = bc_program_incdec(inst);
6513 s = bc_program_return(inst);
6517 case BC_INST_BOOL_OR:
6518 case BC_INST_BOOL_AND:
6520 case BC_INST_REL_EQ:
6521 case BC_INST_REL_LE:
6522 case BC_INST_REL_GE:
6523 case BC_INST_REL_NE:
6524 case BC_INST_REL_LT:
6525 case BC_INST_REL_GT:
6527 s = bc_program_logical(inst);
6533 s = bc_program_read();
6539 s = bc_program_pushVar(code, &ip->idx, false, false);
6543 case BC_INST_ARRAY_ELEM:
6546 s = bc_program_pushArray(code, &ip->idx, inst);
6552 r.t = BC_RESULT_LAST;
6553 bc_vec_push(&G.prog.results, &r);
6561 bc_program_pushGlobal(inst);
6565 case BC_INST_SCALE_FUNC:
6566 case BC_INST_LENGTH:
6569 s = bc_program_builtin(inst);
6575 r.t = BC_RESULT_CONSTANT;
6576 r.d.id.idx = bc_program_index(code, &ip->idx);
6577 bc_vec_push(&G.prog.results, &r);
6583 if (!BC_PROG_STACK(&G.prog.results, 1))
6584 s = bc_error("stack has too few elements");
6586 bc_vec_pop(&G.prog.results);
6590 case BC_INST_POP_EXEC:
6592 bc_vec_pop(&G.prog.stack);
6597 case BC_INST_PRINT_POP:
6598 case BC_INST_PRINT_STR:
6600 s = bc_program_print(inst, 0);
6606 r.t = BC_RESULT_STR;
6607 r.d.id.idx = bc_program_index(code, &ip->idx);
6608 bc_vec_push(&G.prog.results, &r);
6613 case BC_INST_MULTIPLY:
6614 case BC_INST_DIVIDE:
6615 case BC_INST_MODULUS:
6619 s = bc_program_op(inst);
6623 case BC_INST_BOOL_NOT:
6625 s = bc_program_prep(&ptr, &num);
6628 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6629 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6630 bc_program_retire(&r, BC_RESULT_TEMP);
6637 s = bc_program_negate();
6642 case BC_INST_ASSIGN_POWER:
6643 case BC_INST_ASSIGN_MULTIPLY:
6644 case BC_INST_ASSIGN_DIVIDE:
6645 case BC_INST_ASSIGN_MODULUS:
6646 case BC_INST_ASSIGN_PLUS:
6647 case BC_INST_ASSIGN_MINUS:
6649 case BC_INST_ASSIGN:
6651 s = bc_program_assign(inst);
6655 case BC_INST_MODEXP:
6657 s = bc_program_modexp();
6661 case BC_INST_DIVMOD:
6663 s = bc_program_divmod();
6667 case BC_INST_EXECUTE:
6668 case BC_INST_EXEC_COND:
6670 cond = inst == BC_INST_EXEC_COND;
6671 s = bc_program_execStr(code, &ip->idx, cond);
6675 case BC_INST_PRINT_STACK:
6677 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6678 s = bc_program_print(BC_INST_PRINT, idx);
6682 case BC_INST_CLEAR_STACK:
6684 bc_vec_npop(&G.prog.results, G.prog.results.len);
6688 case BC_INST_STACK_LEN:
6690 bc_program_stackLen();
6694 case BC_INST_DUPLICATE:
6696 if (!BC_PROG_STACK(&G.prog.results, 1))
6697 return bc_error("stack has too few elements");
6698 ptr = bc_vec_top(&G.prog.results);
6699 bc_result_copy(&r, ptr);
6700 bc_vec_push(&G.prog.results, &r);
6708 if (!BC_PROG_STACK(&G.prog.results, 2))
6709 return bc_error("stack has too few elements");
6711 ptr = bc_vec_item_rev(&G.prog.results, 0);
6712 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6713 memcpy(&r, ptr, sizeof(BcResult));
6714 memcpy(ptr, ptr2, sizeof(BcResult));
6715 memcpy(ptr2, &r, sizeof(BcResult));
6720 case BC_INST_ASCIIFY:
6722 s = bc_program_asciify();
6726 case BC_INST_PRINT_STREAM:
6728 s = bc_program_printStream();
6733 case BC_INST_PUSH_VAR:
6735 bool copy = inst == BC_INST_LOAD;
6736 s = bc_program_pushVar(code, &ip->idx, true, copy);
6740 case BC_INST_PUSH_TO_VAR:
6742 char *name = bc_program_name(code, &ip->idx);
6743 s = bc_program_copyToVar(name, true);
6750 if (G.prog.stack.len <= 2)
6752 bc_vec_npop(&G.prog.stack, 2);
6758 s = bc_program_nquit();
6764 if (s || G_interrupt) {
6769 // If the stack has changed, pointers may be invalid.
6770 ip = bc_vec_top(&G.prog.stack);
6771 func = bc_vec_item(&G.prog.fns, ip->func);
6772 code = func->code.v;
6778 static void bc_vm_info(void)
6780 printf("%s "BB_VER"\n"
6781 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6782 "Report bugs at: https://github.com/gavinhoward/bc\n"
6783 "This is free software with ABSOLUTELY NO WARRANTY\n"
6788 static void bc_vm_envArgs(void)
6790 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6793 char *env_args = getenv(bc_args_env_name), *buf;
6795 if (!env_args) return;
6797 G.env_args = xstrdup(env_args);
6800 bc_vec_init(&v, sizeof(char *), NULL);
6801 bc_vec_push(&v, &bc_args_env_name);
6804 if (!isspace(*buf)) {
6805 bc_vec_push(&v, &buf);
6806 while (*buf != 0 && !isspace(*buf)) ++buf;
6807 if (*buf != 0) (*(buf++)) = '\0';
6813 bc_args((int) v.len, (char **) v.v);
6819 static size_t bc_vm_envLen(const char *var)
6821 char *lenv = getenv(var);
6822 size_t i, len = BC_NUM_PRINT_WIDTH;
6825 if (!lenv) return len;
6829 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6831 len = (size_t) atoi(lenv) - 1;
6832 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6835 len = BC_NUM_PRINT_WIDTH;
6840 static BcStatus bc_vm_process(const char *text)
6842 BcStatus s = bc_parse_text(&G.prs, text);
6846 while (G.prs.l.t.t != BC_LEX_EOF) {
6847 s = G.prs.parse(&G.prs);
6851 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6852 s = bc_program_exec();
6861 static BcStatus bc_vm_file(const char *file)
6869 data = bc_read_file(file);
6870 if (!data) return bc_error("file '%s' is not text", file);
6872 bc_lex_file(&G.prs.l, file);
6873 s = bc_vm_process(data);
6876 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6877 ip = bc_vec_item(&G.prog.stack, 0);
6879 if (main_func->code.len < ip->idx)
6880 s = bc_error("file '%s' is not executable", file);
6887 static BcStatus bc_vm_stdin(void)
6891 size_t len, i, str = 0;
6892 bool comment = false;
6894 G.prog.file = bc_program_stdin_name;
6895 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6897 bc_vec_init(&buffer, sizeof(char), NULL);
6898 bc_vec_init(&buf, sizeof(char), NULL);
6899 bc_vec_pushByte(&buffer, '\0');
6901 // This loop is complex because the vm tries not to send any lines that end
6902 // with a backslash to the parser. The reason for that is because the parser
6903 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6904 // case, and for strings and comments, the parser will expect more stuff.
6905 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6907 char *string = buf.v;
6912 if (str && buf.v[0] == G.send)
6914 else if (buf.v[0] == G.sbgn)
6917 else if (len > 1 || comment) {
6919 for (i = 0; i < len; ++i) {
6921 bool notend = len > i + 1;
6924 if (i - 1 > len || string[i - 1] != '\\') {
6925 if (G.sbgn == G.send)
6927 else if (c == G.send)
6929 else if (c == G.sbgn)
6933 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6937 else if (c == '*' && notend && comment && string[i + 1] == '/')
6941 if (str || comment || string[len - 2] == '\\') {
6942 bc_vec_concat(&buffer, buf.v);
6947 bc_vec_concat(&buffer, buf.v);
6948 s = bc_vm_process(buffer.v);
6951 fputs("ready for more input\n", stderr);
6954 bc_vec_npop(&buffer, buffer.len);
6958 s = bc_error("string end could not be found");
6961 s = bc_error("comment end could not be found");
6965 bc_vec_free(&buffer);
6969 static BcStatus bc_vm_exec(void)
6971 BcStatus s = BC_STATUS_SUCCESS;
6975 if (G.flags & BC_FLAG_L) {
6977 bc_lex_file(&G.prs.l, bc_lib_name);
6978 s = bc_parse_text(&G.prs, bc_lib);
6980 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6981 s = G.prs.parse(&G.prs);
6984 s = bc_program_exec();
6989 for (i = 0; !s && i < G.files.len; ++i)
6990 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
6995 fputs("ready for more input\n", stderr);
6998 if (IS_BC || !G.files.len)
7000 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7001 s = bc_vm_process("");
7006 #if ENABLE_FEATURE_CLEAN_UP
7007 static void bc_program_free()
7009 bc_num_free(&G.prog.ib);
7010 bc_num_free(&G.prog.ob);
7011 bc_num_free(&G.prog.hexb);
7013 bc_num_free(&G.prog.strmb);
7015 bc_vec_free(&G.prog.fns);
7016 bc_vec_free(&G.prog.fn_map);
7017 bc_vec_free(&G.prog.vars);
7018 bc_vec_free(&G.prog.var_map);
7019 bc_vec_free(&G.prog.arrs);
7020 bc_vec_free(&G.prog.arr_map);
7021 bc_vec_free(&G.prog.strs);
7022 bc_vec_free(&G.prog.consts);
7023 bc_vec_free(&G.prog.results);
7024 bc_vec_free(&G.prog.stack);
7025 bc_num_free(&G.prog.last);
7026 bc_num_free(&G.prog.zero);
7027 bc_num_free(&G.prog.one);
7030 static void bc_vm_free(void)
7032 bc_vec_free(&G.files);
7034 bc_parse_free(&G.prs);
7039 static void bc_program_init(size_t line_len)
7044 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7045 memset(&ip, 0, sizeof(BcInstPtr));
7047 /* G.prog.nchars = G.prog.scale = 0; - already is */
7048 G.prog.len = line_len;
7050 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7051 bc_num_ten(&G.prog.ib);
7054 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7055 bc_num_ten(&G.prog.ob);
7058 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7059 bc_num_ten(&G.prog.hexb);
7060 G.prog.hexb.num[0] = 6;
7063 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7064 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7067 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7068 bc_num_zero(&G.prog.last);
7070 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7071 bc_num_zero(&G.prog.zero);
7073 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7074 bc_num_one(&G.prog.one);
7076 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7077 bc_map_init(&G.prog.fn_map);
7079 bc_program_addFunc(xstrdup("(main)"), &idx);
7080 bc_program_addFunc(xstrdup("(read)"), &idx);
7082 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7083 bc_map_init(&G.prog.var_map);
7085 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7086 bc_map_init(&G.prog.arr_map);
7088 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7089 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7090 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7091 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7092 bc_vec_push(&G.prog.stack, &ip);
7095 static void bc_vm_init(const char *env_len)
7097 size_t len = bc_vm_envLen(env_len);
7099 bc_vec_init(&G.files, sizeof(char *), NULL);
7102 if (getenv("POSIXLY_CORRECT"))
7103 G.flags |= BC_FLAG_S;
7107 bc_program_init(len);
7109 bc_parse_init(&G.prs, BC_PROG_MAIN);
7111 dc_parse_init(&G.prs, BC_PROG_MAIN);
7115 static BcStatus bc_vm_run(int argc, char *argv[],
7116 const char *env_len)
7120 bc_vm_init(env_len);
7121 bc_args(argc, argv);
7123 G.ttyin = isatty(0);
7124 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7127 #if ENABLE_FEATURE_BC_SIGNALS
7128 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7130 if (!(G.flags & BC_FLAG_Q))
7135 #if ENABLE_FEATURE_CLEAN_UP
7142 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7143 int bc_main(int argc, char **argv)
7146 G.sbgn = G.send = '"';
7148 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7153 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7154 int dc_main(int argc, char **argv)
7160 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");