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_POSIX_does_not_allow(const char *msg)
997 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
999 static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1001 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1003 static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1005 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1007 static int bc_error_bad_character(char c)
1009 return bc_error_fmt("bad character '%c'", c);
1011 static int bc_error_bad_expression(void)
1013 return bc_error("bad expression");
1015 static int bc_error_bad_token(void)
1017 return bc_error("bad token");
1019 static int bc_error_stack_has_too_few_elements(void)
1021 return bc_error("stack has too few elements");
1023 static int bc_error_variable_is_wrong_type(void)
1025 return bc_error("variable is wrong type");
1027 static int bc_error_nested_read_call(void)
1029 return bc_error("read() call inside of a read() call");
1032 static void bc_vec_grow(BcVec *v, size_t n)
1034 size_t cap = v->cap * 2;
1035 while (cap < v->len + n) cap *= 2;
1036 v->v = xrealloc(v->v, v->size * cap);
1040 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1043 v->cap = BC_VEC_START_CAP;
1046 v->v = xmalloc(esize * BC_VEC_START_CAP);
1049 static void bc_char_vec_init(BcVec *v)
1051 bc_vec_init(v, sizeof(char), NULL);
1054 static void bc_vec_expand(BcVec *v, size_t req)
1057 v->v = xrealloc(v->v, v->size * req);
1062 static void bc_vec_npop(BcVec *v, size_t n)
1067 size_t len = v->len - n;
1068 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1072 static void bc_vec_pop_all(BcVec *v)
1074 bc_vec_npop(v, v->len);
1077 static void bc_vec_push(BcVec *v, const void *data)
1079 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1080 memmove(v->v + (v->size * v->len), data, v->size);
1084 static void bc_vec_pushByte(BcVec *v, char data)
1086 bc_vec_push(v, &data);
1089 static void bc_vec_pushZeroByte(BcVec *v)
1091 //bc_vec_pushByte(v, '\0');
1093 bc_vec_push(v, &const_int_0);
1096 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1099 bc_vec_push(v, data);
1104 if (v->len == v->cap) bc_vec_grow(v, 1);
1106 ptr = v->v + v->size * idx;
1108 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1109 memmove(ptr, data, v->size);
1113 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1116 bc_vec_expand(v, len + 1);
1117 memcpy(v->v, str, len);
1120 bc_vec_pushZeroByte(v);
1123 static void bc_vec_concat(BcVec *v, const char *str)
1127 if (v->len == 0) bc_vec_pushZeroByte(v);
1129 len = v->len + strlen(str);
1131 if (v->cap < len) bc_vec_grow(v, len - v->len);
1137 static void *bc_vec_item(const BcVec *v, size_t idx)
1139 return v->v + v->size * idx;
1142 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1144 return v->v + v->size * (v->len - idx - 1);
1147 static void bc_vec_free(void *vec)
1149 BcVec *v = (BcVec *) vec;
1154 static size_t bc_map_find(const BcVec *v, const void *ptr)
1156 size_t low = 0, high = v->len;
1158 while (low < high) {
1160 size_t mid = (low + high) / 2;
1161 BcId *id = bc_vec_item(v, mid);
1162 int result = bc_id_cmp(ptr, id);
1166 else if (result < 0)
1175 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1177 size_t n = *i = bc_map_find(v, ptr);
1180 bc_vec_push(v, ptr);
1181 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1182 return 0; // "was not inserted"
1184 bc_vec_pushAt(v, ptr, n);
1185 return 1; // "was inserted"
1188 static size_t bc_map_index(const BcVec *v, const void *ptr)
1190 size_t i = bc_map_find(v, ptr);
1191 if (i >= v->len) return BC_VEC_INVALID_IDX;
1192 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1195 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1203 bc_vec_pop_all(vec);
1206 #if ENABLE_FEATURE_BC_SIGNALS
1207 if (bb_got_signal) { // ^C was pressed
1209 bb_got_signal = 0; // resets G_interrupt to zero
1211 ? "\ninterrupt (type \"quit\" to exit)\n"
1212 : "\ninterrupt (type \"q\" to exit)\n"
1216 if (G.ttyin && !G_posix)
1217 fputs(prompt, stderr);
1219 #if ENABLE_FEATURE_BC_SIGNALS
1225 #if ENABLE_FEATURE_BC_SIGNALS
1226 // Both conditions appear simultaneously, check both just in case
1227 if (errno == EINTR || bb_got_signal) {
1234 quit(); // this emits error message
1236 // Note: EOF does not append '\n', therefore:
1237 // printf 'print 123\n' | bc - works
1238 // printf 'print 123' | bc - fails (syntax error)
1242 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1245 // Bad chars on this line, ignore entire line
1246 bc_error_fmt("illegal character 0x%02x", i);
1249 bc_vec_pushByte(vec, (char)i);
1250 } while (i != '\n');
1251 } while (bad_chars);
1253 bc_vec_pushZeroByte(vec);
1255 return BC_STATUS_SUCCESS;
1258 static char* bc_read_file(const char *path)
1261 size_t size = ((size_t) -1);
1264 buf = xmalloc_open_read_close(path, &size);
1266 for (i = 0; i < size; ++i) {
1268 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1280 static void bc_args(int argc, char **argv)
1286 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1287 opts = getopt32long(argv, "xwvsqli",
1288 "extended-register\0" No_argument "x"
1289 "warn\0" No_argument "w"
1290 "version\0" No_argument "v"
1291 "standard\0" No_argument "s"
1292 "quiet\0" No_argument "q"
1293 "mathlib\0" No_argument "l"
1294 "interactive\0" No_argument "i"
1297 opts = getopt32(argv, "xwvsqli");
1299 if (getenv("POSIXLY_CORRECT"))
1300 option_mask32 |= BC_FLAG_S;
1302 if (opts & BC_FLAG_V) bc_vm_info();
1303 // should not be necessary, getopt32() handles this??
1304 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1306 for (i = optind; i < argc; ++i)
1307 bc_vec_push(&G.files, argv + i);
1310 static void bc_num_setToZero(BcNum *n, size_t scale)
1317 static void bc_num_zero(BcNum *n)
1319 bc_num_setToZero(n, 0);
1322 static void bc_num_one(BcNum *n)
1324 bc_num_setToZero(n, 0);
1329 static void bc_num_ten(BcNum *n)
1331 bc_num_setToZero(n, 0);
1337 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1341 for (i = 0; i < len; ++i) {
1342 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1349 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1353 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1354 return BC_NUM_NEG(i + 1, c < 0);
1357 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1359 size_t i, min, a_int, b_int, diff;
1360 BcDig *max_num, *min_num;
1361 bool a_max, neg = false;
1364 if (a == b) return 0;
1365 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1366 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1376 a_int = BC_NUM_INT(a);
1377 b_int = BC_NUM_INT(b);
1379 a_max = (a->rdx > b->rdx);
1381 if (a_int != 0) return (ssize_t) a_int;
1385 diff = a->rdx - b->rdx;
1386 max_num = a->num + diff;
1391 diff = b->rdx - a->rdx;
1392 max_num = b->num + diff;
1396 cmp = bc_num_compare(max_num, min_num, b_int + min);
1397 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1399 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1400 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1406 static void bc_num_truncate(BcNum *n, size_t places)
1408 if (places == 0) return;
1414 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1418 static void bc_num_extend(BcNum *n, size_t places)
1420 size_t len = n->len + places;
1424 if (n->cap < len) bc_num_expand(n, len);
1426 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1427 memset(n->num, 0, sizeof(BcDig) * places);
1434 static void bc_num_clean(BcNum *n)
1436 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1439 else if (n->len < n->rdx)
1443 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1446 bc_num_extend(n, scale - n->rdx);
1448 bc_num_truncate(n, n->rdx - scale);
1451 if (n->len != 0) n->neg = !neg1 != !neg2;
1454 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1459 b->len = n->len - idx;
1461 a->rdx = b->rdx = 0;
1463 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1464 memcpy(a->num, n->num, idx * sizeof(BcDig));
1475 static BcStatus bc_num_shift(BcNum *n, size_t places)
1477 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1478 if (places + n->len > BC_MAX_NUM)
1479 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1481 if (n->rdx >= places)
1484 bc_num_extend(n, places - n->rdx);
1490 return BC_STATUS_SUCCESS;
1493 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1502 return bc_num_div(&one, a, b, scale);
1505 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1507 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1508 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1511 // Because this function doesn't need to use scale (per the bc spec),
1512 // I am hijacking it to say whether it's doing an add or a subtract.
1516 if (sub && c->len) c->neg = !c->neg;
1517 return BC_STATUS_SUCCESS;
1519 else if (b->len == 0) {
1521 return BC_STATUS_SUCCESS;
1525 c->rdx = BC_MAX(a->rdx, b->rdx);
1526 min_rdx = BC_MIN(a->rdx, b->rdx);
1529 if (a->rdx > b->rdx) {
1530 diff = a->rdx - b->rdx;
1532 ptr_a = a->num + diff;
1536 diff = b->rdx - a->rdx;
1539 ptr_b = b->num + diff;
1542 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1545 a_int = BC_NUM_INT(a);
1546 b_int = BC_NUM_INT(b);
1548 if (a_int > b_int) {
1559 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1560 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1562 ptr_c[i] = (BcDig)(in % 10);
1565 for (; i < max + min_rdx; ++i, ++c->len) {
1566 in = ((int) ptr[i]) + carry;
1568 ptr_c[i] = (BcDig)(in % 10);
1571 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1573 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1576 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1579 BcNum *minuend, *subtrahend;
1581 bool aneg, bneg, neg;
1583 // Because this function doesn't need to use scale (per the bc spec),
1584 // I am hijacking it to say whether it's doing an add or a subtract.
1588 if (sub && c->len) c->neg = !c->neg;
1589 return BC_STATUS_SUCCESS;
1591 else if (b->len == 0) {
1593 return BC_STATUS_SUCCESS;
1598 a->neg = b->neg = false;
1600 cmp = bc_num_cmp(a, b);
1606 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1607 return BC_STATUS_SUCCESS;
1616 if (sub) neg = !neg;
1621 bc_num_copy(c, minuend);
1624 if (c->rdx < subtrahend->rdx) {
1625 bc_num_extend(c, subtrahend->rdx - c->rdx);
1629 start = c->rdx - subtrahend->rdx;
1631 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1635 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1638 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1642 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1643 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1646 if (a->len == 0 || b->len == 0) {
1648 return BC_STATUS_SUCCESS;
1650 aone = BC_NUM_ONE(a);
1651 if (aone || BC_NUM_ONE(b)) {
1652 bc_num_copy(c, aone ? b : a);
1653 return BC_STATUS_SUCCESS;
1656 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1657 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1662 bc_num_expand(c, a->len + b->len + 1);
1664 memset(c->num, 0, sizeof(BcDig) * c->cap);
1667 for (i = 0; i < b->len; ++i) {
1670 for (j = 0; j < a->len; ++j) {
1671 unsigned in = c->num[i + j];
1672 in += ((unsigned) a->num[j]) * ((unsigned) b->num[i]) + carry;
1673 // note: compilers prefer _unsigned_ div/const
1675 c->num[i + j] = (BcDig)(in % 10);
1678 c->num[i + j] += (BcDig) carry;
1679 len = BC_MAX(len, i + j + !!carry);
1682 // a*a <- without check below, this will not be interruptible
1683 if (G_interrupt) return BC_STATUS_FAILURE;
1688 return BC_STATUS_SUCCESS;
1691 bc_num_init(&l1, max);
1692 bc_num_init(&h1, max);
1693 bc_num_init(&l2, max);
1694 bc_num_init(&h2, max);
1695 bc_num_init(&m1, max);
1696 bc_num_init(&m2, max);
1697 bc_num_init(&z0, max);
1698 bc_num_init(&z1, max);
1699 bc_num_init(&z2, max);
1700 bc_num_init(&temp, max + max);
1702 bc_num_split(a, max2, &l1, &h1);
1703 bc_num_split(b, max2, &l2, &h2);
1705 s = bc_num_add(&h1, &l1, &m1, 0);
1707 s = bc_num_add(&h2, &l2, &m2, 0);
1710 s = bc_num_k(&h1, &h2, &z0);
1712 s = bc_num_k(&m1, &m2, &z1);
1714 s = bc_num_k(&l1, &l2, &z2);
1717 s = bc_num_sub(&z1, &z0, &temp, 0);
1719 s = bc_num_sub(&temp, &z2, &z1, 0);
1722 s = bc_num_shift(&z0, max2 * 2);
1724 s = bc_num_shift(&z1, max2);
1726 s = bc_num_add(&z0, &z1, &temp, 0);
1728 s = bc_num_add(&temp, &z2, c, 0);
1744 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1748 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1750 scale = BC_MAX(scale, a->rdx);
1751 scale = BC_MAX(scale, b->rdx);
1752 scale = BC_MIN(a->rdx + b->rdx, scale);
1753 maxrdx = BC_MAX(maxrdx, scale);
1755 bc_num_init(&cpa, a->len);
1756 bc_num_init(&cpb, b->len);
1758 bc_num_copy(&cpa, a);
1759 bc_num_copy(&cpb, b);
1760 cpa.neg = cpb.neg = false;
1762 s = bc_num_shift(&cpa, maxrdx);
1764 s = bc_num_shift(&cpb, maxrdx);
1766 s = bc_num_k(&cpa, &cpb, c);
1770 bc_num_expand(c, c->len + maxrdx);
1772 if (c->len < maxrdx) {
1773 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1778 bc_num_retireMul(c, scale, a->neg, b->neg);
1786 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1788 BcStatus s = BC_STATUS_SUCCESS;
1795 return bc_error("divide by zero");
1796 else if (a->len == 0) {
1797 bc_num_setToZero(c, scale);
1798 return BC_STATUS_SUCCESS;
1800 else if (BC_NUM_ONE(b)) {
1802 bc_num_retireMul(c, scale, a->neg, b->neg);
1803 return BC_STATUS_SUCCESS;
1806 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1807 bc_num_copy(&cp, a);
1811 bc_num_expand(&cp, len + 2);
1812 bc_num_extend(&cp, len - cp.len);
1815 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1817 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1819 if (b->rdx == b->len) {
1820 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1824 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1826 // We want an extra zero in front to make things simpler.
1827 cp.num[cp.len++] = 0;
1830 bc_num_expand(c, cp.len);
1833 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1838 for (i = end - 1; !s && i < end; --i) {
1840 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1841 bc_num_subArrays(n, p, len);
1845 // 1/a <- without check below, this will not be interruptible
1847 s = BC_STATUS_FAILURE;
1852 bc_num_retireMul(c, scale, a->neg, b->neg);
1858 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1859 BcNum *restrict d, size_t scale, size_t ts)
1866 return bc_error("divide by zero");
1869 bc_num_setToZero(d, ts);
1870 return BC_STATUS_SUCCESS;
1873 bc_num_init(&temp, d->cap);
1874 s = bc_num_d(a, b, c, scale);
1877 if (scale != 0) scale = ts;
1879 s = bc_num_m(c, b, &temp, scale);
1881 s = bc_num_sub(a, &temp, d, scale);
1884 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1887 bc_num_retireMul(d, ts, a->neg, b->neg);
1895 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1899 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1901 bc_num_init(&c1, len);
1902 s = bc_num_r(a, b, &c1, c, scale, ts);
1908 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1910 BcStatus s = BC_STATUS_SUCCESS;
1913 size_t i, powrdx, resrdx;
1916 if (b->rdx) return bc_error("non integer number");
1920 return BC_STATUS_SUCCESS;
1922 else if (a->len == 0) {
1923 bc_num_setToZero(c, scale);
1924 return BC_STATUS_SUCCESS;
1926 else if (BC_NUM_ONE(b)) {
1930 s = bc_num_inv(a, c, scale);
1937 s = bc_num_ulong(b, &pow);
1940 bc_num_init(©, a->len);
1941 bc_num_copy(©, a);
1943 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1947 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1949 s = bc_num_mul(©, ©, ©, powrdx);
1951 // Not needed: bc_num_mul() has a check for ^C:
1952 //if (G_interrupt) {
1953 // s = BC_STATUS_FAILURE;
1958 bc_num_copy(c, ©);
1960 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1963 s = bc_num_mul(©, ©, ©, powrdx);
1968 s = bc_num_mul(c, ©, c, resrdx);
1971 // Not needed: bc_num_mul() has a check for ^C:
1972 //if (G_interrupt) {
1973 // s = BC_STATUS_FAILURE;
1979 s = bc_num_inv(c, c, scale);
1983 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1985 // We can't use bc_num_clean() here.
1986 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1987 if (zero) bc_num_setToZero(c, scale);
1994 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1995 BcNumBinaryOp op, size_t req)
1998 BcNum num2, *ptr_a, *ptr_b;
2003 memcpy(ptr_a, c, sizeof(BcNum));
2012 memcpy(ptr_b, c, sizeof(BcNum));
2020 bc_num_init(c, req);
2022 bc_num_expand(c, req);
2024 s = op(ptr_a, ptr_b, c, scale);
2026 if (init) bc_num_free(&num2);
2031 static bool bc_num_strValid(const char *val, size_t base)
2034 bool small, radix = false;
2035 size_t i, len = strlen(val);
2037 if (!len) return true;
2040 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2042 for (i = 0; i < len; ++i) {
2048 if (radix) return false;
2054 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2061 static void bc_num_parseDecimal(BcNum *n, const char *val)
2067 for (i = 0; val[i] == '0'; ++i);
2074 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2075 bc_num_expand(n, len);
2078 ptr = strchr(val, '.');
2082 n->rdx = (size_t)((val + len) - (ptr + 1));
2085 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2086 n->num[n->len] = val[i] - '0';
2090 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2093 BcNum temp, mult, result;
2097 size_t i, digits, len = strlen(val);
2101 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2104 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2105 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2107 for (i = 0; i < len; ++i) {
2110 if (c == '.') break;
2112 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2114 s = bc_num_mul(n, base, &mult, 0);
2115 if (s) goto int_err;
2116 bc_num_ulong2num(&temp, v);
2117 s = bc_num_add(&mult, &temp, n, 0);
2118 if (s) goto int_err;
2123 if (c == 0) goto int_err;
2126 bc_num_init(&result, base->len);
2127 bc_num_zero(&result);
2130 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2135 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2137 s = bc_num_mul(&result, base, &result, 0);
2139 bc_num_ulong2num(&temp, v);
2140 s = bc_num_add(&result, &temp, &result, 0);
2142 s = bc_num_mul(&mult, base, &mult, 0);
2146 s = bc_num_div(&result, &mult, &result, digits);
2148 s = bc_num_add(n, &result, n, digits);
2152 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2158 bc_num_free(&result);
2164 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2166 if (*nchars == line_len - 1) {
2174 static void bc_num_printChar(size_t num, size_t width, bool radix,
2175 size_t *nchars, size_t line_len)
2177 (void) radix, (void) line_len;
2178 bb_putchar((char) num);
2179 *nchars = *nchars + width;
2183 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2184 size_t *nchars, size_t line_len)
2188 bc_num_printNewline(nchars, line_len);
2189 bb_putchar(radix ? '.' : ' ');
2192 bc_num_printNewline(nchars, line_len);
2193 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2196 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2198 bc_num_printNewline(nchars, line_len);
2201 bb_putchar(((char) dig) + '0');
2205 static void bc_num_printHex(size_t num, size_t width, bool radix,
2206 size_t *nchars, size_t line_len)
2209 bc_num_printNewline(nchars, line_len);
2214 bc_num_printNewline(nchars, line_len);
2215 bb_putchar(bb_hexdigits_upcase[num]);
2216 *nchars = *nchars + width;
2219 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2221 size_t i, rdx = n->rdx - 1;
2223 if (n->neg) bb_putchar('-');
2224 (*nchars) += n->neg;
2226 for (i = n->len - 1; i < n->len; --i)
2227 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2230 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2231 size_t *nchars, size_t len, BcNumDigitOp print)
2235 BcNum intp, fracp, digit, frac_len;
2236 unsigned long dig, *ptr;
2241 print(0, width, false, nchars, len);
2242 return BC_STATUS_SUCCESS;
2245 bc_vec_init(&stack, sizeof(long), NULL);
2246 bc_num_init(&intp, n->len);
2247 bc_num_init(&fracp, n->rdx);
2248 bc_num_init(&digit, width);
2249 bc_num_init(&frac_len, BC_NUM_INT(n));
2250 bc_num_copy(&intp, n);
2251 bc_num_one(&frac_len);
2253 bc_num_truncate(&intp, intp.rdx);
2254 s = bc_num_sub(n, &intp, &fracp, 0);
2257 while (intp.len != 0) {
2258 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2260 s = bc_num_ulong(&digit, &dig);
2262 bc_vec_push(&stack, &dig);
2265 for (i = 0; i < stack.len; ++i) {
2266 ptr = bc_vec_item_rev(&stack, i);
2267 print(*ptr, width, false, nchars, len);
2270 if (!n->rdx) goto err;
2272 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2273 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2275 s = bc_num_ulong(&fracp, &dig);
2277 bc_num_ulong2num(&intp, dig);
2278 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2280 print(dig, width, radix, nchars, len);
2281 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2286 bc_num_free(&frac_len);
2287 bc_num_free(&digit);
2288 bc_num_free(&fracp);
2290 bc_vec_free(&stack);
2294 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2295 size_t *nchars, size_t line_len)
2302 if (neg) bb_putchar('-');
2307 if (base_t <= BC_NUM_MAX_IBASE) {
2309 print = bc_num_printHex;
2312 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2313 print = bc_num_printDigits;
2316 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2323 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2325 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2329 static void bc_num_init(BcNum *n, size_t req)
2331 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2332 memset(n, 0, sizeof(BcNum));
2333 n->num = xmalloc(req);
2337 static void bc_num_expand(BcNum *n, size_t req)
2339 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2341 n->num = xrealloc(n->num, req);
2346 static void bc_num_free(void *num)
2348 free(((BcNum *) num)->num);
2351 static void bc_num_copy(BcNum *d, BcNum *s)
2354 bc_num_expand(d, s->cap);
2358 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2362 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2365 if (!bc_num_strValid(val, base_t))
2366 return bc_error("bad number string");
2369 bc_num_parseDecimal(n, val);
2371 bc_num_parseBase(n, val, base);
2373 return BC_STATUS_SUCCESS;
2376 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2377 size_t *nchars, size_t line_len)
2379 BcStatus s = BC_STATUS_SUCCESS;
2381 bc_num_printNewline(nchars, line_len);
2387 else if (base_t == 10)
2388 bc_num_printDecimal(n, nchars, line_len);
2390 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2400 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2405 if (n->neg) return bc_error("negative number");
2407 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2409 unsigned long prev = *result, powprev = pow;
2411 *result += ((unsigned long) n->num[i]) * pow;
2414 if (*result < prev || pow < powprev)
2415 return bc_error("overflow");
2418 return BC_STATUS_SUCCESS;
2421 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2429 if (val == 0) return;
2431 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2432 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2435 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2437 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2439 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2442 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2444 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2446 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2449 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2451 size_t req = BC_NUM_MREQ(a, b, scale);
2452 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2455 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2457 size_t req = BC_NUM_MREQ(a, b, scale);
2458 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2461 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2463 size_t req = BC_NUM_MREQ(a, b, scale);
2464 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2467 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2469 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2472 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2475 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2476 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2477 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2479 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2480 bc_num_expand(b, req);
2483 bc_num_setToZero(b, scale);
2484 return BC_STATUS_SUCCESS;
2487 return bc_error("negative number");
2488 else if (BC_NUM_ONE(a)) {
2490 bc_num_extend(b, scale);
2491 return BC_STATUS_SUCCESS;
2494 scale = BC_MAX(scale, a->rdx) + 1;
2495 len = a->len + scale;
2497 bc_num_init(&num1, len);
2498 bc_num_init(&num2, len);
2499 bc_num_init(&half, BC_NUM_DEF_SIZE);
2505 bc_num_init(&f, len);
2506 bc_num_init(&fprime, len);
2512 pow = BC_NUM_INT(a);
2521 pow -= 2 - (pow & 1);
2523 bc_num_extend(x0, pow);
2525 // Make sure to move the radix back.
2529 x0->rdx = digs = digs1 = 0;
2531 len = BC_NUM_INT(x0) + resrdx - 1;
2533 while (cmp != 0 || digs < len) {
2535 s = bc_num_div(a, x0, &f, resrdx);
2537 s = bc_num_add(x0, &f, &fprime, resrdx);
2539 s = bc_num_mul(&fprime, &half, x1, resrdx);
2542 cmp = bc_num_cmp(x1, x0);
2543 digs = x1->len - (unsigned long long) llabs(cmp);
2545 if (cmp == cmp2 && digs == digs1)
2550 resrdx += times > 4;
2563 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2566 bc_num_free(&fprime);
2574 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2580 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2583 memcpy(&num2, c, sizeof(BcNum));
2585 bc_num_init(c, len);
2590 bc_num_expand(c, len);
2593 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2595 if (init) bc_num_free(&num2);
2601 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2604 BcNum base, exp, two, temp;
2607 return bc_error("divide by zero");
2608 if (a->rdx || b->rdx || c->rdx)
2609 return bc_error("non integer number");
2611 return bc_error("negative number");
2613 bc_num_expand(d, c->len);
2614 bc_num_init(&base, c->len);
2615 bc_num_init(&exp, b->len);
2616 bc_num_init(&two, BC_NUM_DEF_SIZE);
2617 bc_num_init(&temp, b->len);
2623 s = bc_num_rem(a, c, &base, 0);
2625 bc_num_copy(&exp, b);
2627 while (exp.len != 0) {
2629 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2632 if (BC_NUM_ONE(&temp)) {
2633 s = bc_num_mul(d, &base, &temp, 0);
2635 s = bc_num_rem(&temp, c, d, 0);
2639 s = bc_num_mul(&base, &base, &temp, 0);
2641 s = bc_num_rem(&temp, c, &base, 0);
2654 static int bc_id_cmp(const void *e1, const void *e2)
2656 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2659 static void bc_id_free(void *id)
2661 free(((BcId *) id)->name);
2664 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2669 for (i = 0; i < f->autos.len; ++i) {
2670 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2671 return bc_error("function parameter or auto var has the same name as another");
2677 bc_vec_push(&f->autos, &a);
2679 return BC_STATUS_SUCCESS;
2682 static void bc_func_init(BcFunc *f)
2684 bc_char_vec_init(&f->code);
2685 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2686 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2690 static void bc_func_free(void *func)
2692 BcFunc *f = (BcFunc *) func;
2693 bc_vec_free(&f->code);
2694 bc_vec_free(&f->autos);
2695 bc_vec_free(&f->labels);
2698 static void bc_array_init(BcVec *a, bool nums)
2701 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2703 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2704 bc_array_expand(a, 1);
2707 static void bc_array_copy(BcVec *d, const BcVec *s)
2712 bc_vec_expand(d, s->cap);
2715 for (i = 0; i < s->len; ++i) {
2716 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2717 bc_num_init(dnum, snum->len);
2718 bc_num_copy(dnum, snum);
2722 static void bc_array_expand(BcVec *a, size_t len)
2726 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2727 while (len > a->len) {
2728 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2729 bc_vec_push(a, &data.n);
2733 while (len > a->len) {
2734 bc_array_init(&data.v, true);
2735 bc_vec_push(a, &data.v);
2740 static void bc_string_free(void *string)
2742 free(*((char **) string));
2746 static void bc_result_copy(BcResult *d, BcResult *src)
2752 case BC_RESULT_TEMP:
2753 case BC_RESULT_IBASE:
2754 case BC_RESULT_SCALE:
2755 case BC_RESULT_OBASE:
2757 bc_num_init(&d->d.n, src->d.n.len);
2758 bc_num_copy(&d->d.n, &src->d.n);
2763 case BC_RESULT_ARRAY:
2764 case BC_RESULT_ARRAY_ELEM:
2766 d->d.id.name = xstrdup(src->d.id.name);
2770 case BC_RESULT_CONSTANT:
2771 case BC_RESULT_LAST:
2775 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2782 static void bc_result_free(void *result)
2784 BcResult *r = (BcResult *) result;
2788 case BC_RESULT_TEMP:
2789 case BC_RESULT_IBASE:
2790 case BC_RESULT_SCALE:
2791 case BC_RESULT_OBASE:
2793 bc_num_free(&r->d.n);
2798 case BC_RESULT_ARRAY:
2799 case BC_RESULT_ARRAY_ELEM:
2813 static void bc_lex_lineComment(BcLex *l)
2815 l->t.t = BC_LEX_WHITESPACE;
2816 while (l->i < l->len && l->buf[l->i++] != '\n');
2820 static void bc_lex_whitespace(BcLex *l)
2823 l->t.t = BC_LEX_WHITESPACE;
2824 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2827 static BcStatus bc_lex_number(BcLex *l, char start)
2829 const char *buf = l->buf + l->i;
2830 size_t len, hits = 0, bslashes = 0, i = 0, j;
2832 bool last_pt, pt = start == '.';
2835 l->t.t = BC_LEX_NUMBER;
2837 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2838 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2852 len = i + !last_pt - bslashes * 2;
2853 if (len > BC_MAX_NUM)
2854 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2856 bc_vec_pop_all(&l->t.v);
2857 bc_vec_expand(&l->t.v, len + 1);
2858 bc_vec_push(&l->t.v, &start);
2860 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2864 // If we have hit a backslash, skip it. We don't have
2865 // to check for a newline because it's guaranteed.
2866 if (hits < bslashes && c == '\\') {
2872 bc_vec_push(&l->t.v, &c);
2875 bc_vec_pushZeroByte(&l->t.v);
2878 return BC_STATUS_SUCCESS;
2881 static BcStatus bc_lex_name(BcLex *l)
2884 const char *buf = l->buf + l->i - 1;
2887 l->t.t = BC_LEX_NAME;
2889 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2891 if (i > BC_MAX_STRING)
2892 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2893 bc_vec_string(&l->t.v, i, buf);
2895 // Increment the index. We minus 1 because it has already been incremented.
2898 return BC_STATUS_SUCCESS;
2901 static void bc_lex_init(BcLex *l, BcLexNext next)
2904 bc_char_vec_init(&l->t.v);
2907 static void bc_lex_free(BcLex *l)
2909 bc_vec_free(&l->t.v);
2912 static void bc_lex_file(BcLex *l)
2914 G.err_line = l->line = 1;
2918 static BcStatus bc_lex_next(BcLex *l)
2923 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2925 l->line += l->newline;
2926 G.err_line = l->line;
2927 l->t.t = BC_LEX_EOF;
2929 l->newline = (l->i == l->len);
2930 if (l->newline) return BC_STATUS_SUCCESS;
2932 // Loop until failure or we don't have whitespace. This
2933 // is so the parser doesn't get inundated with whitespace.
2936 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2941 static BcStatus bc_lex_text(BcLex *l, const char *text)
2945 l->len = strlen(text);
2946 l->t.t = l->t.last = BC_LEX_INVALID;
2947 return bc_lex_next(l);
2951 static BcStatus bc_lex_identifier(BcLex *l)
2955 const char *buf = l->buf + l->i - 1;
2957 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2958 const char *keyword8 = bc_lex_kws[i].name8;
2960 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2962 if (j == 8) goto match;
2964 if (keyword8[j] != '\0')
2967 // buf starts with keyword bc_lex_kws[i]
2968 l->t.t = BC_LEX_KEY_1st_keyword + i;
2969 if (!((1 << i) & POSIX_KWORD_MASK)) {
2970 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
2974 // We minus 1 because the index has already been incremented.
2976 return BC_STATUS_SUCCESS;
2982 if (l->t.v.len > 2) {
2985 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
2987 unsigned len = strchrnul(buf, '\n') - buf;
2988 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
2994 static BcStatus bc_lex_string(BcLex *l)
2996 size_t len, nls = 0, i = l->i;
2999 l->t.t = BC_LEX_STR;
3001 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3005 return bc_error("string end could not be found");
3009 if (len > BC_MAX_STRING)
3010 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3011 bc_vec_string(&l->t.v, len, l->buf + l->i);
3015 G.err_line = l->line;
3017 return BC_STATUS_SUCCESS;
3020 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3022 if (l->buf[l->i] == '=') {
3030 static BcStatus bc_lex_comment(BcLex *l)
3033 const char *buf = l->buf;
3035 l->t.t = BC_LEX_WHITESPACE;
3048 return bc_error("comment end could not be found");
3056 G.err_line = l->line;
3058 return BC_STATUS_SUCCESS;
3061 static BcStatus bc_lex_token(BcLex *l)
3063 BcStatus s = BC_STATUS_SUCCESS;
3064 char c = l->buf[l->i++], c2;
3066 // This is the workhorse of the lexer.
3073 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3083 bc_lex_whitespace(l);
3089 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3091 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3092 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3101 s = bc_lex_string(l);
3107 s = bc_POSIX_does_not_allow("'#' script comments");
3110 bc_lex_lineComment(l);
3117 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3126 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3130 l->t.t = BC_LEX_OP_BOOL_AND;
3133 l->t.t = BC_LEX_INVALID;
3134 s = bc_error_bad_character('&');
3143 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3149 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3158 l->t.t = BC_LEX_OP_INC;
3161 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3167 l->t.t = BC_LEX_COMMA;
3176 l->t.t = BC_LEX_OP_DEC;
3179 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3185 if (isdigit(l->buf[l->i]))
3186 s = bc_lex_number(l, c);
3188 l->t.t = BC_LEX_KEY_LAST;
3189 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
3198 s = bc_lex_comment(l);
3200 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3221 s = bc_lex_number(l, c);
3227 l->t.t = BC_LEX_SCOLON;
3233 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3239 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3245 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3252 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3258 if (l->buf[l->i] == '\n') {
3259 l->t.t = BC_LEX_WHITESPACE;
3263 s = bc_error_bad_character(c);
3269 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3300 s = bc_lex_identifier(l);
3307 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3316 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3320 l->t.t = BC_LEX_OP_BOOL_OR;
3323 l->t.t = BC_LEX_INVALID;
3324 s = bc_error_bad_character(c);
3332 l->t.t = BC_LEX_INVALID;
3333 s = bc_error_bad_character(c);
3343 static BcStatus dc_lex_register(BcLex *l)
3345 BcStatus s = BC_STATUS_SUCCESS;
3347 if (isspace(l->buf[l->i - 1])) {
3348 bc_lex_whitespace(l);
3351 s = bc_error("extended register");
3356 bc_vec_pop_all(&l->t.v);
3357 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3358 bc_vec_pushZeroByte(&l->t.v);
3359 l->t.t = BC_LEX_NAME;
3365 static BcStatus dc_lex_string(BcLex *l)
3367 size_t depth = 1, nls = 0, i = l->i;
3370 l->t.t = BC_LEX_STR;
3371 bc_vec_pop_all(&l->t.v);
3373 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3375 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3376 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3379 if (depth) bc_vec_push(&l->t.v, &c);
3384 return bc_error("string end could not be found");
3387 bc_vec_pushZeroByte(&l->t.v);
3388 if (i - l->i > BC_MAX_STRING)
3389 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3393 G.err_line = l->line;
3395 return BC_STATUS_SUCCESS;
3398 static BcStatus dc_lex_token(BcLex *l)
3400 BcStatus s = BC_STATUS_SUCCESS;
3401 char c = l->buf[l->i++], c2;
3404 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3405 if (l->t.last == dc_lex_regs[i])
3406 return dc_lex_register(l);
3409 if (c >= '%' && c <= '~' &&
3410 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3415 // This is the workhorse of the lexer.
3420 l->t.t = BC_LEX_EOF;
3431 l->newline = (c == '\n');
3432 bc_lex_whitespace(l);
3441 l->t.t = BC_LEX_OP_REL_NE;
3443 l->t.t = BC_LEX_OP_REL_LE;
3445 l->t.t = BC_LEX_OP_REL_GE;
3447 return bc_error_bad_character(c);
3455 bc_lex_lineComment(l);
3461 if (isdigit(l->buf[l->i]))
3462 s = bc_lex_number(l, c);
3464 s = bc_error_bad_character(c);
3485 s = bc_lex_number(l, c);
3491 s = dc_lex_string(l);
3497 l->t.t = BC_LEX_INVALID;
3498 s = bc_error_bad_character(c);
3507 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3509 bc_program_addFunc(name, idx);
3510 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3513 static void bc_parse_pushName(BcParse *p, char *name)
3515 size_t i = 0, len = strlen(name);
3517 for (; i < len; ++i) bc_parse_push(p, name[i]);
3518 bc_parse_push(p, BC_PARSE_STREND);
3523 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3525 unsigned char amt, i, nums[sizeof(size_t)];
3527 for (amt = 0; idx; ++amt) {
3528 nums[amt] = (char) idx;
3529 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3532 bc_parse_push(p, amt);
3533 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3536 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3538 char *num = xstrdup(p->l.t.v.v);
3539 size_t idx = G.prog.consts.len;
3541 bc_vec_push(&G.prog.consts, &num);
3543 bc_parse_push(p, BC_INST_NUM);
3544 bc_parse_pushIndex(p, idx);
3547 (*prev) = BC_INST_NUM;
3550 static BcStatus bc_parse_text(BcParse *p, const char *text)
3554 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3556 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3557 p->l.t.t = BC_LEX_INVALID;
3560 if (!BC_PARSE_CAN_EXEC(p))
3561 return bc_error("file is not executable");
3564 return bc_lex_text(&p->l, text);
3567 // Called when bc/dc_parse_parse() detects a failure,
3568 // resets parsing structures.
3569 static void bc_parse_reset(BcParse *p)
3571 if (p->fidx != BC_PROG_MAIN) {
3572 p->func->nparams = 0;
3573 bc_vec_pop_all(&p->func->code);
3574 bc_vec_pop_all(&p->func->autos);
3575 bc_vec_pop_all(&p->func->labels);
3577 bc_parse_updateFunc(p, BC_PROG_MAIN);
3581 p->l.t.t = BC_LEX_EOF;
3582 p->auto_part = (p->nbraces = 0);
3584 bc_vec_npop(&p->flags, p->flags.len - 1);
3585 bc_vec_pop_all(&p->exits);
3586 bc_vec_pop_all(&p->conds);
3587 bc_vec_pop_all(&p->ops);
3592 static void bc_parse_free(BcParse *p)
3594 bc_vec_free(&p->flags);
3595 bc_vec_free(&p->exits);
3596 bc_vec_free(&p->conds);
3597 bc_vec_free(&p->ops);
3601 static void bc_parse_create(BcParse *p, size_t func,
3602 BcParseParse parse, BcLexNext next)
3604 memset(p, 0, sizeof(BcParse));
3606 bc_lex_init(&p->l, next);
3607 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3608 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3609 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3610 bc_vec_pushZeroByte(&p->flags);
3611 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3614 // p->auto_part = p->nbraces = 0; - already is
3615 bc_parse_updateFunc(p, func);
3619 static BcStatus bc_parse_else(BcParse *p);
3620 static BcStatus bc_parse_stmt(BcParse *p);
3622 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3623 size_t *nexprs, bool next)
3625 BcStatus s = BC_STATUS_SUCCESS;
3627 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3628 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3630 while (p->ops.len > start) {
3632 t = BC_PARSE_TOP_OP(p);
3633 if (t == BC_LEX_LPAREN) break;
3635 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3636 if (l >= r && (l != r || !left)) break;
3638 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3639 bc_vec_pop(&p->ops);
3640 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3643 bc_vec_push(&p->ops, &type);
3644 if (next) s = bc_lex_next(&p->l);
3649 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3653 if (p->ops.len <= ops_bgn)
3654 return bc_error_bad_expression();
3655 top = BC_PARSE_TOP_OP(p);
3657 while (top != BC_LEX_LPAREN) {
3659 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3661 bc_vec_pop(&p->ops);
3662 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3664 if (p->ops.len <= ops_bgn)
3665 return bc_error_bad_expression();
3666 top = BC_PARSE_TOP_OP(p);
3669 bc_vec_pop(&p->ops);
3671 return bc_lex_next(&p->l);
3674 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3680 s = bc_lex_next(&p->l);
3683 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3685 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3686 s = bc_parse_expr(p, flags, bc_parse_next_param);
3689 comma = p->l.t.t == BC_LEX_COMMA;
3691 s = bc_lex_next(&p->l);
3696 if (comma) return bc_error_bad_token();
3697 bc_parse_push(p, BC_INST_CALL);
3698 bc_parse_pushIndex(p, nparams);
3700 return BC_STATUS_SUCCESS;
3703 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3706 BcId entry, *entry_ptr;
3711 s = bc_parse_params(p, flags);
3714 if (p->l.t.t != BC_LEX_RPAREN) {
3715 s = bc_error_bad_token();
3719 idx = bc_map_index(&G.prog.fn_map, &entry);
3721 if (idx == BC_VEC_INVALID_IDX) {
3722 name = xstrdup(entry.name);
3723 bc_parse_addFunc(p, name, &idx);
3724 idx = bc_map_index(&G.prog.fn_map, &entry);
3730 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3731 bc_parse_pushIndex(p, entry_ptr->idx);
3733 return bc_lex_next(&p->l);
3740 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3745 name = xstrdup(p->l.t.v.v);
3746 s = bc_lex_next(&p->l);
3749 if (p->l.t.t == BC_LEX_LBRACKET) {
3751 s = bc_lex_next(&p->l);
3754 if (p->l.t.t == BC_LEX_RBRACKET) {
3756 if (!(flags & BC_PARSE_ARRAY)) {
3757 s = bc_error_bad_expression();
3761 *type = BC_INST_ARRAY;
3765 *type = BC_INST_ARRAY_ELEM;
3767 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3768 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3772 s = bc_lex_next(&p->l);
3774 bc_parse_push(p, *type);
3775 bc_parse_pushName(p, name);
3777 else if (p->l.t.t == BC_LEX_LPAREN) {
3779 if (flags & BC_PARSE_NOCALL) {
3780 s = bc_error_bad_token();
3784 *type = BC_INST_CALL;
3785 s = bc_parse_call(p, name, flags);
3788 *type = BC_INST_VAR;
3789 bc_parse_push(p, BC_INST_VAR);
3790 bc_parse_pushName(p, name);
3800 static BcStatus bc_parse_read(BcParse *p)
3804 s = bc_lex_next(&p->l);
3806 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3808 s = bc_lex_next(&p->l);
3810 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3812 bc_parse_push(p, BC_INST_READ);
3814 return bc_lex_next(&p->l);
3817 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3822 s = bc_lex_next(&p->l);
3824 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3826 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3828 s = bc_lex_next(&p->l);
3831 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3834 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3836 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3837 bc_parse_push(p, *prev);
3839 return bc_lex_next(&p->l);
3842 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3846 s = bc_lex_next(&p->l);
3849 if (p->l.t.t != BC_LEX_LPAREN) {
3850 *type = BC_INST_SCALE;
3851 bc_parse_push(p, BC_INST_SCALE);
3852 return BC_STATUS_SUCCESS;
3855 *type = BC_INST_SCALE_FUNC;
3856 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3858 s = bc_lex_next(&p->l);
3861 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3863 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3864 bc_parse_push(p, BC_INST_SCALE_FUNC);
3866 return bc_lex_next(&p->l);
3869 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3870 size_t *nexprs, uint8_t flags)
3875 BcInst etype = *prev;
3877 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3878 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3879 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3881 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3882 bc_parse_push(p, inst);
3883 s = bc_lex_next(&p->l);
3887 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3890 s = bc_lex_next(&p->l);
3894 // Because we parse the next part of the expression
3895 // right here, we need to increment this.
3896 *nexprs = *nexprs + 1;
3902 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3906 case BC_LEX_KEY_IBASE:
3907 case BC_LEX_KEY_LAST:
3908 case BC_LEX_KEY_OBASE:
3910 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3911 s = bc_lex_next(&p->l);
3915 case BC_LEX_KEY_SCALE:
3917 s = bc_lex_next(&p->l);
3919 if (p->l.t.t == BC_LEX_LPAREN)
3920 s = bc_error_bad_token();
3922 bc_parse_push(p, BC_INST_SCALE);
3928 s = bc_error_bad_token();
3933 if (!s) bc_parse_push(p, inst);
3939 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3940 bool rparen, size_t *nexprs)
3944 BcInst etype = *prev;
3946 s = bc_lex_next(&p->l);
3949 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3950 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3953 *prev = BC_PARSE_TOKEN_INST(type);
3955 // We can just push onto the op stack because this is the largest
3956 // precedence operator that gets pushed. Inc/dec does not.
3957 if (type != BC_LEX_OP_MINUS)
3958 bc_vec_push(&p->ops, &type);
3960 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3965 static BcStatus bc_parse_string(BcParse *p, char inst)
3967 char *str = xstrdup(p->l.t.v.v);
3969 bc_parse_push(p, BC_INST_STR);
3970 bc_parse_pushIndex(p, G.prog.strs.len);
3971 bc_vec_push(&G.prog.strs, &str);
3972 bc_parse_push(p, inst);
3974 return bc_lex_next(&p->l);
3977 static BcStatus bc_parse_print(BcParse *p)
3983 s = bc_lex_next(&p->l);
3988 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3989 return bc_error("bad print statement");
3991 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3993 if (type == BC_LEX_STR)
3994 s = bc_parse_string(p, BC_INST_PRINT_POP);
3996 s = bc_parse_expr(p, 0, bc_parse_next_print);
3998 bc_parse_push(p, BC_INST_PRINT_POP);
4003 comma = p->l.t.t == BC_LEX_COMMA;
4004 if (comma) s = bc_lex_next(&p->l);
4009 if (comma) return bc_error_bad_token();
4011 return bc_lex_next(&p->l);
4014 static BcStatus bc_parse_return(BcParse *p)
4020 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
4022 s = bc_lex_next(&p->l);
4026 paren = t == BC_LEX_LPAREN;
4028 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4029 bc_parse_push(p, BC_INST_RET0);
4032 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4033 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4036 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4037 bc_parse_push(p, BC_INST_RET0);
4038 s = bc_lex_next(&p->l);
4042 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4043 s = bc_posix_error("POSIX requires parentheses around return expressions");
4047 bc_parse_push(p, BC_INST_RET);
4053 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4055 BcStatus s = BC_STATUS_SUCCESS;
4057 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4058 return bc_error_bad_token();
4062 if (p->l.t.t == BC_LEX_RBRACE) {
4063 if (!p->nbraces) return bc_error_bad_token();
4065 s = bc_lex_next(&p->l);
4069 return bc_error_bad_token();
4072 if (BC_PARSE_IF(p)) {
4076 while (p->l.t.t == BC_LEX_NLINE) {
4077 s = bc_lex_next(&p->l);
4081 bc_vec_pop(&p->flags);
4083 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4084 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4086 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4088 else if (BC_PARSE_ELSE(p)) {
4093 bc_vec_pop(&p->flags);
4095 ip = bc_vec_top(&p->exits);
4096 label = bc_vec_item(&p->func->labels, ip->idx);
4097 *label = p->func->code.len;
4099 bc_vec_pop(&p->exits);
4101 else if (BC_PARSE_FUNC_INNER(p)) {
4102 bc_parse_push(p, BC_INST_RET0);
4103 bc_parse_updateFunc(p, BC_PROG_MAIN);
4104 bc_vec_pop(&p->flags);
4108 BcInstPtr *ip = bc_vec_top(&p->exits);
4109 size_t *label = bc_vec_top(&p->conds);
4111 bc_parse_push(p, BC_INST_JUMP);
4112 bc_parse_pushIndex(p, *label);
4114 label = bc_vec_item(&p->func->labels, ip->idx);
4115 *label = p->func->code.len;
4117 bc_vec_pop(&p->flags);
4118 bc_vec_pop(&p->exits);
4119 bc_vec_pop(&p->conds);
4125 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4127 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4128 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4129 flags |= BC_PARSE_FLAG_BODY;
4130 bc_vec_push(&p->flags, &flags);
4133 static void bc_parse_noElse(BcParse *p)
4137 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4139 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4141 ip = bc_vec_top(&p->exits);
4142 label = bc_vec_item(&p->func->labels, ip->idx);
4143 *label = p->func->code.len;
4145 bc_vec_pop(&p->exits);
4148 static BcStatus bc_parse_if(BcParse *p)
4153 s = bc_lex_next(&p->l);
4155 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4157 s = bc_lex_next(&p->l);
4159 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4161 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4163 s = bc_lex_next(&p->l);
4165 bc_parse_push(p, BC_INST_JUMP_ZERO);
4167 ip.idx = p->func->labels.len;
4168 ip.func = ip.len = 0;
4170 bc_parse_pushIndex(p, ip.idx);
4171 bc_vec_push(&p->exits, &ip);
4172 bc_vec_push(&p->func->labels, &ip.idx);
4173 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4175 return BC_STATUS_SUCCESS;
4178 static BcStatus bc_parse_else(BcParse *p)
4182 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4184 ip.idx = p->func->labels.len;
4185 ip.func = ip.len = 0;
4187 bc_parse_push(p, BC_INST_JUMP);
4188 bc_parse_pushIndex(p, ip.idx);
4192 bc_vec_push(&p->exits, &ip);
4193 bc_vec_push(&p->func->labels, &ip.idx);
4194 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4196 return bc_lex_next(&p->l);
4199 static BcStatus bc_parse_while(BcParse *p)
4204 s = bc_lex_next(&p->l);
4206 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4207 s = bc_lex_next(&p->l);
4210 ip.idx = p->func->labels.len;
4212 bc_vec_push(&p->func->labels, &p->func->code.len);
4213 bc_vec_push(&p->conds, &ip.idx);
4215 ip.idx = p->func->labels.len;
4219 bc_vec_push(&p->exits, &ip);
4220 bc_vec_push(&p->func->labels, &ip.idx);
4222 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4224 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4225 s = bc_lex_next(&p->l);
4228 bc_parse_push(p, BC_INST_JUMP_ZERO);
4229 bc_parse_pushIndex(p, ip.idx);
4230 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4232 return BC_STATUS_SUCCESS;
4235 static BcStatus bc_parse_for(BcParse *p)
4239 size_t cond_idx, exit_idx, body_idx, update_idx;
4241 s = bc_lex_next(&p->l);
4243 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4244 s = bc_lex_next(&p->l);
4247 if (p->l.t.t != BC_LEX_SCOLON)
4248 s = bc_parse_expr(p, 0, bc_parse_next_for);
4250 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4253 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4254 s = bc_lex_next(&p->l);
4257 cond_idx = p->func->labels.len;
4258 update_idx = cond_idx + 1;
4259 body_idx = update_idx + 1;
4260 exit_idx = body_idx + 1;
4262 bc_vec_push(&p->func->labels, &p->func->code.len);
4264 if (p->l.t.t != BC_LEX_SCOLON)
4265 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4267 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4270 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4272 s = bc_lex_next(&p->l);
4275 bc_parse_push(p, BC_INST_JUMP_ZERO);
4276 bc_parse_pushIndex(p, exit_idx);
4277 bc_parse_push(p, BC_INST_JUMP);
4278 bc_parse_pushIndex(p, body_idx);
4280 ip.idx = p->func->labels.len;
4282 bc_vec_push(&p->conds, &update_idx);
4283 bc_vec_push(&p->func->labels, &p->func->code.len);
4285 if (p->l.t.t != BC_LEX_RPAREN)
4286 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4288 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4292 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4293 bc_parse_push(p, BC_INST_JUMP);
4294 bc_parse_pushIndex(p, cond_idx);
4295 bc_vec_push(&p->func->labels, &p->func->code.len);
4301 bc_vec_push(&p->exits, &ip);
4302 bc_vec_push(&p->func->labels, &ip.idx);
4304 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4306 return BC_STATUS_SUCCESS;
4309 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4315 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4317 if (type == BC_LEX_KEY_BREAK) {
4319 if (p->exits.len == 0) return bc_error_bad_token();
4321 i = p->exits.len - 1;
4322 ip = bc_vec_item(&p->exits, i);
4324 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4325 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4330 i = *((size_t *) bc_vec_top(&p->conds));
4332 bc_parse_push(p, BC_INST_JUMP);
4333 bc_parse_pushIndex(p, i);
4335 s = bc_lex_next(&p->l);
4338 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4339 return bc_error_bad_token();
4341 return bc_lex_next(&p->l);
4344 static BcStatus bc_parse_func(BcParse *p)
4347 bool var, comma = false;
4351 s = bc_lex_next(&p->l);
4353 if (p->l.t.t != BC_LEX_NAME)
4354 return bc_error("bad function definition");
4356 name = xstrdup(p->l.t.v.v);
4357 bc_parse_addFunc(p, name, &p->fidx);
4359 s = bc_lex_next(&p->l);
4361 if (p->l.t.t != BC_LEX_LPAREN)
4362 return bc_error("bad function definition");
4363 s = bc_lex_next(&p->l);
4366 while (p->l.t.t != BC_LEX_RPAREN) {
4368 if (p->l.t.t != BC_LEX_NAME)
4369 return bc_error("bad function definition");
4373 name = xstrdup(p->l.t.v.v);
4374 s = bc_lex_next(&p->l);
4377 var = p->l.t.t != BC_LEX_LBRACKET;
4381 s = bc_lex_next(&p->l);
4384 if (p->l.t.t != BC_LEX_RBRACKET) {
4385 s = bc_error("bad function definition");
4389 s = bc_lex_next(&p->l);
4393 comma = p->l.t.t == BC_LEX_COMMA;
4395 s = bc_lex_next(&p->l);
4399 s = bc_func_insert(p->func, name, var);
4403 if (comma) return bc_error("bad function definition");
4405 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4406 bc_parse_startBody(p, flags);
4408 s = bc_lex_next(&p->l);
4411 if (p->l.t.t != BC_LEX_LBRACE)
4412 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4421 static BcStatus bc_parse_auto(BcParse *p)
4424 bool comma, var, one;
4427 if (!p->auto_part) return bc_error_bad_token();
4428 s = bc_lex_next(&p->l);
4431 p->auto_part = comma = false;
4432 one = p->l.t.t == BC_LEX_NAME;
4434 while (p->l.t.t == BC_LEX_NAME) {
4436 name = xstrdup(p->l.t.v.v);
4437 s = bc_lex_next(&p->l);
4440 var = p->l.t.t != BC_LEX_LBRACKET;
4443 s = bc_lex_next(&p->l);
4446 if (p->l.t.t != BC_LEX_RBRACKET) {
4447 s = bc_error("bad function definition");
4451 s = bc_lex_next(&p->l);
4455 comma = p->l.t.t == BC_LEX_COMMA;
4457 s = bc_lex_next(&p->l);
4461 s = bc_func_insert(p->func, name, var);
4465 if (comma) return bc_error("bad function definition");
4466 if (!one) return bc_error("no auto variable found");
4468 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4469 return bc_error_bad_token();
4471 return bc_lex_next(&p->l);
4478 static BcStatus bc_parse_body(BcParse *p, bool brace)
4480 BcStatus s = BC_STATUS_SUCCESS;
4481 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4483 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4485 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4487 if (!brace) return bc_error_bad_token();
4488 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4490 if (!p->auto_part) {
4491 s = bc_parse_auto(p);
4495 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4498 s = bc_parse_stmt(p);
4499 if (!s && !brace) s = bc_parse_endBody(p, false);
4505 static BcStatus bc_parse_stmt(BcParse *p)
4507 BcStatus s = BC_STATUS_SUCCESS;
4513 return bc_lex_next(&p->l);
4516 case BC_LEX_KEY_ELSE:
4518 p->auto_part = false;
4524 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4527 s = bc_lex_next(&p->l);
4530 return bc_parse_body(p, true);
4533 case BC_LEX_KEY_AUTO:
4535 return bc_parse_auto(p);
4540 p->auto_part = false;
4542 if (BC_PARSE_IF_END(p)) {
4544 return BC_STATUS_SUCCESS;
4546 else if (BC_PARSE_BODY(p))
4547 return bc_parse_body(p, false);
4557 case BC_LEX_OP_MINUS:
4558 case BC_LEX_OP_BOOL_NOT:
4562 case BC_LEX_KEY_IBASE:
4563 case BC_LEX_KEY_LAST:
4564 case BC_LEX_KEY_LENGTH:
4565 case BC_LEX_KEY_OBASE:
4566 case BC_LEX_KEY_READ:
4567 case BC_LEX_KEY_SCALE:
4568 case BC_LEX_KEY_SQRT:
4570 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4574 case BC_LEX_KEY_ELSE:
4576 s = bc_parse_else(p);
4582 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4588 s = bc_parse_endBody(p, true);
4594 s = bc_parse_string(p, BC_INST_PRINT_STR);
4598 case BC_LEX_KEY_BREAK:
4599 case BC_LEX_KEY_CONTINUE:
4601 s = bc_parse_loopExit(p, p->l.t.t);
4605 case BC_LEX_KEY_FOR:
4607 s = bc_parse_for(p);
4611 case BC_LEX_KEY_HALT:
4613 bc_parse_push(p, BC_INST_HALT);
4614 s = bc_lex_next(&p->l);
4624 case BC_LEX_KEY_LIMITS:
4626 // "limits" is a compile-time command,
4627 // the output is produced at _parse time_.
4628 s = bc_lex_next(&p->l);
4630 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4631 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4632 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4633 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4634 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4635 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4636 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4637 printf("Number of vars = %lu\n", BC_MAX_VARS);
4641 case BC_LEX_KEY_PRINT:
4643 s = bc_parse_print(p);
4647 case BC_LEX_KEY_QUIT:
4649 // "quit" is a compile-time command. For example,
4650 // "if (0 == 1) quit" terminates when parsing the statement,
4651 // not when it is executed
4655 case BC_LEX_KEY_RETURN:
4657 s = bc_parse_return(p);
4661 case BC_LEX_KEY_WHILE:
4663 s = bc_parse_while(p);
4669 s = bc_error_bad_token();
4677 static BcStatus bc_parse_parse(BcParse *p)
4681 if (p->l.t.t == BC_LEX_EOF)
4682 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4683 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4684 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4685 s = bc_parse_func(p);
4688 s = bc_parse_stmt(p);
4690 if (s || G_interrupt) {
4692 s = BC_STATUS_FAILURE;
4698 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4700 BcStatus s = BC_STATUS_SUCCESS;
4701 BcInst prev = BC_INST_PRINT;
4702 BcLexType top, t = p->l.t.t;
4703 size_t nexprs = 0, ops_bgn = p->ops.len;
4704 uint32_t i, nparens, nrelops;
4705 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4707 paren_first = p->l.t.t == BC_LEX_LPAREN;
4708 nparens = nrelops = 0;
4709 paren_expr = rprn = done = get_token = assign = false;
4712 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4718 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4719 rprn = get_token = bin_last = false;
4723 case BC_LEX_OP_MINUS:
4725 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4726 rprn = get_token = false;
4727 bin_last = prev == BC_INST_MINUS;
4731 case BC_LEX_OP_ASSIGN_POWER:
4732 case BC_LEX_OP_ASSIGN_MULTIPLY:
4733 case BC_LEX_OP_ASSIGN_DIVIDE:
4734 case BC_LEX_OP_ASSIGN_MODULUS:
4735 case BC_LEX_OP_ASSIGN_PLUS:
4736 case BC_LEX_OP_ASSIGN_MINUS:
4737 case BC_LEX_OP_ASSIGN:
4739 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4740 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4741 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4743 s = bc_error("bad assignment:"
4744 " left side must be scale,"
4745 " ibase, obase, last, var,"
4752 case BC_LEX_OP_POWER:
4753 case BC_LEX_OP_MULTIPLY:
4754 case BC_LEX_OP_DIVIDE:
4755 case BC_LEX_OP_MODULUS:
4756 case BC_LEX_OP_PLUS:
4757 case BC_LEX_OP_REL_EQ:
4758 case BC_LEX_OP_REL_LE:
4759 case BC_LEX_OP_REL_GE:
4760 case BC_LEX_OP_REL_NE:
4761 case BC_LEX_OP_REL_LT:
4762 case BC_LEX_OP_REL_GT:
4763 case BC_LEX_OP_BOOL_NOT:
4764 case BC_LEX_OP_BOOL_OR:
4765 case BC_LEX_OP_BOOL_AND:
4767 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4768 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4770 return bc_error_bad_expression();
4773 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4774 prev = BC_PARSE_TOKEN_INST(t);
4775 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4776 rprn = get_token = false;
4777 bin_last = t != BC_LEX_OP_BOOL_NOT;
4784 if (BC_PARSE_LEAF(prev, rprn))
4785 return bc_error_bad_expression();
4787 paren_expr = rprn = bin_last = false;
4789 bc_vec_push(&p->ops, &t);
4796 if (bin_last || prev == BC_INST_BOOL_NOT)
4797 return bc_error_bad_expression();
4800 s = BC_STATUS_SUCCESS;
4805 else if (!paren_expr)
4806 return BC_STATUS_PARSE_EMPTY_EXP;
4809 paren_expr = rprn = true;
4810 get_token = bin_last = false;
4812 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4819 if (BC_PARSE_LEAF(prev, rprn))
4820 return bc_error_bad_expression();
4822 rprn = get_token = bin_last = false;
4823 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4831 if (BC_PARSE_LEAF(prev, rprn))
4832 return bc_error_bad_expression();
4833 bc_parse_number(p, &prev, &nexprs);
4834 paren_expr = get_token = true;
4835 rprn = bin_last = false;
4840 case BC_LEX_KEY_IBASE:
4841 case BC_LEX_KEY_LAST:
4842 case BC_LEX_KEY_OBASE:
4844 if (BC_PARSE_LEAF(prev, rprn))
4845 return bc_error_bad_expression();
4846 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4847 bc_parse_push(p, (char) prev);
4849 paren_expr = get_token = true;
4850 rprn = bin_last = false;
4856 case BC_LEX_KEY_LENGTH:
4857 case BC_LEX_KEY_SQRT:
4859 if (BC_PARSE_LEAF(prev, rprn))
4860 return bc_error_bad_expression();
4861 s = bc_parse_builtin(p, t, flags, &prev);
4863 rprn = get_token = bin_last = false;
4869 case BC_LEX_KEY_READ:
4871 if (BC_PARSE_LEAF(prev, rprn))
4872 return bc_error_bad_expression();
4873 else if (flags & BC_PARSE_NOREAD)
4874 s = bc_error_nested_read_call();
4876 s = bc_parse_read(p);
4879 rprn = get_token = bin_last = false;
4881 prev = BC_INST_READ;
4886 case BC_LEX_KEY_SCALE:
4888 if (BC_PARSE_LEAF(prev, rprn))
4889 return bc_error_bad_expression();
4890 s = bc_parse_scale(p, &prev, flags);
4892 rprn = get_token = bin_last = false;
4894 prev = BC_INST_SCALE;
4901 s = bc_error_bad_token();
4906 if (!s && get_token) s = bc_lex_next(&p->l);
4910 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4912 while (p->ops.len > ops_bgn) {
4914 top = BC_PARSE_TOP_OP(p);
4915 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4917 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4918 return bc_error_bad_expression();
4920 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4922 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4923 bc_vec_pop(&p->ops);
4926 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4927 return bc_error_bad_expression();
4929 for (i = 0; i < next.len; ++i)
4930 if (t == next.tokens[i])
4932 return bc_error_bad_expression();
4935 if (!(flags & BC_PARSE_REL) && nrelops) {
4936 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4939 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4940 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4944 if (flags & BC_PARSE_PRINT) {
4945 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4946 bc_parse_push(p, BC_INST_POP);
4952 static void bc_parse_init(BcParse *p, size_t func)
4954 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4957 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4959 return bc_parse_expr(p, flags, bc_parse_next_read);
4964 static BcStatus dc_parse_register(BcParse *p)
4969 s = bc_lex_next(&p->l);
4971 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4973 name = xstrdup(p->l.t.v.v);
4974 bc_parse_pushName(p, name);
4979 static BcStatus dc_parse_string(BcParse *p)
4981 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4982 size_t idx, len = G.prog.strs.len;
4984 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4987 str = xstrdup(p->l.t.v.v);
4988 bc_parse_push(p, BC_INST_STR);
4989 bc_parse_pushIndex(p, len);
4990 bc_vec_push(&G.prog.strs, &str);
4991 bc_parse_addFunc(p, name, &idx);
4993 return bc_lex_next(&p->l);
4996 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5000 bc_parse_push(p, inst);
5002 s = dc_parse_register(p);
5007 bc_parse_push(p, BC_INST_SWAP);
5008 bc_parse_push(p, BC_INST_ASSIGN);
5009 bc_parse_push(p, BC_INST_POP);
5012 return bc_lex_next(&p->l);
5015 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5019 bc_parse_push(p, inst);
5020 bc_parse_push(p, BC_INST_EXEC_COND);
5022 s = dc_parse_register(p);
5025 s = bc_lex_next(&p->l);
5028 if (p->l.t.t == BC_LEX_ELSE) {
5029 s = dc_parse_register(p);
5031 s = bc_lex_next(&p->l);
5034 bc_parse_push(p, BC_PARSE_STREND);
5039 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5041 BcStatus s = BC_STATUS_SUCCESS;
5044 bool assign, get_token = false;
5048 case BC_LEX_OP_REL_EQ:
5049 case BC_LEX_OP_REL_LE:
5050 case BC_LEX_OP_REL_GE:
5051 case BC_LEX_OP_REL_NE:
5052 case BC_LEX_OP_REL_LT:
5053 case BC_LEX_OP_REL_GT:
5055 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5062 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5068 s = dc_parse_string(p);
5075 if (t == BC_LEX_NEG) {
5076 s = bc_lex_next(&p->l);
5078 if (p->l.t.t != BC_LEX_NUMBER)
5079 return bc_error_bad_token();
5082 bc_parse_number(p, &prev, &p->nbraces);
5084 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5090 case BC_LEX_KEY_READ:
5092 if (flags & BC_PARSE_NOREAD)
5093 s = bc_error_nested_read_call();
5095 bc_parse_push(p, BC_INST_READ);
5100 case BC_LEX_OP_ASSIGN:
5101 case BC_LEX_STORE_PUSH:
5103 assign = t == BC_LEX_OP_ASSIGN;
5104 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5105 s = dc_parse_mem(p, inst, true, assign);
5110 case BC_LEX_LOAD_POP:
5112 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5113 s = dc_parse_mem(p, inst, true, false);
5117 case BC_LEX_STORE_IBASE:
5118 case BC_LEX_STORE_SCALE:
5119 case BC_LEX_STORE_OBASE:
5121 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5122 s = dc_parse_mem(p, inst, false, true);
5128 s = bc_error_bad_token();
5134 if (!s && get_token) s = bc_lex_next(&p->l);
5139 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5141 BcStatus s = BC_STATUS_SUCCESS;
5145 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5147 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5149 inst = dc_parse_insts[t];
5151 if (inst != BC_INST_INVALID) {
5152 bc_parse_push(p, inst);
5153 s = bc_lex_next(&p->l);
5156 s = dc_parse_token(p, t, flags);
5159 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5160 bc_parse_push(p, BC_INST_POP_EXEC);
5165 static BcStatus dc_parse_parse(BcParse *p)
5169 if (p->l.t.t == BC_LEX_EOF)
5170 s = bc_error("end of file");
5172 s = dc_parse_expr(p, 0);
5174 if (s || G_interrupt) {
5176 s = BC_STATUS_FAILURE;
5182 static void dc_parse_init(BcParse *p, size_t func)
5184 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5188 static void common_parse_init(BcParse *p, size_t func)
5191 bc_parse_init(p, func);
5193 dc_parse_init(p, func);
5197 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5200 return bc_parse_expression(p, flags);
5202 return dc_parse_expr(p, flags);
5206 static BcVec* bc_program_search(char *id, bool var)
5214 v = var ? &G.prog.vars : &G.prog.arrs;
5215 map = var ? &G.prog.var_map : &G.prog.arr_map;
5219 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5222 bc_array_init(&data.v, var);
5223 bc_vec_push(v, &data.v);
5226 ptr = bc_vec_item(map, i);
5227 if (new) ptr->name = xstrdup(e.name);
5228 return bc_vec_item(v, ptr->idx);
5231 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5233 BcStatus s = BC_STATUS_SUCCESS;
5238 case BC_RESULT_TEMP:
5239 case BC_RESULT_IBASE:
5240 case BC_RESULT_SCALE:
5241 case BC_RESULT_OBASE:
5247 case BC_RESULT_CONSTANT:
5249 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5250 size_t base_t, len = strlen(*str);
5253 bc_num_init(&r->d.n, len);
5255 hex = hex && len == 1;
5256 base = hex ? &G.prog.hexb : &G.prog.ib;
5257 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5258 s = bc_num_parse(&r->d.n, *str, base, base_t);
5261 bc_num_free(&r->d.n);
5266 r->t = BC_RESULT_TEMP;
5272 case BC_RESULT_ARRAY:
5273 case BC_RESULT_ARRAY_ELEM:
5277 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5279 if (r->t == BC_RESULT_ARRAY_ELEM) {
5281 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5282 *num = bc_vec_item(v, r->d.id.idx);
5285 *num = bc_vec_top(v);
5290 case BC_RESULT_LAST:
5292 *num = &G.prog.last;
5306 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5307 BcResult **r, BcNum **rn, bool assign)
5311 BcResultType lt, rt;
5313 if (!BC_PROG_STACK(&G.prog.results, 2))
5314 return bc_error_stack_has_too_few_elements();
5316 *r = bc_vec_item_rev(&G.prog.results, 0);
5317 *l = bc_vec_item_rev(&G.prog.results, 1);
5321 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5323 s = bc_program_num(*l, ln, false);
5325 s = bc_program_num(*r, rn, hex);
5328 // We run this again under these conditions in case any vector has been
5329 // reallocated out from under the BcNums or arrays we had.
5330 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5331 s = bc_program_num(*l, ln, false);
5335 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5336 return bc_error_variable_is_wrong_type();
5337 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5338 return bc_error_variable_is_wrong_type();
5343 static void bc_program_binOpRetire(BcResult *r)
5345 r->t = BC_RESULT_TEMP;
5346 bc_vec_pop(&G.prog.results);
5347 bc_vec_pop(&G.prog.results);
5348 bc_vec_push(&G.prog.results, r);
5351 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5355 if (!BC_PROG_STACK(&G.prog.results, 1))
5356 return bc_error_stack_has_too_few_elements();
5357 *r = bc_vec_top(&G.prog.results);
5359 s = bc_program_num(*r, n, false);
5362 if (!BC_PROG_NUM((*r), (*n)))
5363 return bc_error_variable_is_wrong_type();
5368 static void bc_program_retire(BcResult *r, BcResultType t)
5371 bc_vec_pop(&G.prog.results);
5372 bc_vec_push(&G.prog.results, r);
5375 static BcStatus bc_program_op(char inst)
5378 BcResult *opd1, *opd2, res;
5379 BcNum *n1, *n2 = NULL;
5381 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5383 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5385 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5387 bc_program_binOpRetire(&res);
5392 bc_num_free(&res.d.n);
5396 static BcStatus bc_program_read(void)
5398 const char *sv_file;
5404 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5406 for (i = 0; i < G.prog.stack.len; ++i) {
5407 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5408 if (ip_ptr->func == BC_PROG_READ)
5409 return bc_error_nested_read_call();
5412 bc_vec_pop_all(&f->code);
5413 bc_char_vec_init(&buf);
5415 sv_file = G.prog.file;
5418 s = bc_read_line(&buf, "read> ");
5421 common_parse_init(&parse, BC_PROG_READ);
5422 bc_lex_file(&parse.l);
5424 s = bc_parse_text(&parse, buf.v);
5425 if (s) goto exec_err;
5426 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5427 if (s) goto exec_err;
5429 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5430 s = bc_error("bad read() expression");
5434 ip.func = BC_PROG_READ;
5436 ip.len = G.prog.results.len;
5438 // Update this pointer, just in case.
5439 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5441 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5442 bc_vec_push(&G.prog.stack, &ip);
5445 G.prog.file = sv_file;
5446 bc_parse_free(&parse);
5452 static size_t bc_program_index(char *code, size_t *bgn)
5454 char amt = code[(*bgn)++], i = 0;
5457 for (; i < amt; ++i, ++(*bgn))
5458 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5463 static char *bc_program_name(char *code, size_t *bgn)
5466 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5468 s = xmalloc(ptr - str + 1);
5471 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5479 static void bc_program_printString(const char *str, size_t *nchars)
5481 size_t i, len = strlen(str);
5490 for (i = 0; i < len; ++i, ++(*nchars)) {
5494 if (c != '\\' || i == len - 1)
5554 // Just print the backslash and following character.
5565 static BcStatus bc_program_print(char inst, size_t idx)
5567 BcStatus s = BC_STATUS_SUCCESS;
5572 bool pop = inst != BC_INST_PRINT;
5574 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5575 return bc_error_stack_has_too_few_elements();
5577 r = bc_vec_item_rev(&G.prog.results, idx);
5578 s = bc_program_num(r, &num, false);
5581 if (BC_PROG_NUM(r, num)) {
5582 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5583 if (!s) bc_num_copy(&G.prog.last, num);
5587 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5588 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5590 if (inst == BC_INST_PRINT_STR) {
5591 for (i = 0, len = strlen(str); i < len; ++i) {
5594 if (c == '\n') G.prog.nchars = SIZE_MAX;
5599 bc_program_printString(str, &G.prog.nchars);
5600 if (inst == BC_INST_PRINT) bb_putchar('\n');
5604 if (!s && pop) bc_vec_pop(&G.prog.results);
5609 static BcStatus bc_program_negate(void)
5615 s = bc_program_prep(&ptr, &num);
5618 bc_num_init(&res.d.n, num->len);
5619 bc_num_copy(&res.d.n, num);
5620 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5622 bc_program_retire(&res, BC_RESULT_TEMP);
5627 static BcStatus bc_program_logical(char inst)
5630 BcResult *opd1, *opd2, res;
5635 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5637 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5639 if (inst == BC_INST_BOOL_AND)
5640 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5641 else if (inst == BC_INST_BOOL_OR)
5642 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5645 cmp = bc_num_cmp(n1, n2);
5649 case BC_INST_REL_EQ:
5655 case BC_INST_REL_LE:
5661 case BC_INST_REL_GE:
5667 case BC_INST_REL_NE:
5673 case BC_INST_REL_LT:
5679 case BC_INST_REL_GT:
5687 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5689 bc_program_binOpRetire(&res);
5695 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5701 memset(&n2, 0, sizeof(BcNum));
5702 n2.rdx = res.d.id.idx = r->d.id.idx;
5703 res.t = BC_RESULT_STR;
5706 if (!BC_PROG_STACK(&G.prog.results, 2))
5707 return bc_error_stack_has_too_few_elements();
5709 bc_vec_pop(&G.prog.results);
5712 bc_vec_pop(&G.prog.results);
5714 bc_vec_push(&G.prog.results, &res);
5715 bc_vec_push(v, &n2);
5717 return BC_STATUS_SUCCESS;
5721 static BcStatus bc_program_copyToVar(char *name, bool var)
5728 if (!BC_PROG_STACK(&G.prog.results, 1))
5729 return bc_error_stack_has_too_few_elements();
5731 ptr = bc_vec_top(&G.prog.results);
5732 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5733 return bc_error_variable_is_wrong_type();
5734 v = bc_program_search(name, var);
5737 if (ptr->t == BC_RESULT_STR && !var)
5738 return bc_error_variable_is_wrong_type();
5739 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5742 s = bc_program_num(ptr, &n, false);
5745 // Do this once more to make sure that pointers were not invalidated.
5746 v = bc_program_search(name, var);
5749 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5750 bc_num_copy(&r.d.n, n);
5753 bc_array_init(&r.d.v, true);
5754 bc_array_copy(&r.d.v, (BcVec *) n);
5757 bc_vec_push(v, &r.d);
5758 bc_vec_pop(&G.prog.results);
5763 static BcStatus bc_program_assign(char inst)
5766 BcResult *left, *right, res;
5767 BcNum *l = NULL, *r = NULL;
5768 unsigned long val, max;
5769 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5771 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5774 ib = left->t == BC_RESULT_IBASE;
5775 sc = left->t == BC_RESULT_SCALE;
5779 if (right->t == BC_RESULT_STR) {
5783 if (left->t != BC_RESULT_VAR)
5784 return bc_error_variable_is_wrong_type();
5785 v = bc_program_search(left->d.id.name, true);
5787 return bc_program_assignStr(right, v, false);
5791 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5792 return bc_error("bad assignment:"
5793 " left side must be scale,"
5794 " ibase, obase, last, var,"
5799 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5800 return bc_error("divide by zero");
5805 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5812 if (ib || sc || left->t == BC_RESULT_OBASE) {
5813 static const char *const msg[] = {
5814 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5815 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5816 "?1", //BC_RESULT_LAST
5817 "?2", //BC_RESULT_CONSTANT
5818 "?3", //BC_RESULT_ONE
5819 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5823 s = bc_num_ulong(l, &val);
5826 s = left->t - BC_RESULT_IBASE;
5829 ptr = &G.prog.scale;
5832 if (val < BC_NUM_MIN_BASE)
5833 return bc_error(msg[s]);
5834 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5835 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5839 return bc_error(msg[s]);
5841 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5843 *ptr = (size_t) val;
5844 s = BC_STATUS_SUCCESS;
5847 bc_num_init(&res.d.n, l->len);
5848 bc_num_copy(&res.d.n, l);
5849 bc_program_binOpRetire(&res);
5855 #define bc_program_pushVar(code, bgn, pop, copy) \
5856 bc_program_pushVar(code, bgn)
5857 // for bc, 'pop' and 'copy' are always false
5859 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5860 bool pop, bool copy)
5862 BcStatus s = BC_STATUS_SUCCESS;
5864 char *name = bc_program_name(code, bgn);
5866 r.t = BC_RESULT_VAR;
5871 BcVec *v = bc_program_search(name, true);
5872 BcNum *num = bc_vec_top(v);
5876 if (!BC_PROG_STACK(v, 2 - copy)) {
5878 return bc_error_stack_has_too_few_elements();
5884 if (!BC_PROG_STR(num)) {
5886 r.t = BC_RESULT_TEMP;
5888 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5889 bc_num_copy(&r.d.n, num);
5892 r.t = BC_RESULT_STR;
5893 r.d.id.idx = num->rdx;
5896 if (!copy) bc_vec_pop(v);
5901 bc_vec_push(&G.prog.results, &r);
5906 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5909 BcStatus s = BC_STATUS_SUCCESS;
5913 r.d.id.name = bc_program_name(code, bgn);
5915 if (inst == BC_INST_ARRAY) {
5916 r.t = BC_RESULT_ARRAY;
5917 bc_vec_push(&G.prog.results, &r);
5924 s = bc_program_prep(&operand, &num);
5926 s = bc_num_ulong(num, &temp);
5929 if (temp > BC_MAX_DIM) {
5930 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5934 r.d.id.idx = (size_t) temp;
5935 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5939 if (s) free(r.d.id.name);
5944 static BcStatus bc_program_incdec(char inst)
5947 BcResult *ptr, res, copy;
5951 s = bc_program_prep(&ptr, &num);
5954 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5955 copy.t = BC_RESULT_TEMP;
5956 bc_num_init(©.d.n, num->len);
5957 bc_num_copy(©.d.n, num);
5960 res.t = BC_RESULT_ONE;
5961 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5962 BC_INST_ASSIGN_PLUS :
5963 BC_INST_ASSIGN_MINUS;
5965 bc_vec_push(&G.prog.results, &res);
5966 bc_program_assign(inst);
5968 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5969 bc_vec_pop(&G.prog.results);
5970 bc_vec_push(&G.prog.results, ©);
5976 static BcStatus bc_program_call(char *code, size_t *idx)
5978 BcStatus s = BC_STATUS_SUCCESS;
5980 size_t i, nparams = bc_program_index(code, idx);
5987 ip.func = bc_program_index(code, idx);
5988 func = bc_vec_item(&G.prog.fns, ip.func);
5990 if (func->code.len == 0) {
5991 return bc_error("undefined function");
5993 if (nparams != func->nparams) {
5994 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5996 ip.len = G.prog.results.len - nparams;
5998 for (i = 0; i < nparams; ++i) {
6000 a = bc_vec_item(&func->autos, nparams - 1 - i);
6001 arg = bc_vec_top(&G.prog.results);
6003 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6004 return bc_error_variable_is_wrong_type();
6006 s = bc_program_copyToVar(a->name, a->idx);
6010 for (; i < func->autos.len; ++i) {
6013 a = bc_vec_item(&func->autos, i);
6014 v = bc_program_search(a->name, a->idx);
6017 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6018 bc_vec_push(v, ¶m.n);
6021 bc_array_init(¶m.v, true);
6022 bc_vec_push(v, ¶m.v);
6026 bc_vec_push(&G.prog.stack, &ip);
6028 return BC_STATUS_SUCCESS;
6031 static BcStatus bc_program_return(char inst)
6037 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6039 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6040 return bc_error_stack_has_too_few_elements();
6042 f = bc_vec_item(&G.prog.fns, ip->func);
6043 res.t = BC_RESULT_TEMP;
6045 if (inst == BC_INST_RET) {
6048 BcResult *operand = bc_vec_top(&G.prog.results);
6050 s = bc_program_num(operand, &num, false);
6052 bc_num_init(&res.d.n, num->len);
6053 bc_num_copy(&res.d.n, num);
6056 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6057 bc_num_zero(&res.d.n);
6060 // We need to pop arguments as well, so this takes that into account.
6061 for (i = 0; i < f->autos.len; ++i) {
6064 BcId *a = bc_vec_item(&f->autos, i);
6066 v = bc_program_search(a->name, a->idx);
6070 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6071 bc_vec_push(&G.prog.results, &res);
6072 bc_vec_pop(&G.prog.stack);
6074 return BC_STATUS_SUCCESS;
6078 static unsigned long bc_program_scale(BcNum *n)
6080 return (unsigned long) n->rdx;
6083 static unsigned long bc_program_len(BcNum *n)
6085 unsigned long len = n->len;
6088 if (n->rdx != n->len) return len;
6089 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6094 static BcStatus bc_program_builtin(char inst)
6100 bool len = inst == BC_INST_LENGTH;
6102 if (!BC_PROG_STACK(&G.prog.results, 1))
6103 return bc_error_stack_has_too_few_elements();
6104 opnd = bc_vec_top(&G.prog.results);
6106 s = bc_program_num(opnd, &num, false);
6110 if (!BC_PROG_NUM(opnd, num) && !len)
6111 return bc_error_variable_is_wrong_type();
6114 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6116 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6118 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6119 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6123 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6126 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6128 str = bc_vec_item(&G.prog.strs, idx);
6129 bc_num_ulong2num(&res.d.n, strlen(*str));
6133 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6134 bc_num_ulong2num(&res.d.n, f(num));
6137 bc_program_retire(&res, BC_RESULT_TEMP);
6143 static BcStatus bc_program_divmod(void)
6146 BcResult *opd1, *opd2, res, res2;
6147 BcNum *n1, *n2 = NULL;
6149 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6152 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6153 bc_num_init(&res2.d.n, n2->len);
6155 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6158 bc_program_binOpRetire(&res2);
6159 res.t = BC_RESULT_TEMP;
6160 bc_vec_push(&G.prog.results, &res);
6165 bc_num_free(&res2.d.n);
6166 bc_num_free(&res.d.n);
6170 static BcStatus bc_program_modexp(void)
6173 BcResult *r1, *r2, *r3, res;
6174 BcNum *n1, *n2, *n3;
6176 if (!BC_PROG_STACK(&G.prog.results, 3))
6177 return bc_error_stack_has_too_few_elements();
6178 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6181 r1 = bc_vec_item_rev(&G.prog.results, 2);
6182 s = bc_program_num(r1, &n1, false);
6184 if (!BC_PROG_NUM(r1, n1))
6185 return bc_error_variable_is_wrong_type();
6187 // Make sure that the values have their pointers updated, if necessary.
6188 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6190 if (r1->t == r2->t) {
6191 s = bc_program_num(r2, &n2, false);
6195 if (r1->t == r3->t) {
6196 s = bc_program_num(r3, &n3, false);
6201 bc_num_init(&res.d.n, n3->len);
6202 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6205 bc_vec_pop(&G.prog.results);
6206 bc_program_binOpRetire(&res);
6211 bc_num_free(&res.d.n);
6215 static void bc_program_stackLen(void)
6218 size_t len = G.prog.results.len;
6220 res.t = BC_RESULT_TEMP;
6222 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6223 bc_num_ulong2num(&res.d.n, len);
6224 bc_vec_push(&G.prog.results, &res);
6227 static BcStatus bc_program_asciify(void)
6231 BcNum *num = NULL, n;
6232 char *str, *str2, c;
6233 size_t len = G.prog.strs.len, idx;
6236 if (!BC_PROG_STACK(&G.prog.results, 1))
6237 return bc_error_stack_has_too_few_elements();
6238 r = bc_vec_top(&G.prog.results);
6240 s = bc_program_num(r, &num, false);
6243 if (BC_PROG_NUM(r, num)) {
6245 bc_num_init(&n, BC_NUM_DEF_SIZE);
6246 bc_num_copy(&n, num);
6247 bc_num_truncate(&n, n.rdx);
6249 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6250 if (s) goto num_err;
6251 s = bc_num_ulong(&n, &val);
6252 if (s) goto num_err;
6259 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6260 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6268 str2 = xstrdup(str);
6269 bc_program_addFunc(str2, &idx);
6271 if (idx != len + BC_PROG_REQ_FUNCS) {
6273 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6274 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6283 bc_vec_push(&G.prog.strs, &str);
6285 res.t = BC_RESULT_STR;
6287 bc_vec_pop(&G.prog.results);
6288 bc_vec_push(&G.prog.results, &res);
6290 return BC_STATUS_SUCCESS;
6297 static BcStatus bc_program_printStream(void)
6305 if (!BC_PROG_STACK(&G.prog.results, 1))
6306 return bc_error_stack_has_too_few_elements();
6307 r = bc_vec_top(&G.prog.results);
6309 s = bc_program_num(r, &n, false);
6312 if (BC_PROG_NUM(r, n))
6313 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6315 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6316 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6323 static BcStatus bc_program_nquit(void)
6330 s = bc_program_prep(&opnd, &num);
6332 s = bc_num_ulong(num, &val);
6335 bc_vec_pop(&G.prog.results);
6337 if (G.prog.stack.len < val)
6338 return bc_error_stack_has_too_few_elements();
6339 if (G.prog.stack.len == val)
6342 bc_vec_npop(&G.prog.stack, val);
6347 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6350 BcStatus s = BC_STATUS_SUCCESS;
6360 if (!BC_PROG_STACK(&G.prog.results, 1))
6361 return bc_error_stack_has_too_few_elements();
6363 r = bc_vec_top(&G.prog.results);
6367 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6369 if (code[*bgn] == BC_PARSE_STREND)
6372 else_name = bc_program_name(code, bgn);
6374 exec = r->d.n.len != 0;
6378 else if (else_name != NULL) {
6385 v = bc_program_search(name, true);
6392 if (!exec) goto exit;
6393 if (!BC_PROG_STR(n)) {
6394 s = bc_error_variable_is_wrong_type();
6402 if (r->t == BC_RESULT_STR)
6404 else if (r->t == BC_RESULT_VAR) {
6405 s = bc_program_num(r, &n, false);
6406 if (s || !BC_PROG_STR(n)) goto exit;
6413 fidx = sidx + BC_PROG_REQ_FUNCS;
6415 str = bc_vec_item(&G.prog.strs, sidx);
6416 f = bc_vec_item(&G.prog.fns, fidx);
6418 if (f->code.len == 0) {
6419 common_parse_init(&prs, fidx);
6420 s = bc_parse_text(&prs, *str);
6422 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6425 if (prs.l.t.t != BC_LEX_EOF) {
6426 s = bc_error_bad_expression();
6430 bc_parse_free(&prs);
6434 ip.len = G.prog.results.len;
6437 bc_vec_pop(&G.prog.results);
6438 bc_vec_push(&G.prog.stack, &ip);
6440 return BC_STATUS_SUCCESS;
6443 bc_parse_free(&prs);
6444 f = bc_vec_item(&G.prog.fns, fidx);
6445 bc_vec_pop_all(&f->code);
6447 bc_vec_pop(&G.prog.results);
6452 static void bc_program_pushGlobal(char inst)
6457 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6458 if (inst == BC_INST_IBASE)
6459 val = (unsigned long) G.prog.ib_t;
6460 else if (inst == BC_INST_SCALE)
6461 val = (unsigned long) G.prog.scale;
6463 val = (unsigned long) G.prog.ob_t;
6465 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6466 bc_num_ulong2num(&res.d.n, val);
6467 bc_vec_push(&G.prog.results, &res);
6470 static void bc_program_addFunc(char *name, size_t *idx)
6472 BcId entry, *entry_ptr;
6477 entry.idx = G.prog.fns.len;
6479 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6480 if (!inserted) free(name);
6482 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6483 *idx = entry_ptr->idx;
6487 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6489 // We need to reset these, so the function can be repopulated.
6491 bc_vec_pop_all(&func->autos);
6492 bc_vec_pop_all(&func->code);
6493 bc_vec_pop_all(&func->labels);
6497 bc_vec_push(&G.prog.fns, &f);
6501 // Called when parsing or execution detects a failure,
6502 // resets execution structures.
6503 static void bc_program_reset(void)
6508 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6509 bc_vec_pop_all(&G.prog.results);
6511 f = bc_vec_item(&G.prog.fns, 0);
6512 ip = bc_vec_top(&G.prog.stack);
6513 ip->idx = f->code.len;
6515 // If !tty, no need to check for ^C: we don't have ^C handler,
6516 // we would be killed by a signal and won't reach this place
6519 static BcStatus bc_program_exec(void)
6521 BcStatus s = BC_STATUS_SUCCESS;
6525 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6526 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6527 char *code = func->code.v;
6530 while (!s && ip->idx < func->code.len) {
6532 char inst = code[(ip->idx)++];
6537 case BC_INST_JUMP_ZERO:
6539 s = bc_program_prep(&ptr, &num);
6541 cond = !bc_num_cmp(num, &G.prog.zero);
6542 bc_vec_pop(&G.prog.results);
6548 idx = bc_program_index(code, &ip->idx);
6549 addr = bc_vec_item(&func->labels, idx);
6550 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6556 s = bc_program_call(code, &ip->idx);
6560 case BC_INST_INC_PRE:
6561 case BC_INST_DEC_PRE:
6562 case BC_INST_INC_POST:
6563 case BC_INST_DEC_POST:
6565 s = bc_program_incdec(inst);
6578 s = bc_program_return(inst);
6582 case BC_INST_BOOL_OR:
6583 case BC_INST_BOOL_AND:
6585 case BC_INST_REL_EQ:
6586 case BC_INST_REL_LE:
6587 case BC_INST_REL_GE:
6588 case BC_INST_REL_NE:
6589 case BC_INST_REL_LT:
6590 case BC_INST_REL_GT:
6592 s = bc_program_logical(inst);
6598 s = bc_program_read();
6604 s = bc_program_pushVar(code, &ip->idx, false, false);
6608 case BC_INST_ARRAY_ELEM:
6611 s = bc_program_pushArray(code, &ip->idx, inst);
6617 r.t = BC_RESULT_LAST;
6618 bc_vec_push(&G.prog.results, &r);
6626 bc_program_pushGlobal(inst);
6630 case BC_INST_SCALE_FUNC:
6631 case BC_INST_LENGTH:
6634 s = bc_program_builtin(inst);
6640 r.t = BC_RESULT_CONSTANT;
6641 r.d.id.idx = bc_program_index(code, &ip->idx);
6642 bc_vec_push(&G.prog.results, &r);
6648 if (!BC_PROG_STACK(&G.prog.results, 1))
6649 s = bc_error_stack_has_too_few_elements();
6651 bc_vec_pop(&G.prog.results);
6655 case BC_INST_POP_EXEC:
6657 bc_vec_pop(&G.prog.stack);
6662 case BC_INST_PRINT_POP:
6663 case BC_INST_PRINT_STR:
6665 s = bc_program_print(inst, 0);
6671 r.t = BC_RESULT_STR;
6672 r.d.id.idx = bc_program_index(code, &ip->idx);
6673 bc_vec_push(&G.prog.results, &r);
6678 case BC_INST_MULTIPLY:
6679 case BC_INST_DIVIDE:
6680 case BC_INST_MODULUS:
6684 s = bc_program_op(inst);
6688 case BC_INST_BOOL_NOT:
6690 s = bc_program_prep(&ptr, &num);
6693 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6694 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6695 bc_program_retire(&r, BC_RESULT_TEMP);
6702 s = bc_program_negate();
6707 case BC_INST_ASSIGN_POWER:
6708 case BC_INST_ASSIGN_MULTIPLY:
6709 case BC_INST_ASSIGN_DIVIDE:
6710 case BC_INST_ASSIGN_MODULUS:
6711 case BC_INST_ASSIGN_PLUS:
6712 case BC_INST_ASSIGN_MINUS:
6714 case BC_INST_ASSIGN:
6716 s = bc_program_assign(inst);
6720 case BC_INST_MODEXP:
6722 s = bc_program_modexp();
6726 case BC_INST_DIVMOD:
6728 s = bc_program_divmod();
6732 case BC_INST_EXECUTE:
6733 case BC_INST_EXEC_COND:
6735 cond = inst == BC_INST_EXEC_COND;
6736 s = bc_program_execStr(code, &ip->idx, cond);
6740 case BC_INST_PRINT_STACK:
6742 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6743 s = bc_program_print(BC_INST_PRINT, idx);
6747 case BC_INST_CLEAR_STACK:
6749 bc_vec_pop_all(&G.prog.results);
6753 case BC_INST_STACK_LEN:
6755 bc_program_stackLen();
6759 case BC_INST_DUPLICATE:
6761 if (!BC_PROG_STACK(&G.prog.results, 1))
6762 return bc_error_stack_has_too_few_elements();
6763 ptr = bc_vec_top(&G.prog.results);
6764 bc_result_copy(&r, ptr);
6765 bc_vec_push(&G.prog.results, &r);
6773 if (!BC_PROG_STACK(&G.prog.results, 2))
6774 return bc_error_stack_has_too_few_elements();
6776 ptr = bc_vec_item_rev(&G.prog.results, 0);
6777 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6778 memcpy(&r, ptr, sizeof(BcResult));
6779 memcpy(ptr, ptr2, sizeof(BcResult));
6780 memcpy(ptr2, &r, sizeof(BcResult));
6785 case BC_INST_ASCIIFY:
6787 s = bc_program_asciify();
6791 case BC_INST_PRINT_STREAM:
6793 s = bc_program_printStream();
6798 case BC_INST_PUSH_VAR:
6800 bool copy = inst == BC_INST_LOAD;
6801 s = bc_program_pushVar(code, &ip->idx, true, copy);
6805 case BC_INST_PUSH_TO_VAR:
6807 char *name = bc_program_name(code, &ip->idx);
6808 s = bc_program_copyToVar(name, true);
6815 if (G.prog.stack.len <= 2)
6817 bc_vec_npop(&G.prog.stack, 2);
6823 s = bc_program_nquit();
6829 if (s || G_interrupt) {
6834 // If the stack has changed, pointers may be invalid.
6835 ip = bc_vec_top(&G.prog.stack);
6836 func = bc_vec_item(&G.prog.fns, ip->func);
6837 code = func->code.v;
6843 static void bc_vm_info(void)
6845 printf("%s "BB_VER"\n"
6846 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6847 "Report bugs at: https://github.com/gavinhoward/bc\n"
6848 "This is free software with ABSOLUTELY NO WARRANTY\n"
6853 static void bc_vm_envArgs(void)
6855 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6858 char *env_args = getenv(bc_args_env_name), *buf;
6860 if (!env_args) return;
6862 G.env_args = xstrdup(env_args);
6865 bc_vec_init(&v, sizeof(char *), NULL);
6866 bc_vec_push(&v, &bc_args_env_name);
6869 if (!isspace(*buf)) {
6870 bc_vec_push(&v, &buf);
6871 while (*buf != 0 && !isspace(*buf)) ++buf;
6872 if (*buf != 0) (*(buf++)) = '\0';
6878 bc_args((int) v.len, (char **) v.v);
6884 static size_t bc_vm_envLen(const char *var)
6886 char *lenv = getenv(var);
6887 size_t i, len = BC_NUM_PRINT_WIDTH;
6890 if (!lenv) return len;
6894 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6896 len = (size_t) atoi(lenv) - 1;
6897 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6900 len = BC_NUM_PRINT_WIDTH;
6905 static BcStatus bc_vm_process(const char *text)
6907 BcStatus s = bc_parse_text(&G.prs, text);
6911 while (G.prs.l.t.t != BC_LEX_EOF) {
6912 s = G.prs.parse(&G.prs);
6916 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6917 s = bc_program_exec();
6926 static BcStatus bc_vm_file(const char *file)
6928 const char *sv_file;
6934 data = bc_read_file(file);
6935 if (!data) return bc_error_fmt("file '%s' is not text", file);
6937 sv_file = G.prog.file;
6939 bc_lex_file(&G.prs.l);
6940 s = bc_vm_process(data);
6943 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6944 ip = bc_vec_item(&G.prog.stack, 0);
6946 if (main_func->code.len < ip->idx)
6947 s = bc_error_fmt("file '%s' is not executable", file);
6950 G.prog.file = sv_file;
6955 static BcStatus bc_vm_stdin(void)
6959 size_t len, i, str = 0;
6960 bool comment = false;
6963 bc_lex_file(&G.prs.l);
6965 bc_char_vec_init(&buffer);
6966 bc_char_vec_init(&buf);
6967 bc_vec_pushZeroByte(&buffer);
6969 // This loop is complex because the vm tries not to send any lines that end
6970 // with a backslash to the parser. The reason for that is because the parser
6971 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6972 // case, and for strings and comments, the parser will expect more stuff.
6973 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6975 char *string = buf.v;
6980 if (str && buf.v[0] == G.send)
6982 else if (buf.v[0] == G.sbgn)
6985 else if (len > 1 || comment) {
6987 for (i = 0; i < len; ++i) {
6989 bool notend = len > i + 1;
6992 if (i - 1 > len || string[i - 1] != '\\') {
6993 if (G.sbgn == G.send)
6995 else if (c == G.send)
6997 else if (c == G.sbgn)
7001 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7005 else if (c == '*' && notend && comment && string[i + 1] == '/')
7009 if (str || comment || string[len - 2] == '\\') {
7010 bc_vec_concat(&buffer, buf.v);
7015 bc_vec_concat(&buffer, buf.v);
7016 s = bc_vm_process(buffer.v);
7019 fputs("ready for more input\n", stderr);
7022 bc_vec_pop_all(&buffer);
7026 s = bc_error("string end could not be found");
7029 s = bc_error("comment end could not be found");
7033 bc_vec_free(&buffer);
7038 static const char bc_lib[] = {
7041 "\n" "auto b,s,n,r,d,i,p,f,v"
7050 "\n" "scale=scale(x)+1"
7060 "\n" "for(i=2;v!=0;++i){"
7066 "\n" "while((d--)!=0)r*=r"
7069 "\n" "if(n!=0)return(1/r)"
7073 "\n" "auto b,s,r,p,a,q,i,v"
7077 "\n" "r=(1-10^scale)/1"
7088 "\n" "while(x<=0.5){"
7092 "\n" "r=a=(x-1)/(x+1)"
7095 "\n" "for(i=3;v!=0;i+=2){"
7106 "\n" "auto b,s,r,n,a,q,i"
7110 "\n" "scale=1.1*s+2"
7119 "\n" "if(q%2!=0)x=-x"
7123 "\n" "for(i=3;a!=0;i+=2){"
7124 "\n" "a*=q/(i*(i-1))"
7129 "\n" "if(n!=0)return(-r/1)"
7138 "\n" "x=s(2*a(1)+x)"
7144 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7153 "\n" "if(scale<65){"
7154 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7158 "\n" "if(scale<65){"
7159 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7170 "\n" "x=(x-.2)/(1+.2*x)"
7175 "\n" "for(i=3;t!=0;i+=2){"
7182 "\n" "return((m*a+r)/n)"
7184 "\n" "define j(n,x){"
7185 "\n" "auto b,s,o,a,i,v,f"
7193 "\n" "if(n%2==1)o=1"
7196 "\n" "for(i=2;i<=n;++i)a*=i"
7198 "\n" "a=(x^n)/2^n/a"
7201 "\n" "scale=scale+length(a)-scale(a)"
7202 "\n" "for(i=1;v!=0;++i){"
7203 "\n" "v=v*f/i/(n+i)"
7209 "\n" "return(a*r/1)"
7214 static BcStatus bc_vm_exec(void)
7216 BcStatus s = BC_STATUS_SUCCESS;
7220 if (option_mask32 & BC_FLAG_L) {
7222 // We know that internal library is not buggy,
7223 // thus error checking is normally disabled.
7224 # define DEBUG_LIB 0
7225 bc_lex_file(&G.prs.l);
7226 s = bc_parse_text(&G.prs, bc_lib);
7227 if (DEBUG_LIB && s) return s;
7229 while (G.prs.l.t.t != BC_LEX_EOF) {
7230 s = G.prs.parse(&G.prs);
7231 if (DEBUG_LIB && s) return s;
7233 s = bc_program_exec();
7234 if (DEBUG_LIB && s) return s;
7238 for (i = 0; !s && i < G.files.len; ++i)
7239 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7242 fputs("ready for more input\n", stderr);
7245 if (IS_BC || !G.files.len)
7247 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7248 s = bc_vm_process("");
7253 #if ENABLE_FEATURE_CLEAN_UP
7254 static void bc_program_free()
7256 bc_num_free(&G.prog.ib);
7257 bc_num_free(&G.prog.ob);
7258 bc_num_free(&G.prog.hexb);
7260 bc_num_free(&G.prog.strmb);
7262 bc_vec_free(&G.prog.fns);
7263 bc_vec_free(&G.prog.fn_map);
7264 bc_vec_free(&G.prog.vars);
7265 bc_vec_free(&G.prog.var_map);
7266 bc_vec_free(&G.prog.arrs);
7267 bc_vec_free(&G.prog.arr_map);
7268 bc_vec_free(&G.prog.strs);
7269 bc_vec_free(&G.prog.consts);
7270 bc_vec_free(&G.prog.results);
7271 bc_vec_free(&G.prog.stack);
7272 bc_num_free(&G.prog.last);
7273 bc_num_free(&G.prog.zero);
7274 bc_num_free(&G.prog.one);
7277 static void bc_vm_free(void)
7279 bc_vec_free(&G.files);
7281 bc_parse_free(&G.prs);
7286 static void bc_program_init(size_t line_len)
7291 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7292 memset(&ip, 0, sizeof(BcInstPtr));
7294 /* G.prog.nchars = G.prog.scale = 0; - already is */
7295 G.prog.len = line_len;
7297 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7298 bc_num_ten(&G.prog.ib);
7301 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7302 bc_num_ten(&G.prog.ob);
7305 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7306 bc_num_ten(&G.prog.hexb);
7307 G.prog.hexb.num[0] = 6;
7310 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7311 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7314 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7315 bc_num_zero(&G.prog.last);
7317 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7318 bc_num_zero(&G.prog.zero);
7320 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7321 bc_num_one(&G.prog.one);
7323 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7324 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7326 bc_program_addFunc(xstrdup("(main)"), &idx);
7327 bc_program_addFunc(xstrdup("(read)"), &idx);
7329 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7330 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7332 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7333 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7335 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7336 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7337 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7338 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7339 bc_vec_push(&G.prog.stack, &ip);
7342 static void bc_vm_init(const char *env_len)
7344 size_t len = bc_vm_envLen(env_len);
7346 bc_vec_init(&G.files, sizeof(char *), NULL);
7352 bc_program_init(len);
7354 bc_parse_init(&G.prs, BC_PROG_MAIN);
7356 dc_parse_init(&G.prs, BC_PROG_MAIN);
7360 static BcStatus bc_vm_run(int argc, char *argv[],
7361 const char *env_len)
7365 bc_vm_init(env_len);
7366 bc_args(argc, argv);
7368 G.ttyin = isatty(0);
7371 #if ENABLE_FEATURE_BC_SIGNALS
7372 // With SA_RESTART, most system calls will restart
7373 // (IOW: they won't fail with EINTR).
7374 // In particular, this means ^C won't cause
7375 // stdout to get into "error state" if SIGINT hits
7376 // within write() syscall.
7377 // The downside is that ^C while line input is taken
7378 // will only be handled after [Enter] since read()
7379 // from stdin is not interrupted by ^C either,
7380 // it restarts, thus fgetc() does not return on ^C.
7381 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7383 // Without SA_RESTART, this exhibits a bug:
7384 // "while (1) print 1" and try ^C-ing it.
7385 // Intermittently, instead of returning to input line,
7386 // you'll get "output error: Interrupted system call"
7388 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7390 if (!(option_mask32 & BC_FLAG_Q))
7395 #if ENABLE_FEATURE_CLEAN_UP
7402 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7403 int bc_main(int argc, char **argv)
7406 G.sbgn = G.send = '"';
7408 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7413 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7414 int dc_main(int argc, char **argv)
7420 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");