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 typedef signed char BcDig;
194 typedef struct BcNum {
202 #define BC_NUM_MIN_BASE ((unsigned long) 2)
203 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
204 #define BC_NUM_DEF_SIZE (16)
205 #define BC_NUM_PRINT_WIDTH (69)
207 #define BC_NUM_KARATSUBA_LEN (32)
209 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212 #define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214 #define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
217 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
220 static void bc_num_init(BcNum *n, size_t req);
221 static void bc_num_expand(BcNum *n, size_t req);
222 static void bc_num_copy(BcNum *d, BcNum *s);
223 static void bc_num_free(void *num);
225 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
226 static void bc_num_ulong2num(BcNum *n, unsigned long val);
228 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 typedef enum BcInst {
268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
273 BC_INST_ASSIGN_MINUS,
319 BC_INST_PRINT_STREAM,
334 BC_INST_INVALID = -1,
339 typedef struct BcId {
344 typedef struct BcFunc {
351 typedef enum BcResultType {
356 BC_RESULT_ARRAY_ELEM,
365 // These are between to calculate ibase, obase, and last from instructions.
373 typedef union BcResultData {
379 typedef struct BcResult {
384 typedef struct BcInstPtr {
390 static void bc_array_expand(BcVec *a, size_t len);
391 static int bc_id_cmp(const void *e1, const void *e2);
393 // BC_LEX_NEG is not used in lexing; it is only for parsing.
394 typedef enum BcLexType {
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
500 // must match order of BC_LEX_KEY_foo etc above
502 struct BcLexKeyword {
505 #define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507 static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
563 typedef BcStatus (*BcLexNext)(struct BcLex *);
565 typedef struct BcLex {
583 #define BC_PARSE_STREND ((char) UCHAR_MAX)
585 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
586 #define bc_parse_updateFunc(p, f) \
587 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
589 #define BC_PARSE_REL (1 << 0)
590 #define BC_PARSE_PRINT (1 << 1)
591 #define BC_PARSE_NOCALL (1 << 2)
592 #define BC_PARSE_NOREAD (1 << 3)
593 #define BC_PARSE_ARRAY (1 << 4)
595 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
596 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
599 #define BC_PARSE_FUNC_INNER(parse) \
600 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602 #define BC_PARSE_FLAG_FUNC (1 << 1)
603 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605 #define BC_PARSE_FLAG_BODY (1 << 2)
606 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608 #define BC_PARSE_FLAG_LOOP (1 << 3)
609 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
612 #define BC_PARSE_LOOP_INNER(parse) \
613 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615 #define BC_PARSE_FLAG_IF (1 << 5)
616 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618 #define BC_PARSE_FLAG_ELSE (1 << 6)
619 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621 #define BC_PARSE_FLAG_IF_END (1 << 7)
622 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624 #define BC_PARSE_CAN_EXEC(parse) \
625 (!(BC_PARSE_TOP_FLAG(parse) & \
626 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
627 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
628 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630 typedef struct BcOp {
635 typedef struct BcParseNext {
640 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
641 #define BC_PARSE_NEXT(a, ...) \
643 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
650 typedef BcStatus (*BcParseParse)(struct BcParse *);
652 typedef struct BcParse {
675 static BcStatus bc_lex_token(BcLex *l);
677 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
678 #define BC_PARSE_LEAF(p, rparen) \
679 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
680 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682 // We can calculate the conversion between tokens and exprs by subtracting the
683 // position of the first operator in the lex enum and adding the position of the
684 // first in the expr enum. Note: This only works for binary operators.
685 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
693 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695 static BcStatus dc_lex_token(BcLex *l);
697 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
701 typedef struct BcProgram {
742 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744 #define BC_PROG_MAIN (0)
745 #define BC_PROG_READ (1)
748 #define BC_PROG_REQ_FUNCS (2)
751 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
752 #define BC_PROG_NUM(r, n) \
753 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757 static void bc_program_addFunc(char *name, size_t *idx);
758 static void bc_program_reset(void);
760 #define BC_FLAG_X (1 << 0)
761 #define BC_FLAG_W (1 << 1)
762 #define BC_FLAG_V (1 << 2)
763 #define BC_FLAG_S (1 << 3)
764 #define BC_FLAG_Q (1 << 4)
765 #define BC_FLAG_L (1 << 5)
766 #define BC_FLAG_I (1 << 6)
768 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
769 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771 #define BC_MAX_OBASE ((unsigned) 999)
772 #define BC_MAX_DIM ((unsigned) INT_MAX)
773 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
774 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
775 #define BC_MAX_NAME BC_MAX_STRING
776 #define BC_MAX_NUM BC_MAX_STRING
777 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
778 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
789 // For error messages. Can be set to current parsed line,
790 // or [TODO] to current executing line (can be before last parsed one)
797 #define G (*ptr_to_globals)
798 #define INIT_G() do { \
799 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
801 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
802 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
803 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
804 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
807 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
809 static void bc_vm_info(void);
813 // This is an array that corresponds to token types. An entry is
814 // true if the token is valid in an expression, false otherwise.
815 static const bool bc_parse_exprs[] = {
816 false, false, true, true, true, true, true, true, true, true, true, true,
817 true, true, true, true, true, true, true, true, true, true, true, true,
818 true, true, true, false, false, true, true, false, false, false, false,
819 false, false, false, true, true, false, false, false, false, false, false,
820 false, true, false, true, true, true, true, false, false, true, false, true,
824 // This is an array of data for operators that correspond to token types.
825 static const BcOp bc_parse_ops[] = {
826 { 0, false }, { 0, false },
829 { 3, true }, { 3, true }, { 3, true },
830 { 4, true }, { 4, true },
831 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
833 { 7, true }, { 7, true },
834 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
835 { 5, false }, { 5, false },
838 // These identify what tokens can come after expressions in certain cases.
839 static const BcParseNext bc_parse_next_expr =
840 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
841 static const BcParseNext bc_parse_next_param =
842 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
843 static const BcParseNext bc_parse_next_print =
844 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
845 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
846 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
847 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
848 static const BcParseNext bc_parse_next_read =
849 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
853 static const BcLexType dc_lex_regs[] = {
854 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
855 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
856 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
860 static const BcLexType dc_lex_tokens[] = {
861 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
862 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
863 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
864 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
868 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
871 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
872 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
873 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
875 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
877 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
878 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
880 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
881 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
882 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
883 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
884 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
888 static const BcInst dc_parse_insts[] = {
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
890 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
891 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
899 BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
904 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
906 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
908 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
909 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
911 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
915 static const BcNumBinaryOp bc_program_ops[] = {
916 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
919 static void fflush_and_check(void)
922 if (ferror(stdout) || ferror(stderr))
923 bb_perror_msg_and_die("output error");
926 static void quit(void) NORETURN;
927 static void quit(void)
930 bb_perror_msg_and_die("input error");
935 static void bc_verror_msg(const char *fmt, va_list p)
937 const char *sv = sv; /* for compiler */
940 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
942 bb_verror_msg(fmt, p, NULL);
944 free((char*)applet_name);
949 static NOINLINE int bc_error_fmt(const char *fmt, ...)
954 bc_verror_msg(fmt, p);
959 return BC_STATUS_FAILURE;
962 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
966 // Are non-POSIX constructs totally ok?
967 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
968 return BC_STATUS_SUCCESS; // yes
971 bc_verror_msg(fmt, p);
974 // Do we treat non-POSIX constructs as errors?
975 if (!(option_mask32 & BC_FLAG_S))
976 return BC_STATUS_SUCCESS; // no, it's a warning
979 return BC_STATUS_FAILURE;
982 // We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
983 // This idiom begs for tail-call optimization, but for it to work,
984 // function must not have calller-cleaned parameters on stack.
985 // Unfortunately, vararg functions do exactly that on most arches.
986 // Thus, these shims for the cases when we have no PARAMS:
987 static int bc_error(const char *msg)
989 return bc_error_fmt("%s", msg);
991 static int bc_posix_error(const char *msg)
993 return bc_posix_error_fmt("%s", msg);
995 static int bc_error_bad_character(char c)
997 return bc_error_fmt("bad character '%c'", c);
999 static int bc_error_bad_expression(void)
1001 return bc_error("bad expression");
1003 static int bc_error_bad_token(void)
1005 return bc_error("bad token");
1007 static int bc_error_stack_has_too_few_elements(void)
1009 return bc_error("stack has too few elements");
1011 static int bc_error_variable_is_wrong_type(void)
1013 return bc_error("variable is wrong type");
1015 static int bc_error_nested_read_call(void)
1017 return bc_error("read() call inside of a read() call");
1020 static void bc_vec_grow(BcVec *v, size_t n)
1022 size_t cap = v->cap * 2;
1023 while (cap < v->len + n) cap *= 2;
1024 v->v = xrealloc(v->v, v->size * cap);
1028 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1031 v->cap = BC_VEC_START_CAP;
1034 v->v = xmalloc(esize * BC_VEC_START_CAP);
1037 static void bc_char_vec_init(BcVec *v)
1039 bc_vec_init(v, sizeof(char), NULL);
1042 static void bc_vec_expand(BcVec *v, size_t req)
1045 v->v = xrealloc(v->v, v->size * req);
1050 static void bc_vec_npop(BcVec *v, size_t n)
1055 size_t len = v->len - n;
1056 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1060 static void bc_vec_pop_all(BcVec *v)
1062 bc_vec_npop(v, v->len);
1065 static void bc_vec_push(BcVec *v, const void *data)
1067 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1068 memmove(v->v + (v->size * v->len), data, v->size);
1072 static void bc_vec_pushByte(BcVec *v, char data)
1074 bc_vec_push(v, &data);
1077 static void bc_vec_pushZeroByte(BcVec *v)
1079 //bc_vec_pushByte(v, '\0');
1081 bc_vec_push(v, &const_int_0);
1084 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1087 bc_vec_push(v, data);
1092 if (v->len == v->cap) bc_vec_grow(v, 1);
1094 ptr = v->v + v->size * idx;
1096 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1097 memmove(ptr, data, v->size);
1101 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1104 bc_vec_expand(v, len + 1);
1105 memcpy(v->v, str, len);
1108 bc_vec_pushZeroByte(v);
1111 static void bc_vec_concat(BcVec *v, const char *str)
1115 if (v->len == 0) bc_vec_pushZeroByte(v);
1117 len = v->len + strlen(str);
1119 if (v->cap < len) bc_vec_grow(v, len - v->len);
1125 static void *bc_vec_item(const BcVec *v, size_t idx)
1127 return v->v + v->size * idx;
1130 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1132 return v->v + v->size * (v->len - idx - 1);
1135 static void bc_vec_free(void *vec)
1137 BcVec *v = (BcVec *) vec;
1142 static size_t bc_map_find(const BcVec *v, const void *ptr)
1144 size_t low = 0, high = v->len;
1146 while (low < high) {
1148 size_t mid = (low + high) / 2;
1149 BcId *id = bc_vec_item(v, mid);
1150 int result = bc_id_cmp(ptr, id);
1154 else if (result < 0)
1163 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1165 size_t n = *i = bc_map_find(v, ptr);
1168 bc_vec_push(v, ptr);
1169 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1170 return 0; // "was not inserted"
1172 bc_vec_pushAt(v, ptr, n);
1173 return 1; // "was inserted"
1176 static size_t bc_map_index(const BcVec *v, const void *ptr)
1178 size_t i = bc_map_find(v, ptr);
1179 if (i >= v->len) return BC_VEC_INVALID_IDX;
1180 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1183 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1191 bc_vec_pop_all(vec);
1194 #if ENABLE_FEATURE_BC_SIGNALS
1195 if (bb_got_signal) { // ^C was pressed
1197 bb_got_signal = 0; // resets G_interrupt to zero
1199 ? "\ninterrupt (type \"quit\" to exit)\n"
1200 : "\ninterrupt (type \"q\" to exit)\n"
1204 if (G.ttyin && !G_posix)
1205 fputs(prompt, stderr);
1207 #if ENABLE_FEATURE_BC_SIGNALS
1213 #if ENABLE_FEATURE_BC_SIGNALS
1214 // Both conditions appear simultaneously, check both just in case
1215 if (errno == EINTR || bb_got_signal) {
1222 quit(); // this emits error message
1224 // Note: EOF does not append '\n', therefore:
1225 // printf 'print 123\n' | bc - works
1226 // printf 'print 123' | bc - fails (syntax error)
1230 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1233 // Bad chars on this line, ignore entire line
1234 bc_error_fmt("illegal character 0x%02x", i);
1237 bc_vec_pushByte(vec, (char)i);
1238 } while (i != '\n');
1239 } while (bad_chars);
1241 bc_vec_pushZeroByte(vec);
1243 return BC_STATUS_SUCCESS;
1246 static char* bc_read_file(const char *path)
1249 size_t size = ((size_t) -1);
1252 buf = xmalloc_open_read_close(path, &size);
1254 for (i = 0; i < size; ++i) {
1256 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1268 static void bc_args(int argc, char **argv)
1274 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1275 opts = getopt32long(argv, "xwvsqli",
1276 "extended-register\0" No_argument "x"
1277 "warn\0" No_argument "w"
1278 "version\0" No_argument "v"
1279 "standard\0" No_argument "s"
1280 "quiet\0" No_argument "q"
1281 "mathlib\0" No_argument "l"
1282 "interactive\0" No_argument "i"
1285 opts = getopt32(argv, "xwvsqli");
1287 if (getenv("POSIXLY_CORRECT"))
1288 option_mask32 |= BC_FLAG_S;
1290 if (opts & BC_FLAG_V) bc_vm_info();
1291 // should not be necessary, getopt32() handles this??
1292 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1294 for (i = optind; i < argc; ++i)
1295 bc_vec_push(&G.files, argv + i);
1298 static void bc_num_setToZero(BcNum *n, size_t scale)
1305 static void bc_num_zero(BcNum *n)
1307 bc_num_setToZero(n, 0);
1310 static void bc_num_one(BcNum *n)
1312 bc_num_setToZero(n, 0);
1317 static void bc_num_ten(BcNum *n)
1319 bc_num_setToZero(n, 0);
1325 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1329 for (i = 0; i < len; ++i) {
1330 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1337 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1341 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1342 return BC_NUM_NEG(i + 1, c < 0);
1345 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1347 size_t i, min, a_int, b_int, diff;
1348 BcDig *max_num, *min_num;
1349 bool a_max, neg = false;
1352 if (a == b) return 0;
1353 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1354 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1364 a_int = BC_NUM_INT(a);
1365 b_int = BC_NUM_INT(b);
1367 a_max = (a->rdx > b->rdx);
1369 if (a_int != 0) return (ssize_t) a_int;
1373 diff = a->rdx - b->rdx;
1374 max_num = a->num + diff;
1379 diff = b->rdx - a->rdx;
1380 max_num = b->num + diff;
1384 cmp = bc_num_compare(max_num, min_num, b_int + min);
1385 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1387 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1388 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1394 static void bc_num_truncate(BcNum *n, size_t places)
1396 if (places == 0) return;
1402 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1406 static void bc_num_extend(BcNum *n, size_t places)
1408 size_t len = n->len + places;
1412 if (n->cap < len) bc_num_expand(n, len);
1414 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1415 memset(n->num, 0, sizeof(BcDig) * places);
1422 static void bc_num_clean(BcNum *n)
1424 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1427 else if (n->len < n->rdx)
1431 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1434 bc_num_extend(n, scale - n->rdx);
1436 bc_num_truncate(n, n->rdx - scale);
1439 if (n->len != 0) n->neg = !neg1 != !neg2;
1442 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1447 b->len = n->len - idx;
1449 a->rdx = b->rdx = 0;
1451 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1452 memcpy(a->num, n->num, idx * sizeof(BcDig));
1463 static BcStatus bc_num_shift(BcNum *n, size_t places)
1465 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1466 if (places + n->len > BC_MAX_NUM)
1467 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1469 if (n->rdx >= places)
1472 bc_num_extend(n, places - n->rdx);
1478 return BC_STATUS_SUCCESS;
1481 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1490 return bc_num_div(&one, a, b, scale);
1493 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1495 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1496 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1499 // Because this function doesn't need to use scale (per the bc spec),
1500 // I am hijacking it to say whether it's doing an add or a subtract.
1504 if (sub && c->len) c->neg = !c->neg;
1505 return BC_STATUS_SUCCESS;
1507 else if (b->len == 0) {
1509 return BC_STATUS_SUCCESS;
1513 c->rdx = BC_MAX(a->rdx, b->rdx);
1514 min_rdx = BC_MIN(a->rdx, b->rdx);
1517 if (a->rdx > b->rdx) {
1518 diff = a->rdx - b->rdx;
1520 ptr_a = a->num + diff;
1524 diff = b->rdx - a->rdx;
1527 ptr_b = b->num + diff;
1530 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1533 a_int = BC_NUM_INT(a);
1534 b_int = BC_NUM_INT(b);
1536 if (a_int > b_int) {
1547 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1548 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1550 ptr_c[i] = (BcDig)(in % 10);
1553 for (; i < max + min_rdx; ++i, ++c->len) {
1554 in = ((int) ptr[i]) + carry;
1556 ptr_c[i] = (BcDig)(in % 10);
1559 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1561 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1564 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1567 BcNum *minuend, *subtrahend;
1569 bool aneg, bneg, neg;
1571 // Because this function doesn't need to use scale (per the bc spec),
1572 // I am hijacking it to say whether it's doing an add or a subtract.
1576 if (sub && c->len) c->neg = !c->neg;
1577 return BC_STATUS_SUCCESS;
1579 else if (b->len == 0) {
1581 return BC_STATUS_SUCCESS;
1586 a->neg = b->neg = false;
1588 cmp = bc_num_cmp(a, b);
1594 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1595 return BC_STATUS_SUCCESS;
1604 if (sub) neg = !neg;
1609 bc_num_copy(c, minuend);
1612 if (c->rdx < subtrahend->rdx) {
1613 bc_num_extend(c, subtrahend->rdx - c->rdx);
1617 start = c->rdx - subtrahend->rdx;
1619 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1623 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1626 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1631 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1632 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1633 bool aone = BC_NUM_ONE(a);
1635 if (a->len == 0 || b->len == 0) {
1637 return BC_STATUS_SUCCESS;
1639 else if (aone || BC_NUM_ONE(b)) {
1640 bc_num_copy(c, aone ? b : a);
1641 return BC_STATUS_SUCCESS;
1644 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1645 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1647 bc_num_expand(c, a->len + b->len + 1);
1649 memset(c->num, 0, sizeof(BcDig) * c->cap);
1650 c->len = carry = len = 0;
1652 for (i = 0; i < b->len; ++i) {
1654 for (j = 0; j < a->len; ++j) {
1655 int in = (int) c->num[i + j];
1656 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1658 c->num[i + j] = (BcDig)(in % 10);
1661 c->num[i + j] += (BcDig) carry;
1662 len = BC_MAX(len, i + j + !!carry);
1668 return BC_STATUS_SUCCESS;
1671 bc_num_init(&l1, max);
1672 bc_num_init(&h1, max);
1673 bc_num_init(&l2, max);
1674 bc_num_init(&h2, max);
1675 bc_num_init(&m1, max);
1676 bc_num_init(&m2, max);
1677 bc_num_init(&z0, max);
1678 bc_num_init(&z1, max);
1679 bc_num_init(&z2, max);
1680 bc_num_init(&temp, max + max);
1682 bc_num_split(a, max2, &l1, &h1);
1683 bc_num_split(b, max2, &l2, &h2);
1685 s = bc_num_add(&h1, &l1, &m1, 0);
1687 s = bc_num_add(&h2, &l2, &m2, 0);
1690 s = bc_num_k(&h1, &h2, &z0);
1692 s = bc_num_k(&m1, &m2, &z1);
1694 s = bc_num_k(&l1, &l2, &z2);
1697 s = bc_num_sub(&z1, &z0, &temp, 0);
1699 s = bc_num_sub(&temp, &z2, &z1, 0);
1702 s = bc_num_shift(&z0, max2 * 2);
1704 s = bc_num_shift(&z1, max2);
1706 s = bc_num_add(&z0, &z1, &temp, 0);
1708 s = bc_num_add(&temp, &z2, c, 0);
1724 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1728 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1730 scale = BC_MAX(scale, a->rdx);
1731 scale = BC_MAX(scale, b->rdx);
1732 scale = BC_MIN(a->rdx + b->rdx, scale);
1733 maxrdx = BC_MAX(maxrdx, scale);
1735 bc_num_init(&cpa, a->len);
1736 bc_num_init(&cpb, b->len);
1738 bc_num_copy(&cpa, a);
1739 bc_num_copy(&cpb, b);
1740 cpa.neg = cpb.neg = false;
1742 s = bc_num_shift(&cpa, maxrdx);
1744 s = bc_num_shift(&cpb, maxrdx);
1746 s = bc_num_k(&cpa, &cpb, c);
1750 bc_num_expand(c, c->len + maxrdx);
1752 if (c->len < maxrdx) {
1753 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1758 bc_num_retireMul(c, scale, a->neg, b->neg);
1766 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1768 BcStatus s = BC_STATUS_SUCCESS;
1775 return bc_error("divide by zero");
1776 else if (a->len == 0) {
1777 bc_num_setToZero(c, scale);
1778 return BC_STATUS_SUCCESS;
1780 else if (BC_NUM_ONE(b)) {
1782 bc_num_retireMul(c, scale, a->neg, b->neg);
1783 return BC_STATUS_SUCCESS;
1786 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1787 bc_num_copy(&cp, a);
1791 bc_num_expand(&cp, len + 2);
1792 bc_num_extend(&cp, len - cp.len);
1795 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1797 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1799 if (b->rdx == b->len) {
1800 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1804 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1806 // We want an extra zero in front to make things simpler.
1807 cp.num[cp.len++] = 0;
1810 bc_num_expand(c, cp.len);
1813 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1818 for (i = end - 1; !s && i < end; --i) {
1820 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1821 bc_num_subArrays(n, p, len);
1825 bc_num_retireMul(c, scale, a->neg, b->neg);
1828 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1831 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1832 BcNum *restrict d, size_t scale, size_t ts)
1839 return bc_error("divide by zero");
1842 bc_num_setToZero(d, ts);
1843 return BC_STATUS_SUCCESS;
1846 bc_num_init(&temp, d->cap);
1847 bc_num_d(a, b, c, scale);
1849 if (scale != 0) scale = ts;
1851 s = bc_num_m(c, b, &temp, scale);
1853 s = bc_num_sub(a, &temp, d, scale);
1856 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1859 bc_num_retireMul(d, ts, a->neg, b->neg);
1867 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1871 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1873 bc_num_init(&c1, len);
1874 s = bc_num_r(a, b, &c1, c, scale, ts);
1880 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1882 BcStatus s = BC_STATUS_SUCCESS;
1885 size_t i, powrdx, resrdx;
1888 if (b->rdx) return bc_error("non integer number");
1892 return BC_STATUS_SUCCESS;
1894 else if (a->len == 0) {
1895 bc_num_setToZero(c, scale);
1896 return BC_STATUS_SUCCESS;
1898 else if (BC_NUM_ONE(b)) {
1902 s = bc_num_inv(a, c, scale);
1909 s = bc_num_ulong(b, &pow);
1912 bc_num_init(©, a->len);
1913 bc_num_copy(©, a);
1915 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1919 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1921 s = bc_num_mul(©, ©, ©, powrdx);
1923 // It is too slow to handle ^C only after entire "2^1000000" completes
1925 s = BC_STATUS_FAILURE;
1930 bc_num_copy(c, ©);
1932 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1935 s = bc_num_mul(©, ©, ©, powrdx);
1940 s = bc_num_mul(c, ©, c, resrdx);
1943 // It is too slow to handle ^C only after entire "2^1000000" completes
1945 s = BC_STATUS_FAILURE;
1951 s = bc_num_inv(c, c, scale);
1955 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1957 // We can't use bc_num_clean() here.
1958 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1959 if (zero) bc_num_setToZero(c, scale);
1966 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1967 BcNumBinaryOp op, size_t req)
1970 BcNum num2, *ptr_a, *ptr_b;
1975 memcpy(ptr_a, c, sizeof(BcNum));
1984 memcpy(ptr_b, c, sizeof(BcNum));
1992 bc_num_init(c, req);
1994 bc_num_expand(c, req);
1996 s = op(ptr_a, ptr_b, c, scale);
1998 if (init) bc_num_free(&num2);
2003 static bool bc_num_strValid(const char *val, size_t base)
2006 bool small, radix = false;
2007 size_t i, len = strlen(val);
2009 if (!len) return true;
2012 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2014 for (i = 0; i < len; ++i) {
2020 if (radix) return false;
2026 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2033 static void bc_num_parseDecimal(BcNum *n, const char *val)
2039 for (i = 0; val[i] == '0'; ++i);
2046 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2047 bc_num_expand(n, len);
2050 ptr = strchr(val, '.');
2054 n->rdx = (size_t)((val + len) - (ptr + 1));
2057 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2058 n->num[n->len] = val[i] - '0';
2062 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2065 BcNum temp, mult, result;
2069 size_t i, digits, len = strlen(val);
2073 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2076 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2077 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2079 for (i = 0; i < len; ++i) {
2082 if (c == '.') break;
2084 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2086 s = bc_num_mul(n, base, &mult, 0);
2087 if (s) goto int_err;
2088 bc_num_ulong2num(&temp, v);
2089 s = bc_num_add(&mult, &temp, n, 0);
2090 if (s) goto int_err;
2095 if (c == 0) goto int_err;
2098 bc_num_init(&result, base->len);
2099 bc_num_zero(&result);
2102 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2107 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2109 s = bc_num_mul(&result, base, &result, 0);
2111 bc_num_ulong2num(&temp, v);
2112 s = bc_num_add(&result, &temp, &result, 0);
2114 s = bc_num_mul(&mult, base, &mult, 0);
2118 s = bc_num_div(&result, &mult, &result, digits);
2120 s = bc_num_add(n, &result, n, digits);
2124 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2130 bc_num_free(&result);
2136 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2138 if (*nchars == line_len - 1) {
2146 static void bc_num_printChar(size_t num, size_t width, bool radix,
2147 size_t *nchars, size_t line_len)
2149 (void) radix, (void) line_len;
2150 bb_putchar((char) num);
2151 *nchars = *nchars + width;
2155 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2156 size_t *nchars, size_t line_len)
2160 bc_num_printNewline(nchars, line_len);
2161 bb_putchar(radix ? '.' : ' ');
2164 bc_num_printNewline(nchars, line_len);
2165 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2168 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2170 bc_num_printNewline(nchars, line_len);
2173 bb_putchar(((char) dig) + '0');
2177 static void bc_num_printHex(size_t num, size_t width, bool radix,
2178 size_t *nchars, size_t line_len)
2181 bc_num_printNewline(nchars, line_len);
2186 bc_num_printNewline(nchars, line_len);
2187 bb_putchar(bb_hexdigits_upcase[num]);
2188 *nchars = *nchars + width;
2191 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2193 size_t i, rdx = n->rdx - 1;
2195 if (n->neg) bb_putchar('-');
2196 (*nchars) += n->neg;
2198 for (i = n->len - 1; i < n->len; --i)
2199 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2202 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2203 size_t *nchars, size_t len, BcNumDigitOp print)
2207 BcNum intp, fracp, digit, frac_len;
2208 unsigned long dig, *ptr;
2213 print(0, width, false, nchars, len);
2214 return BC_STATUS_SUCCESS;
2217 bc_vec_init(&stack, sizeof(long), NULL);
2218 bc_num_init(&intp, n->len);
2219 bc_num_init(&fracp, n->rdx);
2220 bc_num_init(&digit, width);
2221 bc_num_init(&frac_len, BC_NUM_INT(n));
2222 bc_num_copy(&intp, n);
2223 bc_num_one(&frac_len);
2225 bc_num_truncate(&intp, intp.rdx);
2226 s = bc_num_sub(n, &intp, &fracp, 0);
2229 while (intp.len != 0) {
2230 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2232 s = bc_num_ulong(&digit, &dig);
2234 bc_vec_push(&stack, &dig);
2237 for (i = 0; i < stack.len; ++i) {
2238 ptr = bc_vec_item_rev(&stack, i);
2239 print(*ptr, width, false, nchars, len);
2242 if (!n->rdx) goto err;
2244 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2245 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2247 s = bc_num_ulong(&fracp, &dig);
2249 bc_num_ulong2num(&intp, dig);
2250 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2252 print(dig, width, radix, nchars, len);
2253 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2258 bc_num_free(&frac_len);
2259 bc_num_free(&digit);
2260 bc_num_free(&fracp);
2262 bc_vec_free(&stack);
2266 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2267 size_t *nchars, size_t line_len)
2274 if (neg) bb_putchar('-');
2279 if (base_t <= BC_NUM_MAX_IBASE) {
2281 print = bc_num_printHex;
2284 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2285 print = bc_num_printDigits;
2288 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2295 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2297 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2301 static void bc_num_init(BcNum *n, size_t req)
2303 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2304 memset(n, 0, sizeof(BcNum));
2305 n->num = xmalloc(req);
2309 static void bc_num_expand(BcNum *n, size_t req)
2311 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2313 n->num = xrealloc(n->num, req);
2318 static void bc_num_free(void *num)
2320 free(((BcNum *) num)->num);
2323 static void bc_num_copy(BcNum *d, BcNum *s)
2326 bc_num_expand(d, s->cap);
2330 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2334 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2337 if (!bc_num_strValid(val, base_t))
2338 return bc_error("bad number string");
2341 bc_num_parseDecimal(n, val);
2343 bc_num_parseBase(n, val, base);
2345 return BC_STATUS_SUCCESS;
2348 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2349 size_t *nchars, size_t line_len)
2351 BcStatus s = BC_STATUS_SUCCESS;
2353 bc_num_printNewline(nchars, line_len);
2359 else if (base_t == 10)
2360 bc_num_printDecimal(n, nchars, line_len);
2362 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2372 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2377 if (n->neg) return bc_error("negative number");
2379 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2381 unsigned long prev = *result, powprev = pow;
2383 *result += ((unsigned long) n->num[i]) * pow;
2386 if (*result < prev || pow < powprev)
2387 return bc_error("overflow");
2390 return BC_STATUS_SUCCESS;
2393 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2401 if (val == 0) return;
2403 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2404 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2407 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2409 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2411 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2414 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2416 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2418 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2421 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2423 size_t req = BC_NUM_MREQ(a, b, scale);
2424 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2427 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2429 size_t req = BC_NUM_MREQ(a, b, scale);
2430 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2433 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2435 size_t req = BC_NUM_MREQ(a, b, scale);
2436 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2439 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2441 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2444 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2447 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2448 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2449 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2451 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2452 bc_num_expand(b, req);
2455 bc_num_setToZero(b, scale);
2456 return BC_STATUS_SUCCESS;
2459 return bc_error("negative number");
2460 else if (BC_NUM_ONE(a)) {
2462 bc_num_extend(b, scale);
2463 return BC_STATUS_SUCCESS;
2466 scale = BC_MAX(scale, a->rdx) + 1;
2467 len = a->len + scale;
2469 bc_num_init(&num1, len);
2470 bc_num_init(&num2, len);
2471 bc_num_init(&half, BC_NUM_DEF_SIZE);
2477 bc_num_init(&f, len);
2478 bc_num_init(&fprime, len);
2484 pow = BC_NUM_INT(a);
2493 pow -= 2 - (pow & 1);
2495 bc_num_extend(x0, pow);
2497 // Make sure to move the radix back.
2501 x0->rdx = digs = digs1 = 0;
2503 len = BC_NUM_INT(x0) + resrdx - 1;
2505 while (cmp != 0 || digs < len) {
2507 s = bc_num_div(a, x0, &f, resrdx);
2509 s = bc_num_add(x0, &f, &fprime, resrdx);
2511 s = bc_num_mul(&fprime, &half, x1, resrdx);
2514 cmp = bc_num_cmp(x1, x0);
2515 digs = x1->len - (unsigned long long) llabs(cmp);
2517 if (cmp == cmp2 && digs == digs1)
2522 resrdx += times > 4;
2535 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2538 bc_num_free(&fprime);
2546 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2552 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2555 memcpy(&num2, c, sizeof(BcNum));
2557 bc_num_init(c, len);
2562 bc_num_expand(c, len);
2565 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2567 if (init) bc_num_free(&num2);
2573 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2576 BcNum base, exp, two, temp;
2579 return bc_error("divide by zero");
2580 if (a->rdx || b->rdx || c->rdx)
2581 return bc_error("non integer number");
2583 return bc_error("negative number");
2585 bc_num_expand(d, c->len);
2586 bc_num_init(&base, c->len);
2587 bc_num_init(&exp, b->len);
2588 bc_num_init(&two, BC_NUM_DEF_SIZE);
2589 bc_num_init(&temp, b->len);
2595 s = bc_num_rem(a, c, &base, 0);
2597 bc_num_copy(&exp, b);
2599 while (exp.len != 0) {
2601 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2604 if (BC_NUM_ONE(&temp)) {
2605 s = bc_num_mul(d, &base, &temp, 0);
2607 s = bc_num_rem(&temp, c, d, 0);
2611 s = bc_num_mul(&base, &base, &temp, 0);
2613 s = bc_num_rem(&temp, c, &base, 0);
2626 static int bc_id_cmp(const void *e1, const void *e2)
2628 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2631 static void bc_id_free(void *id)
2633 free(((BcId *) id)->name);
2636 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2641 for (i = 0; i < f->autos.len; ++i) {
2642 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2643 return bc_error("function parameter or auto var has the same name as another");
2649 bc_vec_push(&f->autos, &a);
2651 return BC_STATUS_SUCCESS;
2654 static void bc_func_init(BcFunc *f)
2656 bc_char_vec_init(&f->code);
2657 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2658 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2662 static void bc_func_free(void *func)
2664 BcFunc *f = (BcFunc *) func;
2665 bc_vec_free(&f->code);
2666 bc_vec_free(&f->autos);
2667 bc_vec_free(&f->labels);
2670 static void bc_array_init(BcVec *a, bool nums)
2673 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2675 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2676 bc_array_expand(a, 1);
2679 static void bc_array_copy(BcVec *d, const BcVec *s)
2684 bc_vec_expand(d, s->cap);
2687 for (i = 0; i < s->len; ++i) {
2688 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2689 bc_num_init(dnum, snum->len);
2690 bc_num_copy(dnum, snum);
2694 static void bc_array_expand(BcVec *a, size_t len)
2698 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2699 while (len > a->len) {
2700 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2701 bc_vec_push(a, &data.n);
2705 while (len > a->len) {
2706 bc_array_init(&data.v, true);
2707 bc_vec_push(a, &data.v);
2712 static void bc_string_free(void *string)
2714 free(*((char **) string));
2718 static void bc_result_copy(BcResult *d, BcResult *src)
2724 case BC_RESULT_TEMP:
2725 case BC_RESULT_IBASE:
2726 case BC_RESULT_SCALE:
2727 case BC_RESULT_OBASE:
2729 bc_num_init(&d->d.n, src->d.n.len);
2730 bc_num_copy(&d->d.n, &src->d.n);
2735 case BC_RESULT_ARRAY:
2736 case BC_RESULT_ARRAY_ELEM:
2738 d->d.id.name = xstrdup(src->d.id.name);
2742 case BC_RESULT_CONSTANT:
2743 case BC_RESULT_LAST:
2747 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2754 static void bc_result_free(void *result)
2756 BcResult *r = (BcResult *) result;
2760 case BC_RESULT_TEMP:
2761 case BC_RESULT_IBASE:
2762 case BC_RESULT_SCALE:
2763 case BC_RESULT_OBASE:
2765 bc_num_free(&r->d.n);
2770 case BC_RESULT_ARRAY:
2771 case BC_RESULT_ARRAY_ELEM:
2785 static void bc_lex_lineComment(BcLex *l)
2787 l->t.t = BC_LEX_WHITESPACE;
2788 while (l->i < l->len && l->buf[l->i++] != '\n');
2792 static void bc_lex_whitespace(BcLex *l)
2795 l->t.t = BC_LEX_WHITESPACE;
2796 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2799 static BcStatus bc_lex_number(BcLex *l, char start)
2801 const char *buf = l->buf + l->i;
2802 size_t len, hits = 0, bslashes = 0, i = 0, j;
2804 bool last_pt, pt = start == '.';
2807 l->t.t = BC_LEX_NUMBER;
2809 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2810 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2824 len = i + !last_pt - bslashes * 2;
2825 if (len > BC_MAX_NUM)
2826 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2828 bc_vec_pop_all(&l->t.v);
2829 bc_vec_expand(&l->t.v, len + 1);
2830 bc_vec_push(&l->t.v, &start);
2832 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2836 // If we have hit a backslash, skip it. We don't have
2837 // to check for a newline because it's guaranteed.
2838 if (hits < bslashes && c == '\\') {
2844 bc_vec_push(&l->t.v, &c);
2847 bc_vec_pushZeroByte(&l->t.v);
2850 return BC_STATUS_SUCCESS;
2853 static BcStatus bc_lex_name(BcLex *l)
2856 const char *buf = l->buf + l->i - 1;
2859 l->t.t = BC_LEX_NAME;
2861 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2863 if (i > BC_MAX_STRING)
2864 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2865 bc_vec_string(&l->t.v, i, buf);
2867 // Increment the index. We minus 1 because it has already been incremented.
2870 return BC_STATUS_SUCCESS;
2873 static void bc_lex_init(BcLex *l, BcLexNext next)
2876 bc_char_vec_init(&l->t.v);
2879 static void bc_lex_free(BcLex *l)
2881 bc_vec_free(&l->t.v);
2884 static void bc_lex_file(BcLex *l)
2886 G.err_line = l->line = 1;
2890 static BcStatus bc_lex_next(BcLex *l)
2895 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2897 l->line += l->newline;
2898 G.err_line = l->line;
2899 l->t.t = BC_LEX_EOF;
2901 l->newline = (l->i == l->len);
2902 if (l->newline) return BC_STATUS_SUCCESS;
2904 // Loop until failure or we don't have whitespace. This
2905 // is so the parser doesn't get inundated with whitespace.
2908 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2913 static BcStatus bc_lex_text(BcLex *l, const char *text)
2917 l->len = strlen(text);
2918 l->t.t = l->t.last = BC_LEX_INVALID;
2919 return bc_lex_next(l);
2923 static BcStatus bc_lex_identifier(BcLex *l)
2927 const char *buf = l->buf + l->i - 1;
2929 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2930 const char *keyword8 = bc_lex_kws[i].name8;
2932 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2934 if (j == 8) goto match;
2936 if (keyword8[j] != '\0')
2939 // buf starts with keyword bc_lex_kws[i]
2940 l->t.t = BC_LEX_KEY_1st_keyword + i;
2941 if ((1 << i) & POSIX_KWORD_MASK) {
2942 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
2946 // We minus 1 because the index has already been incremented.
2948 return BC_STATUS_SUCCESS;
2955 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2960 static BcStatus bc_lex_string(BcLex *l)
2962 size_t len, nls = 0, i = l->i;
2965 l->t.t = BC_LEX_STR;
2967 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2971 return bc_error("string end could not be found");
2975 if (len > BC_MAX_STRING)
2976 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2977 bc_vec_string(&l->t.v, len, l->buf + l->i);
2981 G.err_line = l->line;
2983 return BC_STATUS_SUCCESS;
2986 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2988 if (l->buf[l->i] == '=') {
2996 static BcStatus bc_lex_comment(BcLex *l)
2999 const char *buf = l->buf;
3001 l->t.t = BC_LEX_WHITESPACE;
3014 return bc_error("comment end could not be found");
3022 G.err_line = l->line;
3024 return BC_STATUS_SUCCESS;
3027 static BcStatus bc_lex_token(BcLex *l)
3029 BcStatus s = BC_STATUS_SUCCESS;
3030 char c = l->buf[l->i++], c2;
3032 // This is the workhorse of the lexer.
3039 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3049 bc_lex_whitespace(l);
3055 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3057 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3058 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3067 s = bc_lex_string(l);
3073 s = bc_posix_error("POSIX does not allow '#' script comments");
3076 bc_lex_lineComment(l);
3083 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3092 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3096 l->t.t = BC_LEX_OP_BOOL_AND;
3099 l->t.t = BC_LEX_INVALID;
3100 s = bc_error_bad_character('&');
3109 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3115 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3124 l->t.t = BC_LEX_OP_INC;
3127 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3133 l->t.t = BC_LEX_COMMA;
3142 l->t.t = BC_LEX_OP_DEC;
3145 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3151 if (isdigit(l->buf[l->i]))
3152 s = bc_lex_number(l, c);
3154 l->t.t = BC_LEX_KEY_LAST;
3155 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3164 s = bc_lex_comment(l);
3166 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3187 s = bc_lex_number(l, c);
3193 l->t.t = BC_LEX_SCOLON;
3199 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3205 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3211 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3218 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3224 if (l->buf[l->i] == '\n') {
3225 l->t.t = BC_LEX_WHITESPACE;
3229 s = bc_error_bad_character(c);
3235 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3266 s = bc_lex_identifier(l);
3273 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3282 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3286 l->t.t = BC_LEX_OP_BOOL_OR;
3289 l->t.t = BC_LEX_INVALID;
3290 s = bc_error_bad_character(c);
3298 l->t.t = BC_LEX_INVALID;
3299 s = bc_error_bad_character(c);
3309 static BcStatus dc_lex_register(BcLex *l)
3311 BcStatus s = BC_STATUS_SUCCESS;
3313 if (isspace(l->buf[l->i - 1])) {
3314 bc_lex_whitespace(l);
3317 s = bc_error("extended register");
3322 bc_vec_pop_all(&l->t.v);
3323 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3324 bc_vec_pushZeroByte(&l->t.v);
3325 l->t.t = BC_LEX_NAME;
3331 static BcStatus dc_lex_string(BcLex *l)
3333 size_t depth = 1, nls = 0, i = l->i;
3336 l->t.t = BC_LEX_STR;
3337 bc_vec_pop_all(&l->t.v);
3339 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3341 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3342 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3345 if (depth) bc_vec_push(&l->t.v, &c);
3350 return bc_error("string end could not be found");
3353 bc_vec_pushZeroByte(&l->t.v);
3354 if (i - l->i > BC_MAX_STRING)
3355 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3359 G.err_line = l->line;
3361 return BC_STATUS_SUCCESS;
3364 static BcStatus dc_lex_token(BcLex *l)
3366 BcStatus s = BC_STATUS_SUCCESS;
3367 char c = l->buf[l->i++], c2;
3370 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3371 if (l->t.last == dc_lex_regs[i])
3372 return dc_lex_register(l);
3375 if (c >= '%' && c <= '~' &&
3376 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3381 // This is the workhorse of the lexer.
3386 l->t.t = BC_LEX_EOF;
3397 l->newline = (c == '\n');
3398 bc_lex_whitespace(l);
3407 l->t.t = BC_LEX_OP_REL_NE;
3409 l->t.t = BC_LEX_OP_REL_LE;
3411 l->t.t = BC_LEX_OP_REL_GE;
3413 return bc_error_bad_character(c);
3421 bc_lex_lineComment(l);
3427 if (isdigit(l->buf[l->i]))
3428 s = bc_lex_number(l, c);
3430 s = bc_error_bad_character(c);
3451 s = bc_lex_number(l, c);
3457 s = dc_lex_string(l);
3463 l->t.t = BC_LEX_INVALID;
3464 s = bc_error_bad_character(c);
3473 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3475 bc_program_addFunc(name, idx);
3476 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3479 static void bc_parse_pushName(BcParse *p, char *name)
3481 size_t i = 0, len = strlen(name);
3483 for (; i < len; ++i) bc_parse_push(p, name[i]);
3484 bc_parse_push(p, BC_PARSE_STREND);
3489 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3491 unsigned char amt, i, nums[sizeof(size_t)];
3493 for (amt = 0; idx; ++amt) {
3494 nums[amt] = (char) idx;
3495 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3498 bc_parse_push(p, amt);
3499 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3502 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3504 char *num = xstrdup(p->l.t.v.v);
3505 size_t idx = G.prog.consts.len;
3507 bc_vec_push(&G.prog.consts, &num);
3509 bc_parse_push(p, BC_INST_NUM);
3510 bc_parse_pushIndex(p, idx);
3513 (*prev) = BC_INST_NUM;
3516 static BcStatus bc_parse_text(BcParse *p, const char *text)
3520 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3522 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3523 p->l.t.t = BC_LEX_INVALID;
3526 if (!BC_PARSE_CAN_EXEC(p))
3527 return bc_error("file is not executable");
3530 return bc_lex_text(&p->l, text);
3533 // Called when bc/dc_parse_parse() detects a failure,
3534 // resets parsing structures.
3535 static void bc_parse_reset(BcParse *p)
3537 if (p->fidx != BC_PROG_MAIN) {
3538 p->func->nparams = 0;
3539 bc_vec_pop_all(&p->func->code);
3540 bc_vec_pop_all(&p->func->autos);
3541 bc_vec_pop_all(&p->func->labels);
3543 bc_parse_updateFunc(p, BC_PROG_MAIN);
3547 p->l.t.t = BC_LEX_EOF;
3548 p->auto_part = (p->nbraces = 0);
3550 bc_vec_npop(&p->flags, p->flags.len - 1);
3551 bc_vec_pop_all(&p->exits);
3552 bc_vec_pop_all(&p->conds);
3553 bc_vec_pop_all(&p->ops);
3558 static void bc_parse_free(BcParse *p)
3560 bc_vec_free(&p->flags);
3561 bc_vec_free(&p->exits);
3562 bc_vec_free(&p->conds);
3563 bc_vec_free(&p->ops);
3567 static void bc_parse_create(BcParse *p, size_t func,
3568 BcParseParse parse, BcLexNext next)
3570 memset(p, 0, sizeof(BcParse));
3572 bc_lex_init(&p->l, next);
3573 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3574 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3575 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3576 bc_vec_pushZeroByte(&p->flags);
3577 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3580 // p->auto_part = p->nbraces = 0; - already is
3581 bc_parse_updateFunc(p, func);
3585 static BcStatus bc_parse_else(BcParse *p);
3586 static BcStatus bc_parse_stmt(BcParse *p);
3588 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3589 size_t *nexprs, bool next)
3591 BcStatus s = BC_STATUS_SUCCESS;
3593 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3594 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3596 while (p->ops.len > start) {
3598 t = BC_PARSE_TOP_OP(p);
3599 if (t == BC_LEX_LPAREN) break;
3601 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3602 if (l >= r && (l != r || !left)) break;
3604 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3605 bc_vec_pop(&p->ops);
3606 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3609 bc_vec_push(&p->ops, &type);
3610 if (next) s = bc_lex_next(&p->l);
3615 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3619 if (p->ops.len <= ops_bgn)
3620 return bc_error_bad_expression();
3621 top = BC_PARSE_TOP_OP(p);
3623 while (top != BC_LEX_LPAREN) {
3625 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3627 bc_vec_pop(&p->ops);
3628 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3630 if (p->ops.len <= ops_bgn)
3631 return bc_error_bad_expression();
3632 top = BC_PARSE_TOP_OP(p);
3635 bc_vec_pop(&p->ops);
3637 return bc_lex_next(&p->l);
3640 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3646 s = bc_lex_next(&p->l);
3649 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3651 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3652 s = bc_parse_expr(p, flags, bc_parse_next_param);
3655 comma = p->l.t.t == BC_LEX_COMMA;
3657 s = bc_lex_next(&p->l);
3662 if (comma) return bc_error_bad_token();
3663 bc_parse_push(p, BC_INST_CALL);
3664 bc_parse_pushIndex(p, nparams);
3666 return BC_STATUS_SUCCESS;
3669 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3672 BcId entry, *entry_ptr;
3677 s = bc_parse_params(p, flags);
3680 if (p->l.t.t != BC_LEX_RPAREN) {
3681 s = bc_error_bad_token();
3685 idx = bc_map_index(&G.prog.fn_map, &entry);
3687 if (idx == BC_VEC_INVALID_IDX) {
3688 name = xstrdup(entry.name);
3689 bc_parse_addFunc(p, name, &idx);
3690 idx = bc_map_index(&G.prog.fn_map, &entry);
3696 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3697 bc_parse_pushIndex(p, entry_ptr->idx);
3699 return bc_lex_next(&p->l);
3706 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3711 name = xstrdup(p->l.t.v.v);
3712 s = bc_lex_next(&p->l);
3715 if (p->l.t.t == BC_LEX_LBRACKET) {
3717 s = bc_lex_next(&p->l);
3720 if (p->l.t.t == BC_LEX_RBRACKET) {
3722 if (!(flags & BC_PARSE_ARRAY)) {
3723 s = bc_error_bad_expression();
3727 *type = BC_INST_ARRAY;
3731 *type = BC_INST_ARRAY_ELEM;
3733 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3734 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3738 s = bc_lex_next(&p->l);
3740 bc_parse_push(p, *type);
3741 bc_parse_pushName(p, name);
3743 else if (p->l.t.t == BC_LEX_LPAREN) {
3745 if (flags & BC_PARSE_NOCALL) {
3746 s = bc_error_bad_token();
3750 *type = BC_INST_CALL;
3751 s = bc_parse_call(p, name, flags);
3754 *type = BC_INST_VAR;
3755 bc_parse_push(p, BC_INST_VAR);
3756 bc_parse_pushName(p, name);
3766 static BcStatus bc_parse_read(BcParse *p)
3770 s = bc_lex_next(&p->l);
3772 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3774 s = bc_lex_next(&p->l);
3776 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3778 bc_parse_push(p, BC_INST_READ);
3780 return bc_lex_next(&p->l);
3783 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3788 s = bc_lex_next(&p->l);
3790 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3792 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3794 s = bc_lex_next(&p->l);
3797 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3800 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3802 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3803 bc_parse_push(p, *prev);
3805 return bc_lex_next(&p->l);
3808 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3812 s = bc_lex_next(&p->l);
3815 if (p->l.t.t != BC_LEX_LPAREN) {
3816 *type = BC_INST_SCALE;
3817 bc_parse_push(p, BC_INST_SCALE);
3818 return BC_STATUS_SUCCESS;
3821 *type = BC_INST_SCALE_FUNC;
3822 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3824 s = bc_lex_next(&p->l);
3827 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3829 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3830 bc_parse_push(p, BC_INST_SCALE_FUNC);
3832 return bc_lex_next(&p->l);
3835 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3836 size_t *nexprs, uint8_t flags)
3841 BcInst etype = *prev;
3843 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3844 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3845 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3847 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3848 bc_parse_push(p, inst);
3849 s = bc_lex_next(&p->l);
3853 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3856 s = bc_lex_next(&p->l);
3860 // Because we parse the next part of the expression
3861 // right here, we need to increment this.
3862 *nexprs = *nexprs + 1;
3868 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3872 case BC_LEX_KEY_IBASE:
3873 case BC_LEX_KEY_LAST:
3874 case BC_LEX_KEY_OBASE:
3876 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3877 s = bc_lex_next(&p->l);
3881 case BC_LEX_KEY_SCALE:
3883 s = bc_lex_next(&p->l);
3885 if (p->l.t.t == BC_LEX_LPAREN)
3886 s = bc_error_bad_token();
3888 bc_parse_push(p, BC_INST_SCALE);
3894 s = bc_error_bad_token();
3899 if (!s) bc_parse_push(p, inst);
3905 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3906 bool rparen, size_t *nexprs)
3910 BcInst etype = *prev;
3912 s = bc_lex_next(&p->l);
3915 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3916 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3919 *prev = BC_PARSE_TOKEN_INST(type);
3921 // We can just push onto the op stack because this is the largest
3922 // precedence operator that gets pushed. Inc/dec does not.
3923 if (type != BC_LEX_OP_MINUS)
3924 bc_vec_push(&p->ops, &type);
3926 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3931 static BcStatus bc_parse_string(BcParse *p, char inst)
3933 char *str = xstrdup(p->l.t.v.v);
3935 bc_parse_push(p, BC_INST_STR);
3936 bc_parse_pushIndex(p, G.prog.strs.len);
3937 bc_vec_push(&G.prog.strs, &str);
3938 bc_parse_push(p, inst);
3940 return bc_lex_next(&p->l);
3943 static BcStatus bc_parse_print(BcParse *p)
3949 s = bc_lex_next(&p->l);
3954 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3955 return bc_error("bad print statement");
3957 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3959 if (type == BC_LEX_STR)
3960 s = bc_parse_string(p, BC_INST_PRINT_POP);
3962 s = bc_parse_expr(p, 0, bc_parse_next_print);
3964 bc_parse_push(p, BC_INST_PRINT_POP);
3969 comma = p->l.t.t == BC_LEX_COMMA;
3970 if (comma) s = bc_lex_next(&p->l);
3975 if (comma) return bc_error_bad_token();
3977 return bc_lex_next(&p->l);
3980 static BcStatus bc_parse_return(BcParse *p)
3986 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
3988 s = bc_lex_next(&p->l);
3992 paren = t == BC_LEX_LPAREN;
3994 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3995 bc_parse_push(p, BC_INST_RET0);
3998 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3999 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4002 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4003 bc_parse_push(p, BC_INST_RET0);
4004 s = bc_lex_next(&p->l);
4008 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4009 s = bc_posix_error("POSIX requires parentheses around return expressions");
4013 bc_parse_push(p, BC_INST_RET);
4019 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4021 BcStatus s = BC_STATUS_SUCCESS;
4023 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4024 return bc_error_bad_token();
4028 if (p->l.t.t == BC_LEX_RBRACE) {
4029 if (!p->nbraces) return bc_error_bad_token();
4031 s = bc_lex_next(&p->l);
4035 return bc_error_bad_token();
4038 if (BC_PARSE_IF(p)) {
4042 while (p->l.t.t == BC_LEX_NLINE) {
4043 s = bc_lex_next(&p->l);
4047 bc_vec_pop(&p->flags);
4049 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4050 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4052 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4054 else if (BC_PARSE_ELSE(p)) {
4059 bc_vec_pop(&p->flags);
4061 ip = bc_vec_top(&p->exits);
4062 label = bc_vec_item(&p->func->labels, ip->idx);
4063 *label = p->func->code.len;
4065 bc_vec_pop(&p->exits);
4067 else if (BC_PARSE_FUNC_INNER(p)) {
4068 bc_parse_push(p, BC_INST_RET0);
4069 bc_parse_updateFunc(p, BC_PROG_MAIN);
4070 bc_vec_pop(&p->flags);
4074 BcInstPtr *ip = bc_vec_top(&p->exits);
4075 size_t *label = bc_vec_top(&p->conds);
4077 bc_parse_push(p, BC_INST_JUMP);
4078 bc_parse_pushIndex(p, *label);
4080 label = bc_vec_item(&p->func->labels, ip->idx);
4081 *label = p->func->code.len;
4083 bc_vec_pop(&p->flags);
4084 bc_vec_pop(&p->exits);
4085 bc_vec_pop(&p->conds);
4091 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4093 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4094 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4095 flags |= BC_PARSE_FLAG_BODY;
4096 bc_vec_push(&p->flags, &flags);
4099 static void bc_parse_noElse(BcParse *p)
4103 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4105 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4107 ip = bc_vec_top(&p->exits);
4108 label = bc_vec_item(&p->func->labels, ip->idx);
4109 *label = p->func->code.len;
4111 bc_vec_pop(&p->exits);
4114 static BcStatus bc_parse_if(BcParse *p)
4119 s = bc_lex_next(&p->l);
4121 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4123 s = bc_lex_next(&p->l);
4125 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4127 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4129 s = bc_lex_next(&p->l);
4131 bc_parse_push(p, BC_INST_JUMP_ZERO);
4133 ip.idx = p->func->labels.len;
4134 ip.func = ip.len = 0;
4136 bc_parse_pushIndex(p, ip.idx);
4137 bc_vec_push(&p->exits, &ip);
4138 bc_vec_push(&p->func->labels, &ip.idx);
4139 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4141 return BC_STATUS_SUCCESS;
4144 static BcStatus bc_parse_else(BcParse *p)
4148 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4150 ip.idx = p->func->labels.len;
4151 ip.func = ip.len = 0;
4153 bc_parse_push(p, BC_INST_JUMP);
4154 bc_parse_pushIndex(p, ip.idx);
4158 bc_vec_push(&p->exits, &ip);
4159 bc_vec_push(&p->func->labels, &ip.idx);
4160 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4162 return bc_lex_next(&p->l);
4165 static BcStatus bc_parse_while(BcParse *p)
4170 s = bc_lex_next(&p->l);
4172 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4173 s = bc_lex_next(&p->l);
4176 ip.idx = p->func->labels.len;
4178 bc_vec_push(&p->func->labels, &p->func->code.len);
4179 bc_vec_push(&p->conds, &ip.idx);
4181 ip.idx = p->func->labels.len;
4185 bc_vec_push(&p->exits, &ip);
4186 bc_vec_push(&p->func->labels, &ip.idx);
4188 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4190 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4191 s = bc_lex_next(&p->l);
4194 bc_parse_push(p, BC_INST_JUMP_ZERO);
4195 bc_parse_pushIndex(p, ip.idx);
4196 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4198 return BC_STATUS_SUCCESS;
4201 static BcStatus bc_parse_for(BcParse *p)
4205 size_t cond_idx, exit_idx, body_idx, update_idx;
4207 s = bc_lex_next(&p->l);
4209 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4210 s = bc_lex_next(&p->l);
4213 if (p->l.t.t != BC_LEX_SCOLON)
4214 s = bc_parse_expr(p, 0, bc_parse_next_for);
4216 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4219 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4220 s = bc_lex_next(&p->l);
4223 cond_idx = p->func->labels.len;
4224 update_idx = cond_idx + 1;
4225 body_idx = update_idx + 1;
4226 exit_idx = body_idx + 1;
4228 bc_vec_push(&p->func->labels, &p->func->code.len);
4230 if (p->l.t.t != BC_LEX_SCOLON)
4231 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4233 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4236 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4238 s = bc_lex_next(&p->l);
4241 bc_parse_push(p, BC_INST_JUMP_ZERO);
4242 bc_parse_pushIndex(p, exit_idx);
4243 bc_parse_push(p, BC_INST_JUMP);
4244 bc_parse_pushIndex(p, body_idx);
4246 ip.idx = p->func->labels.len;
4248 bc_vec_push(&p->conds, &update_idx);
4249 bc_vec_push(&p->func->labels, &p->func->code.len);
4251 if (p->l.t.t != BC_LEX_RPAREN)
4252 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4254 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4258 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4259 bc_parse_push(p, BC_INST_JUMP);
4260 bc_parse_pushIndex(p, cond_idx);
4261 bc_vec_push(&p->func->labels, &p->func->code.len);
4267 bc_vec_push(&p->exits, &ip);
4268 bc_vec_push(&p->func->labels, &ip.idx);
4270 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4272 return BC_STATUS_SUCCESS;
4275 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4281 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4283 if (type == BC_LEX_KEY_BREAK) {
4285 if (p->exits.len == 0) return bc_error_bad_token();
4287 i = p->exits.len - 1;
4288 ip = bc_vec_item(&p->exits, i);
4290 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4291 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4296 i = *((size_t *) bc_vec_top(&p->conds));
4298 bc_parse_push(p, BC_INST_JUMP);
4299 bc_parse_pushIndex(p, i);
4301 s = bc_lex_next(&p->l);
4304 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4305 return bc_error_bad_token();
4307 return bc_lex_next(&p->l);
4310 static BcStatus bc_parse_func(BcParse *p)
4313 bool var, comma = false;
4317 s = bc_lex_next(&p->l);
4319 if (p->l.t.t != BC_LEX_NAME)
4320 return bc_error("bad function definition");
4322 name = xstrdup(p->l.t.v.v);
4323 bc_parse_addFunc(p, name, &p->fidx);
4325 s = bc_lex_next(&p->l);
4327 if (p->l.t.t != BC_LEX_LPAREN)
4328 return bc_error("bad function definition");
4329 s = bc_lex_next(&p->l);
4332 while (p->l.t.t != BC_LEX_RPAREN) {
4334 if (p->l.t.t != BC_LEX_NAME)
4335 return bc_error("bad function definition");
4339 name = xstrdup(p->l.t.v.v);
4340 s = bc_lex_next(&p->l);
4343 var = p->l.t.t != BC_LEX_LBRACKET;
4347 s = bc_lex_next(&p->l);
4350 if (p->l.t.t != BC_LEX_RBRACKET) {
4351 s = bc_error("bad function definition");
4355 s = bc_lex_next(&p->l);
4359 comma = p->l.t.t == BC_LEX_COMMA;
4361 s = bc_lex_next(&p->l);
4365 s = bc_func_insert(p->func, name, var);
4369 if (comma) return bc_error("bad function definition");
4371 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4372 bc_parse_startBody(p, flags);
4374 s = bc_lex_next(&p->l);
4377 if (p->l.t.t != BC_LEX_LBRACE)
4378 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4387 static BcStatus bc_parse_auto(BcParse *p)
4390 bool comma, var, one;
4393 if (!p->auto_part) return bc_error_bad_token();
4394 s = bc_lex_next(&p->l);
4397 p->auto_part = comma = false;
4398 one = p->l.t.t == BC_LEX_NAME;
4400 while (p->l.t.t == BC_LEX_NAME) {
4402 name = xstrdup(p->l.t.v.v);
4403 s = bc_lex_next(&p->l);
4406 var = p->l.t.t != BC_LEX_LBRACKET;
4409 s = bc_lex_next(&p->l);
4412 if (p->l.t.t != BC_LEX_RBRACKET) {
4413 s = bc_error("bad function definition");
4417 s = bc_lex_next(&p->l);
4421 comma = p->l.t.t == BC_LEX_COMMA;
4423 s = bc_lex_next(&p->l);
4427 s = bc_func_insert(p->func, name, var);
4431 if (comma) return bc_error("bad function definition");
4432 if (!one) return bc_error("no auto variable found");
4434 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4435 return bc_error_bad_token();
4437 return bc_lex_next(&p->l);
4444 static BcStatus bc_parse_body(BcParse *p, bool brace)
4446 BcStatus s = BC_STATUS_SUCCESS;
4447 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4449 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4451 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4453 if (!brace) return bc_error_bad_token();
4454 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4456 if (!p->auto_part) {
4457 s = bc_parse_auto(p);
4461 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4464 s = bc_parse_stmt(p);
4465 if (!s && !brace) s = bc_parse_endBody(p, false);
4471 static BcStatus bc_parse_stmt(BcParse *p)
4473 BcStatus s = BC_STATUS_SUCCESS;
4479 return bc_lex_next(&p->l);
4482 case BC_LEX_KEY_ELSE:
4484 p->auto_part = false;
4490 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4493 s = bc_lex_next(&p->l);
4496 return bc_parse_body(p, true);
4499 case BC_LEX_KEY_AUTO:
4501 return bc_parse_auto(p);
4506 p->auto_part = false;
4508 if (BC_PARSE_IF_END(p)) {
4510 return BC_STATUS_SUCCESS;
4512 else if (BC_PARSE_BODY(p))
4513 return bc_parse_body(p, false);
4523 case BC_LEX_OP_MINUS:
4524 case BC_LEX_OP_BOOL_NOT:
4528 case BC_LEX_KEY_IBASE:
4529 case BC_LEX_KEY_LAST:
4530 case BC_LEX_KEY_LENGTH:
4531 case BC_LEX_KEY_OBASE:
4532 case BC_LEX_KEY_READ:
4533 case BC_LEX_KEY_SCALE:
4534 case BC_LEX_KEY_SQRT:
4536 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4540 case BC_LEX_KEY_ELSE:
4542 s = bc_parse_else(p);
4548 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4554 s = bc_parse_endBody(p, true);
4560 s = bc_parse_string(p, BC_INST_PRINT_STR);
4564 case BC_LEX_KEY_BREAK:
4565 case BC_LEX_KEY_CONTINUE:
4567 s = bc_parse_loopExit(p, p->l.t.t);
4571 case BC_LEX_KEY_FOR:
4573 s = bc_parse_for(p);
4577 case BC_LEX_KEY_HALT:
4579 bc_parse_push(p, BC_INST_HALT);
4580 s = bc_lex_next(&p->l);
4590 case BC_LEX_KEY_LIMITS:
4592 // "limits" is a compile-time command,
4593 // the output is produced at _parse time_.
4594 s = bc_lex_next(&p->l);
4596 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4597 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4598 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4599 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4600 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4601 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4602 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4603 printf("Number of vars = %lu\n", BC_MAX_VARS);
4607 case BC_LEX_KEY_PRINT:
4609 s = bc_parse_print(p);
4613 case BC_LEX_KEY_QUIT:
4615 // "quit" is a compile-time command. For example,
4616 // "if (0 == 1) quit" terminates when parsing the statement,
4617 // not when it is executed
4621 case BC_LEX_KEY_RETURN:
4623 s = bc_parse_return(p);
4627 case BC_LEX_KEY_WHILE:
4629 s = bc_parse_while(p);
4635 s = bc_error_bad_token();
4643 static BcStatus bc_parse_parse(BcParse *p)
4647 if (p->l.t.t == BC_LEX_EOF)
4648 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4649 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4650 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4651 s = bc_parse_func(p);
4654 s = bc_parse_stmt(p);
4656 if (s || G_interrupt) {
4658 s = BC_STATUS_FAILURE;
4664 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4666 BcStatus s = BC_STATUS_SUCCESS;
4667 BcInst prev = BC_INST_PRINT;
4668 BcLexType top, t = p->l.t.t;
4669 size_t nexprs = 0, ops_bgn = p->ops.len;
4670 uint32_t i, nparens, nrelops;
4671 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4673 paren_first = p->l.t.t == BC_LEX_LPAREN;
4674 nparens = nrelops = 0;
4675 paren_expr = rprn = done = get_token = assign = false;
4678 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4684 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4685 rprn = get_token = bin_last = false;
4689 case BC_LEX_OP_MINUS:
4691 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4692 rprn = get_token = false;
4693 bin_last = prev == BC_INST_MINUS;
4697 case BC_LEX_OP_ASSIGN_POWER:
4698 case BC_LEX_OP_ASSIGN_MULTIPLY:
4699 case BC_LEX_OP_ASSIGN_DIVIDE:
4700 case BC_LEX_OP_ASSIGN_MODULUS:
4701 case BC_LEX_OP_ASSIGN_PLUS:
4702 case BC_LEX_OP_ASSIGN_MINUS:
4703 case BC_LEX_OP_ASSIGN:
4705 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4706 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4707 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4709 s = bc_error("bad assignment:"
4710 " left side must be scale,"
4711 " ibase, obase, last, var,"
4718 case BC_LEX_OP_POWER:
4719 case BC_LEX_OP_MULTIPLY:
4720 case BC_LEX_OP_DIVIDE:
4721 case BC_LEX_OP_MODULUS:
4722 case BC_LEX_OP_PLUS:
4723 case BC_LEX_OP_REL_EQ:
4724 case BC_LEX_OP_REL_LE:
4725 case BC_LEX_OP_REL_GE:
4726 case BC_LEX_OP_REL_NE:
4727 case BC_LEX_OP_REL_LT:
4728 case BC_LEX_OP_REL_GT:
4729 case BC_LEX_OP_BOOL_NOT:
4730 case BC_LEX_OP_BOOL_OR:
4731 case BC_LEX_OP_BOOL_AND:
4733 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4734 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4736 return bc_error_bad_expression();
4739 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4740 prev = BC_PARSE_TOKEN_INST(t);
4741 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4742 rprn = get_token = false;
4743 bin_last = t != BC_LEX_OP_BOOL_NOT;
4750 if (BC_PARSE_LEAF(prev, rprn))
4751 return bc_error_bad_expression();
4753 paren_expr = rprn = bin_last = false;
4755 bc_vec_push(&p->ops, &t);
4762 if (bin_last || prev == BC_INST_BOOL_NOT)
4763 return bc_error_bad_expression();
4766 s = BC_STATUS_SUCCESS;
4771 else if (!paren_expr)
4772 return BC_STATUS_PARSE_EMPTY_EXP;
4775 paren_expr = rprn = true;
4776 get_token = bin_last = false;
4778 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4785 if (BC_PARSE_LEAF(prev, rprn))
4786 return bc_error_bad_expression();
4788 rprn = get_token = bin_last = false;
4789 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4797 if (BC_PARSE_LEAF(prev, rprn))
4798 return bc_error_bad_expression();
4799 bc_parse_number(p, &prev, &nexprs);
4800 paren_expr = get_token = true;
4801 rprn = bin_last = false;
4806 case BC_LEX_KEY_IBASE:
4807 case BC_LEX_KEY_LAST:
4808 case BC_LEX_KEY_OBASE:
4810 if (BC_PARSE_LEAF(prev, rprn))
4811 return bc_error_bad_expression();
4812 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4813 bc_parse_push(p, (char) prev);
4815 paren_expr = get_token = true;
4816 rprn = bin_last = false;
4822 case BC_LEX_KEY_LENGTH:
4823 case BC_LEX_KEY_SQRT:
4825 if (BC_PARSE_LEAF(prev, rprn))
4826 return bc_error_bad_expression();
4827 s = bc_parse_builtin(p, t, flags, &prev);
4829 rprn = get_token = bin_last = false;
4835 case BC_LEX_KEY_READ:
4837 if (BC_PARSE_LEAF(prev, rprn))
4838 return bc_error_bad_expression();
4839 else if (flags & BC_PARSE_NOREAD)
4840 s = bc_error_nested_read_call();
4842 s = bc_parse_read(p);
4845 rprn = get_token = bin_last = false;
4847 prev = BC_INST_READ;
4852 case BC_LEX_KEY_SCALE:
4854 if (BC_PARSE_LEAF(prev, rprn))
4855 return bc_error_bad_expression();
4856 s = bc_parse_scale(p, &prev, flags);
4858 rprn = get_token = bin_last = false;
4860 prev = BC_INST_SCALE;
4867 s = bc_error_bad_token();
4872 if (!s && get_token) s = bc_lex_next(&p->l);
4876 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4878 while (p->ops.len > ops_bgn) {
4880 top = BC_PARSE_TOP_OP(p);
4881 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4883 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4884 return bc_error_bad_expression();
4886 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4888 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4889 bc_vec_pop(&p->ops);
4892 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4893 return bc_error_bad_expression();
4895 for (i = 0; i < next.len; ++i)
4896 if (t == next.tokens[i])
4898 return bc_error_bad_expression();
4901 if (!(flags & BC_PARSE_REL) && nrelops) {
4902 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4905 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4906 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4910 if (flags & BC_PARSE_PRINT) {
4911 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4912 bc_parse_push(p, BC_INST_POP);
4918 static void bc_parse_init(BcParse *p, size_t func)
4920 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4923 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4925 return bc_parse_expr(p, flags, bc_parse_next_read);
4930 static BcStatus dc_parse_register(BcParse *p)
4935 s = bc_lex_next(&p->l);
4937 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4939 name = xstrdup(p->l.t.v.v);
4940 bc_parse_pushName(p, name);
4945 static BcStatus dc_parse_string(BcParse *p)
4947 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4948 size_t idx, len = G.prog.strs.len;
4950 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4953 str = xstrdup(p->l.t.v.v);
4954 bc_parse_push(p, BC_INST_STR);
4955 bc_parse_pushIndex(p, len);
4956 bc_vec_push(&G.prog.strs, &str);
4957 bc_parse_addFunc(p, name, &idx);
4959 return bc_lex_next(&p->l);
4962 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4966 bc_parse_push(p, inst);
4968 s = dc_parse_register(p);
4973 bc_parse_push(p, BC_INST_SWAP);
4974 bc_parse_push(p, BC_INST_ASSIGN);
4975 bc_parse_push(p, BC_INST_POP);
4978 return bc_lex_next(&p->l);
4981 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4985 bc_parse_push(p, inst);
4986 bc_parse_push(p, BC_INST_EXEC_COND);
4988 s = dc_parse_register(p);
4991 s = bc_lex_next(&p->l);
4994 if (p->l.t.t == BC_LEX_ELSE) {
4995 s = dc_parse_register(p);
4997 s = bc_lex_next(&p->l);
5000 bc_parse_push(p, BC_PARSE_STREND);
5005 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5007 BcStatus s = BC_STATUS_SUCCESS;
5010 bool assign, get_token = false;
5014 case BC_LEX_OP_REL_EQ:
5015 case BC_LEX_OP_REL_LE:
5016 case BC_LEX_OP_REL_GE:
5017 case BC_LEX_OP_REL_NE:
5018 case BC_LEX_OP_REL_LT:
5019 case BC_LEX_OP_REL_GT:
5021 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5028 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5034 s = dc_parse_string(p);
5041 if (t == BC_LEX_NEG) {
5042 s = bc_lex_next(&p->l);
5044 if (p->l.t.t != BC_LEX_NUMBER)
5045 return bc_error_bad_token();
5048 bc_parse_number(p, &prev, &p->nbraces);
5050 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5056 case BC_LEX_KEY_READ:
5058 if (flags & BC_PARSE_NOREAD)
5059 s = bc_error_nested_read_call();
5061 bc_parse_push(p, BC_INST_READ);
5066 case BC_LEX_OP_ASSIGN:
5067 case BC_LEX_STORE_PUSH:
5069 assign = t == BC_LEX_OP_ASSIGN;
5070 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5071 s = dc_parse_mem(p, inst, true, assign);
5076 case BC_LEX_LOAD_POP:
5078 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5079 s = dc_parse_mem(p, inst, true, false);
5083 case BC_LEX_STORE_IBASE:
5084 case BC_LEX_STORE_SCALE:
5085 case BC_LEX_STORE_OBASE:
5087 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5088 s = dc_parse_mem(p, inst, false, true);
5094 s = bc_error_bad_token();
5100 if (!s && get_token) s = bc_lex_next(&p->l);
5105 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5107 BcStatus s = BC_STATUS_SUCCESS;
5111 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5113 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5115 inst = dc_parse_insts[t];
5117 if (inst != BC_INST_INVALID) {
5118 bc_parse_push(p, inst);
5119 s = bc_lex_next(&p->l);
5122 s = dc_parse_token(p, t, flags);
5125 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5126 bc_parse_push(p, BC_INST_POP_EXEC);
5131 static BcStatus dc_parse_parse(BcParse *p)
5135 if (p->l.t.t == BC_LEX_EOF)
5136 s = bc_error("end of file");
5138 s = dc_parse_expr(p, 0);
5140 if (s || G_interrupt) {
5142 s = BC_STATUS_FAILURE;
5148 static void dc_parse_init(BcParse *p, size_t func)
5150 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5154 static void common_parse_init(BcParse *p, size_t func)
5157 bc_parse_init(p, func);
5159 dc_parse_init(p, func);
5163 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5166 return bc_parse_expression(p, flags);
5168 return dc_parse_expr(p, flags);
5172 static BcVec* bc_program_search(char *id, bool var)
5180 v = var ? &G.prog.vars : &G.prog.arrs;
5181 map = var ? &G.prog.var_map : &G.prog.arr_map;
5185 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5188 bc_array_init(&data.v, var);
5189 bc_vec_push(v, &data.v);
5192 ptr = bc_vec_item(map, i);
5193 if (new) ptr->name = xstrdup(e.name);
5194 return bc_vec_item(v, ptr->idx);
5197 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5199 BcStatus s = BC_STATUS_SUCCESS;
5204 case BC_RESULT_TEMP:
5205 case BC_RESULT_IBASE:
5206 case BC_RESULT_SCALE:
5207 case BC_RESULT_OBASE:
5213 case BC_RESULT_CONSTANT:
5215 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5216 size_t base_t, len = strlen(*str);
5219 bc_num_init(&r->d.n, len);
5221 hex = hex && len == 1;
5222 base = hex ? &G.prog.hexb : &G.prog.ib;
5223 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5224 s = bc_num_parse(&r->d.n, *str, base, base_t);
5227 bc_num_free(&r->d.n);
5232 r->t = BC_RESULT_TEMP;
5238 case BC_RESULT_ARRAY:
5239 case BC_RESULT_ARRAY_ELEM:
5243 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5245 if (r->t == BC_RESULT_ARRAY_ELEM) {
5247 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5248 *num = bc_vec_item(v, r->d.id.idx);
5251 *num = bc_vec_top(v);
5256 case BC_RESULT_LAST:
5258 *num = &G.prog.last;
5272 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5273 BcResult **r, BcNum **rn, bool assign)
5277 BcResultType lt, rt;
5279 if (!BC_PROG_STACK(&G.prog.results, 2))
5280 return bc_error_stack_has_too_few_elements();
5282 *r = bc_vec_item_rev(&G.prog.results, 0);
5283 *l = bc_vec_item_rev(&G.prog.results, 1);
5287 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5289 s = bc_program_num(*l, ln, false);
5291 s = bc_program_num(*r, rn, hex);
5294 // We run this again under these conditions in case any vector has been
5295 // reallocated out from under the BcNums or arrays we had.
5296 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5297 s = bc_program_num(*l, ln, false);
5301 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5302 return bc_error_variable_is_wrong_type();
5303 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5304 return bc_error_variable_is_wrong_type();
5309 static void bc_program_binOpRetire(BcResult *r)
5311 r->t = BC_RESULT_TEMP;
5312 bc_vec_pop(&G.prog.results);
5313 bc_vec_pop(&G.prog.results);
5314 bc_vec_push(&G.prog.results, r);
5317 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5321 if (!BC_PROG_STACK(&G.prog.results, 1))
5322 return bc_error_stack_has_too_few_elements();
5323 *r = bc_vec_top(&G.prog.results);
5325 s = bc_program_num(*r, n, false);
5328 if (!BC_PROG_NUM((*r), (*n)))
5329 return bc_error_variable_is_wrong_type();
5334 static void bc_program_retire(BcResult *r, BcResultType t)
5337 bc_vec_pop(&G.prog.results);
5338 bc_vec_push(&G.prog.results, r);
5341 static BcStatus bc_program_op(char inst)
5344 BcResult *opd1, *opd2, res;
5345 BcNum *n1, *n2 = NULL;
5347 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5349 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5351 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5353 bc_program_binOpRetire(&res);
5358 bc_num_free(&res.d.n);
5362 static BcStatus bc_program_read(void)
5364 const char *sv_file;
5370 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5372 for (i = 0; i < G.prog.stack.len; ++i) {
5373 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5374 if (ip_ptr->func == BC_PROG_READ)
5375 return bc_error_nested_read_call();
5378 bc_vec_pop_all(&f->code);
5379 bc_char_vec_init(&buf);
5381 sv_file = G.prog.file;
5384 s = bc_read_line(&buf, "read> ");
5387 common_parse_init(&parse, BC_PROG_READ);
5388 bc_lex_file(&parse.l);
5390 s = bc_parse_text(&parse, buf.v);
5391 if (s) goto exec_err;
5392 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5393 if (s) goto exec_err;
5395 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5396 s = bc_error("bad read() expression");
5400 ip.func = BC_PROG_READ;
5402 ip.len = G.prog.results.len;
5404 // Update this pointer, just in case.
5405 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5407 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5408 bc_vec_push(&G.prog.stack, &ip);
5411 G.prog.file = sv_file;
5412 bc_parse_free(&parse);
5418 static size_t bc_program_index(char *code, size_t *bgn)
5420 char amt = code[(*bgn)++], i = 0;
5423 for (; i < amt; ++i, ++(*bgn))
5424 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5429 static char *bc_program_name(char *code, size_t *bgn)
5432 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5434 s = xmalloc(ptr - str + 1);
5437 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5445 static void bc_program_printString(const char *str, size_t *nchars)
5447 size_t i, len = strlen(str);
5456 for (i = 0; i < len; ++i, ++(*nchars)) {
5460 if (c != '\\' || i == len - 1)
5520 // Just print the backslash and following character.
5531 static BcStatus bc_program_print(char inst, size_t idx)
5533 BcStatus s = BC_STATUS_SUCCESS;
5538 bool pop = inst != BC_INST_PRINT;
5540 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5541 return bc_error_stack_has_too_few_elements();
5543 r = bc_vec_item_rev(&G.prog.results, idx);
5544 s = bc_program_num(r, &num, false);
5547 if (BC_PROG_NUM(r, num)) {
5548 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5549 if (!s) bc_num_copy(&G.prog.last, num);
5553 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5554 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5556 if (inst == BC_INST_PRINT_STR) {
5557 for (i = 0, len = strlen(str); i < len; ++i) {
5560 if (c == '\n') G.prog.nchars = SIZE_MAX;
5565 bc_program_printString(str, &G.prog.nchars);
5566 if (inst == BC_INST_PRINT) bb_putchar('\n');
5570 if (!s && pop) bc_vec_pop(&G.prog.results);
5575 static BcStatus bc_program_negate(void)
5581 s = bc_program_prep(&ptr, &num);
5584 bc_num_init(&res.d.n, num->len);
5585 bc_num_copy(&res.d.n, num);
5586 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5588 bc_program_retire(&res, BC_RESULT_TEMP);
5593 static BcStatus bc_program_logical(char inst)
5596 BcResult *opd1, *opd2, res;
5601 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5603 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5605 if (inst == BC_INST_BOOL_AND)
5606 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5607 else if (inst == BC_INST_BOOL_OR)
5608 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5611 cmp = bc_num_cmp(n1, n2);
5615 case BC_INST_REL_EQ:
5621 case BC_INST_REL_LE:
5627 case BC_INST_REL_GE:
5633 case BC_INST_REL_NE:
5639 case BC_INST_REL_LT:
5645 case BC_INST_REL_GT:
5653 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5655 bc_program_binOpRetire(&res);
5661 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5667 memset(&n2, 0, sizeof(BcNum));
5668 n2.rdx = res.d.id.idx = r->d.id.idx;
5669 res.t = BC_RESULT_STR;
5672 if (!BC_PROG_STACK(&G.prog.results, 2))
5673 return bc_error_stack_has_too_few_elements();
5675 bc_vec_pop(&G.prog.results);
5678 bc_vec_pop(&G.prog.results);
5680 bc_vec_push(&G.prog.results, &res);
5681 bc_vec_push(v, &n2);
5683 return BC_STATUS_SUCCESS;
5687 static BcStatus bc_program_copyToVar(char *name, bool var)
5694 if (!BC_PROG_STACK(&G.prog.results, 1))
5695 return bc_error_stack_has_too_few_elements();
5697 ptr = bc_vec_top(&G.prog.results);
5698 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5699 return bc_error_variable_is_wrong_type();
5700 v = bc_program_search(name, var);
5703 if (ptr->t == BC_RESULT_STR && !var)
5704 return bc_error_variable_is_wrong_type();
5705 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5708 s = bc_program_num(ptr, &n, false);
5711 // Do this once more to make sure that pointers were not invalidated.
5712 v = bc_program_search(name, var);
5715 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5716 bc_num_copy(&r.d.n, n);
5719 bc_array_init(&r.d.v, true);
5720 bc_array_copy(&r.d.v, (BcVec *) n);
5723 bc_vec_push(v, &r.d);
5724 bc_vec_pop(&G.prog.results);
5729 static BcStatus bc_program_assign(char inst)
5732 BcResult *left, *right, res;
5733 BcNum *l = NULL, *r = NULL;
5734 unsigned long val, max;
5735 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5737 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5740 ib = left->t == BC_RESULT_IBASE;
5741 sc = left->t == BC_RESULT_SCALE;
5745 if (right->t == BC_RESULT_STR) {
5749 if (left->t != BC_RESULT_VAR)
5750 return bc_error_variable_is_wrong_type();
5751 v = bc_program_search(left->d.id.name, true);
5753 return bc_program_assignStr(right, v, false);
5757 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5758 return bc_error("bad assignment:"
5759 " left side must be scale,"
5760 " ibase, obase, last, var,"
5765 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5766 return bc_error("divide by zero");
5771 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5778 if (ib || sc || left->t == BC_RESULT_OBASE) {
5779 static const char *const msg[] = {
5780 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5781 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5782 "?1", //BC_RESULT_LAST
5783 "?2", //BC_RESULT_CONSTANT
5784 "?3", //BC_RESULT_ONE
5785 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5789 s = bc_num_ulong(l, &val);
5792 s = left->t - BC_RESULT_IBASE;
5795 ptr = &G.prog.scale;
5798 if (val < BC_NUM_MIN_BASE)
5799 return bc_error(msg[s]);
5800 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5801 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5805 return bc_error(msg[s]);
5807 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5809 *ptr = (size_t) val;
5810 s = BC_STATUS_SUCCESS;
5813 bc_num_init(&res.d.n, l->len);
5814 bc_num_copy(&res.d.n, l);
5815 bc_program_binOpRetire(&res);
5821 #define bc_program_pushVar(code, bgn, pop, copy) \
5822 bc_program_pushVar(code, bgn)
5823 // for bc, 'pop' and 'copy' are always false
5825 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5826 bool pop, bool copy)
5828 BcStatus s = BC_STATUS_SUCCESS;
5830 char *name = bc_program_name(code, bgn);
5832 r.t = BC_RESULT_VAR;
5837 BcVec *v = bc_program_search(name, true);
5838 BcNum *num = bc_vec_top(v);
5842 if (!BC_PROG_STACK(v, 2 - copy)) {
5844 return bc_error_stack_has_too_few_elements();
5850 if (!BC_PROG_STR(num)) {
5852 r.t = BC_RESULT_TEMP;
5854 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5855 bc_num_copy(&r.d.n, num);
5858 r.t = BC_RESULT_STR;
5859 r.d.id.idx = num->rdx;
5862 if (!copy) bc_vec_pop(v);
5867 bc_vec_push(&G.prog.results, &r);
5872 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5875 BcStatus s = BC_STATUS_SUCCESS;
5879 r.d.id.name = bc_program_name(code, bgn);
5881 if (inst == BC_INST_ARRAY) {
5882 r.t = BC_RESULT_ARRAY;
5883 bc_vec_push(&G.prog.results, &r);
5890 s = bc_program_prep(&operand, &num);
5892 s = bc_num_ulong(num, &temp);
5895 if (temp > BC_MAX_DIM) {
5896 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5900 r.d.id.idx = (size_t) temp;
5901 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5905 if (s) free(r.d.id.name);
5910 static BcStatus bc_program_incdec(char inst)
5913 BcResult *ptr, res, copy;
5917 s = bc_program_prep(&ptr, &num);
5920 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5921 copy.t = BC_RESULT_TEMP;
5922 bc_num_init(©.d.n, num->len);
5923 bc_num_copy(©.d.n, num);
5926 res.t = BC_RESULT_ONE;
5927 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5928 BC_INST_ASSIGN_PLUS :
5929 BC_INST_ASSIGN_MINUS;
5931 bc_vec_push(&G.prog.results, &res);
5932 bc_program_assign(inst);
5934 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5935 bc_vec_pop(&G.prog.results);
5936 bc_vec_push(&G.prog.results, ©);
5942 static BcStatus bc_program_call(char *code, size_t *idx)
5944 BcStatus s = BC_STATUS_SUCCESS;
5946 size_t i, nparams = bc_program_index(code, idx);
5953 ip.func = bc_program_index(code, idx);
5954 func = bc_vec_item(&G.prog.fns, ip.func);
5956 if (func->code.len == 0) {
5957 return bc_error("undefined function");
5959 if (nparams != func->nparams) {
5960 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5962 ip.len = G.prog.results.len - nparams;
5964 for (i = 0; i < nparams; ++i) {
5966 a = bc_vec_item(&func->autos, nparams - 1 - i);
5967 arg = bc_vec_top(&G.prog.results);
5969 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5970 return bc_error_variable_is_wrong_type();
5972 s = bc_program_copyToVar(a->name, a->idx);
5976 for (; i < func->autos.len; ++i) {
5979 a = bc_vec_item(&func->autos, i);
5980 v = bc_program_search(a->name, a->idx);
5983 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5984 bc_vec_push(v, ¶m.n);
5987 bc_array_init(¶m.v, true);
5988 bc_vec_push(v, ¶m.v);
5992 bc_vec_push(&G.prog.stack, &ip);
5994 return BC_STATUS_SUCCESS;
5997 static BcStatus bc_program_return(char inst)
6003 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6005 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6006 return bc_error_stack_has_too_few_elements();
6008 f = bc_vec_item(&G.prog.fns, ip->func);
6009 res.t = BC_RESULT_TEMP;
6011 if (inst == BC_INST_RET) {
6014 BcResult *operand = bc_vec_top(&G.prog.results);
6016 s = bc_program_num(operand, &num, false);
6018 bc_num_init(&res.d.n, num->len);
6019 bc_num_copy(&res.d.n, num);
6022 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6023 bc_num_zero(&res.d.n);
6026 // We need to pop arguments as well, so this takes that into account.
6027 for (i = 0; i < f->autos.len; ++i) {
6030 BcId *a = bc_vec_item(&f->autos, i);
6032 v = bc_program_search(a->name, a->idx);
6036 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6037 bc_vec_push(&G.prog.results, &res);
6038 bc_vec_pop(&G.prog.stack);
6040 return BC_STATUS_SUCCESS;
6044 static unsigned long bc_program_scale(BcNum *n)
6046 return (unsigned long) n->rdx;
6049 static unsigned long bc_program_len(BcNum *n)
6051 unsigned long len = n->len;
6054 if (n->rdx != n->len) return len;
6055 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6060 static BcStatus bc_program_builtin(char inst)
6066 bool len = inst == BC_INST_LENGTH;
6068 if (!BC_PROG_STACK(&G.prog.results, 1))
6069 return bc_error_stack_has_too_few_elements();
6070 opnd = bc_vec_top(&G.prog.results);
6072 s = bc_program_num(opnd, &num, false);
6076 if (!BC_PROG_NUM(opnd, num) && !len)
6077 return bc_error_variable_is_wrong_type();
6080 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6082 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6084 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6085 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6089 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6092 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6094 str = bc_vec_item(&G.prog.strs, idx);
6095 bc_num_ulong2num(&res.d.n, strlen(*str));
6099 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6100 bc_num_ulong2num(&res.d.n, f(num));
6103 bc_program_retire(&res, BC_RESULT_TEMP);
6109 static BcStatus bc_program_divmod(void)
6112 BcResult *opd1, *opd2, res, res2;
6113 BcNum *n1, *n2 = NULL;
6115 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6118 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6119 bc_num_init(&res2.d.n, n2->len);
6121 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6124 bc_program_binOpRetire(&res2);
6125 res.t = BC_RESULT_TEMP;
6126 bc_vec_push(&G.prog.results, &res);
6131 bc_num_free(&res2.d.n);
6132 bc_num_free(&res.d.n);
6136 static BcStatus bc_program_modexp(void)
6139 BcResult *r1, *r2, *r3, res;
6140 BcNum *n1, *n2, *n3;
6142 if (!BC_PROG_STACK(&G.prog.results, 3))
6143 return bc_error_stack_has_too_few_elements();
6144 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6147 r1 = bc_vec_item_rev(&G.prog.results, 2);
6148 s = bc_program_num(r1, &n1, false);
6150 if (!BC_PROG_NUM(r1, n1))
6151 return bc_error_variable_is_wrong_type();
6153 // Make sure that the values have their pointers updated, if necessary.
6154 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6156 if (r1->t == r2->t) {
6157 s = bc_program_num(r2, &n2, false);
6161 if (r1->t == r3->t) {
6162 s = bc_program_num(r3, &n3, false);
6167 bc_num_init(&res.d.n, n3->len);
6168 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6171 bc_vec_pop(&G.prog.results);
6172 bc_program_binOpRetire(&res);
6177 bc_num_free(&res.d.n);
6181 static void bc_program_stackLen(void)
6184 size_t len = G.prog.results.len;
6186 res.t = BC_RESULT_TEMP;
6188 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6189 bc_num_ulong2num(&res.d.n, len);
6190 bc_vec_push(&G.prog.results, &res);
6193 static BcStatus bc_program_asciify(void)
6197 BcNum *num = NULL, n;
6198 char *str, *str2, c;
6199 size_t len = G.prog.strs.len, idx;
6202 if (!BC_PROG_STACK(&G.prog.results, 1))
6203 return bc_error_stack_has_too_few_elements();
6204 r = bc_vec_top(&G.prog.results);
6206 s = bc_program_num(r, &num, false);
6209 if (BC_PROG_NUM(r, num)) {
6211 bc_num_init(&n, BC_NUM_DEF_SIZE);
6212 bc_num_copy(&n, num);
6213 bc_num_truncate(&n, n.rdx);
6215 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6216 if (s) goto num_err;
6217 s = bc_num_ulong(&n, &val);
6218 if (s) goto num_err;
6225 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6226 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6234 str2 = xstrdup(str);
6235 bc_program_addFunc(str2, &idx);
6237 if (idx != len + BC_PROG_REQ_FUNCS) {
6239 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6240 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6249 bc_vec_push(&G.prog.strs, &str);
6251 res.t = BC_RESULT_STR;
6253 bc_vec_pop(&G.prog.results);
6254 bc_vec_push(&G.prog.results, &res);
6256 return BC_STATUS_SUCCESS;
6263 static BcStatus bc_program_printStream(void)
6271 if (!BC_PROG_STACK(&G.prog.results, 1))
6272 return bc_error_stack_has_too_few_elements();
6273 r = bc_vec_top(&G.prog.results);
6275 s = bc_program_num(r, &n, false);
6278 if (BC_PROG_NUM(r, n))
6279 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6281 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6282 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6289 static BcStatus bc_program_nquit(void)
6296 s = bc_program_prep(&opnd, &num);
6298 s = bc_num_ulong(num, &val);
6301 bc_vec_pop(&G.prog.results);
6303 if (G.prog.stack.len < val)
6304 return bc_error_stack_has_too_few_elements();
6305 if (G.prog.stack.len == val)
6308 bc_vec_npop(&G.prog.stack, val);
6313 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6316 BcStatus s = BC_STATUS_SUCCESS;
6326 if (!BC_PROG_STACK(&G.prog.results, 1))
6327 return bc_error_stack_has_too_few_elements();
6329 r = bc_vec_top(&G.prog.results);
6333 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6335 if (code[*bgn] == BC_PARSE_STREND)
6338 else_name = bc_program_name(code, bgn);
6340 exec = r->d.n.len != 0;
6344 else if (else_name != NULL) {
6351 v = bc_program_search(name, true);
6358 if (!exec) goto exit;
6359 if (!BC_PROG_STR(n)) {
6360 s = bc_error_variable_is_wrong_type();
6368 if (r->t == BC_RESULT_STR)
6370 else if (r->t == BC_RESULT_VAR) {
6371 s = bc_program_num(r, &n, false);
6372 if (s || !BC_PROG_STR(n)) goto exit;
6379 fidx = sidx + BC_PROG_REQ_FUNCS;
6381 str = bc_vec_item(&G.prog.strs, sidx);
6382 f = bc_vec_item(&G.prog.fns, fidx);
6384 if (f->code.len == 0) {
6385 common_parse_init(&prs, fidx);
6386 s = bc_parse_text(&prs, *str);
6388 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6391 if (prs.l.t.t != BC_LEX_EOF) {
6392 s = bc_error_bad_expression();
6396 bc_parse_free(&prs);
6400 ip.len = G.prog.results.len;
6403 bc_vec_pop(&G.prog.results);
6404 bc_vec_push(&G.prog.stack, &ip);
6406 return BC_STATUS_SUCCESS;
6409 bc_parse_free(&prs);
6410 f = bc_vec_item(&G.prog.fns, fidx);
6411 bc_vec_pop_all(&f->code);
6413 bc_vec_pop(&G.prog.results);
6418 static void bc_program_pushGlobal(char inst)
6423 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6424 if (inst == BC_INST_IBASE)
6425 val = (unsigned long) G.prog.ib_t;
6426 else if (inst == BC_INST_SCALE)
6427 val = (unsigned long) G.prog.scale;
6429 val = (unsigned long) G.prog.ob_t;
6431 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6432 bc_num_ulong2num(&res.d.n, val);
6433 bc_vec_push(&G.prog.results, &res);
6436 static void bc_program_addFunc(char *name, size_t *idx)
6438 BcId entry, *entry_ptr;
6443 entry.idx = G.prog.fns.len;
6445 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6446 if (!inserted) free(name);
6448 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6449 *idx = entry_ptr->idx;
6453 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6455 // We need to reset these, so the function can be repopulated.
6457 bc_vec_pop_all(&func->autos);
6458 bc_vec_pop_all(&func->code);
6459 bc_vec_pop_all(&func->labels);
6463 bc_vec_push(&G.prog.fns, &f);
6467 // Called when parsing or execution detects a failure,
6468 // resets execution structures.
6469 static void bc_program_reset(void)
6474 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6475 bc_vec_pop_all(&G.prog.results);
6477 f = bc_vec_item(&G.prog.fns, 0);
6478 ip = bc_vec_top(&G.prog.stack);
6479 ip->idx = f->code.len;
6481 // If !tty, no need to check for ^C: we don't have ^C handler,
6482 // we would be killed by a signal and won't reach this place
6485 static BcStatus bc_program_exec(void)
6487 BcStatus s = BC_STATUS_SUCCESS;
6491 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6492 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6493 char *code = func->code.v;
6496 while (!s && ip->idx < func->code.len) {
6498 char inst = code[(ip->idx)++];
6503 case BC_INST_JUMP_ZERO:
6505 s = bc_program_prep(&ptr, &num);
6507 cond = !bc_num_cmp(num, &G.prog.zero);
6508 bc_vec_pop(&G.prog.results);
6514 idx = bc_program_index(code, &ip->idx);
6515 addr = bc_vec_item(&func->labels, idx);
6516 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6522 s = bc_program_call(code, &ip->idx);
6526 case BC_INST_INC_PRE:
6527 case BC_INST_DEC_PRE:
6528 case BC_INST_INC_POST:
6529 case BC_INST_DEC_POST:
6531 s = bc_program_incdec(inst);
6544 s = bc_program_return(inst);
6548 case BC_INST_BOOL_OR:
6549 case BC_INST_BOOL_AND:
6551 case BC_INST_REL_EQ:
6552 case BC_INST_REL_LE:
6553 case BC_INST_REL_GE:
6554 case BC_INST_REL_NE:
6555 case BC_INST_REL_LT:
6556 case BC_INST_REL_GT:
6558 s = bc_program_logical(inst);
6564 s = bc_program_read();
6570 s = bc_program_pushVar(code, &ip->idx, false, false);
6574 case BC_INST_ARRAY_ELEM:
6577 s = bc_program_pushArray(code, &ip->idx, inst);
6583 r.t = BC_RESULT_LAST;
6584 bc_vec_push(&G.prog.results, &r);
6592 bc_program_pushGlobal(inst);
6596 case BC_INST_SCALE_FUNC:
6597 case BC_INST_LENGTH:
6600 s = bc_program_builtin(inst);
6606 r.t = BC_RESULT_CONSTANT;
6607 r.d.id.idx = bc_program_index(code, &ip->idx);
6608 bc_vec_push(&G.prog.results, &r);
6614 if (!BC_PROG_STACK(&G.prog.results, 1))
6615 s = bc_error_stack_has_too_few_elements();
6617 bc_vec_pop(&G.prog.results);
6621 case BC_INST_POP_EXEC:
6623 bc_vec_pop(&G.prog.stack);
6628 case BC_INST_PRINT_POP:
6629 case BC_INST_PRINT_STR:
6631 s = bc_program_print(inst, 0);
6637 r.t = BC_RESULT_STR;
6638 r.d.id.idx = bc_program_index(code, &ip->idx);
6639 bc_vec_push(&G.prog.results, &r);
6644 case BC_INST_MULTIPLY:
6645 case BC_INST_DIVIDE:
6646 case BC_INST_MODULUS:
6650 s = bc_program_op(inst);
6654 case BC_INST_BOOL_NOT:
6656 s = bc_program_prep(&ptr, &num);
6659 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6660 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6661 bc_program_retire(&r, BC_RESULT_TEMP);
6668 s = bc_program_negate();
6673 case BC_INST_ASSIGN_POWER:
6674 case BC_INST_ASSIGN_MULTIPLY:
6675 case BC_INST_ASSIGN_DIVIDE:
6676 case BC_INST_ASSIGN_MODULUS:
6677 case BC_INST_ASSIGN_PLUS:
6678 case BC_INST_ASSIGN_MINUS:
6680 case BC_INST_ASSIGN:
6682 s = bc_program_assign(inst);
6686 case BC_INST_MODEXP:
6688 s = bc_program_modexp();
6692 case BC_INST_DIVMOD:
6694 s = bc_program_divmod();
6698 case BC_INST_EXECUTE:
6699 case BC_INST_EXEC_COND:
6701 cond = inst == BC_INST_EXEC_COND;
6702 s = bc_program_execStr(code, &ip->idx, cond);
6706 case BC_INST_PRINT_STACK:
6708 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6709 s = bc_program_print(BC_INST_PRINT, idx);
6713 case BC_INST_CLEAR_STACK:
6715 bc_vec_pop_all(&G.prog.results);
6719 case BC_INST_STACK_LEN:
6721 bc_program_stackLen();
6725 case BC_INST_DUPLICATE:
6727 if (!BC_PROG_STACK(&G.prog.results, 1))
6728 return bc_error_stack_has_too_few_elements();
6729 ptr = bc_vec_top(&G.prog.results);
6730 bc_result_copy(&r, ptr);
6731 bc_vec_push(&G.prog.results, &r);
6739 if (!BC_PROG_STACK(&G.prog.results, 2))
6740 return bc_error_stack_has_too_few_elements();
6742 ptr = bc_vec_item_rev(&G.prog.results, 0);
6743 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6744 memcpy(&r, ptr, sizeof(BcResult));
6745 memcpy(ptr, ptr2, sizeof(BcResult));
6746 memcpy(ptr2, &r, sizeof(BcResult));
6751 case BC_INST_ASCIIFY:
6753 s = bc_program_asciify();
6757 case BC_INST_PRINT_STREAM:
6759 s = bc_program_printStream();
6764 case BC_INST_PUSH_VAR:
6766 bool copy = inst == BC_INST_LOAD;
6767 s = bc_program_pushVar(code, &ip->idx, true, copy);
6771 case BC_INST_PUSH_TO_VAR:
6773 char *name = bc_program_name(code, &ip->idx);
6774 s = bc_program_copyToVar(name, true);
6781 if (G.prog.stack.len <= 2)
6783 bc_vec_npop(&G.prog.stack, 2);
6789 s = bc_program_nquit();
6795 if (s || G_interrupt) {
6800 // If the stack has changed, pointers may be invalid.
6801 ip = bc_vec_top(&G.prog.stack);
6802 func = bc_vec_item(&G.prog.fns, ip->func);
6803 code = func->code.v;
6809 static void bc_vm_info(void)
6811 printf("%s "BB_VER"\n"
6812 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6813 "Report bugs at: https://github.com/gavinhoward/bc\n"
6814 "This is free software with ABSOLUTELY NO WARRANTY\n"
6819 static void bc_vm_envArgs(void)
6821 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6824 char *env_args = getenv(bc_args_env_name), *buf;
6826 if (!env_args) return;
6828 G.env_args = xstrdup(env_args);
6831 bc_vec_init(&v, sizeof(char *), NULL);
6832 bc_vec_push(&v, &bc_args_env_name);
6835 if (!isspace(*buf)) {
6836 bc_vec_push(&v, &buf);
6837 while (*buf != 0 && !isspace(*buf)) ++buf;
6838 if (*buf != 0) (*(buf++)) = '\0';
6844 bc_args((int) v.len, (char **) v.v);
6850 static size_t bc_vm_envLen(const char *var)
6852 char *lenv = getenv(var);
6853 size_t i, len = BC_NUM_PRINT_WIDTH;
6856 if (!lenv) return len;
6860 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6862 len = (size_t) atoi(lenv) - 1;
6863 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6866 len = BC_NUM_PRINT_WIDTH;
6871 static BcStatus bc_vm_process(const char *text)
6873 BcStatus s = bc_parse_text(&G.prs, text);
6877 while (G.prs.l.t.t != BC_LEX_EOF) {
6878 s = G.prs.parse(&G.prs);
6882 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6883 s = bc_program_exec();
6892 static BcStatus bc_vm_file(const char *file)
6894 const char *sv_file;
6900 data = bc_read_file(file);
6901 if (!data) return bc_error_fmt("file '%s' is not text", file);
6903 sv_file = G.prog.file;
6905 bc_lex_file(&G.prs.l);
6906 s = bc_vm_process(data);
6909 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6910 ip = bc_vec_item(&G.prog.stack, 0);
6912 if (main_func->code.len < ip->idx)
6913 s = bc_error_fmt("file '%s' is not executable", file);
6916 G.prog.file = sv_file;
6921 static BcStatus bc_vm_stdin(void)
6925 size_t len, i, str = 0;
6926 bool comment = false;
6929 bc_lex_file(&G.prs.l);
6931 bc_char_vec_init(&buffer);
6932 bc_char_vec_init(&buf);
6933 bc_vec_pushZeroByte(&buffer);
6935 // This loop is complex because the vm tries not to send any lines that end
6936 // with a backslash to the parser. The reason for that is because the parser
6937 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6938 // case, and for strings and comments, the parser will expect more stuff.
6939 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6941 char *string = buf.v;
6946 if (str && buf.v[0] == G.send)
6948 else if (buf.v[0] == G.sbgn)
6951 else if (len > 1 || comment) {
6953 for (i = 0; i < len; ++i) {
6955 bool notend = len > i + 1;
6958 if (i - 1 > len || string[i - 1] != '\\') {
6959 if (G.sbgn == G.send)
6961 else if (c == G.send)
6963 else if (c == G.sbgn)
6967 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6971 else if (c == '*' && notend && comment && string[i + 1] == '/')
6975 if (str || comment || string[len - 2] == '\\') {
6976 bc_vec_concat(&buffer, buf.v);
6981 bc_vec_concat(&buffer, buf.v);
6982 s = bc_vm_process(buffer.v);
6985 fputs("ready for more input\n", stderr);
6988 bc_vec_pop_all(&buffer);
6992 s = bc_error("string end could not be found");
6995 s = bc_error("comment end could not be found");
6999 bc_vec_free(&buffer);
7004 static const char bc_lib[] = {
7007 "\n" "auto b,s,n,r,d,i,p,f,v"
7016 "\n" "scale=scale(x)+1"
7026 "\n" "for(i=2;v!=0;++i){"
7032 "\n" "while((d--)!=0)r*=r"
7035 "\n" "if(n!=0)return(1/r)"
7039 "\n" "auto b,s,r,p,a,q,i,v"
7043 "\n" "r=(1-10^scale)/1"
7054 "\n" "while(x<=0.5){"
7058 "\n" "r=a=(x-1)/(x+1)"
7061 "\n" "for(i=3;v!=0;i+=2){"
7072 "\n" "auto b,s,r,n,a,q,i"
7076 "\n" "scale=1.1*s+2"
7085 "\n" "if(q%2!=0)x=-x"
7089 "\n" "for(i=3;a!=0;i+=2){"
7090 "\n" "a*=q/(i*(i-1))"
7095 "\n" "if(n!=0)return(-r/1)"
7104 "\n" "x=s(2*a(1)+x)"
7110 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7119 "\n" "if(scale<65){"
7120 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7124 "\n" "if(scale<65){"
7125 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7136 "\n" "x=(x-.2)/(1+.2*x)"
7141 "\n" "for(i=3;t!=0;i+=2){"
7148 "\n" "return((m*a+r)/n)"
7150 "\n" "define j(n,x){"
7151 "\n" "auto b,s,o,a,i,v,f"
7159 "\n" "if(n%2==1)o=1"
7162 "\n" "for(i=2;i<=n;++i)a*=i"
7164 "\n" "a=(x^n)/2^n/a"
7167 "\n" "scale=scale+length(a)-scale(a)"
7168 "\n" "for(i=1;v!=0;++i){"
7169 "\n" "v=v*f/i/(n+i)"
7175 "\n" "return(a*r/1)"
7180 static BcStatus bc_vm_exec(void)
7182 BcStatus s = BC_STATUS_SUCCESS;
7186 if (option_mask32 & BC_FLAG_L) {
7188 // We know that internal library is not buggy,
7189 // thus error checking is normally disabled.
7190 # define DEBUG_LIB 0
7191 bc_lex_file(&G.prs.l);
7192 s = bc_parse_text(&G.prs, bc_lib);
7193 if (DEBUG_LIB && s) return s;
7195 while (G.prs.l.t.t != BC_LEX_EOF) {
7196 s = G.prs.parse(&G.prs);
7197 if (DEBUG_LIB && s) return s;
7199 s = bc_program_exec();
7200 if (DEBUG_LIB && s) return s;
7204 for (i = 0; !s && i < G.files.len; ++i)
7205 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7208 fputs("ready for more input\n", stderr);
7211 if (IS_BC || !G.files.len)
7213 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7214 s = bc_vm_process("");
7219 #if ENABLE_FEATURE_CLEAN_UP
7220 static void bc_program_free()
7222 bc_num_free(&G.prog.ib);
7223 bc_num_free(&G.prog.ob);
7224 bc_num_free(&G.prog.hexb);
7226 bc_num_free(&G.prog.strmb);
7228 bc_vec_free(&G.prog.fns);
7229 bc_vec_free(&G.prog.fn_map);
7230 bc_vec_free(&G.prog.vars);
7231 bc_vec_free(&G.prog.var_map);
7232 bc_vec_free(&G.prog.arrs);
7233 bc_vec_free(&G.prog.arr_map);
7234 bc_vec_free(&G.prog.strs);
7235 bc_vec_free(&G.prog.consts);
7236 bc_vec_free(&G.prog.results);
7237 bc_vec_free(&G.prog.stack);
7238 bc_num_free(&G.prog.last);
7239 bc_num_free(&G.prog.zero);
7240 bc_num_free(&G.prog.one);
7243 static void bc_vm_free(void)
7245 bc_vec_free(&G.files);
7247 bc_parse_free(&G.prs);
7252 static void bc_program_init(size_t line_len)
7257 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7258 memset(&ip, 0, sizeof(BcInstPtr));
7260 /* G.prog.nchars = G.prog.scale = 0; - already is */
7261 G.prog.len = line_len;
7263 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7264 bc_num_ten(&G.prog.ib);
7267 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7268 bc_num_ten(&G.prog.ob);
7271 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7272 bc_num_ten(&G.prog.hexb);
7273 G.prog.hexb.num[0] = 6;
7276 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7277 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7280 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7281 bc_num_zero(&G.prog.last);
7283 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7284 bc_num_zero(&G.prog.zero);
7286 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7287 bc_num_one(&G.prog.one);
7289 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7290 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7292 bc_program_addFunc(xstrdup("(main)"), &idx);
7293 bc_program_addFunc(xstrdup("(read)"), &idx);
7295 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7296 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7298 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7299 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7301 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7302 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7303 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7304 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7305 bc_vec_push(&G.prog.stack, &ip);
7308 static void bc_vm_init(const char *env_len)
7310 size_t len = bc_vm_envLen(env_len);
7312 bc_vec_init(&G.files, sizeof(char *), NULL);
7318 bc_program_init(len);
7320 bc_parse_init(&G.prs, BC_PROG_MAIN);
7322 dc_parse_init(&G.prs, BC_PROG_MAIN);
7326 static BcStatus bc_vm_run(int argc, char *argv[],
7327 const char *env_len)
7331 bc_vm_init(env_len);
7332 bc_args(argc, argv);
7334 G.ttyin = isatty(0);
7337 #if ENABLE_FEATURE_BC_SIGNALS
7338 // With SA_RESTART, most system calls will restart
7339 // (IOW: they won't fail with EINTR).
7340 // In particular, this means ^C won't cause
7341 // stdout to get into "error state" if SIGINT hits
7342 // within write() syscall.
7343 // The downside is that ^C while line input is taken
7344 // will only be handled after [Enter] since read()
7345 // from stdin is not interrupted by ^C either,
7346 // it restarts, thus fgetc() does not return on ^C.
7347 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7349 // Without SA_RESTART, this exhibits a bug:
7350 // "while (1) print 1" and try ^C-ing it.
7351 // Intermittently, instead of returning to input line,
7352 // you'll get "output error: Interrupted system call"
7354 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7356 if (!(option_mask32 & BC_FLAG_Q))
7361 #if ENABLE_FEATURE_CLEAN_UP
7368 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7369 int bc_main(int argc, char **argv)
7372 G.sbgn = G.send = '"';
7374 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7379 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7380 int dc_main(int argc, char **argv)
7386 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");