1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
194 typedef signed char BcDig;
196 typedef struct BcNum {
204 #define BC_NUM_MIN_BASE ((unsigned long) 2)
205 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
206 #define BC_NUM_DEF_SIZE (16)
207 #define BC_NUM_PRINT_WIDTH (69)
209 #define BC_NUM_KARATSUBA_LEN (32)
211 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
212 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
213 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
214 #define BC_NUM_AREQ(a, b) \
215 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
216 #define BC_NUM_MREQ(a, b, scale) \
217 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
219 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
220 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
222 static void bc_num_init(BcNum *n, size_t req);
223 static void bc_num_expand(BcNum *n, size_t req);
224 static void bc_num_copy(BcNum *d, BcNum *s);
225 static void bc_num_free(void *num);
227 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
228 static void bc_num_ulong2num(BcNum *n, unsigned long val);
230 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
235 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
236 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
237 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
240 typedef enum BcInst {
270 BC_INST_ASSIGN_POWER,
271 BC_INST_ASSIGN_MULTIPLY,
272 BC_INST_ASSIGN_DIVIDE,
273 BC_INST_ASSIGN_MODULUS,
275 BC_INST_ASSIGN_MINUS,
321 BC_INST_PRINT_STREAM,
336 BC_INST_INVALID = -1,
341 typedef struct BcId {
346 typedef struct BcFunc {
353 typedef enum BcResultType {
358 BC_RESULT_ARRAY_ELEM,
367 // These are between to calculate ibase, obase, and last from instructions.
375 typedef union BcResultData {
381 typedef struct BcResult {
386 typedef struct BcInstPtr {
392 static void bc_array_expand(BcVec *a, size_t len);
393 static int bc_id_cmp(const void *e1, const void *e2);
395 // BC_LEX_NEG is not used in lexing; it is only for parsing.
396 typedef enum BcLexType {
424 BC_LEX_OP_ASSIGN_POWER,
425 BC_LEX_OP_ASSIGN_MULTIPLY,
426 BC_LEX_OP_ASSIGN_DIVIDE,
427 BC_LEX_OP_ASSIGN_MODULUS,
428 BC_LEX_OP_ASSIGN_PLUS,
429 BC_LEX_OP_ASSIGN_MINUS,
503 typedef BcStatus (*BcLexNext)(struct BcLex *);
505 typedef struct BcLex {
524 #define BC_PARSE_STREND ((char) UCHAR_MAX)
526 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
527 #define bc_parse_updateFunc(p, f) \
528 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
530 #define BC_PARSE_REL (1 << 0)
531 #define BC_PARSE_PRINT (1 << 1)
532 #define BC_PARSE_NOCALL (1 << 2)
533 #define BC_PARSE_NOREAD (1 << 3)
534 #define BC_PARSE_ARRAY (1 << 4)
536 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
537 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
539 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
540 #define BC_PARSE_FUNC_INNER(parse) \
541 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
543 #define BC_PARSE_FLAG_FUNC (1 << 1)
544 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
546 #define BC_PARSE_FLAG_BODY (1 << 2)
547 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
549 #define BC_PARSE_FLAG_LOOP (1 << 3)
550 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
552 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
553 #define BC_PARSE_LOOP_INNER(parse) \
554 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
556 #define BC_PARSE_FLAG_IF (1 << 5)
557 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
559 #define BC_PARSE_FLAG_ELSE (1 << 6)
560 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
562 #define BC_PARSE_FLAG_IF_END (1 << 7)
563 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
565 #define BC_PARSE_CAN_EXEC(parse) \
566 (!(BC_PARSE_TOP_FLAG(parse) & \
567 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
568 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
569 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
571 typedef struct BcOp {
576 typedef struct BcParseNext {
581 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
582 #define BC_PARSE_NEXT(a, ...) \
584 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
591 typedef BcStatus (*BcParseParse)(struct BcParse *);
593 typedef struct BcParse {
616 typedef struct BcLexKeyword {
622 #define BC_LEX_KW_ENTRY(a, b, c) \
624 .name = a, .len = (b), .posix = (c) \
627 static BcStatus bc_lex_token(BcLex *l);
629 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
630 #define BC_PARSE_LEAF(p, rparen) \
631 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
632 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
634 // We can calculate the conversion between tokens and exprs by subtracting the
635 // position of the first operator in the lex enum and adding the position of the
636 // first in the expr enum. Note: This only works for binary operators.
637 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
639 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
645 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
647 static BcStatus dc_lex_token(BcLex *l);
649 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
653 typedef struct BcProgram {
694 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
696 #define BC_PROG_MAIN (0)
697 #define BC_PROG_READ (1)
700 #define BC_PROG_REQ_FUNCS (2)
703 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
704 #define BC_PROG_NUM(r, n) \
705 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
707 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
709 static void bc_program_addFunc(char *name, size_t *idx);
710 static void bc_program_reset(void);
712 #define BC_FLAG_X (1 << 0)
713 #define BC_FLAG_W (1 << 1)
714 #define BC_FLAG_V (1 << 2)
715 #define BC_FLAG_S (1 << 3)
716 #define BC_FLAG_Q (1 << 4)
717 #define BC_FLAG_L (1 << 5)
718 #define BC_FLAG_I (1 << 6)
720 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
721 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
723 #define BC_MAX_OBASE ((unsigned) 999)
724 #define BC_MAX_DIM ((unsigned) INT_MAX)
725 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
726 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
727 #define BC_MAX_NAME BC_MAX_STRING
728 #define BC_MAX_NUM BC_MAX_STRING
729 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
730 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
745 #define G (*ptr_to_globals)
746 #define INIT_G() do { \
747 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
749 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
750 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
751 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
752 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
755 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
757 static void bc_vm_info(void);
760 static const BcLexKeyword bc_lex_kws[20] = {
761 BC_LEX_KW_ENTRY("auto", 4, true),
762 BC_LEX_KW_ENTRY("break", 5, true),
763 BC_LEX_KW_ENTRY("continue", 8, false),
764 BC_LEX_KW_ENTRY("define", 6, true),
765 BC_LEX_KW_ENTRY("else", 4, false),
766 BC_LEX_KW_ENTRY("for", 3, true),
767 BC_LEX_KW_ENTRY("halt", 4, false),
768 BC_LEX_KW_ENTRY("ibase", 5, true),
769 BC_LEX_KW_ENTRY("if", 2, true),
770 BC_LEX_KW_ENTRY("last", 4, false),
771 BC_LEX_KW_ENTRY("length", 6, true),
772 BC_LEX_KW_ENTRY("limits", 6, false),
773 BC_LEX_KW_ENTRY("obase", 5, true),
774 BC_LEX_KW_ENTRY("print", 5, false),
775 BC_LEX_KW_ENTRY("quit", 4, true),
776 BC_LEX_KW_ENTRY("read", 4, false),
777 BC_LEX_KW_ENTRY("return", 6, true),
778 BC_LEX_KW_ENTRY("scale", 5, true),
779 BC_LEX_KW_ENTRY("sqrt", 4, true),
780 BC_LEX_KW_ENTRY("while", 5, true),
783 // This is an array that corresponds to token types. An entry is
784 // true if the token is valid in an expression, false otherwise.
785 static const bool bc_parse_exprs[] = {
786 false, false, true, true, true, true, true, true, true, true, true, true,
787 true, true, true, true, true, true, true, true, true, true, true, true,
788 true, true, true, false, false, true, true, false, false, false, false,
789 false, false, false, true, true, false, false, false, false, false, false,
790 false, true, false, true, true, true, true, false, false, true, false, true,
794 // This is an array of data for operators that correspond to token types.
795 static const BcOp bc_parse_ops[] = {
796 { 0, false }, { 0, false },
799 { 3, true }, { 3, true }, { 3, true },
800 { 4, true }, { 4, true },
801 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
803 { 7, true }, { 7, true },
804 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
805 { 5, false }, { 5, false },
808 // These identify what tokens can come after expressions in certain cases.
809 static const BcParseNext bc_parse_next_expr =
810 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
811 static const BcParseNext bc_parse_next_param =
812 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
813 static const BcParseNext bc_parse_next_print =
814 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
815 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
816 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
817 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
818 static const BcParseNext bc_parse_next_read =
819 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
823 static const BcLexType dc_lex_regs[] = {
824 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
825 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
826 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
830 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
832 static const BcLexType dc_lex_tokens[] = {
833 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
834 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
835 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
836 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
838 BC_LEX_INVALID, BC_LEX_INVALID,
839 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
840 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
843 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
844 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
845 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
847 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
848 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
849 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
850 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
852 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
853 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
854 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
855 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
856 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
860 static const BcInst dc_parse_insts[] = {
861 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
862 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
863 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
871 BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
874 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
876 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
878 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
879 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
880 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
881 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
883 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
887 static const BcNumBinaryOp bc_program_ops[] = {
888 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
891 static const char bc_program_stdin_name[] = "<stdin>";
894 static const char *bc_lib_name = "gen/lib.bc";
896 static const char bc_lib[] = {
897 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
898 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
899 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
900 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
901 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
902 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
903 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
904 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
905 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
906 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
907 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
908 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
909 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
910 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
911 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
912 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
913 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
914 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
915 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
916 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
917 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
918 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
919 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
920 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
921 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
922 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
923 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
924 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
925 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
926 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
927 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
928 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
929 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
930 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
931 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
932 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
933 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
934 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
935 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
936 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
937 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
938 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
939 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
940 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
941 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
942 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
943 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
944 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
945 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
946 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
947 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
948 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
949 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
950 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
951 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
952 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
953 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
954 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
955 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
956 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
957 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
958 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
959 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
960 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
961 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
962 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
963 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
964 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
965 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
966 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
967 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
968 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
969 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
970 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
971 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
972 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
973 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
974 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
975 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
976 117,114,110,40,97,42,114,47,49,41,10,125,10,0
980 static void fflush_and_check(void)
983 if (ferror(stdout) || ferror(stderr))
984 bb_perror_msg_and_die("output error");
987 static void quit(void) NORETURN;
988 static void quit(void)
991 bb_perror_msg_and_die("input error");
996 static int bc_error(const char *fmt, ...)
1001 bb_verror_msg(fmt, p, NULL);
1005 return BC_STATUS_FAILURE;
1008 static int bc_posix_error(const char *fmt, ...)
1012 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
1013 return BC_STATUS_SUCCESS;
1016 bb_verror_msg(fmt, p, NULL);
1019 // Do we treat non-POSIX constructs as errors?
1020 if (!(option_mask32 & BC_FLAG_S))
1021 return BC_STATUS_SUCCESS; // no, it's a warning
1024 return BC_STATUS_FAILURE;
1027 static void bc_vec_grow(BcVec *v, size_t n)
1029 size_t cap = v->cap * 2;
1030 while (cap < v->len + n) cap *= 2;
1031 v->v = xrealloc(v->v, v->size * cap);
1035 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1038 v->cap = BC_VEC_START_CAP;
1041 v->v = xmalloc(esize * BC_VEC_START_CAP);
1044 static void bc_vec_expand(BcVec *v, size_t req)
1047 v->v = xrealloc(v->v, v->size * req);
1052 static void bc_vec_npop(BcVec *v, size_t n)
1057 size_t len = v->len - n;
1058 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1062 static void bc_vec_push(BcVec *v, const void *data)
1064 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1065 memmove(v->v + (v->size * v->len), data, v->size);
1069 static void bc_vec_pushByte(BcVec *v, char data)
1071 bc_vec_push(v, &data);
1074 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1077 bc_vec_push(v, data);
1082 if (v->len == v->cap) bc_vec_grow(v, 1);
1084 ptr = v->v + v->size * idx;
1086 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1087 memmove(ptr, data, v->size);
1091 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1093 bc_vec_npop(v, v->len);
1094 bc_vec_expand(v, len + 1);
1095 memcpy(v->v, str, len);
1098 bc_vec_pushByte(v, '\0');
1101 static void bc_vec_concat(BcVec *v, const char *str)
1105 if (v->len == 0) bc_vec_pushByte(v, '\0');
1107 len = v->len + strlen(str);
1109 if (v->cap < len) bc_vec_grow(v, len - v->len);
1115 static void *bc_vec_item(const BcVec *v, size_t idx)
1117 return v->v + v->size * idx;
1120 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1122 return v->v + v->size * (v->len - idx - 1);
1125 static void bc_vec_free(void *vec)
1127 BcVec *v = (BcVec *) vec;
1128 bc_vec_npop(v, v->len);
1132 static size_t bc_map_find(const BcVec *v, const void *ptr)
1134 size_t low = 0, high = v->len;
1136 while (low < high) {
1138 size_t mid = (low + high) / 2;
1139 BcId *id = bc_vec_item(v, mid);
1140 int result = bc_id_cmp(ptr, id);
1144 else if (result < 0)
1153 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1155 size_t n = *i = bc_map_find(v, ptr);
1158 bc_vec_push(v, ptr);
1159 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1160 return 0; // "was not inserted"
1162 bc_vec_pushAt(v, ptr, n);
1163 return 1; // "was inserted"
1166 static size_t bc_map_index(const BcVec *v, const void *ptr)
1168 size_t i = bc_map_find(v, ptr);
1169 if (i >= v->len) return BC_VEC_INVALID_IDX;
1170 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1173 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1182 bc_vec_npop(vec, vec->len);
1185 #if ENABLE_FEATURE_BC_SIGNALS
1186 if (bb_got_signal) { // ^C was pressed
1188 bb_got_signal = 0; // resets G_interrupt to zero
1190 ? "\ninterrupt (type \"quit\" to exit)\n"
1191 : "\ninterrupt (type \"q\" to exit)\n"
1195 if (G.ttyin && !G_posix)
1196 fputs(prompt, stderr);
1198 #if ENABLE_FEATURE_BC_SIGNALS
1204 #if ENABLE_FEATURE_BC_SIGNALS
1205 // Both conditions appear simultaneously, check both just in case
1206 if (errno == EINTR || bb_got_signal) {
1213 quit(); // this emits error message
1215 // Note: EOF does not append '\n', therefore:
1216 // printf 'print 123\n' | bc - works
1217 // printf 'print 123' | bc - fails (syntax error)
1221 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1224 // Bad chars on this line, ignore entire line
1225 bc_error("illegal character 0x%02x", i);
1229 bc_vec_push(vec, &c);
1230 } while (i != '\n');
1231 } while (bad_chars);
1233 bc_vec_pushByte(vec, '\0');
1235 return BC_STATUS_SUCCESS;
1238 static char* bc_read_file(const char *path)
1241 size_t size = ((size_t) -1);
1244 buf = xmalloc_open_read_close(path, &size);
1246 for (i = 0; i < size; ++i) {
1248 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1260 static void bc_args(int argc, char **argv)
1266 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1267 opts = getopt32long(argv, "xwvsqli",
1268 "extended-register\0" No_argument "x"
1269 "warn\0" No_argument "w"
1270 "version\0" No_argument "v"
1271 "standard\0" No_argument "s"
1272 "quiet\0" No_argument "q"
1273 "mathlib\0" No_argument "l"
1274 "interactive\0" No_argument "i"
1277 opts = getopt32(argv, "xwvsqli");
1279 if (getenv("POSIXLY_CORRECT"))
1280 option_mask32 |= BC_FLAG_S;
1282 if (opts & BC_FLAG_V) bc_vm_info();
1283 // should not be necessary, getopt32() handles this??
1284 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1286 for (i = optind; i < argc; ++i)
1287 bc_vec_push(&G.files, argv + i);
1290 static void bc_num_setToZero(BcNum *n, size_t scale)
1297 static void bc_num_zero(BcNum *n)
1299 bc_num_setToZero(n, 0);
1302 static void bc_num_one(BcNum *n)
1304 bc_num_setToZero(n, 0);
1309 static void bc_num_ten(BcNum *n)
1311 bc_num_setToZero(n, 0);
1317 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1321 for (i = 0; i < len; ++i) {
1322 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1329 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1333 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1334 return BC_NUM_NEG(i + 1, c < 0);
1337 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1339 size_t i, min, a_int, b_int, diff;
1340 BcDig *max_num, *min_num;
1341 bool a_max, neg = false;
1344 if (a == b) return 0;
1345 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1346 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1356 a_int = BC_NUM_INT(a);
1357 b_int = BC_NUM_INT(b);
1359 a_max = (a->rdx > b->rdx);
1361 if (a_int != 0) return (ssize_t) a_int;
1365 diff = a->rdx - b->rdx;
1366 max_num = a->num + diff;
1371 diff = b->rdx - a->rdx;
1372 max_num = b->num + diff;
1376 cmp = bc_num_compare(max_num, min_num, b_int + min);
1377 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1379 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1380 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1386 static void bc_num_truncate(BcNum *n, size_t places)
1388 if (places == 0) return;
1394 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1398 static void bc_num_extend(BcNum *n, size_t places)
1400 size_t len = n->len + places;
1404 if (n->cap < len) bc_num_expand(n, len);
1406 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1407 memset(n->num, 0, sizeof(BcDig) * places);
1414 static void bc_num_clean(BcNum *n)
1416 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1419 else if (n->len < n->rdx)
1423 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1426 bc_num_extend(n, scale - n->rdx);
1428 bc_num_truncate(n, n->rdx - scale);
1431 if (n->len != 0) n->neg = !neg1 != !neg2;
1434 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1439 b->len = n->len - idx;
1441 a->rdx = b->rdx = 0;
1443 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1444 memcpy(a->num, n->num, idx * sizeof(BcDig));
1455 static BcStatus bc_num_shift(BcNum *n, size_t places)
1457 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1458 if (places + n->len > BC_MAX_NUM)
1459 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1461 if (n->rdx >= places)
1464 bc_num_extend(n, places - n->rdx);
1470 return BC_STATUS_SUCCESS;
1473 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1482 return bc_num_div(&one, a, b, scale);
1485 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1487 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1488 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1491 // Because this function doesn't need to use scale (per the bc spec),
1492 // I am hijacking it to say whether it's doing an add or a subtract.
1496 if (sub && c->len) c->neg = !c->neg;
1497 return BC_STATUS_SUCCESS;
1499 else if (b->len == 0) {
1501 return BC_STATUS_SUCCESS;
1505 c->rdx = BC_MAX(a->rdx, b->rdx);
1506 min_rdx = BC_MIN(a->rdx, b->rdx);
1509 if (a->rdx > b->rdx) {
1510 diff = a->rdx - b->rdx;
1512 ptr_a = a->num + diff;
1516 diff = b->rdx - a->rdx;
1519 ptr_b = b->num + diff;
1522 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1525 a_int = BC_NUM_INT(a);
1526 b_int = BC_NUM_INT(b);
1528 if (a_int > b_int) {
1539 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1540 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1542 ptr_c[i] = (BcDig)(in % 10);
1545 for (; i < max + min_rdx; ++i, ++c->len) {
1546 in = ((int) ptr[i]) + carry;
1548 ptr_c[i] = (BcDig)(in % 10);
1551 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1553 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1556 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1559 BcNum *minuend, *subtrahend;
1561 bool aneg, bneg, neg;
1563 // Because this function doesn't need to use scale (per the bc spec),
1564 // I am hijacking it to say whether it's doing an add or a subtract.
1568 if (sub && c->len) c->neg = !c->neg;
1569 return BC_STATUS_SUCCESS;
1571 else if (b->len == 0) {
1573 return BC_STATUS_SUCCESS;
1578 a->neg = b->neg = false;
1580 cmp = bc_num_cmp(a, b);
1586 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1587 return BC_STATUS_SUCCESS;
1596 if (sub) neg = !neg;
1601 bc_num_copy(c, minuend);
1604 if (c->rdx < subtrahend->rdx) {
1605 bc_num_extend(c, subtrahend->rdx - c->rdx);
1609 start = c->rdx - subtrahend->rdx;
1611 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1615 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1618 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1623 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1624 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1625 bool aone = BC_NUM_ONE(a);
1627 if (a->len == 0 || b->len == 0) {
1629 return BC_STATUS_SUCCESS;
1631 else if (aone || BC_NUM_ONE(b)) {
1632 bc_num_copy(c, aone ? b : a);
1633 return BC_STATUS_SUCCESS;
1636 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1637 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1639 bc_num_expand(c, a->len + b->len + 1);
1641 memset(c->num, 0, sizeof(BcDig) * c->cap);
1642 c->len = carry = len = 0;
1644 for (i = 0; i < b->len; ++i) {
1646 for (j = 0; j < a->len; ++j) {
1647 int in = (int) c->num[i + j];
1648 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1650 c->num[i + j] = (BcDig)(in % 10);
1653 c->num[i + j] += (BcDig) carry;
1654 len = BC_MAX(len, i + j + !!carry);
1660 return BC_STATUS_SUCCESS;
1663 bc_num_init(&l1, max);
1664 bc_num_init(&h1, max);
1665 bc_num_init(&l2, max);
1666 bc_num_init(&h2, max);
1667 bc_num_init(&m1, max);
1668 bc_num_init(&m2, max);
1669 bc_num_init(&z0, max);
1670 bc_num_init(&z1, max);
1671 bc_num_init(&z2, max);
1672 bc_num_init(&temp, max + max);
1674 bc_num_split(a, max2, &l1, &h1);
1675 bc_num_split(b, max2, &l2, &h2);
1677 s = bc_num_add(&h1, &l1, &m1, 0);
1679 s = bc_num_add(&h2, &l2, &m2, 0);
1682 s = bc_num_k(&h1, &h2, &z0);
1684 s = bc_num_k(&m1, &m2, &z1);
1686 s = bc_num_k(&l1, &l2, &z2);
1689 s = bc_num_sub(&z1, &z0, &temp, 0);
1691 s = bc_num_sub(&temp, &z2, &z1, 0);
1694 s = bc_num_shift(&z0, max2 * 2);
1696 s = bc_num_shift(&z1, max2);
1698 s = bc_num_add(&z0, &z1, &temp, 0);
1700 s = bc_num_add(&temp, &z2, c, 0);
1716 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1720 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1722 scale = BC_MAX(scale, a->rdx);
1723 scale = BC_MAX(scale, b->rdx);
1724 scale = BC_MIN(a->rdx + b->rdx, scale);
1725 maxrdx = BC_MAX(maxrdx, scale);
1727 bc_num_init(&cpa, a->len);
1728 bc_num_init(&cpb, b->len);
1730 bc_num_copy(&cpa, a);
1731 bc_num_copy(&cpb, b);
1732 cpa.neg = cpb.neg = false;
1734 s = bc_num_shift(&cpa, maxrdx);
1736 s = bc_num_shift(&cpb, maxrdx);
1738 s = bc_num_k(&cpa, &cpb, c);
1742 bc_num_expand(c, c->len + maxrdx);
1744 if (c->len < maxrdx) {
1745 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1750 bc_num_retireMul(c, scale, a->neg, b->neg);
1758 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1760 BcStatus s = BC_STATUS_SUCCESS;
1767 return bc_error("divide by zero");
1768 else if (a->len == 0) {
1769 bc_num_setToZero(c, scale);
1770 return BC_STATUS_SUCCESS;
1772 else if (BC_NUM_ONE(b)) {
1774 bc_num_retireMul(c, scale, a->neg, b->neg);
1775 return BC_STATUS_SUCCESS;
1778 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1779 bc_num_copy(&cp, a);
1783 bc_num_expand(&cp, len + 2);
1784 bc_num_extend(&cp, len - cp.len);
1787 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1789 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1791 if (b->rdx == b->len) {
1792 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1796 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1798 // We want an extra zero in front to make things simpler.
1799 cp.num[cp.len++] = 0;
1802 bc_num_expand(c, cp.len);
1805 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1810 for (i = end - 1; !s && i < end; --i) {
1812 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1813 bc_num_subArrays(n, p, len);
1817 bc_num_retireMul(c, scale, a->neg, b->neg);
1820 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1823 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1824 BcNum *restrict d, size_t scale, size_t ts)
1831 return bc_error("divide by zero");
1834 bc_num_setToZero(d, ts);
1835 return BC_STATUS_SUCCESS;
1838 bc_num_init(&temp, d->cap);
1839 bc_num_d(a, b, c, scale);
1841 if (scale != 0) scale = ts;
1843 s = bc_num_m(c, b, &temp, scale);
1845 s = bc_num_sub(a, &temp, d, scale);
1848 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1851 bc_num_retireMul(d, ts, a->neg, b->neg);
1859 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1863 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1865 bc_num_init(&c1, len);
1866 s = bc_num_r(a, b, &c1, c, scale, ts);
1872 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1874 BcStatus s = BC_STATUS_SUCCESS;
1877 size_t i, powrdx, resrdx;
1880 if (b->rdx) return bc_error("non integer number");
1884 return BC_STATUS_SUCCESS;
1886 else if (a->len == 0) {
1887 bc_num_setToZero(c, scale);
1888 return BC_STATUS_SUCCESS;
1890 else if (BC_NUM_ONE(b)) {
1894 s = bc_num_inv(a, c, scale);
1901 s = bc_num_ulong(b, &pow);
1904 bc_num_init(©, a->len);
1905 bc_num_copy(©, a);
1907 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1911 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1913 s = bc_num_mul(©, ©, ©, powrdx);
1917 bc_num_copy(c, ©);
1919 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1922 s = bc_num_mul(©, ©, ©, powrdx);
1927 s = bc_num_mul(c, ©, c, resrdx);
1933 s = bc_num_inv(c, c, scale);
1937 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1939 // We can't use bc_num_clean() here.
1940 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1941 if (zero) bc_num_setToZero(c, scale);
1948 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1949 BcNumBinaryOp op, size_t req)
1952 BcNum num2, *ptr_a, *ptr_b;
1957 memcpy(ptr_a, c, sizeof(BcNum));
1966 memcpy(ptr_b, c, sizeof(BcNum));
1974 bc_num_init(c, req);
1976 bc_num_expand(c, req);
1978 s = op(ptr_a, ptr_b, c, scale);
1980 if (init) bc_num_free(&num2);
1985 static bool bc_num_strValid(const char *val, size_t base)
1988 bool small, radix = false;
1989 size_t i, len = strlen(val);
1991 if (!len) return true;
1994 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1996 for (i = 0; i < len; ++i) {
2002 if (radix) return false;
2008 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2015 static void bc_num_parseDecimal(BcNum *n, const char *val)
2021 for (i = 0; val[i] == '0'; ++i);
2028 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2029 bc_num_expand(n, len);
2032 ptr = strchr(val, '.');
2036 n->rdx = (size_t)((val + len) - (ptr + 1));
2039 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2040 n->num[n->len] = val[i] - '0';
2044 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2047 BcNum temp, mult, result;
2051 size_t i, digits, len = strlen(val);
2055 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2058 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2059 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2061 for (i = 0; i < len; ++i) {
2064 if (c == '.') break;
2066 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2068 s = bc_num_mul(n, base, &mult, 0);
2069 if (s) goto int_err;
2070 bc_num_ulong2num(&temp, v);
2071 s = bc_num_add(&mult, &temp, n, 0);
2072 if (s) goto int_err;
2077 if (c == 0) goto int_err;
2080 bc_num_init(&result, base->len);
2081 bc_num_zero(&result);
2084 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2089 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2091 s = bc_num_mul(&result, base, &result, 0);
2093 bc_num_ulong2num(&temp, v);
2094 s = bc_num_add(&result, &temp, &result, 0);
2096 s = bc_num_mul(&mult, base, &mult, 0);
2100 s = bc_num_div(&result, &mult, &result, digits);
2102 s = bc_num_add(n, &result, n, digits);
2106 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2112 bc_num_free(&result);
2118 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2120 if (*nchars == line_len - 1) {
2128 static void bc_num_printChar(size_t num, size_t width, bool radix,
2129 size_t *nchars, size_t line_len)
2131 (void) radix, (void) line_len;
2132 bb_putchar((char) num);
2133 *nchars = *nchars + width;
2137 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2138 size_t *nchars, size_t line_len)
2142 bc_num_printNewline(nchars, line_len);
2143 bb_putchar(radix ? '.' : ' ');
2146 bc_num_printNewline(nchars, line_len);
2147 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2150 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2152 bc_num_printNewline(nchars, line_len);
2155 bb_putchar(((char) dig) + '0');
2159 static void bc_num_printHex(size_t num, size_t width, bool radix,
2160 size_t *nchars, size_t line_len)
2163 bc_num_printNewline(nchars, line_len);
2168 bc_num_printNewline(nchars, line_len);
2169 bb_putchar(bb_hexdigits_upcase[num]);
2170 *nchars = *nchars + width;
2173 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2175 size_t i, rdx = n->rdx - 1;
2177 if (n->neg) bb_putchar('-');
2178 (*nchars) += n->neg;
2180 for (i = n->len - 1; i < n->len; --i)
2181 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2184 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2185 size_t *nchars, size_t len, BcNumDigitOp print)
2189 BcNum intp, fracp, digit, frac_len;
2190 unsigned long dig, *ptr;
2195 print(0, width, false, nchars, len);
2196 return BC_STATUS_SUCCESS;
2199 bc_vec_init(&stack, sizeof(long), NULL);
2200 bc_num_init(&intp, n->len);
2201 bc_num_init(&fracp, n->rdx);
2202 bc_num_init(&digit, width);
2203 bc_num_init(&frac_len, BC_NUM_INT(n));
2204 bc_num_copy(&intp, n);
2205 bc_num_one(&frac_len);
2207 bc_num_truncate(&intp, intp.rdx);
2208 s = bc_num_sub(n, &intp, &fracp, 0);
2211 while (intp.len != 0) {
2212 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2214 s = bc_num_ulong(&digit, &dig);
2216 bc_vec_push(&stack, &dig);
2219 for (i = 0; i < stack.len; ++i) {
2220 ptr = bc_vec_item_rev(&stack, i);
2221 print(*ptr, width, false, nchars, len);
2224 if (!n->rdx) goto err;
2226 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2227 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2229 s = bc_num_ulong(&fracp, &dig);
2231 bc_num_ulong2num(&intp, dig);
2232 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2234 print(dig, width, radix, nchars, len);
2235 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2240 bc_num_free(&frac_len);
2241 bc_num_free(&digit);
2242 bc_num_free(&fracp);
2244 bc_vec_free(&stack);
2248 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2249 size_t *nchars, size_t line_len)
2256 if (neg) bb_putchar('-');
2261 if (base_t <= BC_NUM_MAX_IBASE) {
2263 print = bc_num_printHex;
2266 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2267 print = bc_num_printDigits;
2270 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2277 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2279 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2283 static void bc_num_init(BcNum *n, size_t req)
2285 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2286 memset(n, 0, sizeof(BcNum));
2287 n->num = xmalloc(req);
2291 static void bc_num_expand(BcNum *n, size_t req)
2293 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2295 n->num = xrealloc(n->num, req);
2300 static void bc_num_free(void *num)
2302 free(((BcNum *) num)->num);
2305 static void bc_num_copy(BcNum *d, BcNum *s)
2308 bc_num_expand(d, s->cap);
2312 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2316 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2319 if (!bc_num_strValid(val, base_t))
2320 return bc_error("bad number string");
2323 bc_num_parseDecimal(n, val);
2325 bc_num_parseBase(n, val, base);
2327 return BC_STATUS_SUCCESS;
2330 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2331 size_t *nchars, size_t line_len)
2333 BcStatus s = BC_STATUS_SUCCESS;
2335 bc_num_printNewline(nchars, line_len);
2341 else if (base_t == 10)
2342 bc_num_printDecimal(n, nchars, line_len);
2344 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2354 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2359 if (n->neg) return bc_error("negative number");
2361 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2363 unsigned long prev = *result, powprev = pow;
2365 *result += ((unsigned long) n->num[i]) * pow;
2368 if (*result < prev || pow < powprev)
2369 return bc_error("overflow");
2372 return BC_STATUS_SUCCESS;
2375 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2383 if (val == 0) return;
2385 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2386 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2389 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2391 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2393 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2396 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2398 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2400 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2403 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2405 size_t req = BC_NUM_MREQ(a, b, scale);
2406 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2409 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2411 size_t req = BC_NUM_MREQ(a, b, scale);
2412 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2415 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2417 size_t req = BC_NUM_MREQ(a, b, scale);
2418 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2421 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2423 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2426 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2429 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2430 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2431 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2433 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2434 bc_num_expand(b, req);
2437 bc_num_setToZero(b, scale);
2438 return BC_STATUS_SUCCESS;
2441 return bc_error("negative number");
2442 else if (BC_NUM_ONE(a)) {
2444 bc_num_extend(b, scale);
2445 return BC_STATUS_SUCCESS;
2448 scale = BC_MAX(scale, a->rdx) + 1;
2449 len = a->len + scale;
2451 bc_num_init(&num1, len);
2452 bc_num_init(&num2, len);
2453 bc_num_init(&half, BC_NUM_DEF_SIZE);
2459 bc_num_init(&f, len);
2460 bc_num_init(&fprime, len);
2466 pow = BC_NUM_INT(a);
2475 pow -= 2 - (pow & 1);
2477 bc_num_extend(x0, pow);
2479 // Make sure to move the radix back.
2483 x0->rdx = digs = digs1 = 0;
2485 len = BC_NUM_INT(x0) + resrdx - 1;
2487 while (cmp != 0 || digs < len) {
2489 s = bc_num_div(a, x0, &f, resrdx);
2491 s = bc_num_add(x0, &f, &fprime, resrdx);
2493 s = bc_num_mul(&fprime, &half, x1, resrdx);
2496 cmp = bc_num_cmp(x1, x0);
2497 digs = x1->len - (unsigned long long) llabs(cmp);
2499 if (cmp == cmp2 && digs == digs1)
2504 resrdx += times > 4;
2517 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2520 bc_num_free(&fprime);
2528 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2534 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2537 memcpy(&num2, c, sizeof(BcNum));
2539 bc_num_init(c, len);
2544 bc_num_expand(c, len);
2547 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2549 if (init) bc_num_free(&num2);
2555 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2558 BcNum base, exp, two, temp;
2561 return bc_error("divide by zero");
2562 if (a->rdx || b->rdx || c->rdx)
2563 return bc_error("non integer number");
2565 return bc_error("negative number");
2567 bc_num_expand(d, c->len);
2568 bc_num_init(&base, c->len);
2569 bc_num_init(&exp, b->len);
2570 bc_num_init(&two, BC_NUM_DEF_SIZE);
2571 bc_num_init(&temp, b->len);
2577 s = bc_num_rem(a, c, &base, 0);
2579 bc_num_copy(&exp, b);
2581 while (exp.len != 0) {
2583 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2586 if (BC_NUM_ONE(&temp)) {
2587 s = bc_num_mul(d, &base, &temp, 0);
2589 s = bc_num_rem(&temp, c, d, 0);
2593 s = bc_num_mul(&base, &base, &temp, 0);
2595 s = bc_num_rem(&temp, c, &base, 0);
2608 static int bc_id_cmp(const void *e1, const void *e2)
2610 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2613 static void bc_id_free(void *id)
2615 free(((BcId *) id)->name);
2618 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2623 for (i = 0; i < f->autos.len; ++i) {
2624 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2625 return bc_error("function parameter or auto var has the same name as another");
2631 bc_vec_push(&f->autos, &a);
2633 return BC_STATUS_SUCCESS;
2636 static void bc_func_init(BcFunc *f)
2638 bc_vec_init(&f->code, sizeof(char), NULL);
2639 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2640 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2644 static void bc_func_free(void *func)
2646 BcFunc *f = (BcFunc *) func;
2647 bc_vec_free(&f->code);
2648 bc_vec_free(&f->autos);
2649 bc_vec_free(&f->labels);
2652 static void bc_array_init(BcVec *a, bool nums)
2655 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2657 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2658 bc_array_expand(a, 1);
2661 static void bc_array_copy(BcVec *d, const BcVec *s)
2665 bc_vec_npop(d, d->len);
2666 bc_vec_expand(d, s->cap);
2669 for (i = 0; i < s->len; ++i) {
2670 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2671 bc_num_init(dnum, snum->len);
2672 bc_num_copy(dnum, snum);
2676 static void bc_array_expand(BcVec *a, size_t len)
2680 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2681 while (len > a->len) {
2682 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2683 bc_vec_push(a, &data.n);
2687 while (len > a->len) {
2688 bc_array_init(&data.v, true);
2689 bc_vec_push(a, &data.v);
2694 static void bc_string_free(void *string)
2696 free(*((char **) string));
2700 static void bc_result_copy(BcResult *d, BcResult *src)
2706 case BC_RESULT_TEMP:
2707 case BC_RESULT_IBASE:
2708 case BC_RESULT_SCALE:
2709 case BC_RESULT_OBASE:
2711 bc_num_init(&d->d.n, src->d.n.len);
2712 bc_num_copy(&d->d.n, &src->d.n);
2717 case BC_RESULT_ARRAY:
2718 case BC_RESULT_ARRAY_ELEM:
2720 d->d.id.name = xstrdup(src->d.id.name);
2724 case BC_RESULT_CONSTANT:
2725 case BC_RESULT_LAST:
2729 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2736 static void bc_result_free(void *result)
2738 BcResult *r = (BcResult *) result;
2742 case BC_RESULT_TEMP:
2743 case BC_RESULT_IBASE:
2744 case BC_RESULT_SCALE:
2745 case BC_RESULT_OBASE:
2747 bc_num_free(&r->d.n);
2752 case BC_RESULT_ARRAY:
2753 case BC_RESULT_ARRAY_ELEM:
2767 static void bc_lex_lineComment(BcLex *l)
2769 l->t.t = BC_LEX_WHITESPACE;
2770 while (l->i < l->len && l->buf[l->i++] != '\n');
2774 static void bc_lex_whitespace(BcLex *l)
2777 l->t.t = BC_LEX_WHITESPACE;
2778 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2781 static BcStatus bc_lex_number(BcLex *l, char start)
2783 const char *buf = l->buf + l->i;
2784 size_t len, hits = 0, bslashes = 0, i = 0, j;
2786 bool last_pt, pt = start == '.';
2789 l->t.t = BC_LEX_NUMBER;
2791 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2792 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2806 len = i + !last_pt - bslashes * 2;
2807 if (len > BC_MAX_NUM)
2808 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2810 bc_vec_npop(&l->t.v, l->t.v.len);
2811 bc_vec_expand(&l->t.v, len + 1);
2812 bc_vec_push(&l->t.v, &start);
2814 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2818 // If we have hit a backslash, skip it. We don't have
2819 // to check for a newline because it's guaranteed.
2820 if (hits < bslashes && c == '\\') {
2826 bc_vec_push(&l->t.v, &c);
2829 bc_vec_pushByte(&l->t.v, '\0');
2832 return BC_STATUS_SUCCESS;
2835 static BcStatus bc_lex_name(BcLex *l)
2838 const char *buf = l->buf + l->i - 1;
2841 l->t.t = BC_LEX_NAME;
2843 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2845 if (i > BC_MAX_STRING)
2846 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2847 bc_vec_string(&l->t.v, i, buf);
2849 // Increment the index. We minus 1 because it has already been incremented.
2852 return BC_STATUS_SUCCESS;
2855 static void bc_lex_init(BcLex *l, BcLexNext next)
2858 bc_vec_init(&l->t.v, sizeof(char), NULL);
2861 static void bc_lex_free(BcLex *l)
2863 bc_vec_free(&l->t.v);
2866 static void bc_lex_file(BcLex *l, const char *file)
2873 static BcStatus bc_lex_next(BcLex *l)
2878 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2880 l->line += l->newline;
2881 l->t.t = BC_LEX_EOF;
2883 l->newline = (l->i == l->len);
2884 if (l->newline) return BC_STATUS_SUCCESS;
2886 // Loop until failure or we don't have whitespace. This
2887 // is so the parser doesn't get inundated with whitespace.
2890 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2895 static BcStatus bc_lex_text(BcLex *l, const char *text)
2899 l->len = strlen(text);
2900 l->t.t = l->t.last = BC_LEX_INVALID;
2901 return bc_lex_next(l);
2905 static BcStatus bc_lex_identifier(BcLex *l)
2909 const char *buf = l->buf + l->i - 1;
2911 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2913 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2915 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2917 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2919 if (!bc_lex_kws[i].posix) {
2920 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
2924 // We minus 1 because the index has already been incremented.
2926 return BC_STATUS_SUCCESS;
2933 if (l->t.v.len - 1 > 1)
2934 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2939 static BcStatus bc_lex_string(BcLex *l)
2941 size_t len, nls = 0, i = l->i;
2944 l->t.t = BC_LEX_STR;
2946 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2950 return bc_error("string end could not be found");
2954 if (len > BC_MAX_STRING)
2955 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2956 bc_vec_string(&l->t.v, len, l->buf + l->i);
2961 return BC_STATUS_SUCCESS;
2964 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2966 if (l->buf[l->i] == '=') {
2974 static BcStatus bc_lex_comment(BcLex *l)
2977 const char *buf = l->buf;
2979 l->t.t = BC_LEX_WHITESPACE;
2992 return bc_error("comment end could not be found");
3001 return BC_STATUS_SUCCESS;
3004 static BcStatus bc_lex_token(BcLex *l)
3006 BcStatus s = BC_STATUS_SUCCESS;
3007 char c = l->buf[l->i++], c2;
3009 // This is the workhorse of the lexer.
3016 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3026 bc_lex_whitespace(l);
3032 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3034 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3035 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3044 s = bc_lex_string(l);
3050 s = bc_posix_error("POSIX does not allow '#' script comments");
3053 bc_lex_lineComment(l);
3060 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3069 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3073 l->t.t = BC_LEX_OP_BOOL_AND;
3076 l->t.t = BC_LEX_INVALID;
3077 s = bc_error("bad character '%c'", '&');
3086 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3092 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3101 l->t.t = BC_LEX_OP_INC;
3104 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3110 l->t.t = BC_LEX_COMMA;
3119 l->t.t = BC_LEX_OP_DEC;
3122 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3128 if (isdigit(l->buf[l->i]))
3129 s = bc_lex_number(l, c);
3131 l->t.t = BC_LEX_KEY_LAST;
3132 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3141 s = bc_lex_comment(l);
3143 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3164 s = bc_lex_number(l, c);
3170 l->t.t = BC_LEX_SCOLON;
3176 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3182 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3188 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3195 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3201 if (l->buf[l->i] == '\n') {
3202 l->t.t = BC_LEX_WHITESPACE;
3206 s = bc_error("bad character '%c'", c);
3212 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3243 s = bc_lex_identifier(l);
3250 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3259 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3263 l->t.t = BC_LEX_OP_BOOL_OR;
3266 l->t.t = BC_LEX_INVALID;
3267 s = bc_error("bad character '%c'", c);
3275 l->t.t = BC_LEX_INVALID;
3276 s = bc_error("bad character '%c'", c);
3286 static BcStatus dc_lex_register(BcLex *l)
3288 BcStatus s = BC_STATUS_SUCCESS;
3290 if (isspace(l->buf[l->i - 1])) {
3291 bc_lex_whitespace(l);
3294 s = bc_error("extended register");
3299 bc_vec_npop(&l->t.v, l->t.v.len);
3300 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3301 bc_vec_pushByte(&l->t.v, '\0');
3302 l->t.t = BC_LEX_NAME;
3308 static BcStatus dc_lex_string(BcLex *l)
3310 size_t depth = 1, nls = 0, i = l->i;
3313 l->t.t = BC_LEX_STR;
3314 bc_vec_npop(&l->t.v, l->t.v.len);
3316 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3318 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3319 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3322 if (depth) bc_vec_push(&l->t.v, &c);
3327 return bc_error("string end could not be found");
3330 bc_vec_pushByte(&l->t.v, '\0');
3331 if (i - l->i > BC_MAX_STRING)
3332 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3337 return BC_STATUS_SUCCESS;
3340 static BcStatus dc_lex_token(BcLex *l)
3342 BcStatus s = BC_STATUS_SUCCESS;
3343 char c = l->buf[l->i++], c2;
3346 for (i = 0; i < dc_lex_regs_len; ++i) {
3347 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3350 if (c >= '%' && c <= '~' &&
3351 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3356 // This is the workhorse of the lexer.
3361 l->t.t = BC_LEX_EOF;
3372 l->newline = (c == '\n');
3373 bc_lex_whitespace(l);
3382 l->t.t = BC_LEX_OP_REL_NE;
3384 l->t.t = BC_LEX_OP_REL_LE;
3386 l->t.t = BC_LEX_OP_REL_GE;
3388 return bc_error("bad character '%c'", c);
3396 bc_lex_lineComment(l);
3402 if (isdigit(l->buf[l->i]))
3403 s = bc_lex_number(l, c);
3405 s = bc_error("bad character '%c'", c);
3426 s = bc_lex_number(l, c);
3432 s = dc_lex_string(l);
3438 l->t.t = BC_LEX_INVALID;
3439 s = bc_error("bad character '%c'", c);
3448 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3450 bc_program_addFunc(name, idx);
3451 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3454 static void bc_parse_pushName(BcParse *p, char *name)
3456 size_t i = 0, len = strlen(name);
3458 for (; i < len; ++i) bc_parse_push(p, name[i]);
3459 bc_parse_push(p, BC_PARSE_STREND);
3464 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3466 unsigned char amt, i, nums[sizeof(size_t)];
3468 for (amt = 0; idx; ++amt) {
3469 nums[amt] = (char) idx;
3470 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3473 bc_parse_push(p, amt);
3474 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3477 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3479 char *num = xstrdup(p->l.t.v.v);
3480 size_t idx = G.prog.consts.len;
3482 bc_vec_push(&G.prog.consts, &num);
3484 bc_parse_push(p, BC_INST_NUM);
3485 bc_parse_pushIndex(p, idx);
3488 (*prev) = BC_INST_NUM;
3491 static BcStatus bc_parse_text(BcParse *p, const char *text)
3495 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3497 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3498 p->l.t.t = BC_LEX_INVALID;
3501 if (!BC_PARSE_CAN_EXEC(p))
3502 return bc_error("file is not executable");
3505 return bc_lex_text(&p->l, text);
3508 // Called when bc/dc_parse_parse() detects a failure,
3509 // resets parsing structures.
3510 static void bc_parse_reset(BcParse *p)
3512 if (p->fidx != BC_PROG_MAIN) {
3514 p->func->nparams = 0;
3515 bc_vec_npop(&p->func->code, p->func->code.len);
3516 bc_vec_npop(&p->func->autos, p->func->autos.len);
3517 bc_vec_npop(&p->func->labels, p->func->labels.len);
3519 bc_parse_updateFunc(p, BC_PROG_MAIN);
3523 p->l.t.t = BC_LEX_EOF;
3524 p->auto_part = (p->nbraces = 0);
3526 bc_vec_npop(&p->flags, p->flags.len - 1);
3527 bc_vec_npop(&p->exits, p->exits.len);
3528 bc_vec_npop(&p->conds, p->conds.len);
3529 bc_vec_npop(&p->ops, p->ops.len);
3534 static void bc_parse_free(BcParse *p)
3536 bc_vec_free(&p->flags);
3537 bc_vec_free(&p->exits);
3538 bc_vec_free(&p->conds);
3539 bc_vec_free(&p->ops);
3543 static void bc_parse_create(BcParse *p, size_t func,
3544 BcParseParse parse, BcLexNext next)
3546 memset(p, 0, sizeof(BcParse));
3548 bc_lex_init(&p->l, next);
3549 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3550 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3551 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3552 bc_vec_pushByte(&p->flags, 0);
3553 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3556 // p->auto_part = p->nbraces = 0; - already is
3557 bc_parse_updateFunc(p, func);
3561 static BcStatus bc_parse_else(BcParse *p);
3562 static BcStatus bc_parse_stmt(BcParse *p);
3564 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3565 size_t *nexprs, bool next)
3567 BcStatus s = BC_STATUS_SUCCESS;
3569 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3570 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3572 while (p->ops.len > start) {
3574 t = BC_PARSE_TOP_OP(p);
3575 if (t == BC_LEX_LPAREN) break;
3577 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3578 if (l >= r && (l != r || !left)) break;
3580 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3581 bc_vec_pop(&p->ops);
3582 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3585 bc_vec_push(&p->ops, &type);
3586 if (next) s = bc_lex_next(&p->l);
3591 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3595 if (p->ops.len <= ops_bgn)
3596 return bc_error("bad expression");
3597 top = BC_PARSE_TOP_OP(p);
3599 while (top != BC_LEX_LPAREN) {
3601 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3603 bc_vec_pop(&p->ops);
3604 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3606 if (p->ops.len <= ops_bgn)
3607 return bc_error("bad expression");
3608 top = BC_PARSE_TOP_OP(p);
3611 bc_vec_pop(&p->ops);
3613 return bc_lex_next(&p->l);
3616 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3622 s = bc_lex_next(&p->l);
3625 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3627 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3628 s = bc_parse_expr(p, flags, bc_parse_next_param);
3631 comma = p->l.t.t == BC_LEX_COMMA;
3633 s = bc_lex_next(&p->l);
3638 if (comma) return bc_error("bad token");
3639 bc_parse_push(p, BC_INST_CALL);
3640 bc_parse_pushIndex(p, nparams);
3642 return BC_STATUS_SUCCESS;
3645 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3648 BcId entry, *entry_ptr;
3653 s = bc_parse_params(p, flags);
3656 if (p->l.t.t != BC_LEX_RPAREN) {
3657 s = bc_error("bad token");
3661 idx = bc_map_index(&G.prog.fn_map, &entry);
3663 if (idx == BC_VEC_INVALID_IDX) {
3664 name = xstrdup(entry.name);
3665 bc_parse_addFunc(p, name, &idx);
3666 idx = bc_map_index(&G.prog.fn_map, &entry);
3672 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3673 bc_parse_pushIndex(p, entry_ptr->idx);
3675 return bc_lex_next(&p->l);
3682 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3687 name = xstrdup(p->l.t.v.v);
3688 s = bc_lex_next(&p->l);
3691 if (p->l.t.t == BC_LEX_LBRACKET) {
3693 s = bc_lex_next(&p->l);
3696 if (p->l.t.t == BC_LEX_RBRACKET) {
3698 if (!(flags & BC_PARSE_ARRAY)) {
3699 s = bc_error("bad expression");
3703 *type = BC_INST_ARRAY;
3707 *type = BC_INST_ARRAY_ELEM;
3709 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3710 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3714 s = bc_lex_next(&p->l);
3716 bc_parse_push(p, *type);
3717 bc_parse_pushName(p, name);
3719 else if (p->l.t.t == BC_LEX_LPAREN) {
3721 if (flags & BC_PARSE_NOCALL) {
3722 s = bc_error("bad token");
3726 *type = BC_INST_CALL;
3727 s = bc_parse_call(p, name, flags);
3730 *type = BC_INST_VAR;
3731 bc_parse_push(p, BC_INST_VAR);
3732 bc_parse_pushName(p, name);
3742 static BcStatus bc_parse_read(BcParse *p)
3746 s = bc_lex_next(&p->l);
3748 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3750 s = bc_lex_next(&p->l);
3752 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3754 bc_parse_push(p, BC_INST_READ);
3756 return bc_lex_next(&p->l);
3759 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3764 s = bc_lex_next(&p->l);
3766 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3768 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3770 s = bc_lex_next(&p->l);
3773 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3776 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3778 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3779 bc_parse_push(p, *prev);
3781 return bc_lex_next(&p->l);
3784 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3788 s = bc_lex_next(&p->l);
3791 if (p->l.t.t != BC_LEX_LPAREN) {
3792 *type = BC_INST_SCALE;
3793 bc_parse_push(p, BC_INST_SCALE);
3794 return BC_STATUS_SUCCESS;
3797 *type = BC_INST_SCALE_FUNC;
3798 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3800 s = bc_lex_next(&p->l);
3803 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3805 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3806 bc_parse_push(p, BC_INST_SCALE_FUNC);
3808 return bc_lex_next(&p->l);
3811 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3812 size_t *nexprs, uint8_t flags)
3817 BcInst etype = *prev;
3819 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3820 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3821 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3823 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3824 bc_parse_push(p, inst);
3825 s = bc_lex_next(&p->l);
3829 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3832 s = bc_lex_next(&p->l);
3836 // Because we parse the next part of the expression
3837 // right here, we need to increment this.
3838 *nexprs = *nexprs + 1;
3844 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3848 case BC_LEX_KEY_IBASE:
3849 case BC_LEX_KEY_LAST:
3850 case BC_LEX_KEY_OBASE:
3852 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3853 s = bc_lex_next(&p->l);
3857 case BC_LEX_KEY_SCALE:
3859 s = bc_lex_next(&p->l);
3861 if (p->l.t.t == BC_LEX_LPAREN)
3862 s = bc_error("bad token");
3864 bc_parse_push(p, BC_INST_SCALE);
3870 s = bc_error("bad token");
3875 if (!s) bc_parse_push(p, inst);
3881 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3882 bool rparen, size_t *nexprs)
3886 BcInst etype = *prev;
3888 s = bc_lex_next(&p->l);
3891 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3892 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3895 *prev = BC_PARSE_TOKEN_INST(type);
3897 // We can just push onto the op stack because this is the largest
3898 // precedence operator that gets pushed. Inc/dec does not.
3899 if (type != BC_LEX_OP_MINUS)
3900 bc_vec_push(&p->ops, &type);
3902 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3907 static BcStatus bc_parse_string(BcParse *p, char inst)
3909 char *str = xstrdup(p->l.t.v.v);
3911 bc_parse_push(p, BC_INST_STR);
3912 bc_parse_pushIndex(p, G.prog.strs.len);
3913 bc_vec_push(&G.prog.strs, &str);
3914 bc_parse_push(p, inst);
3916 return bc_lex_next(&p->l);
3919 static BcStatus bc_parse_print(BcParse *p)
3925 s = bc_lex_next(&p->l);
3930 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3931 return bc_error("bad print statement");
3933 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3935 if (type == BC_LEX_STR)
3936 s = bc_parse_string(p, BC_INST_PRINT_POP);
3938 s = bc_parse_expr(p, 0, bc_parse_next_print);
3940 bc_parse_push(p, BC_INST_PRINT_POP);
3945 comma = p->l.t.t == BC_LEX_COMMA;
3946 if (comma) s = bc_lex_next(&p->l);
3951 if (comma) return bc_error("bad token");
3953 return bc_lex_next(&p->l);
3956 static BcStatus bc_parse_return(BcParse *p)
3962 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
3964 s = bc_lex_next(&p->l);
3968 paren = t == BC_LEX_LPAREN;
3970 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3971 bc_parse_push(p, BC_INST_RET0);
3974 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3975 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3978 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3979 bc_parse_push(p, BC_INST_RET0);
3980 s = bc_lex_next(&p->l);
3984 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3985 s = bc_posix_error("POSIX requires parentheses around return expressions");
3989 bc_parse_push(p, BC_INST_RET);
3995 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3997 BcStatus s = BC_STATUS_SUCCESS;
3999 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4000 return bc_error("bad token");
4004 if (p->l.t.t == BC_LEX_RBRACE) {
4005 if (!p->nbraces) return bc_error("bad token");
4007 s = bc_lex_next(&p->l);
4011 return bc_error("bad token");
4014 if (BC_PARSE_IF(p)) {
4018 while (p->l.t.t == BC_LEX_NLINE) {
4019 s = bc_lex_next(&p->l);
4023 bc_vec_pop(&p->flags);
4025 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4026 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4028 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4030 else if (BC_PARSE_ELSE(p)) {
4035 bc_vec_pop(&p->flags);
4037 ip = bc_vec_top(&p->exits);
4038 label = bc_vec_item(&p->func->labels, ip->idx);
4039 *label = p->func->code.len;
4041 bc_vec_pop(&p->exits);
4043 else if (BC_PARSE_FUNC_INNER(p)) {
4044 bc_parse_push(p, BC_INST_RET0);
4045 bc_parse_updateFunc(p, BC_PROG_MAIN);
4046 bc_vec_pop(&p->flags);
4050 BcInstPtr *ip = bc_vec_top(&p->exits);
4051 size_t *label = bc_vec_top(&p->conds);
4053 bc_parse_push(p, BC_INST_JUMP);
4054 bc_parse_pushIndex(p, *label);
4056 label = bc_vec_item(&p->func->labels, ip->idx);
4057 *label = p->func->code.len;
4059 bc_vec_pop(&p->flags);
4060 bc_vec_pop(&p->exits);
4061 bc_vec_pop(&p->conds);
4067 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4069 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4070 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4071 flags |= BC_PARSE_FLAG_BODY;
4072 bc_vec_push(&p->flags, &flags);
4075 static void bc_parse_noElse(BcParse *p)
4079 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4081 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4083 ip = bc_vec_top(&p->exits);
4084 label = bc_vec_item(&p->func->labels, ip->idx);
4085 *label = p->func->code.len;
4087 bc_vec_pop(&p->exits);
4090 static BcStatus bc_parse_if(BcParse *p)
4095 s = bc_lex_next(&p->l);
4097 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4099 s = bc_lex_next(&p->l);
4101 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4103 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4105 s = bc_lex_next(&p->l);
4107 bc_parse_push(p, BC_INST_JUMP_ZERO);
4109 ip.idx = p->func->labels.len;
4110 ip.func = ip.len = 0;
4112 bc_parse_pushIndex(p, ip.idx);
4113 bc_vec_push(&p->exits, &ip);
4114 bc_vec_push(&p->func->labels, &ip.idx);
4115 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4117 return BC_STATUS_SUCCESS;
4120 static BcStatus bc_parse_else(BcParse *p)
4124 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4126 ip.idx = p->func->labels.len;
4127 ip.func = ip.len = 0;
4129 bc_parse_push(p, BC_INST_JUMP);
4130 bc_parse_pushIndex(p, ip.idx);
4134 bc_vec_push(&p->exits, &ip);
4135 bc_vec_push(&p->func->labels, &ip.idx);
4136 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4138 return bc_lex_next(&p->l);
4141 static BcStatus bc_parse_while(BcParse *p)
4146 s = bc_lex_next(&p->l);
4148 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4149 s = bc_lex_next(&p->l);
4152 ip.idx = p->func->labels.len;
4154 bc_vec_push(&p->func->labels, &p->func->code.len);
4155 bc_vec_push(&p->conds, &ip.idx);
4157 ip.idx = p->func->labels.len;
4161 bc_vec_push(&p->exits, &ip);
4162 bc_vec_push(&p->func->labels, &ip.idx);
4164 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4166 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4167 s = bc_lex_next(&p->l);
4170 bc_parse_push(p, BC_INST_JUMP_ZERO);
4171 bc_parse_pushIndex(p, ip.idx);
4172 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4174 return BC_STATUS_SUCCESS;
4177 static BcStatus bc_parse_for(BcParse *p)
4181 size_t cond_idx, exit_idx, body_idx, update_idx;
4183 s = bc_lex_next(&p->l);
4185 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4186 s = bc_lex_next(&p->l);
4189 if (p->l.t.t != BC_LEX_SCOLON)
4190 s = bc_parse_expr(p, 0, bc_parse_next_for);
4192 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4195 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4196 s = bc_lex_next(&p->l);
4199 cond_idx = p->func->labels.len;
4200 update_idx = cond_idx + 1;
4201 body_idx = update_idx + 1;
4202 exit_idx = body_idx + 1;
4204 bc_vec_push(&p->func->labels, &p->func->code.len);
4206 if (p->l.t.t != BC_LEX_SCOLON)
4207 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4209 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4212 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4214 s = bc_lex_next(&p->l);
4217 bc_parse_push(p, BC_INST_JUMP_ZERO);
4218 bc_parse_pushIndex(p, exit_idx);
4219 bc_parse_push(p, BC_INST_JUMP);
4220 bc_parse_pushIndex(p, body_idx);
4222 ip.idx = p->func->labels.len;
4224 bc_vec_push(&p->conds, &update_idx);
4225 bc_vec_push(&p->func->labels, &p->func->code.len);
4227 if (p->l.t.t != BC_LEX_RPAREN)
4228 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4230 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4234 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4235 bc_parse_push(p, BC_INST_JUMP);
4236 bc_parse_pushIndex(p, cond_idx);
4237 bc_vec_push(&p->func->labels, &p->func->code.len);
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4246 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4248 return BC_STATUS_SUCCESS;
4251 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4257 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4259 if (type == BC_LEX_KEY_BREAK) {
4261 if (p->exits.len == 0) return bc_error("bad token");
4263 i = p->exits.len - 1;
4264 ip = bc_vec_item(&p->exits, i);
4266 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4267 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4272 i = *((size_t *) bc_vec_top(&p->conds));
4274 bc_parse_push(p, BC_INST_JUMP);
4275 bc_parse_pushIndex(p, i);
4277 s = bc_lex_next(&p->l);
4280 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4281 return bc_error("bad token");
4283 return bc_lex_next(&p->l);
4286 static BcStatus bc_parse_func(BcParse *p)
4289 bool var, comma = false;
4293 s = bc_lex_next(&p->l);
4295 if (p->l.t.t != BC_LEX_NAME)
4296 return bc_error("bad function definition");
4298 name = xstrdup(p->l.t.v.v);
4299 bc_parse_addFunc(p, name, &p->fidx);
4301 s = bc_lex_next(&p->l);
4303 if (p->l.t.t != BC_LEX_LPAREN)
4304 return bc_error("bad function definition");
4305 s = bc_lex_next(&p->l);
4308 while (p->l.t.t != BC_LEX_RPAREN) {
4310 if (p->l.t.t != BC_LEX_NAME)
4311 return bc_error("bad function definition");
4315 name = xstrdup(p->l.t.v.v);
4316 s = bc_lex_next(&p->l);
4319 var = p->l.t.t != BC_LEX_LBRACKET;
4323 s = bc_lex_next(&p->l);
4326 if (p->l.t.t != BC_LEX_RBRACKET) {
4327 s = bc_error("bad function definition");
4331 s = bc_lex_next(&p->l);
4335 comma = p->l.t.t == BC_LEX_COMMA;
4337 s = bc_lex_next(&p->l);
4341 s = bc_func_insert(p->func, name, var);
4345 if (comma) return bc_error("bad function definition");
4347 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4348 bc_parse_startBody(p, flags);
4350 s = bc_lex_next(&p->l);
4353 if (p->l.t.t != BC_LEX_LBRACE)
4354 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4363 static BcStatus bc_parse_auto(BcParse *p)
4366 bool comma, var, one;
4369 if (!p->auto_part) return bc_error("bad token");
4370 s = bc_lex_next(&p->l);
4373 p->auto_part = comma = false;
4374 one = p->l.t.t == BC_LEX_NAME;
4376 while (p->l.t.t == BC_LEX_NAME) {
4378 name = xstrdup(p->l.t.v.v);
4379 s = bc_lex_next(&p->l);
4382 var = p->l.t.t != BC_LEX_LBRACKET;
4385 s = bc_lex_next(&p->l);
4388 if (p->l.t.t != BC_LEX_RBRACKET) {
4389 s = bc_error("bad function definition");
4393 s = bc_lex_next(&p->l);
4397 comma = p->l.t.t == BC_LEX_COMMA;
4399 s = bc_lex_next(&p->l);
4403 s = bc_func_insert(p->func, name, var);
4407 if (comma) return bc_error("bad function definition");
4408 if (!one) return bc_error("no auto variable found");
4410 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4411 return bc_error("bad token");
4413 return bc_lex_next(&p->l);
4420 static BcStatus bc_parse_body(BcParse *p, bool brace)
4422 BcStatus s = BC_STATUS_SUCCESS;
4423 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4425 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4427 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4429 if (!brace) return bc_error("bad token");
4430 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4432 if (!p->auto_part) {
4433 s = bc_parse_auto(p);
4437 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4440 s = bc_parse_stmt(p);
4441 if (!s && !brace) s = bc_parse_endBody(p, false);
4447 static BcStatus bc_parse_stmt(BcParse *p)
4449 BcStatus s = BC_STATUS_SUCCESS;
4455 return bc_lex_next(&p->l);
4458 case BC_LEX_KEY_ELSE:
4460 p->auto_part = false;
4466 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4469 s = bc_lex_next(&p->l);
4472 return bc_parse_body(p, true);
4475 case BC_LEX_KEY_AUTO:
4477 return bc_parse_auto(p);
4482 p->auto_part = false;
4484 if (BC_PARSE_IF_END(p)) {
4486 return BC_STATUS_SUCCESS;
4488 else if (BC_PARSE_BODY(p))
4489 return bc_parse_body(p, false);
4499 case BC_LEX_OP_MINUS:
4500 case BC_LEX_OP_BOOL_NOT:
4504 case BC_LEX_KEY_IBASE:
4505 case BC_LEX_KEY_LAST:
4506 case BC_LEX_KEY_LENGTH:
4507 case BC_LEX_KEY_OBASE:
4508 case BC_LEX_KEY_READ:
4509 case BC_LEX_KEY_SCALE:
4510 case BC_LEX_KEY_SQRT:
4512 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4516 case BC_LEX_KEY_ELSE:
4518 s = bc_parse_else(p);
4524 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4530 s = bc_parse_endBody(p, true);
4536 s = bc_parse_string(p, BC_INST_PRINT_STR);
4540 case BC_LEX_KEY_BREAK:
4541 case BC_LEX_KEY_CONTINUE:
4543 s = bc_parse_loopExit(p, p->l.t.t);
4547 case BC_LEX_KEY_FOR:
4549 s = bc_parse_for(p);
4553 case BC_LEX_KEY_HALT:
4555 bc_parse_push(p, BC_INST_HALT);
4556 s = bc_lex_next(&p->l);
4566 case BC_LEX_KEY_LIMITS:
4568 // "limits" is a compile-time command,
4569 // the output is produced at _parse time_.
4570 s = bc_lex_next(&p->l);
4572 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4573 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4574 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4575 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4576 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4577 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4578 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4579 printf("Number of vars = %lu\n", BC_MAX_VARS);
4583 case BC_LEX_KEY_PRINT:
4585 s = bc_parse_print(p);
4589 case BC_LEX_KEY_QUIT:
4591 // "quit" is a compile-time command. For example,
4592 // "if (0 == 1) quit" terminates when parsing the statement,
4593 // not when it is executed
4597 case BC_LEX_KEY_RETURN:
4599 s = bc_parse_return(p);
4603 case BC_LEX_KEY_WHILE:
4605 s = bc_parse_while(p);
4611 s = bc_error("bad token");
4619 static BcStatus bc_parse_parse(BcParse *p)
4623 if (p->l.t.t == BC_LEX_EOF)
4624 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4625 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4626 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4627 s = bc_parse_func(p);
4630 s = bc_parse_stmt(p);
4632 if (s || G_interrupt) {
4634 s = BC_STATUS_FAILURE;
4640 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4642 BcStatus s = BC_STATUS_SUCCESS;
4643 BcInst prev = BC_INST_PRINT;
4644 BcLexType top, t = p->l.t.t;
4645 size_t nexprs = 0, ops_bgn = p->ops.len;
4646 uint32_t i, nparens, nrelops;
4647 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4649 paren_first = p->l.t.t == BC_LEX_LPAREN;
4650 nparens = nrelops = 0;
4651 paren_expr = rprn = done = get_token = assign = false;
4654 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4660 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4661 rprn = get_token = bin_last = false;
4665 case BC_LEX_OP_MINUS:
4667 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4668 rprn = get_token = false;
4669 bin_last = prev == BC_INST_MINUS;
4673 case BC_LEX_OP_ASSIGN_POWER:
4674 case BC_LEX_OP_ASSIGN_MULTIPLY:
4675 case BC_LEX_OP_ASSIGN_DIVIDE:
4676 case BC_LEX_OP_ASSIGN_MODULUS:
4677 case BC_LEX_OP_ASSIGN_PLUS:
4678 case BC_LEX_OP_ASSIGN_MINUS:
4679 case BC_LEX_OP_ASSIGN:
4681 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4682 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4683 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4685 s = bc_error("bad assignment:"
4686 " left side must be scale,"
4687 " ibase, obase, last, var,"
4694 case BC_LEX_OP_POWER:
4695 case BC_LEX_OP_MULTIPLY:
4696 case BC_LEX_OP_DIVIDE:
4697 case BC_LEX_OP_MODULUS:
4698 case BC_LEX_OP_PLUS:
4699 case BC_LEX_OP_REL_EQ:
4700 case BC_LEX_OP_REL_LE:
4701 case BC_LEX_OP_REL_GE:
4702 case BC_LEX_OP_REL_NE:
4703 case BC_LEX_OP_REL_LT:
4704 case BC_LEX_OP_REL_GT:
4705 case BC_LEX_OP_BOOL_NOT:
4706 case BC_LEX_OP_BOOL_OR:
4707 case BC_LEX_OP_BOOL_AND:
4709 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4710 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4712 return bc_error("bad expression");
4715 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4716 prev = BC_PARSE_TOKEN_INST(t);
4717 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4718 rprn = get_token = false;
4719 bin_last = t != BC_LEX_OP_BOOL_NOT;
4726 if (BC_PARSE_LEAF(prev, rprn))
4727 return bc_error("bad expression");
4729 paren_expr = rprn = bin_last = false;
4731 bc_vec_push(&p->ops, &t);
4738 if (bin_last || prev == BC_INST_BOOL_NOT)
4739 return bc_error("bad expression");
4742 s = BC_STATUS_SUCCESS;
4747 else if (!paren_expr)
4748 return BC_STATUS_PARSE_EMPTY_EXP;
4751 paren_expr = rprn = true;
4752 get_token = bin_last = false;
4754 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4761 if (BC_PARSE_LEAF(prev, rprn))
4762 return bc_error("bad expression");
4764 rprn = get_token = bin_last = false;
4765 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4773 if (BC_PARSE_LEAF(prev, rprn))
4774 return bc_error("bad expression");
4775 bc_parse_number(p, &prev, &nexprs);
4776 paren_expr = get_token = true;
4777 rprn = bin_last = false;
4782 case BC_LEX_KEY_IBASE:
4783 case BC_LEX_KEY_LAST:
4784 case BC_LEX_KEY_OBASE:
4786 if (BC_PARSE_LEAF(prev, rprn))
4787 return bc_error("bad expression");
4788 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4789 bc_parse_push(p, (char) prev);
4791 paren_expr = get_token = true;
4792 rprn = bin_last = false;
4798 case BC_LEX_KEY_LENGTH:
4799 case BC_LEX_KEY_SQRT:
4801 if (BC_PARSE_LEAF(prev, rprn))
4802 return bc_error("bad expression");
4803 s = bc_parse_builtin(p, t, flags, &prev);
4805 rprn = get_token = bin_last = false;
4811 case BC_LEX_KEY_READ:
4813 if (BC_PARSE_LEAF(prev, rprn))
4814 return bc_error("bad expression");
4815 else if (flags & BC_PARSE_NOREAD)
4816 s = bc_error("read() call inside of a read() call");
4818 s = bc_parse_read(p);
4821 rprn = get_token = bin_last = false;
4823 prev = BC_INST_READ;
4828 case BC_LEX_KEY_SCALE:
4830 if (BC_PARSE_LEAF(prev, rprn))
4831 return bc_error("bad expression");
4832 s = bc_parse_scale(p, &prev, flags);
4834 rprn = get_token = bin_last = false;
4836 prev = BC_INST_SCALE;
4843 s = bc_error("bad token");
4848 if (!s && get_token) s = bc_lex_next(&p->l);
4852 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4854 while (p->ops.len > ops_bgn) {
4856 top = BC_PARSE_TOP_OP(p);
4857 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4859 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4860 return bc_error("bad expression");
4862 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4864 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4865 bc_vec_pop(&p->ops);
4868 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4869 return bc_error("bad expression");
4871 for (i = 0; i < next.len; ++i)
4872 if (t == next.tokens[i])
4874 return bc_error("bad expression");
4877 if (!(flags & BC_PARSE_REL) && nrelops) {
4878 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4881 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4882 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4886 if (flags & BC_PARSE_PRINT) {
4887 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4888 bc_parse_push(p, BC_INST_POP);
4894 static void bc_parse_init(BcParse *p, size_t func)
4896 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4899 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4901 return bc_parse_expr(p, flags, bc_parse_next_read);
4906 static BcStatus dc_parse_register(BcParse *p)
4911 s = bc_lex_next(&p->l);
4913 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
4915 name = xstrdup(p->l.t.v.v);
4916 bc_parse_pushName(p, name);
4921 static BcStatus dc_parse_string(BcParse *p)
4923 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4924 size_t idx, len = G.prog.strs.len;
4926 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4929 str = xstrdup(p->l.t.v.v);
4930 bc_parse_push(p, BC_INST_STR);
4931 bc_parse_pushIndex(p, len);
4932 bc_vec_push(&G.prog.strs, &str);
4933 bc_parse_addFunc(p, name, &idx);
4935 return bc_lex_next(&p->l);
4938 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4942 bc_parse_push(p, inst);
4944 s = dc_parse_register(p);
4949 bc_parse_push(p, BC_INST_SWAP);
4950 bc_parse_push(p, BC_INST_ASSIGN);
4951 bc_parse_push(p, BC_INST_POP);
4954 return bc_lex_next(&p->l);
4957 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4961 bc_parse_push(p, inst);
4962 bc_parse_push(p, BC_INST_EXEC_COND);
4964 s = dc_parse_register(p);
4967 s = bc_lex_next(&p->l);
4970 if (p->l.t.t == BC_LEX_ELSE) {
4971 s = dc_parse_register(p);
4973 s = bc_lex_next(&p->l);
4976 bc_parse_push(p, BC_PARSE_STREND);
4981 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4983 BcStatus s = BC_STATUS_SUCCESS;
4986 bool assign, get_token = false;
4990 case BC_LEX_OP_REL_EQ:
4991 case BC_LEX_OP_REL_LE:
4992 case BC_LEX_OP_REL_GE:
4993 case BC_LEX_OP_REL_NE:
4994 case BC_LEX_OP_REL_LT:
4995 case BC_LEX_OP_REL_GT:
4997 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5004 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5010 s = dc_parse_string(p);
5017 if (t == BC_LEX_NEG) {
5018 s = bc_lex_next(&p->l);
5020 if (p->l.t.t != BC_LEX_NUMBER)
5021 return bc_error("bad token");
5024 bc_parse_number(p, &prev, &p->nbraces);
5026 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5032 case BC_LEX_KEY_READ:
5034 if (flags & BC_PARSE_NOREAD)
5035 s = bc_error("read() call inside of a read() call");
5037 bc_parse_push(p, BC_INST_READ);
5042 case BC_LEX_OP_ASSIGN:
5043 case BC_LEX_STORE_PUSH:
5045 assign = t == BC_LEX_OP_ASSIGN;
5046 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5047 s = dc_parse_mem(p, inst, true, assign);
5052 case BC_LEX_LOAD_POP:
5054 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5055 s = dc_parse_mem(p, inst, true, false);
5059 case BC_LEX_STORE_IBASE:
5060 case BC_LEX_STORE_SCALE:
5061 case BC_LEX_STORE_OBASE:
5063 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5064 s = dc_parse_mem(p, inst, false, true);
5070 s = bc_error("bad token");
5076 if (!s && get_token) s = bc_lex_next(&p->l);
5081 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5083 BcStatus s = BC_STATUS_SUCCESS;
5087 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5089 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5091 inst = dc_parse_insts[t];
5093 if (inst != BC_INST_INVALID) {
5094 bc_parse_push(p, inst);
5095 s = bc_lex_next(&p->l);
5098 s = dc_parse_token(p, t, flags);
5101 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5102 bc_parse_push(p, BC_INST_POP_EXEC);
5107 static BcStatus dc_parse_parse(BcParse *p)
5111 if (p->l.t.t == BC_LEX_EOF)
5112 s = bc_error("end of file");
5114 s = dc_parse_expr(p, 0);
5116 if (s || G_interrupt) {
5118 s = BC_STATUS_FAILURE;
5124 static void dc_parse_init(BcParse *p, size_t func)
5126 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5130 static void common_parse_init(BcParse *p, size_t func)
5133 bc_parse_init(p, func);
5135 dc_parse_init(p, func);
5139 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5142 return bc_parse_expression(p, flags);
5144 return dc_parse_expr(p, flags);
5148 static BcVec* bc_program_search(char *id, bool var)
5156 v = var ? &G.prog.vars : &G.prog.arrs;
5157 map = var ? &G.prog.var_map : &G.prog.arr_map;
5161 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5164 bc_array_init(&data.v, var);
5165 bc_vec_push(v, &data.v);
5168 ptr = bc_vec_item(map, i);
5169 if (new) ptr->name = xstrdup(e.name);
5170 return bc_vec_item(v, ptr->idx);
5173 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5175 BcStatus s = BC_STATUS_SUCCESS;
5180 case BC_RESULT_TEMP:
5181 case BC_RESULT_IBASE:
5182 case BC_RESULT_SCALE:
5183 case BC_RESULT_OBASE:
5189 case BC_RESULT_CONSTANT:
5191 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5192 size_t base_t, len = strlen(*str);
5195 bc_num_init(&r->d.n, len);
5197 hex = hex && len == 1;
5198 base = hex ? &G.prog.hexb : &G.prog.ib;
5199 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5200 s = bc_num_parse(&r->d.n, *str, base, base_t);
5203 bc_num_free(&r->d.n);
5208 r->t = BC_RESULT_TEMP;
5214 case BC_RESULT_ARRAY:
5215 case BC_RESULT_ARRAY_ELEM:
5219 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5221 if (r->t == BC_RESULT_ARRAY_ELEM) {
5223 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5224 *num = bc_vec_item(v, r->d.id.idx);
5227 *num = bc_vec_top(v);
5232 case BC_RESULT_LAST:
5234 *num = &G.prog.last;
5248 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5249 BcResult **r, BcNum **rn, bool assign)
5253 BcResultType lt, rt;
5255 if (!BC_PROG_STACK(&G.prog.results, 2))
5256 return bc_error("stack has too few elements");
5258 *r = bc_vec_item_rev(&G.prog.results, 0);
5259 *l = bc_vec_item_rev(&G.prog.results, 1);
5263 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5265 s = bc_program_num(*l, ln, false);
5267 s = bc_program_num(*r, rn, hex);
5270 // We run this again under these conditions in case any vector has been
5271 // reallocated out from under the BcNums or arrays we had.
5272 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5273 s = bc_program_num(*l, ln, false);
5277 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5278 return bc_error("variable is wrong type");
5279 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5280 return bc_error("variable is wrong type");
5285 static void bc_program_binOpRetire(BcResult *r)
5287 r->t = BC_RESULT_TEMP;
5288 bc_vec_pop(&G.prog.results);
5289 bc_vec_pop(&G.prog.results);
5290 bc_vec_push(&G.prog.results, r);
5293 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5297 if (!BC_PROG_STACK(&G.prog.results, 1))
5298 return bc_error("stack has too few elements");
5299 *r = bc_vec_top(&G.prog.results);
5301 s = bc_program_num(*r, n, false);
5304 if (!BC_PROG_NUM((*r), (*n)))
5305 return bc_error("variable is wrong type");
5310 static void bc_program_retire(BcResult *r, BcResultType t)
5313 bc_vec_pop(&G.prog.results);
5314 bc_vec_push(&G.prog.results, r);
5317 static BcStatus bc_program_op(char inst)
5320 BcResult *opd1, *opd2, res;
5321 BcNum *n1, *n2 = NULL;
5323 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5325 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5327 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5329 bc_program_binOpRetire(&res);
5334 bc_num_free(&res.d.n);
5338 static BcStatus bc_program_read(void)
5345 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5347 for (i = 0; i < G.prog.stack.len; ++i) {
5348 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5349 if (ip_ptr->func == BC_PROG_READ)
5350 return bc_error("read() call inside of a read() call");
5353 bc_vec_npop(&f->code, f->code.len);
5354 bc_vec_init(&buf, sizeof(char), NULL);
5356 s = bc_read_line(&buf, "read> ");
5359 common_parse_init(&parse, BC_PROG_READ);
5360 bc_lex_file(&parse.l, bc_program_stdin_name);
5362 s = bc_parse_text(&parse, buf.v);
5363 if (s) goto exec_err;
5364 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5365 if (s) goto exec_err;
5367 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5368 s = bc_error("bad read() expression");
5372 ip.func = BC_PROG_READ;
5374 ip.len = G.prog.results.len;
5376 // Update this pointer, just in case.
5377 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5379 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5380 bc_vec_push(&G.prog.stack, &ip);
5383 bc_parse_free(&parse);
5389 static size_t bc_program_index(char *code, size_t *bgn)
5391 char amt = code[(*bgn)++], i = 0;
5394 for (; i < amt; ++i, ++(*bgn))
5395 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5400 static char *bc_program_name(char *code, size_t *bgn)
5403 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5405 s = xmalloc(ptr - str + 1);
5408 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5416 static void bc_program_printString(const char *str, size_t *nchars)
5418 size_t i, len = strlen(str);
5427 for (i = 0; i < len; ++i, ++(*nchars)) {
5431 if (c != '\\' || i == len - 1)
5491 // Just print the backslash and following character.
5502 static BcStatus bc_program_print(char inst, size_t idx)
5504 BcStatus s = BC_STATUS_SUCCESS;
5509 bool pop = inst != BC_INST_PRINT;
5511 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5512 return bc_error("stack has too few elements");
5514 r = bc_vec_item_rev(&G.prog.results, idx);
5515 s = bc_program_num(r, &num, false);
5518 if (BC_PROG_NUM(r, num)) {
5519 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5520 if (!s) bc_num_copy(&G.prog.last, num);
5524 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5525 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5527 if (inst == BC_INST_PRINT_STR) {
5528 for (i = 0, len = strlen(str); i < len; ++i) {
5531 if (c == '\n') G.prog.nchars = SIZE_MAX;
5536 bc_program_printString(str, &G.prog.nchars);
5537 if (inst == BC_INST_PRINT) bb_putchar('\n');
5541 if (!s && pop) bc_vec_pop(&G.prog.results);
5546 static BcStatus bc_program_negate(void)
5552 s = bc_program_prep(&ptr, &num);
5555 bc_num_init(&res.d.n, num->len);
5556 bc_num_copy(&res.d.n, num);
5557 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5559 bc_program_retire(&res, BC_RESULT_TEMP);
5564 static BcStatus bc_program_logical(char inst)
5567 BcResult *opd1, *opd2, res;
5572 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5574 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5576 if (inst == BC_INST_BOOL_AND)
5577 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5578 else if (inst == BC_INST_BOOL_OR)
5579 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5582 cmp = bc_num_cmp(n1, n2);
5586 case BC_INST_REL_EQ:
5592 case BC_INST_REL_LE:
5598 case BC_INST_REL_GE:
5604 case BC_INST_REL_NE:
5610 case BC_INST_REL_LT:
5616 case BC_INST_REL_GT:
5624 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5626 bc_program_binOpRetire(&res);
5632 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5638 memset(&n2, 0, sizeof(BcNum));
5639 n2.rdx = res.d.id.idx = r->d.id.idx;
5640 res.t = BC_RESULT_STR;
5643 if (!BC_PROG_STACK(&G.prog.results, 2))
5644 return bc_error("stack has too few elements");
5646 bc_vec_pop(&G.prog.results);
5649 bc_vec_pop(&G.prog.results);
5651 bc_vec_push(&G.prog.results, &res);
5652 bc_vec_push(v, &n2);
5654 return BC_STATUS_SUCCESS;
5658 static BcStatus bc_program_copyToVar(char *name, bool var)
5665 if (!BC_PROG_STACK(&G.prog.results, 1))
5666 return bc_error("stack has too few elements");
5668 ptr = bc_vec_top(&G.prog.results);
5669 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5670 return bc_error("variable is wrong type");
5671 v = bc_program_search(name, var);
5674 if (ptr->t == BC_RESULT_STR && !var)
5675 return bc_error("variable is wrong type");
5676 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5679 s = bc_program_num(ptr, &n, false);
5682 // Do this once more to make sure that pointers were not invalidated.
5683 v = bc_program_search(name, var);
5686 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5687 bc_num_copy(&r.d.n, n);
5690 bc_array_init(&r.d.v, true);
5691 bc_array_copy(&r.d.v, (BcVec *) n);
5694 bc_vec_push(v, &r.d);
5695 bc_vec_pop(&G.prog.results);
5700 static BcStatus bc_program_assign(char inst)
5703 BcResult *left, *right, res;
5704 BcNum *l = NULL, *r = NULL;
5705 unsigned long val, max;
5706 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5708 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5711 ib = left->t == BC_RESULT_IBASE;
5712 sc = left->t == BC_RESULT_SCALE;
5716 if (right->t == BC_RESULT_STR) {
5720 if (left->t != BC_RESULT_VAR)
5721 return bc_error("variable is wrong type");
5722 v = bc_program_search(left->d.id.name, true);
5724 return bc_program_assignStr(right, v, false);
5728 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5729 return bc_error("bad assignment:"
5730 " left side must be scale,"
5731 " ibase, obase, last, var,"
5736 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5737 return bc_error("divide by zero");
5742 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5749 if (ib || sc || left->t == BC_RESULT_OBASE) {
5750 static const char *const msg[] = {
5751 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5752 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5753 "?1", //BC_RESULT_LAST
5754 "?2", //BC_RESULT_CONSTANT
5755 "?3", //BC_RESULT_ONE
5756 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5760 s = bc_num_ulong(l, &val);
5763 s = left->t - BC_RESULT_IBASE;
5766 ptr = &G.prog.scale;
5769 if (val < BC_NUM_MIN_BASE)
5770 return bc_error(msg[s]);
5771 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5772 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5776 return bc_error(msg[s]);
5778 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5780 *ptr = (size_t) val;
5781 s = BC_STATUS_SUCCESS;
5784 bc_num_init(&res.d.n, l->len);
5785 bc_num_copy(&res.d.n, l);
5786 bc_program_binOpRetire(&res);
5792 #define bc_program_pushVar(code, bgn, pop, copy) \
5793 bc_program_pushVar(code, bgn)
5794 // for bc, 'pop' and 'copy' are always false
5796 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5797 bool pop, bool copy)
5799 BcStatus s = BC_STATUS_SUCCESS;
5801 char *name = bc_program_name(code, bgn);
5803 r.t = BC_RESULT_VAR;
5808 BcVec *v = bc_program_search(name, true);
5809 BcNum *num = bc_vec_top(v);
5813 if (!BC_PROG_STACK(v, 2 - copy)) {
5815 return bc_error("stack has too few elements");
5821 if (!BC_PROG_STR(num)) {
5823 r.t = BC_RESULT_TEMP;
5825 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5826 bc_num_copy(&r.d.n, num);
5829 r.t = BC_RESULT_STR;
5830 r.d.id.idx = num->rdx;
5833 if (!copy) bc_vec_pop(v);
5838 bc_vec_push(&G.prog.results, &r);
5843 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5846 BcStatus s = BC_STATUS_SUCCESS;
5850 r.d.id.name = bc_program_name(code, bgn);
5852 if (inst == BC_INST_ARRAY) {
5853 r.t = BC_RESULT_ARRAY;
5854 bc_vec_push(&G.prog.results, &r);
5861 s = bc_program_prep(&operand, &num);
5863 s = bc_num_ulong(num, &temp);
5866 if (temp > BC_MAX_DIM) {
5867 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5871 r.d.id.idx = (size_t) temp;
5872 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5876 if (s) free(r.d.id.name);
5881 static BcStatus bc_program_incdec(char inst)
5884 BcResult *ptr, res, copy;
5888 s = bc_program_prep(&ptr, &num);
5891 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5892 copy.t = BC_RESULT_TEMP;
5893 bc_num_init(©.d.n, num->len);
5894 bc_num_copy(©.d.n, num);
5897 res.t = BC_RESULT_ONE;
5898 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5899 BC_INST_ASSIGN_PLUS :
5900 BC_INST_ASSIGN_MINUS;
5902 bc_vec_push(&G.prog.results, &res);
5903 bc_program_assign(inst);
5905 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5906 bc_vec_pop(&G.prog.results);
5907 bc_vec_push(&G.prog.results, ©);
5913 static BcStatus bc_program_call(char *code, size_t *idx)
5915 BcStatus s = BC_STATUS_SUCCESS;
5917 size_t i, nparams = bc_program_index(code, idx);
5924 ip.func = bc_program_index(code, idx);
5925 func = bc_vec_item(&G.prog.fns, ip.func);
5927 if (func->code.len == 0) {
5928 return bc_error("undefined function");
5930 if (nparams != func->nparams) {
5931 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5933 ip.len = G.prog.results.len - nparams;
5935 for (i = 0; i < nparams; ++i) {
5937 a = bc_vec_item(&func->autos, nparams - 1 - i);
5938 arg = bc_vec_top(&G.prog.results);
5940 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5941 return bc_error("variable is wrong type");
5943 s = bc_program_copyToVar(a->name, a->idx);
5947 for (; i < func->autos.len; ++i) {
5950 a = bc_vec_item(&func->autos, i);
5951 v = bc_program_search(a->name, a->idx);
5954 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5955 bc_vec_push(v, ¶m.n);
5958 bc_array_init(¶m.v, true);
5959 bc_vec_push(v, ¶m.v);
5963 bc_vec_push(&G.prog.stack, &ip);
5965 return BC_STATUS_SUCCESS;
5968 static BcStatus bc_program_return(char inst)
5974 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5976 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5977 return bc_error("stack has too few elements");
5979 f = bc_vec_item(&G.prog.fns, ip->func);
5980 res.t = BC_RESULT_TEMP;
5982 if (inst == BC_INST_RET) {
5985 BcResult *operand = bc_vec_top(&G.prog.results);
5987 s = bc_program_num(operand, &num, false);
5989 bc_num_init(&res.d.n, num->len);
5990 bc_num_copy(&res.d.n, num);
5993 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5994 bc_num_zero(&res.d.n);
5997 // We need to pop arguments as well, so this takes that into account.
5998 for (i = 0; i < f->autos.len; ++i) {
6001 BcId *a = bc_vec_item(&f->autos, i);
6003 v = bc_program_search(a->name, a->idx);
6007 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6008 bc_vec_push(&G.prog.results, &res);
6009 bc_vec_pop(&G.prog.stack);
6011 return BC_STATUS_SUCCESS;
6015 static unsigned long bc_program_scale(BcNum *n)
6017 return (unsigned long) n->rdx;
6020 static unsigned long bc_program_len(BcNum *n)
6022 unsigned long len = n->len;
6025 if (n->rdx != n->len) return len;
6026 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6031 static BcStatus bc_program_builtin(char inst)
6037 bool len = inst == BC_INST_LENGTH;
6039 if (!BC_PROG_STACK(&G.prog.results, 1))
6040 return bc_error("stack has too few elements");
6041 opnd = bc_vec_top(&G.prog.results);
6043 s = bc_program_num(opnd, &num, false);
6047 if (!BC_PROG_NUM(opnd, num) && !len)
6048 return bc_error("variable is wrong type");
6051 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6053 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6055 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6056 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6060 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6063 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6065 str = bc_vec_item(&G.prog.strs, idx);
6066 bc_num_ulong2num(&res.d.n, strlen(*str));
6070 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6071 bc_num_ulong2num(&res.d.n, f(num));
6074 bc_program_retire(&res, BC_RESULT_TEMP);
6080 static BcStatus bc_program_divmod(void)
6083 BcResult *opd1, *opd2, res, res2;
6084 BcNum *n1, *n2 = NULL;
6086 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6089 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6090 bc_num_init(&res2.d.n, n2->len);
6092 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6095 bc_program_binOpRetire(&res2);
6096 res.t = BC_RESULT_TEMP;
6097 bc_vec_push(&G.prog.results, &res);
6102 bc_num_free(&res2.d.n);
6103 bc_num_free(&res.d.n);
6107 static BcStatus bc_program_modexp(void)
6110 BcResult *r1, *r2, *r3, res;
6111 BcNum *n1, *n2, *n3;
6113 if (!BC_PROG_STACK(&G.prog.results, 3))
6114 return bc_error("stack has too few elements");
6115 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6118 r1 = bc_vec_item_rev(&G.prog.results, 2);
6119 s = bc_program_num(r1, &n1, false);
6121 if (!BC_PROG_NUM(r1, n1))
6122 return bc_error("variable is wrong type");
6124 // Make sure that the values have their pointers updated, if necessary.
6125 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6127 if (r1->t == r2->t) {
6128 s = bc_program_num(r2, &n2, false);
6132 if (r1->t == r3->t) {
6133 s = bc_program_num(r3, &n3, false);
6138 bc_num_init(&res.d.n, n3->len);
6139 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6142 bc_vec_pop(&G.prog.results);
6143 bc_program_binOpRetire(&res);
6148 bc_num_free(&res.d.n);
6152 static void bc_program_stackLen(void)
6155 size_t len = G.prog.results.len;
6157 res.t = BC_RESULT_TEMP;
6159 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6160 bc_num_ulong2num(&res.d.n, len);
6161 bc_vec_push(&G.prog.results, &res);
6164 static BcStatus bc_program_asciify(void)
6168 BcNum *num = NULL, n;
6169 char *str, *str2, c;
6170 size_t len = G.prog.strs.len, idx;
6173 if (!BC_PROG_STACK(&G.prog.results, 1))
6174 return bc_error("stack has too few elements");
6175 r = bc_vec_top(&G.prog.results);
6177 s = bc_program_num(r, &num, false);
6180 if (BC_PROG_NUM(r, num)) {
6182 bc_num_init(&n, BC_NUM_DEF_SIZE);
6183 bc_num_copy(&n, num);
6184 bc_num_truncate(&n, n.rdx);
6186 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6187 if (s) goto num_err;
6188 s = bc_num_ulong(&n, &val);
6189 if (s) goto num_err;
6196 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6197 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6205 str2 = xstrdup(str);
6206 bc_program_addFunc(str2, &idx);
6208 if (idx != len + BC_PROG_REQ_FUNCS) {
6210 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6211 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6220 bc_vec_push(&G.prog.strs, &str);
6222 res.t = BC_RESULT_STR;
6224 bc_vec_pop(&G.prog.results);
6225 bc_vec_push(&G.prog.results, &res);
6227 return BC_STATUS_SUCCESS;
6234 static BcStatus bc_program_printStream(void)
6242 if (!BC_PROG_STACK(&G.prog.results, 1))
6243 return bc_error("stack has too few elements");
6244 r = bc_vec_top(&G.prog.results);
6246 s = bc_program_num(r, &n, false);
6249 if (BC_PROG_NUM(r, n))
6250 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6252 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6253 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6260 static BcStatus bc_program_nquit(void)
6267 s = bc_program_prep(&opnd, &num);
6269 s = bc_num_ulong(num, &val);
6272 bc_vec_pop(&G.prog.results);
6274 if (G.prog.stack.len < val)
6275 return bc_error("stack has too few elements");
6276 if (G.prog.stack.len == val)
6279 bc_vec_npop(&G.prog.stack, val);
6284 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6287 BcStatus s = BC_STATUS_SUCCESS;
6297 if (!BC_PROG_STACK(&G.prog.results, 1))
6298 return bc_error("stack has too few elements");
6300 r = bc_vec_top(&G.prog.results);
6304 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6306 if (code[*bgn] == BC_PARSE_STREND)
6309 else_name = bc_program_name(code, bgn);
6311 exec = r->d.n.len != 0;
6315 else if (else_name != NULL) {
6322 v = bc_program_search(name, true);
6329 if (!exec) goto exit;
6330 if (!BC_PROG_STR(n)) {
6331 s = bc_error("variable is wrong type");
6339 if (r->t == BC_RESULT_STR)
6341 else if (r->t == BC_RESULT_VAR) {
6342 s = bc_program_num(r, &n, false);
6343 if (s || !BC_PROG_STR(n)) goto exit;
6350 fidx = sidx + BC_PROG_REQ_FUNCS;
6352 str = bc_vec_item(&G.prog.strs, sidx);
6353 f = bc_vec_item(&G.prog.fns, fidx);
6355 if (f->code.len == 0) {
6356 common_parse_init(&prs, fidx);
6357 s = bc_parse_text(&prs, *str);
6359 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6362 if (prs.l.t.t != BC_LEX_EOF) {
6363 s = bc_error("bad expression");
6367 bc_parse_free(&prs);
6371 ip.len = G.prog.results.len;
6374 bc_vec_pop(&G.prog.results);
6375 bc_vec_push(&G.prog.stack, &ip);
6377 return BC_STATUS_SUCCESS;
6380 bc_parse_free(&prs);
6381 f = bc_vec_item(&G.prog.fns, fidx);
6382 bc_vec_npop(&f->code, f->code.len);
6384 bc_vec_pop(&G.prog.results);
6389 static void bc_program_pushGlobal(char inst)
6394 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6395 if (inst == BC_INST_IBASE)
6396 val = (unsigned long) G.prog.ib_t;
6397 else if (inst == BC_INST_SCALE)
6398 val = (unsigned long) G.prog.scale;
6400 val = (unsigned long) G.prog.ob_t;
6402 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6403 bc_num_ulong2num(&res.d.n, val);
6404 bc_vec_push(&G.prog.results, &res);
6407 static void bc_program_addFunc(char *name, size_t *idx)
6409 BcId entry, *entry_ptr;
6414 entry.idx = G.prog.fns.len;
6416 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6417 if (!inserted) free(name);
6419 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6420 *idx = entry_ptr->idx;
6424 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6426 // We need to reset these, so the function can be repopulated.
6428 bc_vec_npop(&func->autos, func->autos.len);
6429 bc_vec_npop(&func->code, func->code.len);
6430 bc_vec_npop(&func->labels, func->labels.len);
6434 bc_vec_push(&G.prog.fns, &f);
6438 // Called when parsing or execution detects a failure,
6439 // resets execution structures.
6440 static void bc_program_reset(void)
6445 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6446 bc_vec_npop(&G.prog.results, G.prog.results.len);
6448 f = bc_vec_item(&G.prog.fns, 0);
6449 ip = bc_vec_top(&G.prog.stack);
6450 ip->idx = f->code.len;
6452 // If !tty, no need to check for ^C: we don't have ^C handler,
6453 // we would be killed by a signal and won't reach this place
6456 static BcStatus bc_program_exec(void)
6458 BcStatus s = BC_STATUS_SUCCESS;
6462 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6463 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6464 char *code = func->code.v;
6467 while (!s && ip->idx < func->code.len) {
6469 char inst = code[(ip->idx)++];
6474 case BC_INST_JUMP_ZERO:
6476 s = bc_program_prep(&ptr, &num);
6478 cond = !bc_num_cmp(num, &G.prog.zero);
6479 bc_vec_pop(&G.prog.results);
6485 idx = bc_program_index(code, &ip->idx);
6486 addr = bc_vec_item(&func->labels, idx);
6487 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6493 s = bc_program_call(code, &ip->idx);
6497 case BC_INST_INC_PRE:
6498 case BC_INST_DEC_PRE:
6499 case BC_INST_INC_POST:
6500 case BC_INST_DEC_POST:
6502 s = bc_program_incdec(inst);
6515 s = bc_program_return(inst);
6519 case BC_INST_BOOL_OR:
6520 case BC_INST_BOOL_AND:
6522 case BC_INST_REL_EQ:
6523 case BC_INST_REL_LE:
6524 case BC_INST_REL_GE:
6525 case BC_INST_REL_NE:
6526 case BC_INST_REL_LT:
6527 case BC_INST_REL_GT:
6529 s = bc_program_logical(inst);
6535 s = bc_program_read();
6541 s = bc_program_pushVar(code, &ip->idx, false, false);
6545 case BC_INST_ARRAY_ELEM:
6548 s = bc_program_pushArray(code, &ip->idx, inst);
6554 r.t = BC_RESULT_LAST;
6555 bc_vec_push(&G.prog.results, &r);
6563 bc_program_pushGlobal(inst);
6567 case BC_INST_SCALE_FUNC:
6568 case BC_INST_LENGTH:
6571 s = bc_program_builtin(inst);
6577 r.t = BC_RESULT_CONSTANT;
6578 r.d.id.idx = bc_program_index(code, &ip->idx);
6579 bc_vec_push(&G.prog.results, &r);
6585 if (!BC_PROG_STACK(&G.prog.results, 1))
6586 s = bc_error("stack has too few elements");
6588 bc_vec_pop(&G.prog.results);
6592 case BC_INST_POP_EXEC:
6594 bc_vec_pop(&G.prog.stack);
6599 case BC_INST_PRINT_POP:
6600 case BC_INST_PRINT_STR:
6602 s = bc_program_print(inst, 0);
6608 r.t = BC_RESULT_STR;
6609 r.d.id.idx = bc_program_index(code, &ip->idx);
6610 bc_vec_push(&G.prog.results, &r);
6615 case BC_INST_MULTIPLY:
6616 case BC_INST_DIVIDE:
6617 case BC_INST_MODULUS:
6621 s = bc_program_op(inst);
6625 case BC_INST_BOOL_NOT:
6627 s = bc_program_prep(&ptr, &num);
6630 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6631 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6632 bc_program_retire(&r, BC_RESULT_TEMP);
6639 s = bc_program_negate();
6644 case BC_INST_ASSIGN_POWER:
6645 case BC_INST_ASSIGN_MULTIPLY:
6646 case BC_INST_ASSIGN_DIVIDE:
6647 case BC_INST_ASSIGN_MODULUS:
6648 case BC_INST_ASSIGN_PLUS:
6649 case BC_INST_ASSIGN_MINUS:
6651 case BC_INST_ASSIGN:
6653 s = bc_program_assign(inst);
6657 case BC_INST_MODEXP:
6659 s = bc_program_modexp();
6663 case BC_INST_DIVMOD:
6665 s = bc_program_divmod();
6669 case BC_INST_EXECUTE:
6670 case BC_INST_EXEC_COND:
6672 cond = inst == BC_INST_EXEC_COND;
6673 s = bc_program_execStr(code, &ip->idx, cond);
6677 case BC_INST_PRINT_STACK:
6679 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6680 s = bc_program_print(BC_INST_PRINT, idx);
6684 case BC_INST_CLEAR_STACK:
6686 bc_vec_npop(&G.prog.results, G.prog.results.len);
6690 case BC_INST_STACK_LEN:
6692 bc_program_stackLen();
6696 case BC_INST_DUPLICATE:
6698 if (!BC_PROG_STACK(&G.prog.results, 1))
6699 return bc_error("stack has too few elements");
6700 ptr = bc_vec_top(&G.prog.results);
6701 bc_result_copy(&r, ptr);
6702 bc_vec_push(&G.prog.results, &r);
6710 if (!BC_PROG_STACK(&G.prog.results, 2))
6711 return bc_error("stack has too few elements");
6713 ptr = bc_vec_item_rev(&G.prog.results, 0);
6714 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6715 memcpy(&r, ptr, sizeof(BcResult));
6716 memcpy(ptr, ptr2, sizeof(BcResult));
6717 memcpy(ptr2, &r, sizeof(BcResult));
6722 case BC_INST_ASCIIFY:
6724 s = bc_program_asciify();
6728 case BC_INST_PRINT_STREAM:
6730 s = bc_program_printStream();
6735 case BC_INST_PUSH_VAR:
6737 bool copy = inst == BC_INST_LOAD;
6738 s = bc_program_pushVar(code, &ip->idx, true, copy);
6742 case BC_INST_PUSH_TO_VAR:
6744 char *name = bc_program_name(code, &ip->idx);
6745 s = bc_program_copyToVar(name, true);
6752 if (G.prog.stack.len <= 2)
6754 bc_vec_npop(&G.prog.stack, 2);
6760 s = bc_program_nquit();
6766 if (s || G_interrupt) {
6771 // If the stack has changed, pointers may be invalid.
6772 ip = bc_vec_top(&G.prog.stack);
6773 func = bc_vec_item(&G.prog.fns, ip->func);
6774 code = func->code.v;
6780 static void bc_vm_info(void)
6782 printf("%s "BB_VER"\n"
6783 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6784 "Report bugs at: https://github.com/gavinhoward/bc\n"
6785 "This is free software with ABSOLUTELY NO WARRANTY\n"
6790 static void bc_vm_envArgs(void)
6792 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6795 char *env_args = getenv(bc_args_env_name), *buf;
6797 if (!env_args) return;
6799 G.env_args = xstrdup(env_args);
6802 bc_vec_init(&v, sizeof(char *), NULL);
6803 bc_vec_push(&v, &bc_args_env_name);
6806 if (!isspace(*buf)) {
6807 bc_vec_push(&v, &buf);
6808 while (*buf != 0 && !isspace(*buf)) ++buf;
6809 if (*buf != 0) (*(buf++)) = '\0';
6815 bc_args((int) v.len, (char **) v.v);
6821 static size_t bc_vm_envLen(const char *var)
6823 char *lenv = getenv(var);
6824 size_t i, len = BC_NUM_PRINT_WIDTH;
6827 if (!lenv) return len;
6831 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6833 len = (size_t) atoi(lenv) - 1;
6834 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6837 len = BC_NUM_PRINT_WIDTH;
6842 static BcStatus bc_vm_process(const char *text)
6844 BcStatus s = bc_parse_text(&G.prs, text);
6848 while (G.prs.l.t.t != BC_LEX_EOF) {
6849 s = G.prs.parse(&G.prs);
6853 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6854 s = bc_program_exec();
6863 static BcStatus bc_vm_file(const char *file)
6871 data = bc_read_file(file);
6872 if (!data) return bc_error("file '%s' is not text", file);
6874 bc_lex_file(&G.prs.l, file);
6875 s = bc_vm_process(data);
6878 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6879 ip = bc_vec_item(&G.prog.stack, 0);
6881 if (main_func->code.len < ip->idx)
6882 s = bc_error("file '%s' is not executable", file);
6889 static BcStatus bc_vm_stdin(void)
6893 size_t len, i, str = 0;
6894 bool comment = false;
6896 G.prog.file = bc_program_stdin_name;
6897 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6899 bc_vec_init(&buffer, sizeof(char), NULL);
6900 bc_vec_init(&buf, sizeof(char), NULL);
6901 bc_vec_pushByte(&buffer, '\0');
6903 // This loop is complex because the vm tries not to send any lines that end
6904 // with a backslash to the parser. The reason for that is because the parser
6905 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6906 // case, and for strings and comments, the parser will expect more stuff.
6907 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6909 char *string = buf.v;
6914 if (str && buf.v[0] == G.send)
6916 else if (buf.v[0] == G.sbgn)
6919 else if (len > 1 || comment) {
6921 for (i = 0; i < len; ++i) {
6923 bool notend = len > i + 1;
6926 if (i - 1 > len || string[i - 1] != '\\') {
6927 if (G.sbgn == G.send)
6929 else if (c == G.send)
6931 else if (c == G.sbgn)
6935 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6939 else if (c == '*' && notend && comment && string[i + 1] == '/')
6943 if (str || comment || string[len - 2] == '\\') {
6944 bc_vec_concat(&buffer, buf.v);
6949 bc_vec_concat(&buffer, buf.v);
6950 s = bc_vm_process(buffer.v);
6953 fputs("ready for more input\n", stderr);
6956 bc_vec_npop(&buffer, buffer.len);
6960 s = bc_error("string end could not be found");
6963 s = bc_error("comment end could not be found");
6967 bc_vec_free(&buffer);
6971 static BcStatus bc_vm_exec(void)
6973 BcStatus s = BC_STATUS_SUCCESS;
6977 if (option_mask32 & BC_FLAG_L) {
6979 bc_lex_file(&G.prs.l, bc_lib_name);
6980 s = bc_parse_text(&G.prs, bc_lib);
6982 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6983 s = G.prs.parse(&G.prs);
6986 s = bc_program_exec();
6991 for (i = 0; !s && i < G.files.len; ++i)
6992 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);
7105 bc_program_init(len);
7107 bc_parse_init(&G.prs, BC_PROG_MAIN);
7109 dc_parse_init(&G.prs, BC_PROG_MAIN);
7113 static BcStatus bc_vm_run(int argc, char *argv[],
7114 const char *env_len)
7118 bc_vm_init(env_len);
7119 bc_args(argc, argv);
7121 G.ttyin = isatty(0);
7124 #if ENABLE_FEATURE_BC_SIGNALS
7125 // With SA_RESTART, most system calls will restart
7126 // (IOW: they won't fail with EINTR).
7127 // In particular, this means ^C won't cause
7128 // stdout to get into "error state" if SIGINT hits
7129 // within write() syscall.
7130 // The downside is that ^C while line input is taken
7131 // will only be handled after [Enter] since read()
7132 // from stdin is not interrupted by ^C either,
7133 // it restarts, thus fgetc() does not return on ^C.
7134 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7136 // Without SA_RESTART, this exhibits a bug:
7137 // "while (1) print 1" and try ^C-ing it.
7138 // Intermittently, instead of returning to input line,
7139 // you'll get "output error: Interrupted system call"
7141 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7143 if (!(option_mask32 & BC_FLAG_Q))
7148 #if ENABLE_FEATURE_CLEAN_UP
7155 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7156 int bc_main(int argc, char **argv)
7159 G.sbgn = G.send = '"';
7161 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7166 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7167 int dc_main(int argc, char **argv)
7173 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");