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 int in = (int) c->num[i + j];
1672 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1674 c->num[i + j] = (BcDig)(in % 10);
1677 c->num[i + j] += (BcDig) carry;
1678 len = BC_MAX(len, i + j + !!carry);
1683 return BC_STATUS_SUCCESS;
1686 bc_num_init(&l1, max);
1687 bc_num_init(&h1, max);
1688 bc_num_init(&l2, max);
1689 bc_num_init(&h2, max);
1690 bc_num_init(&m1, max);
1691 bc_num_init(&m2, max);
1692 bc_num_init(&z0, max);
1693 bc_num_init(&z1, max);
1694 bc_num_init(&z2, max);
1695 bc_num_init(&temp, max + max);
1697 bc_num_split(a, max2, &l1, &h1);
1698 bc_num_split(b, max2, &l2, &h2);
1700 s = bc_num_add(&h1, &l1, &m1, 0);
1702 s = bc_num_add(&h2, &l2, &m2, 0);
1705 s = bc_num_k(&h1, &h2, &z0);
1707 s = bc_num_k(&m1, &m2, &z1);
1709 s = bc_num_k(&l1, &l2, &z2);
1712 s = bc_num_sub(&z1, &z0, &temp, 0);
1714 s = bc_num_sub(&temp, &z2, &z1, 0);
1717 s = bc_num_shift(&z0, max2 * 2);
1719 s = bc_num_shift(&z1, max2);
1721 s = bc_num_add(&z0, &z1, &temp, 0);
1723 s = bc_num_add(&temp, &z2, c, 0);
1739 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1743 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1745 scale = BC_MAX(scale, a->rdx);
1746 scale = BC_MAX(scale, b->rdx);
1747 scale = BC_MIN(a->rdx + b->rdx, scale);
1748 maxrdx = BC_MAX(maxrdx, scale);
1750 bc_num_init(&cpa, a->len);
1751 bc_num_init(&cpb, b->len);
1753 bc_num_copy(&cpa, a);
1754 bc_num_copy(&cpb, b);
1755 cpa.neg = cpb.neg = false;
1757 s = bc_num_shift(&cpa, maxrdx);
1759 s = bc_num_shift(&cpb, maxrdx);
1761 s = bc_num_k(&cpa, &cpb, c);
1765 bc_num_expand(c, c->len + maxrdx);
1767 if (c->len < maxrdx) {
1768 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1773 bc_num_retireMul(c, scale, a->neg, b->neg);
1781 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1783 BcStatus s = BC_STATUS_SUCCESS;
1790 return bc_error("divide by zero");
1791 else if (a->len == 0) {
1792 bc_num_setToZero(c, scale);
1793 return BC_STATUS_SUCCESS;
1795 else if (BC_NUM_ONE(b)) {
1797 bc_num_retireMul(c, scale, a->neg, b->neg);
1798 return BC_STATUS_SUCCESS;
1801 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1802 bc_num_copy(&cp, a);
1806 bc_num_expand(&cp, len + 2);
1807 bc_num_extend(&cp, len - cp.len);
1810 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1812 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1814 if (b->rdx == b->len) {
1815 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1819 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1821 // We want an extra zero in front to make things simpler.
1822 cp.num[cp.len++] = 0;
1825 bc_num_expand(c, cp.len);
1828 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1833 for (i = end - 1; !s && i < end; --i) {
1835 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1836 bc_num_subArrays(n, p, len);
1840 bc_num_retireMul(c, scale, a->neg, b->neg);
1843 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1846 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1847 BcNum *restrict d, size_t scale, size_t ts)
1854 return bc_error("divide by zero");
1857 bc_num_setToZero(d, ts);
1858 return BC_STATUS_SUCCESS;
1861 bc_num_init(&temp, d->cap);
1862 bc_num_d(a, b, c, scale);
1864 if (scale != 0) scale = ts;
1866 s = bc_num_m(c, b, &temp, scale);
1868 s = bc_num_sub(a, &temp, d, scale);
1871 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1874 bc_num_retireMul(d, ts, a->neg, b->neg);
1882 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1886 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1888 bc_num_init(&c1, len);
1889 s = bc_num_r(a, b, &c1, c, scale, ts);
1895 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1897 BcStatus s = BC_STATUS_SUCCESS;
1900 size_t i, powrdx, resrdx;
1903 if (b->rdx) return bc_error("non integer number");
1907 return BC_STATUS_SUCCESS;
1909 else if (a->len == 0) {
1910 bc_num_setToZero(c, scale);
1911 return BC_STATUS_SUCCESS;
1913 else if (BC_NUM_ONE(b)) {
1917 s = bc_num_inv(a, c, scale);
1924 s = bc_num_ulong(b, &pow);
1927 bc_num_init(©, a->len);
1928 bc_num_copy(©, a);
1930 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1934 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1936 s = bc_num_mul(©, ©, ©, powrdx);
1938 // It is too slow to handle ^C only after entire "2^1000000" completes
1940 s = BC_STATUS_FAILURE;
1945 bc_num_copy(c, ©);
1947 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1950 s = bc_num_mul(©, ©, ©, powrdx);
1955 s = bc_num_mul(c, ©, c, resrdx);
1958 // It is too slow to handle ^C only after entire "2^1000000" completes
1960 s = BC_STATUS_FAILURE;
1966 s = bc_num_inv(c, c, scale);
1970 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1972 // We can't use bc_num_clean() here.
1973 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1974 if (zero) bc_num_setToZero(c, scale);
1981 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1982 BcNumBinaryOp op, size_t req)
1985 BcNum num2, *ptr_a, *ptr_b;
1990 memcpy(ptr_a, c, sizeof(BcNum));
1999 memcpy(ptr_b, c, sizeof(BcNum));
2007 bc_num_init(c, req);
2009 bc_num_expand(c, req);
2011 s = op(ptr_a, ptr_b, c, scale);
2013 if (init) bc_num_free(&num2);
2018 static bool bc_num_strValid(const char *val, size_t base)
2021 bool small, radix = false;
2022 size_t i, len = strlen(val);
2024 if (!len) return true;
2027 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2029 for (i = 0; i < len; ++i) {
2035 if (radix) return false;
2041 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2048 static void bc_num_parseDecimal(BcNum *n, const char *val)
2054 for (i = 0; val[i] == '0'; ++i);
2061 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2062 bc_num_expand(n, len);
2065 ptr = strchr(val, '.');
2069 n->rdx = (size_t)((val + len) - (ptr + 1));
2072 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2073 n->num[n->len] = val[i] - '0';
2077 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2080 BcNum temp, mult, result;
2084 size_t i, digits, len = strlen(val);
2088 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2091 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2092 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2094 for (i = 0; i < len; ++i) {
2097 if (c == '.') break;
2099 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2101 s = bc_num_mul(n, base, &mult, 0);
2102 if (s) goto int_err;
2103 bc_num_ulong2num(&temp, v);
2104 s = bc_num_add(&mult, &temp, n, 0);
2105 if (s) goto int_err;
2110 if (c == 0) goto int_err;
2113 bc_num_init(&result, base->len);
2114 bc_num_zero(&result);
2117 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2122 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2124 s = bc_num_mul(&result, base, &result, 0);
2126 bc_num_ulong2num(&temp, v);
2127 s = bc_num_add(&result, &temp, &result, 0);
2129 s = bc_num_mul(&mult, base, &mult, 0);
2133 s = bc_num_div(&result, &mult, &result, digits);
2135 s = bc_num_add(n, &result, n, digits);
2139 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2145 bc_num_free(&result);
2151 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2153 if (*nchars == line_len - 1) {
2161 static void bc_num_printChar(size_t num, size_t width, bool radix,
2162 size_t *nchars, size_t line_len)
2164 (void) radix, (void) line_len;
2165 bb_putchar((char) num);
2166 *nchars = *nchars + width;
2170 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2171 size_t *nchars, size_t line_len)
2175 bc_num_printNewline(nchars, line_len);
2176 bb_putchar(radix ? '.' : ' ');
2179 bc_num_printNewline(nchars, line_len);
2180 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2183 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2185 bc_num_printNewline(nchars, line_len);
2188 bb_putchar(((char) dig) + '0');
2192 static void bc_num_printHex(size_t num, size_t width, bool radix,
2193 size_t *nchars, size_t line_len)
2196 bc_num_printNewline(nchars, line_len);
2201 bc_num_printNewline(nchars, line_len);
2202 bb_putchar(bb_hexdigits_upcase[num]);
2203 *nchars = *nchars + width;
2206 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2208 size_t i, rdx = n->rdx - 1;
2210 if (n->neg) bb_putchar('-');
2211 (*nchars) += n->neg;
2213 for (i = n->len - 1; i < n->len; --i)
2214 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2217 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2218 size_t *nchars, size_t len, BcNumDigitOp print)
2222 BcNum intp, fracp, digit, frac_len;
2223 unsigned long dig, *ptr;
2228 print(0, width, false, nchars, len);
2229 return BC_STATUS_SUCCESS;
2232 bc_vec_init(&stack, sizeof(long), NULL);
2233 bc_num_init(&intp, n->len);
2234 bc_num_init(&fracp, n->rdx);
2235 bc_num_init(&digit, width);
2236 bc_num_init(&frac_len, BC_NUM_INT(n));
2237 bc_num_copy(&intp, n);
2238 bc_num_one(&frac_len);
2240 bc_num_truncate(&intp, intp.rdx);
2241 s = bc_num_sub(n, &intp, &fracp, 0);
2244 while (intp.len != 0) {
2245 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2247 s = bc_num_ulong(&digit, &dig);
2249 bc_vec_push(&stack, &dig);
2252 for (i = 0; i < stack.len; ++i) {
2253 ptr = bc_vec_item_rev(&stack, i);
2254 print(*ptr, width, false, nchars, len);
2257 if (!n->rdx) goto err;
2259 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2260 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2262 s = bc_num_ulong(&fracp, &dig);
2264 bc_num_ulong2num(&intp, dig);
2265 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2267 print(dig, width, radix, nchars, len);
2268 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2273 bc_num_free(&frac_len);
2274 bc_num_free(&digit);
2275 bc_num_free(&fracp);
2277 bc_vec_free(&stack);
2281 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2282 size_t *nchars, size_t line_len)
2289 if (neg) bb_putchar('-');
2294 if (base_t <= BC_NUM_MAX_IBASE) {
2296 print = bc_num_printHex;
2299 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2300 print = bc_num_printDigits;
2303 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2310 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2312 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2316 static void bc_num_init(BcNum *n, size_t req)
2318 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2319 memset(n, 0, sizeof(BcNum));
2320 n->num = xmalloc(req);
2324 static void bc_num_expand(BcNum *n, size_t req)
2326 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2328 n->num = xrealloc(n->num, req);
2333 static void bc_num_free(void *num)
2335 free(((BcNum *) num)->num);
2338 static void bc_num_copy(BcNum *d, BcNum *s)
2341 bc_num_expand(d, s->cap);
2345 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2349 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2352 if (!bc_num_strValid(val, base_t))
2353 return bc_error("bad number string");
2356 bc_num_parseDecimal(n, val);
2358 bc_num_parseBase(n, val, base);
2360 return BC_STATUS_SUCCESS;
2363 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2364 size_t *nchars, size_t line_len)
2366 BcStatus s = BC_STATUS_SUCCESS;
2368 bc_num_printNewline(nchars, line_len);
2374 else if (base_t == 10)
2375 bc_num_printDecimal(n, nchars, line_len);
2377 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2387 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2392 if (n->neg) return bc_error("negative number");
2394 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2396 unsigned long prev = *result, powprev = pow;
2398 *result += ((unsigned long) n->num[i]) * pow;
2401 if (*result < prev || pow < powprev)
2402 return bc_error("overflow");
2405 return BC_STATUS_SUCCESS;
2408 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2416 if (val == 0) return;
2418 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2419 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2422 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2424 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2426 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2429 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2431 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2433 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2436 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2438 size_t req = BC_NUM_MREQ(a, b, scale);
2439 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2442 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2444 size_t req = BC_NUM_MREQ(a, b, scale);
2445 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2448 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2450 size_t req = BC_NUM_MREQ(a, b, scale);
2451 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2454 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2456 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2459 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2462 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2463 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2464 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2466 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2467 bc_num_expand(b, req);
2470 bc_num_setToZero(b, scale);
2471 return BC_STATUS_SUCCESS;
2474 return bc_error("negative number");
2475 else if (BC_NUM_ONE(a)) {
2477 bc_num_extend(b, scale);
2478 return BC_STATUS_SUCCESS;
2481 scale = BC_MAX(scale, a->rdx) + 1;
2482 len = a->len + scale;
2484 bc_num_init(&num1, len);
2485 bc_num_init(&num2, len);
2486 bc_num_init(&half, BC_NUM_DEF_SIZE);
2492 bc_num_init(&f, len);
2493 bc_num_init(&fprime, len);
2499 pow = BC_NUM_INT(a);
2508 pow -= 2 - (pow & 1);
2510 bc_num_extend(x0, pow);
2512 // Make sure to move the radix back.
2516 x0->rdx = digs = digs1 = 0;
2518 len = BC_NUM_INT(x0) + resrdx - 1;
2520 while (cmp != 0 || digs < len) {
2522 s = bc_num_div(a, x0, &f, resrdx);
2524 s = bc_num_add(x0, &f, &fprime, resrdx);
2526 s = bc_num_mul(&fprime, &half, x1, resrdx);
2529 cmp = bc_num_cmp(x1, x0);
2530 digs = x1->len - (unsigned long long) llabs(cmp);
2532 if (cmp == cmp2 && digs == digs1)
2537 resrdx += times > 4;
2550 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2553 bc_num_free(&fprime);
2561 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2567 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2570 memcpy(&num2, c, sizeof(BcNum));
2572 bc_num_init(c, len);
2577 bc_num_expand(c, len);
2580 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2582 if (init) bc_num_free(&num2);
2588 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2591 BcNum base, exp, two, temp;
2594 return bc_error("divide by zero");
2595 if (a->rdx || b->rdx || c->rdx)
2596 return bc_error("non integer number");
2598 return bc_error("negative number");
2600 bc_num_expand(d, c->len);
2601 bc_num_init(&base, c->len);
2602 bc_num_init(&exp, b->len);
2603 bc_num_init(&two, BC_NUM_DEF_SIZE);
2604 bc_num_init(&temp, b->len);
2610 s = bc_num_rem(a, c, &base, 0);
2612 bc_num_copy(&exp, b);
2614 while (exp.len != 0) {
2616 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2619 if (BC_NUM_ONE(&temp)) {
2620 s = bc_num_mul(d, &base, &temp, 0);
2622 s = bc_num_rem(&temp, c, d, 0);
2626 s = bc_num_mul(&base, &base, &temp, 0);
2628 s = bc_num_rem(&temp, c, &base, 0);
2641 static int bc_id_cmp(const void *e1, const void *e2)
2643 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2646 static void bc_id_free(void *id)
2648 free(((BcId *) id)->name);
2651 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2656 for (i = 0; i < f->autos.len; ++i) {
2657 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2658 return bc_error("function parameter or auto var has the same name as another");
2664 bc_vec_push(&f->autos, &a);
2666 return BC_STATUS_SUCCESS;
2669 static void bc_func_init(BcFunc *f)
2671 bc_char_vec_init(&f->code);
2672 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2673 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2677 static void bc_func_free(void *func)
2679 BcFunc *f = (BcFunc *) func;
2680 bc_vec_free(&f->code);
2681 bc_vec_free(&f->autos);
2682 bc_vec_free(&f->labels);
2685 static void bc_array_init(BcVec *a, bool nums)
2688 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2690 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2691 bc_array_expand(a, 1);
2694 static void bc_array_copy(BcVec *d, const BcVec *s)
2699 bc_vec_expand(d, s->cap);
2702 for (i = 0; i < s->len; ++i) {
2703 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2704 bc_num_init(dnum, snum->len);
2705 bc_num_copy(dnum, snum);
2709 static void bc_array_expand(BcVec *a, size_t len)
2713 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2714 while (len > a->len) {
2715 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2716 bc_vec_push(a, &data.n);
2720 while (len > a->len) {
2721 bc_array_init(&data.v, true);
2722 bc_vec_push(a, &data.v);
2727 static void bc_string_free(void *string)
2729 free(*((char **) string));
2733 static void bc_result_copy(BcResult *d, BcResult *src)
2739 case BC_RESULT_TEMP:
2740 case BC_RESULT_IBASE:
2741 case BC_RESULT_SCALE:
2742 case BC_RESULT_OBASE:
2744 bc_num_init(&d->d.n, src->d.n.len);
2745 bc_num_copy(&d->d.n, &src->d.n);
2750 case BC_RESULT_ARRAY:
2751 case BC_RESULT_ARRAY_ELEM:
2753 d->d.id.name = xstrdup(src->d.id.name);
2757 case BC_RESULT_CONSTANT:
2758 case BC_RESULT_LAST:
2762 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2769 static void bc_result_free(void *result)
2771 BcResult *r = (BcResult *) result;
2775 case BC_RESULT_TEMP:
2776 case BC_RESULT_IBASE:
2777 case BC_RESULT_SCALE:
2778 case BC_RESULT_OBASE:
2780 bc_num_free(&r->d.n);
2785 case BC_RESULT_ARRAY:
2786 case BC_RESULT_ARRAY_ELEM:
2800 static void bc_lex_lineComment(BcLex *l)
2802 l->t.t = BC_LEX_WHITESPACE;
2803 while (l->i < l->len && l->buf[l->i++] != '\n');
2807 static void bc_lex_whitespace(BcLex *l)
2810 l->t.t = BC_LEX_WHITESPACE;
2811 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2814 static BcStatus bc_lex_number(BcLex *l, char start)
2816 const char *buf = l->buf + l->i;
2817 size_t len, hits = 0, bslashes = 0, i = 0, j;
2819 bool last_pt, pt = start == '.';
2822 l->t.t = BC_LEX_NUMBER;
2824 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2825 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2839 len = i + !last_pt - bslashes * 2;
2840 if (len > BC_MAX_NUM)
2841 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2843 bc_vec_pop_all(&l->t.v);
2844 bc_vec_expand(&l->t.v, len + 1);
2845 bc_vec_push(&l->t.v, &start);
2847 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2851 // If we have hit a backslash, skip it. We don't have
2852 // to check for a newline because it's guaranteed.
2853 if (hits < bslashes && c == '\\') {
2859 bc_vec_push(&l->t.v, &c);
2862 bc_vec_pushZeroByte(&l->t.v);
2865 return BC_STATUS_SUCCESS;
2868 static BcStatus bc_lex_name(BcLex *l)
2871 const char *buf = l->buf + l->i - 1;
2874 l->t.t = BC_LEX_NAME;
2876 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2878 if (i > BC_MAX_STRING)
2879 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2880 bc_vec_string(&l->t.v, i, buf);
2882 // Increment the index. We minus 1 because it has already been incremented.
2885 return BC_STATUS_SUCCESS;
2888 static void bc_lex_init(BcLex *l, BcLexNext next)
2891 bc_char_vec_init(&l->t.v);
2894 static void bc_lex_free(BcLex *l)
2896 bc_vec_free(&l->t.v);
2899 static void bc_lex_file(BcLex *l)
2901 G.err_line = l->line = 1;
2905 static BcStatus bc_lex_next(BcLex *l)
2910 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2912 l->line += l->newline;
2913 G.err_line = l->line;
2914 l->t.t = BC_LEX_EOF;
2916 l->newline = (l->i == l->len);
2917 if (l->newline) return BC_STATUS_SUCCESS;
2919 // Loop until failure or we don't have whitespace. This
2920 // is so the parser doesn't get inundated with whitespace.
2923 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2928 static BcStatus bc_lex_text(BcLex *l, const char *text)
2932 l->len = strlen(text);
2933 l->t.t = l->t.last = BC_LEX_INVALID;
2934 return bc_lex_next(l);
2938 static BcStatus bc_lex_identifier(BcLex *l)
2942 const char *buf = l->buf + l->i - 1;
2944 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2945 const char *keyword8 = bc_lex_kws[i].name8;
2947 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2949 if (j == 8) goto match;
2951 if (keyword8[j] != '\0')
2954 // buf starts with keyword bc_lex_kws[i]
2955 l->t.t = BC_LEX_KEY_1st_keyword + i;
2956 if (!((1 << i) & POSIX_KWORD_MASK)) {
2957 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
2961 // We minus 1 because the index has already been incremented.
2963 return BC_STATUS_SUCCESS;
2969 if (l->t.v.len > 2) {
2972 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
2974 unsigned len = strchrnul(buf, '\n') - buf;
2975 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
2981 static BcStatus bc_lex_string(BcLex *l)
2983 size_t len, nls = 0, i = l->i;
2986 l->t.t = BC_LEX_STR;
2988 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2992 return bc_error("string end could not be found");
2996 if (len > BC_MAX_STRING)
2997 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2998 bc_vec_string(&l->t.v, len, l->buf + l->i);
3002 G.err_line = l->line;
3004 return BC_STATUS_SUCCESS;
3007 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3009 if (l->buf[l->i] == '=') {
3017 static BcStatus bc_lex_comment(BcLex *l)
3020 const char *buf = l->buf;
3022 l->t.t = BC_LEX_WHITESPACE;
3035 return bc_error("comment end could not be found");
3043 G.err_line = l->line;
3045 return BC_STATUS_SUCCESS;
3048 static BcStatus bc_lex_token(BcLex *l)
3050 BcStatus s = BC_STATUS_SUCCESS;
3051 char c = l->buf[l->i++], c2;
3053 // This is the workhorse of the lexer.
3060 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3070 bc_lex_whitespace(l);
3076 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3078 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3079 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3088 s = bc_lex_string(l);
3094 s = bc_POSIX_does_not_allow("'#' script comments");
3097 bc_lex_lineComment(l);
3104 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3113 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3117 l->t.t = BC_LEX_OP_BOOL_AND;
3120 l->t.t = BC_LEX_INVALID;
3121 s = bc_error_bad_character('&');
3130 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3136 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3145 l->t.t = BC_LEX_OP_INC;
3148 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3154 l->t.t = BC_LEX_COMMA;
3163 l->t.t = BC_LEX_OP_DEC;
3166 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3172 if (isdigit(l->buf[l->i]))
3173 s = bc_lex_number(l, c);
3175 l->t.t = BC_LEX_KEY_LAST;
3176 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
3185 s = bc_lex_comment(l);
3187 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3208 s = bc_lex_number(l, c);
3214 l->t.t = BC_LEX_SCOLON;
3220 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3226 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3232 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3239 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3245 if (l->buf[l->i] == '\n') {
3246 l->t.t = BC_LEX_WHITESPACE;
3250 s = bc_error_bad_character(c);
3256 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3287 s = bc_lex_identifier(l);
3294 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3303 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3307 l->t.t = BC_LEX_OP_BOOL_OR;
3310 l->t.t = BC_LEX_INVALID;
3311 s = bc_error_bad_character(c);
3319 l->t.t = BC_LEX_INVALID;
3320 s = bc_error_bad_character(c);
3330 static BcStatus dc_lex_register(BcLex *l)
3332 BcStatus s = BC_STATUS_SUCCESS;
3334 if (isspace(l->buf[l->i - 1])) {
3335 bc_lex_whitespace(l);
3338 s = bc_error("extended register");
3343 bc_vec_pop_all(&l->t.v);
3344 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3345 bc_vec_pushZeroByte(&l->t.v);
3346 l->t.t = BC_LEX_NAME;
3352 static BcStatus dc_lex_string(BcLex *l)
3354 size_t depth = 1, nls = 0, i = l->i;
3357 l->t.t = BC_LEX_STR;
3358 bc_vec_pop_all(&l->t.v);
3360 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3362 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3363 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3366 if (depth) bc_vec_push(&l->t.v, &c);
3371 return bc_error("string end could not be found");
3374 bc_vec_pushZeroByte(&l->t.v);
3375 if (i - l->i > BC_MAX_STRING)
3376 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3380 G.err_line = l->line;
3382 return BC_STATUS_SUCCESS;
3385 static BcStatus dc_lex_token(BcLex *l)
3387 BcStatus s = BC_STATUS_SUCCESS;
3388 char c = l->buf[l->i++], c2;
3391 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3392 if (l->t.last == dc_lex_regs[i])
3393 return dc_lex_register(l);
3396 if (c >= '%' && c <= '~' &&
3397 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3402 // This is the workhorse of the lexer.
3407 l->t.t = BC_LEX_EOF;
3418 l->newline = (c == '\n');
3419 bc_lex_whitespace(l);
3428 l->t.t = BC_LEX_OP_REL_NE;
3430 l->t.t = BC_LEX_OP_REL_LE;
3432 l->t.t = BC_LEX_OP_REL_GE;
3434 return bc_error_bad_character(c);
3442 bc_lex_lineComment(l);
3448 if (isdigit(l->buf[l->i]))
3449 s = bc_lex_number(l, c);
3451 s = bc_error_bad_character(c);
3472 s = bc_lex_number(l, c);
3478 s = dc_lex_string(l);
3484 l->t.t = BC_LEX_INVALID;
3485 s = bc_error_bad_character(c);
3494 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3496 bc_program_addFunc(name, idx);
3497 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3500 static void bc_parse_pushName(BcParse *p, char *name)
3502 size_t i = 0, len = strlen(name);
3504 for (; i < len; ++i) bc_parse_push(p, name[i]);
3505 bc_parse_push(p, BC_PARSE_STREND);
3510 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3512 unsigned char amt, i, nums[sizeof(size_t)];
3514 for (amt = 0; idx; ++amt) {
3515 nums[amt] = (char) idx;
3516 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3519 bc_parse_push(p, amt);
3520 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3523 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3525 char *num = xstrdup(p->l.t.v.v);
3526 size_t idx = G.prog.consts.len;
3528 bc_vec_push(&G.prog.consts, &num);
3530 bc_parse_push(p, BC_INST_NUM);
3531 bc_parse_pushIndex(p, idx);
3534 (*prev) = BC_INST_NUM;
3537 static BcStatus bc_parse_text(BcParse *p, const char *text)
3541 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3543 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3544 p->l.t.t = BC_LEX_INVALID;
3547 if (!BC_PARSE_CAN_EXEC(p))
3548 return bc_error("file is not executable");
3551 return bc_lex_text(&p->l, text);
3554 // Called when bc/dc_parse_parse() detects a failure,
3555 // resets parsing structures.
3556 static void bc_parse_reset(BcParse *p)
3558 if (p->fidx != BC_PROG_MAIN) {
3559 p->func->nparams = 0;
3560 bc_vec_pop_all(&p->func->code);
3561 bc_vec_pop_all(&p->func->autos);
3562 bc_vec_pop_all(&p->func->labels);
3564 bc_parse_updateFunc(p, BC_PROG_MAIN);
3568 p->l.t.t = BC_LEX_EOF;
3569 p->auto_part = (p->nbraces = 0);
3571 bc_vec_npop(&p->flags, p->flags.len - 1);
3572 bc_vec_pop_all(&p->exits);
3573 bc_vec_pop_all(&p->conds);
3574 bc_vec_pop_all(&p->ops);
3579 static void bc_parse_free(BcParse *p)
3581 bc_vec_free(&p->flags);
3582 bc_vec_free(&p->exits);
3583 bc_vec_free(&p->conds);
3584 bc_vec_free(&p->ops);
3588 static void bc_parse_create(BcParse *p, size_t func,
3589 BcParseParse parse, BcLexNext next)
3591 memset(p, 0, sizeof(BcParse));
3593 bc_lex_init(&p->l, next);
3594 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3595 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3596 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3597 bc_vec_pushZeroByte(&p->flags);
3598 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3601 // p->auto_part = p->nbraces = 0; - already is
3602 bc_parse_updateFunc(p, func);
3606 static BcStatus bc_parse_else(BcParse *p);
3607 static BcStatus bc_parse_stmt(BcParse *p);
3609 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3610 size_t *nexprs, bool next)
3612 BcStatus s = BC_STATUS_SUCCESS;
3614 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3615 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3617 while (p->ops.len > start) {
3619 t = BC_PARSE_TOP_OP(p);
3620 if (t == BC_LEX_LPAREN) break;
3622 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3623 if (l >= r && (l != r || !left)) break;
3625 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3626 bc_vec_pop(&p->ops);
3627 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3630 bc_vec_push(&p->ops, &type);
3631 if (next) s = bc_lex_next(&p->l);
3636 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3640 if (p->ops.len <= ops_bgn)
3641 return bc_error_bad_expression();
3642 top = BC_PARSE_TOP_OP(p);
3644 while (top != BC_LEX_LPAREN) {
3646 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3648 bc_vec_pop(&p->ops);
3649 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3651 if (p->ops.len <= ops_bgn)
3652 return bc_error_bad_expression();
3653 top = BC_PARSE_TOP_OP(p);
3656 bc_vec_pop(&p->ops);
3658 return bc_lex_next(&p->l);
3661 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3667 s = bc_lex_next(&p->l);
3670 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3672 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3673 s = bc_parse_expr(p, flags, bc_parse_next_param);
3676 comma = p->l.t.t == BC_LEX_COMMA;
3678 s = bc_lex_next(&p->l);
3683 if (comma) return bc_error_bad_token();
3684 bc_parse_push(p, BC_INST_CALL);
3685 bc_parse_pushIndex(p, nparams);
3687 return BC_STATUS_SUCCESS;
3690 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3693 BcId entry, *entry_ptr;
3698 s = bc_parse_params(p, flags);
3701 if (p->l.t.t != BC_LEX_RPAREN) {
3702 s = bc_error_bad_token();
3706 idx = bc_map_index(&G.prog.fn_map, &entry);
3708 if (idx == BC_VEC_INVALID_IDX) {
3709 name = xstrdup(entry.name);
3710 bc_parse_addFunc(p, name, &idx);
3711 idx = bc_map_index(&G.prog.fn_map, &entry);
3717 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3718 bc_parse_pushIndex(p, entry_ptr->idx);
3720 return bc_lex_next(&p->l);
3727 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3732 name = xstrdup(p->l.t.v.v);
3733 s = bc_lex_next(&p->l);
3736 if (p->l.t.t == BC_LEX_LBRACKET) {
3738 s = bc_lex_next(&p->l);
3741 if (p->l.t.t == BC_LEX_RBRACKET) {
3743 if (!(flags & BC_PARSE_ARRAY)) {
3744 s = bc_error_bad_expression();
3748 *type = BC_INST_ARRAY;
3752 *type = BC_INST_ARRAY_ELEM;
3754 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3755 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3759 s = bc_lex_next(&p->l);
3761 bc_parse_push(p, *type);
3762 bc_parse_pushName(p, name);
3764 else if (p->l.t.t == BC_LEX_LPAREN) {
3766 if (flags & BC_PARSE_NOCALL) {
3767 s = bc_error_bad_token();
3771 *type = BC_INST_CALL;
3772 s = bc_parse_call(p, name, flags);
3775 *type = BC_INST_VAR;
3776 bc_parse_push(p, BC_INST_VAR);
3777 bc_parse_pushName(p, name);
3787 static BcStatus bc_parse_read(BcParse *p)
3791 s = bc_lex_next(&p->l);
3793 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3795 s = bc_lex_next(&p->l);
3797 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3799 bc_parse_push(p, BC_INST_READ);
3801 return bc_lex_next(&p->l);
3804 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3809 s = bc_lex_next(&p->l);
3811 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3813 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3815 s = bc_lex_next(&p->l);
3818 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3821 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3823 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3824 bc_parse_push(p, *prev);
3826 return bc_lex_next(&p->l);
3829 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3833 s = bc_lex_next(&p->l);
3836 if (p->l.t.t != BC_LEX_LPAREN) {
3837 *type = BC_INST_SCALE;
3838 bc_parse_push(p, BC_INST_SCALE);
3839 return BC_STATUS_SUCCESS;
3842 *type = BC_INST_SCALE_FUNC;
3843 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3845 s = bc_lex_next(&p->l);
3848 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3850 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3851 bc_parse_push(p, BC_INST_SCALE_FUNC);
3853 return bc_lex_next(&p->l);
3856 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3857 size_t *nexprs, uint8_t flags)
3862 BcInst etype = *prev;
3864 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3865 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3866 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3868 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3869 bc_parse_push(p, inst);
3870 s = bc_lex_next(&p->l);
3874 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3877 s = bc_lex_next(&p->l);
3881 // Because we parse the next part of the expression
3882 // right here, we need to increment this.
3883 *nexprs = *nexprs + 1;
3889 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3893 case BC_LEX_KEY_IBASE:
3894 case BC_LEX_KEY_LAST:
3895 case BC_LEX_KEY_OBASE:
3897 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3898 s = bc_lex_next(&p->l);
3902 case BC_LEX_KEY_SCALE:
3904 s = bc_lex_next(&p->l);
3906 if (p->l.t.t == BC_LEX_LPAREN)
3907 s = bc_error_bad_token();
3909 bc_parse_push(p, BC_INST_SCALE);
3915 s = bc_error_bad_token();
3920 if (!s) bc_parse_push(p, inst);
3926 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3927 bool rparen, size_t *nexprs)
3931 BcInst etype = *prev;
3933 s = bc_lex_next(&p->l);
3936 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3937 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3940 *prev = BC_PARSE_TOKEN_INST(type);
3942 // We can just push onto the op stack because this is the largest
3943 // precedence operator that gets pushed. Inc/dec does not.
3944 if (type != BC_LEX_OP_MINUS)
3945 bc_vec_push(&p->ops, &type);
3947 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3952 static BcStatus bc_parse_string(BcParse *p, char inst)
3954 char *str = xstrdup(p->l.t.v.v);
3956 bc_parse_push(p, BC_INST_STR);
3957 bc_parse_pushIndex(p, G.prog.strs.len);
3958 bc_vec_push(&G.prog.strs, &str);
3959 bc_parse_push(p, inst);
3961 return bc_lex_next(&p->l);
3964 static BcStatus bc_parse_print(BcParse *p)
3970 s = bc_lex_next(&p->l);
3975 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3976 return bc_error("bad print statement");
3978 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3980 if (type == BC_LEX_STR)
3981 s = bc_parse_string(p, BC_INST_PRINT_POP);
3983 s = bc_parse_expr(p, 0, bc_parse_next_print);
3985 bc_parse_push(p, BC_INST_PRINT_POP);
3990 comma = p->l.t.t == BC_LEX_COMMA;
3991 if (comma) s = bc_lex_next(&p->l);
3996 if (comma) return bc_error_bad_token();
3998 return bc_lex_next(&p->l);
4001 static BcStatus bc_parse_return(BcParse *p)
4007 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
4009 s = bc_lex_next(&p->l);
4013 paren = t == BC_LEX_LPAREN;
4015 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4016 bc_parse_push(p, BC_INST_RET0);
4019 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4020 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4023 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4024 bc_parse_push(p, BC_INST_RET0);
4025 s = bc_lex_next(&p->l);
4029 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4030 s = bc_posix_error("POSIX requires parentheses around return expressions");
4034 bc_parse_push(p, BC_INST_RET);
4040 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4042 BcStatus s = BC_STATUS_SUCCESS;
4044 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4045 return bc_error_bad_token();
4049 if (p->l.t.t == BC_LEX_RBRACE) {
4050 if (!p->nbraces) return bc_error_bad_token();
4052 s = bc_lex_next(&p->l);
4056 return bc_error_bad_token();
4059 if (BC_PARSE_IF(p)) {
4063 while (p->l.t.t == BC_LEX_NLINE) {
4064 s = bc_lex_next(&p->l);
4068 bc_vec_pop(&p->flags);
4070 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4071 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4073 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4075 else if (BC_PARSE_ELSE(p)) {
4080 bc_vec_pop(&p->flags);
4082 ip = bc_vec_top(&p->exits);
4083 label = bc_vec_item(&p->func->labels, ip->idx);
4084 *label = p->func->code.len;
4086 bc_vec_pop(&p->exits);
4088 else if (BC_PARSE_FUNC_INNER(p)) {
4089 bc_parse_push(p, BC_INST_RET0);
4090 bc_parse_updateFunc(p, BC_PROG_MAIN);
4091 bc_vec_pop(&p->flags);
4095 BcInstPtr *ip = bc_vec_top(&p->exits);
4096 size_t *label = bc_vec_top(&p->conds);
4098 bc_parse_push(p, BC_INST_JUMP);
4099 bc_parse_pushIndex(p, *label);
4101 label = bc_vec_item(&p->func->labels, ip->idx);
4102 *label = p->func->code.len;
4104 bc_vec_pop(&p->flags);
4105 bc_vec_pop(&p->exits);
4106 bc_vec_pop(&p->conds);
4112 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4114 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4115 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4116 flags |= BC_PARSE_FLAG_BODY;
4117 bc_vec_push(&p->flags, &flags);
4120 static void bc_parse_noElse(BcParse *p)
4124 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4126 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4128 ip = bc_vec_top(&p->exits);
4129 label = bc_vec_item(&p->func->labels, ip->idx);
4130 *label = p->func->code.len;
4132 bc_vec_pop(&p->exits);
4135 static BcStatus bc_parse_if(BcParse *p)
4140 s = bc_lex_next(&p->l);
4142 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4144 s = bc_lex_next(&p->l);
4146 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4148 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4150 s = bc_lex_next(&p->l);
4152 bc_parse_push(p, BC_INST_JUMP_ZERO);
4154 ip.idx = p->func->labels.len;
4155 ip.func = ip.len = 0;
4157 bc_parse_pushIndex(p, ip.idx);
4158 bc_vec_push(&p->exits, &ip);
4159 bc_vec_push(&p->func->labels, &ip.idx);
4160 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4162 return BC_STATUS_SUCCESS;
4165 static BcStatus bc_parse_else(BcParse *p)
4169 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4171 ip.idx = p->func->labels.len;
4172 ip.func = ip.len = 0;
4174 bc_parse_push(p, BC_INST_JUMP);
4175 bc_parse_pushIndex(p, ip.idx);
4179 bc_vec_push(&p->exits, &ip);
4180 bc_vec_push(&p->func->labels, &ip.idx);
4181 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4183 return bc_lex_next(&p->l);
4186 static BcStatus bc_parse_while(BcParse *p)
4191 s = bc_lex_next(&p->l);
4193 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4194 s = bc_lex_next(&p->l);
4197 ip.idx = p->func->labels.len;
4199 bc_vec_push(&p->func->labels, &p->func->code.len);
4200 bc_vec_push(&p->conds, &ip.idx);
4202 ip.idx = p->func->labels.len;
4206 bc_vec_push(&p->exits, &ip);
4207 bc_vec_push(&p->func->labels, &ip.idx);
4209 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4211 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4212 s = bc_lex_next(&p->l);
4215 bc_parse_push(p, BC_INST_JUMP_ZERO);
4216 bc_parse_pushIndex(p, ip.idx);
4217 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4219 return BC_STATUS_SUCCESS;
4222 static BcStatus bc_parse_for(BcParse *p)
4226 size_t cond_idx, exit_idx, body_idx, update_idx;
4228 s = bc_lex_next(&p->l);
4230 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4231 s = bc_lex_next(&p->l);
4234 if (p->l.t.t != BC_LEX_SCOLON)
4235 s = bc_parse_expr(p, 0, bc_parse_next_for);
4237 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4240 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4241 s = bc_lex_next(&p->l);
4244 cond_idx = p->func->labels.len;
4245 update_idx = cond_idx + 1;
4246 body_idx = update_idx + 1;
4247 exit_idx = body_idx + 1;
4249 bc_vec_push(&p->func->labels, &p->func->code.len);
4251 if (p->l.t.t != BC_LEX_SCOLON)
4252 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4254 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4257 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4259 s = bc_lex_next(&p->l);
4262 bc_parse_push(p, BC_INST_JUMP_ZERO);
4263 bc_parse_pushIndex(p, exit_idx);
4264 bc_parse_push(p, BC_INST_JUMP);
4265 bc_parse_pushIndex(p, body_idx);
4267 ip.idx = p->func->labels.len;
4269 bc_vec_push(&p->conds, &update_idx);
4270 bc_vec_push(&p->func->labels, &p->func->code.len);
4272 if (p->l.t.t != BC_LEX_RPAREN)
4273 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4275 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4279 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4280 bc_parse_push(p, BC_INST_JUMP);
4281 bc_parse_pushIndex(p, cond_idx);
4282 bc_vec_push(&p->func->labels, &p->func->code.len);
4288 bc_vec_push(&p->exits, &ip);
4289 bc_vec_push(&p->func->labels, &ip.idx);
4291 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4293 return BC_STATUS_SUCCESS;
4296 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4302 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4304 if (type == BC_LEX_KEY_BREAK) {
4306 if (p->exits.len == 0) return bc_error_bad_token();
4308 i = p->exits.len - 1;
4309 ip = bc_vec_item(&p->exits, i);
4311 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4312 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4317 i = *((size_t *) bc_vec_top(&p->conds));
4319 bc_parse_push(p, BC_INST_JUMP);
4320 bc_parse_pushIndex(p, i);
4322 s = bc_lex_next(&p->l);
4325 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4326 return bc_error_bad_token();
4328 return bc_lex_next(&p->l);
4331 static BcStatus bc_parse_func(BcParse *p)
4334 bool var, comma = false;
4338 s = bc_lex_next(&p->l);
4340 if (p->l.t.t != BC_LEX_NAME)
4341 return bc_error("bad function definition");
4343 name = xstrdup(p->l.t.v.v);
4344 bc_parse_addFunc(p, name, &p->fidx);
4346 s = bc_lex_next(&p->l);
4348 if (p->l.t.t != BC_LEX_LPAREN)
4349 return bc_error("bad function definition");
4350 s = bc_lex_next(&p->l);
4353 while (p->l.t.t != BC_LEX_RPAREN) {
4355 if (p->l.t.t != BC_LEX_NAME)
4356 return bc_error("bad function definition");
4360 name = xstrdup(p->l.t.v.v);
4361 s = bc_lex_next(&p->l);
4364 var = p->l.t.t != BC_LEX_LBRACKET;
4368 s = bc_lex_next(&p->l);
4371 if (p->l.t.t != BC_LEX_RBRACKET) {
4372 s = bc_error("bad function definition");
4376 s = bc_lex_next(&p->l);
4380 comma = p->l.t.t == BC_LEX_COMMA;
4382 s = bc_lex_next(&p->l);
4386 s = bc_func_insert(p->func, name, var);
4390 if (comma) return bc_error("bad function definition");
4392 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4393 bc_parse_startBody(p, flags);
4395 s = bc_lex_next(&p->l);
4398 if (p->l.t.t != BC_LEX_LBRACE)
4399 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4408 static BcStatus bc_parse_auto(BcParse *p)
4411 bool comma, var, one;
4414 if (!p->auto_part) return bc_error_bad_token();
4415 s = bc_lex_next(&p->l);
4418 p->auto_part = comma = false;
4419 one = p->l.t.t == BC_LEX_NAME;
4421 while (p->l.t.t == BC_LEX_NAME) {
4423 name = xstrdup(p->l.t.v.v);
4424 s = bc_lex_next(&p->l);
4427 var = p->l.t.t != BC_LEX_LBRACKET;
4430 s = bc_lex_next(&p->l);
4433 if (p->l.t.t != BC_LEX_RBRACKET) {
4434 s = bc_error("bad function definition");
4438 s = bc_lex_next(&p->l);
4442 comma = p->l.t.t == BC_LEX_COMMA;
4444 s = bc_lex_next(&p->l);
4448 s = bc_func_insert(p->func, name, var);
4452 if (comma) return bc_error("bad function definition");
4453 if (!one) return bc_error("no auto variable found");
4455 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4456 return bc_error_bad_token();
4458 return bc_lex_next(&p->l);
4465 static BcStatus bc_parse_body(BcParse *p, bool brace)
4467 BcStatus s = BC_STATUS_SUCCESS;
4468 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4470 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4472 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4474 if (!brace) return bc_error_bad_token();
4475 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4477 if (!p->auto_part) {
4478 s = bc_parse_auto(p);
4482 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4485 s = bc_parse_stmt(p);
4486 if (!s && !brace) s = bc_parse_endBody(p, false);
4492 static BcStatus bc_parse_stmt(BcParse *p)
4494 BcStatus s = BC_STATUS_SUCCESS;
4500 return bc_lex_next(&p->l);
4503 case BC_LEX_KEY_ELSE:
4505 p->auto_part = false;
4511 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4514 s = bc_lex_next(&p->l);
4517 return bc_parse_body(p, true);
4520 case BC_LEX_KEY_AUTO:
4522 return bc_parse_auto(p);
4527 p->auto_part = false;
4529 if (BC_PARSE_IF_END(p)) {
4531 return BC_STATUS_SUCCESS;
4533 else if (BC_PARSE_BODY(p))
4534 return bc_parse_body(p, false);
4544 case BC_LEX_OP_MINUS:
4545 case BC_LEX_OP_BOOL_NOT:
4549 case BC_LEX_KEY_IBASE:
4550 case BC_LEX_KEY_LAST:
4551 case BC_LEX_KEY_LENGTH:
4552 case BC_LEX_KEY_OBASE:
4553 case BC_LEX_KEY_READ:
4554 case BC_LEX_KEY_SCALE:
4555 case BC_LEX_KEY_SQRT:
4557 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4561 case BC_LEX_KEY_ELSE:
4563 s = bc_parse_else(p);
4569 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4575 s = bc_parse_endBody(p, true);
4581 s = bc_parse_string(p, BC_INST_PRINT_STR);
4585 case BC_LEX_KEY_BREAK:
4586 case BC_LEX_KEY_CONTINUE:
4588 s = bc_parse_loopExit(p, p->l.t.t);
4592 case BC_LEX_KEY_FOR:
4594 s = bc_parse_for(p);
4598 case BC_LEX_KEY_HALT:
4600 bc_parse_push(p, BC_INST_HALT);
4601 s = bc_lex_next(&p->l);
4611 case BC_LEX_KEY_LIMITS:
4613 // "limits" is a compile-time command,
4614 // the output is produced at _parse time_.
4615 s = bc_lex_next(&p->l);
4617 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4618 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4619 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4620 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4621 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4622 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4623 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4624 printf("Number of vars = %lu\n", BC_MAX_VARS);
4628 case BC_LEX_KEY_PRINT:
4630 s = bc_parse_print(p);
4634 case BC_LEX_KEY_QUIT:
4636 // "quit" is a compile-time command. For example,
4637 // "if (0 == 1) quit" terminates when parsing the statement,
4638 // not when it is executed
4642 case BC_LEX_KEY_RETURN:
4644 s = bc_parse_return(p);
4648 case BC_LEX_KEY_WHILE:
4650 s = bc_parse_while(p);
4656 s = bc_error_bad_token();
4664 static BcStatus bc_parse_parse(BcParse *p)
4668 if (p->l.t.t == BC_LEX_EOF)
4669 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4670 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4671 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4672 s = bc_parse_func(p);
4675 s = bc_parse_stmt(p);
4677 if (s || G_interrupt) {
4679 s = BC_STATUS_FAILURE;
4685 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4687 BcStatus s = BC_STATUS_SUCCESS;
4688 BcInst prev = BC_INST_PRINT;
4689 BcLexType top, t = p->l.t.t;
4690 size_t nexprs = 0, ops_bgn = p->ops.len;
4691 uint32_t i, nparens, nrelops;
4692 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4694 paren_first = p->l.t.t == BC_LEX_LPAREN;
4695 nparens = nrelops = 0;
4696 paren_expr = rprn = done = get_token = assign = false;
4699 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4705 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4706 rprn = get_token = bin_last = false;
4710 case BC_LEX_OP_MINUS:
4712 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4713 rprn = get_token = false;
4714 bin_last = prev == BC_INST_MINUS;
4718 case BC_LEX_OP_ASSIGN_POWER:
4719 case BC_LEX_OP_ASSIGN_MULTIPLY:
4720 case BC_LEX_OP_ASSIGN_DIVIDE:
4721 case BC_LEX_OP_ASSIGN_MODULUS:
4722 case BC_LEX_OP_ASSIGN_PLUS:
4723 case BC_LEX_OP_ASSIGN_MINUS:
4724 case BC_LEX_OP_ASSIGN:
4726 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4727 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4728 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4730 s = bc_error("bad assignment:"
4731 " left side must be scale,"
4732 " ibase, obase, last, var,"
4739 case BC_LEX_OP_POWER:
4740 case BC_LEX_OP_MULTIPLY:
4741 case BC_LEX_OP_DIVIDE:
4742 case BC_LEX_OP_MODULUS:
4743 case BC_LEX_OP_PLUS:
4744 case BC_LEX_OP_REL_EQ:
4745 case BC_LEX_OP_REL_LE:
4746 case BC_LEX_OP_REL_GE:
4747 case BC_LEX_OP_REL_NE:
4748 case BC_LEX_OP_REL_LT:
4749 case BC_LEX_OP_REL_GT:
4750 case BC_LEX_OP_BOOL_NOT:
4751 case BC_LEX_OP_BOOL_OR:
4752 case BC_LEX_OP_BOOL_AND:
4754 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4755 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4757 return bc_error_bad_expression();
4760 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4761 prev = BC_PARSE_TOKEN_INST(t);
4762 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4763 rprn = get_token = false;
4764 bin_last = t != BC_LEX_OP_BOOL_NOT;
4771 if (BC_PARSE_LEAF(prev, rprn))
4772 return bc_error_bad_expression();
4774 paren_expr = rprn = bin_last = false;
4776 bc_vec_push(&p->ops, &t);
4783 if (bin_last || prev == BC_INST_BOOL_NOT)
4784 return bc_error_bad_expression();
4787 s = BC_STATUS_SUCCESS;
4792 else if (!paren_expr)
4793 return BC_STATUS_PARSE_EMPTY_EXP;
4796 paren_expr = rprn = true;
4797 get_token = bin_last = false;
4799 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4806 if (BC_PARSE_LEAF(prev, rprn))
4807 return bc_error_bad_expression();
4809 rprn = get_token = bin_last = false;
4810 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4818 if (BC_PARSE_LEAF(prev, rprn))
4819 return bc_error_bad_expression();
4820 bc_parse_number(p, &prev, &nexprs);
4821 paren_expr = get_token = true;
4822 rprn = bin_last = false;
4827 case BC_LEX_KEY_IBASE:
4828 case BC_LEX_KEY_LAST:
4829 case BC_LEX_KEY_OBASE:
4831 if (BC_PARSE_LEAF(prev, rprn))
4832 return bc_error_bad_expression();
4833 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4834 bc_parse_push(p, (char) prev);
4836 paren_expr = get_token = true;
4837 rprn = bin_last = false;
4843 case BC_LEX_KEY_LENGTH:
4844 case BC_LEX_KEY_SQRT:
4846 if (BC_PARSE_LEAF(prev, rprn))
4847 return bc_error_bad_expression();
4848 s = bc_parse_builtin(p, t, flags, &prev);
4850 rprn = get_token = bin_last = false;
4856 case BC_LEX_KEY_READ:
4858 if (BC_PARSE_LEAF(prev, rprn))
4859 return bc_error_bad_expression();
4860 else if (flags & BC_PARSE_NOREAD)
4861 s = bc_error_nested_read_call();
4863 s = bc_parse_read(p);
4866 rprn = get_token = bin_last = false;
4868 prev = BC_INST_READ;
4873 case BC_LEX_KEY_SCALE:
4875 if (BC_PARSE_LEAF(prev, rprn))
4876 return bc_error_bad_expression();
4877 s = bc_parse_scale(p, &prev, flags);
4879 rprn = get_token = bin_last = false;
4881 prev = BC_INST_SCALE;
4888 s = bc_error_bad_token();
4893 if (!s && get_token) s = bc_lex_next(&p->l);
4897 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4899 while (p->ops.len > ops_bgn) {
4901 top = BC_PARSE_TOP_OP(p);
4902 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4904 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4905 return bc_error_bad_expression();
4907 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4909 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4910 bc_vec_pop(&p->ops);
4913 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4914 return bc_error_bad_expression();
4916 for (i = 0; i < next.len; ++i)
4917 if (t == next.tokens[i])
4919 return bc_error_bad_expression();
4922 if (!(flags & BC_PARSE_REL) && nrelops) {
4923 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4926 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4927 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4931 if (flags & BC_PARSE_PRINT) {
4932 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4933 bc_parse_push(p, BC_INST_POP);
4939 static void bc_parse_init(BcParse *p, size_t func)
4941 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4944 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4946 return bc_parse_expr(p, flags, bc_parse_next_read);
4951 static BcStatus dc_parse_register(BcParse *p)
4956 s = bc_lex_next(&p->l);
4958 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4960 name = xstrdup(p->l.t.v.v);
4961 bc_parse_pushName(p, name);
4966 static BcStatus dc_parse_string(BcParse *p)
4968 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4969 size_t idx, len = G.prog.strs.len;
4971 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4974 str = xstrdup(p->l.t.v.v);
4975 bc_parse_push(p, BC_INST_STR);
4976 bc_parse_pushIndex(p, len);
4977 bc_vec_push(&G.prog.strs, &str);
4978 bc_parse_addFunc(p, name, &idx);
4980 return bc_lex_next(&p->l);
4983 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4987 bc_parse_push(p, inst);
4989 s = dc_parse_register(p);
4994 bc_parse_push(p, BC_INST_SWAP);
4995 bc_parse_push(p, BC_INST_ASSIGN);
4996 bc_parse_push(p, BC_INST_POP);
4999 return bc_lex_next(&p->l);
5002 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5006 bc_parse_push(p, inst);
5007 bc_parse_push(p, BC_INST_EXEC_COND);
5009 s = dc_parse_register(p);
5012 s = bc_lex_next(&p->l);
5015 if (p->l.t.t == BC_LEX_ELSE) {
5016 s = dc_parse_register(p);
5018 s = bc_lex_next(&p->l);
5021 bc_parse_push(p, BC_PARSE_STREND);
5026 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5028 BcStatus s = BC_STATUS_SUCCESS;
5031 bool assign, get_token = false;
5035 case BC_LEX_OP_REL_EQ:
5036 case BC_LEX_OP_REL_LE:
5037 case BC_LEX_OP_REL_GE:
5038 case BC_LEX_OP_REL_NE:
5039 case BC_LEX_OP_REL_LT:
5040 case BC_LEX_OP_REL_GT:
5042 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5049 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5055 s = dc_parse_string(p);
5062 if (t == BC_LEX_NEG) {
5063 s = bc_lex_next(&p->l);
5065 if (p->l.t.t != BC_LEX_NUMBER)
5066 return bc_error_bad_token();
5069 bc_parse_number(p, &prev, &p->nbraces);
5071 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5077 case BC_LEX_KEY_READ:
5079 if (flags & BC_PARSE_NOREAD)
5080 s = bc_error_nested_read_call();
5082 bc_parse_push(p, BC_INST_READ);
5087 case BC_LEX_OP_ASSIGN:
5088 case BC_LEX_STORE_PUSH:
5090 assign = t == BC_LEX_OP_ASSIGN;
5091 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5092 s = dc_parse_mem(p, inst, true, assign);
5097 case BC_LEX_LOAD_POP:
5099 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5100 s = dc_parse_mem(p, inst, true, false);
5104 case BC_LEX_STORE_IBASE:
5105 case BC_LEX_STORE_SCALE:
5106 case BC_LEX_STORE_OBASE:
5108 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5109 s = dc_parse_mem(p, inst, false, true);
5115 s = bc_error_bad_token();
5121 if (!s && get_token) s = bc_lex_next(&p->l);
5126 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5128 BcStatus s = BC_STATUS_SUCCESS;
5132 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5134 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5136 inst = dc_parse_insts[t];
5138 if (inst != BC_INST_INVALID) {
5139 bc_parse_push(p, inst);
5140 s = bc_lex_next(&p->l);
5143 s = dc_parse_token(p, t, flags);
5146 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5147 bc_parse_push(p, BC_INST_POP_EXEC);
5152 static BcStatus dc_parse_parse(BcParse *p)
5156 if (p->l.t.t == BC_LEX_EOF)
5157 s = bc_error("end of file");
5159 s = dc_parse_expr(p, 0);
5161 if (s || G_interrupt) {
5163 s = BC_STATUS_FAILURE;
5169 static void dc_parse_init(BcParse *p, size_t func)
5171 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5175 static void common_parse_init(BcParse *p, size_t func)
5178 bc_parse_init(p, func);
5180 dc_parse_init(p, func);
5184 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5187 return bc_parse_expression(p, flags);
5189 return dc_parse_expr(p, flags);
5193 static BcVec* bc_program_search(char *id, bool var)
5201 v = var ? &G.prog.vars : &G.prog.arrs;
5202 map = var ? &G.prog.var_map : &G.prog.arr_map;
5206 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5209 bc_array_init(&data.v, var);
5210 bc_vec_push(v, &data.v);
5213 ptr = bc_vec_item(map, i);
5214 if (new) ptr->name = xstrdup(e.name);
5215 return bc_vec_item(v, ptr->idx);
5218 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5220 BcStatus s = BC_STATUS_SUCCESS;
5225 case BC_RESULT_TEMP:
5226 case BC_RESULT_IBASE:
5227 case BC_RESULT_SCALE:
5228 case BC_RESULT_OBASE:
5234 case BC_RESULT_CONSTANT:
5236 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5237 size_t base_t, len = strlen(*str);
5240 bc_num_init(&r->d.n, len);
5242 hex = hex && len == 1;
5243 base = hex ? &G.prog.hexb : &G.prog.ib;
5244 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5245 s = bc_num_parse(&r->d.n, *str, base, base_t);
5248 bc_num_free(&r->d.n);
5253 r->t = BC_RESULT_TEMP;
5259 case BC_RESULT_ARRAY:
5260 case BC_RESULT_ARRAY_ELEM:
5264 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5266 if (r->t == BC_RESULT_ARRAY_ELEM) {
5268 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5269 *num = bc_vec_item(v, r->d.id.idx);
5272 *num = bc_vec_top(v);
5277 case BC_RESULT_LAST:
5279 *num = &G.prog.last;
5293 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5294 BcResult **r, BcNum **rn, bool assign)
5298 BcResultType lt, rt;
5300 if (!BC_PROG_STACK(&G.prog.results, 2))
5301 return bc_error_stack_has_too_few_elements();
5303 *r = bc_vec_item_rev(&G.prog.results, 0);
5304 *l = bc_vec_item_rev(&G.prog.results, 1);
5308 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5310 s = bc_program_num(*l, ln, false);
5312 s = bc_program_num(*r, rn, hex);
5315 // We run this again under these conditions in case any vector has been
5316 // reallocated out from under the BcNums or arrays we had.
5317 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5318 s = bc_program_num(*l, ln, false);
5322 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5323 return bc_error_variable_is_wrong_type();
5324 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5325 return bc_error_variable_is_wrong_type();
5330 static void bc_program_binOpRetire(BcResult *r)
5332 r->t = BC_RESULT_TEMP;
5333 bc_vec_pop(&G.prog.results);
5334 bc_vec_pop(&G.prog.results);
5335 bc_vec_push(&G.prog.results, r);
5338 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5342 if (!BC_PROG_STACK(&G.prog.results, 1))
5343 return bc_error_stack_has_too_few_elements();
5344 *r = bc_vec_top(&G.prog.results);
5346 s = bc_program_num(*r, n, false);
5349 if (!BC_PROG_NUM((*r), (*n)))
5350 return bc_error_variable_is_wrong_type();
5355 static void bc_program_retire(BcResult *r, BcResultType t)
5358 bc_vec_pop(&G.prog.results);
5359 bc_vec_push(&G.prog.results, r);
5362 static BcStatus bc_program_op(char inst)
5365 BcResult *opd1, *opd2, res;
5366 BcNum *n1, *n2 = NULL;
5368 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5370 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5372 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5374 bc_program_binOpRetire(&res);
5379 bc_num_free(&res.d.n);
5383 static BcStatus bc_program_read(void)
5385 const char *sv_file;
5391 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5393 for (i = 0; i < G.prog.stack.len; ++i) {
5394 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5395 if (ip_ptr->func == BC_PROG_READ)
5396 return bc_error_nested_read_call();
5399 bc_vec_pop_all(&f->code);
5400 bc_char_vec_init(&buf);
5402 sv_file = G.prog.file;
5405 s = bc_read_line(&buf, "read> ");
5408 common_parse_init(&parse, BC_PROG_READ);
5409 bc_lex_file(&parse.l);
5411 s = bc_parse_text(&parse, buf.v);
5412 if (s) goto exec_err;
5413 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5414 if (s) goto exec_err;
5416 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5417 s = bc_error("bad read() expression");
5421 ip.func = BC_PROG_READ;
5423 ip.len = G.prog.results.len;
5425 // Update this pointer, just in case.
5426 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5428 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5429 bc_vec_push(&G.prog.stack, &ip);
5432 G.prog.file = sv_file;
5433 bc_parse_free(&parse);
5439 static size_t bc_program_index(char *code, size_t *bgn)
5441 char amt = code[(*bgn)++], i = 0;
5444 for (; i < amt; ++i, ++(*bgn))
5445 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5450 static char *bc_program_name(char *code, size_t *bgn)
5453 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5455 s = xmalloc(ptr - str + 1);
5458 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5466 static void bc_program_printString(const char *str, size_t *nchars)
5468 size_t i, len = strlen(str);
5477 for (i = 0; i < len; ++i, ++(*nchars)) {
5481 if (c != '\\' || i == len - 1)
5541 // Just print the backslash and following character.
5552 static BcStatus bc_program_print(char inst, size_t idx)
5554 BcStatus s = BC_STATUS_SUCCESS;
5559 bool pop = inst != BC_INST_PRINT;
5561 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5562 return bc_error_stack_has_too_few_elements();
5564 r = bc_vec_item_rev(&G.prog.results, idx);
5565 s = bc_program_num(r, &num, false);
5568 if (BC_PROG_NUM(r, num)) {
5569 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5570 if (!s) bc_num_copy(&G.prog.last, num);
5574 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5575 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5577 if (inst == BC_INST_PRINT_STR) {
5578 for (i = 0, len = strlen(str); i < len; ++i) {
5581 if (c == '\n') G.prog.nchars = SIZE_MAX;
5586 bc_program_printString(str, &G.prog.nchars);
5587 if (inst == BC_INST_PRINT) bb_putchar('\n');
5591 if (!s && pop) bc_vec_pop(&G.prog.results);
5596 static BcStatus bc_program_negate(void)
5602 s = bc_program_prep(&ptr, &num);
5605 bc_num_init(&res.d.n, num->len);
5606 bc_num_copy(&res.d.n, num);
5607 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5609 bc_program_retire(&res, BC_RESULT_TEMP);
5614 static BcStatus bc_program_logical(char inst)
5617 BcResult *opd1, *opd2, res;
5622 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5624 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5626 if (inst == BC_INST_BOOL_AND)
5627 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5628 else if (inst == BC_INST_BOOL_OR)
5629 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5632 cmp = bc_num_cmp(n1, n2);
5636 case BC_INST_REL_EQ:
5642 case BC_INST_REL_LE:
5648 case BC_INST_REL_GE:
5654 case BC_INST_REL_NE:
5660 case BC_INST_REL_LT:
5666 case BC_INST_REL_GT:
5674 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5676 bc_program_binOpRetire(&res);
5682 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5688 memset(&n2, 0, sizeof(BcNum));
5689 n2.rdx = res.d.id.idx = r->d.id.idx;
5690 res.t = BC_RESULT_STR;
5693 if (!BC_PROG_STACK(&G.prog.results, 2))
5694 return bc_error_stack_has_too_few_elements();
5696 bc_vec_pop(&G.prog.results);
5699 bc_vec_pop(&G.prog.results);
5701 bc_vec_push(&G.prog.results, &res);
5702 bc_vec_push(v, &n2);
5704 return BC_STATUS_SUCCESS;
5708 static BcStatus bc_program_copyToVar(char *name, bool var)
5715 if (!BC_PROG_STACK(&G.prog.results, 1))
5716 return bc_error_stack_has_too_few_elements();
5718 ptr = bc_vec_top(&G.prog.results);
5719 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5720 return bc_error_variable_is_wrong_type();
5721 v = bc_program_search(name, var);
5724 if (ptr->t == BC_RESULT_STR && !var)
5725 return bc_error_variable_is_wrong_type();
5726 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5729 s = bc_program_num(ptr, &n, false);
5732 // Do this once more to make sure that pointers were not invalidated.
5733 v = bc_program_search(name, var);
5736 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5737 bc_num_copy(&r.d.n, n);
5740 bc_array_init(&r.d.v, true);
5741 bc_array_copy(&r.d.v, (BcVec *) n);
5744 bc_vec_push(v, &r.d);
5745 bc_vec_pop(&G.prog.results);
5750 static BcStatus bc_program_assign(char inst)
5753 BcResult *left, *right, res;
5754 BcNum *l = NULL, *r = NULL;
5755 unsigned long val, max;
5756 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5758 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5761 ib = left->t == BC_RESULT_IBASE;
5762 sc = left->t == BC_RESULT_SCALE;
5766 if (right->t == BC_RESULT_STR) {
5770 if (left->t != BC_RESULT_VAR)
5771 return bc_error_variable_is_wrong_type();
5772 v = bc_program_search(left->d.id.name, true);
5774 return bc_program_assignStr(right, v, false);
5778 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5779 return bc_error("bad assignment:"
5780 " left side must be scale,"
5781 " ibase, obase, last, var,"
5786 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5787 return bc_error("divide by zero");
5792 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5799 if (ib || sc || left->t == BC_RESULT_OBASE) {
5800 static const char *const msg[] = {
5801 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5802 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5803 "?1", //BC_RESULT_LAST
5804 "?2", //BC_RESULT_CONSTANT
5805 "?3", //BC_RESULT_ONE
5806 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5810 s = bc_num_ulong(l, &val);
5813 s = left->t - BC_RESULT_IBASE;
5816 ptr = &G.prog.scale;
5819 if (val < BC_NUM_MIN_BASE)
5820 return bc_error(msg[s]);
5821 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5822 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5826 return bc_error(msg[s]);
5828 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5830 *ptr = (size_t) val;
5831 s = BC_STATUS_SUCCESS;
5834 bc_num_init(&res.d.n, l->len);
5835 bc_num_copy(&res.d.n, l);
5836 bc_program_binOpRetire(&res);
5842 #define bc_program_pushVar(code, bgn, pop, copy) \
5843 bc_program_pushVar(code, bgn)
5844 // for bc, 'pop' and 'copy' are always false
5846 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5847 bool pop, bool copy)
5849 BcStatus s = BC_STATUS_SUCCESS;
5851 char *name = bc_program_name(code, bgn);
5853 r.t = BC_RESULT_VAR;
5858 BcVec *v = bc_program_search(name, true);
5859 BcNum *num = bc_vec_top(v);
5863 if (!BC_PROG_STACK(v, 2 - copy)) {
5865 return bc_error_stack_has_too_few_elements();
5871 if (!BC_PROG_STR(num)) {
5873 r.t = BC_RESULT_TEMP;
5875 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5876 bc_num_copy(&r.d.n, num);
5879 r.t = BC_RESULT_STR;
5880 r.d.id.idx = num->rdx;
5883 if (!copy) bc_vec_pop(v);
5888 bc_vec_push(&G.prog.results, &r);
5893 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5896 BcStatus s = BC_STATUS_SUCCESS;
5900 r.d.id.name = bc_program_name(code, bgn);
5902 if (inst == BC_INST_ARRAY) {
5903 r.t = BC_RESULT_ARRAY;
5904 bc_vec_push(&G.prog.results, &r);
5911 s = bc_program_prep(&operand, &num);
5913 s = bc_num_ulong(num, &temp);
5916 if (temp > BC_MAX_DIM) {
5917 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5921 r.d.id.idx = (size_t) temp;
5922 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5926 if (s) free(r.d.id.name);
5931 static BcStatus bc_program_incdec(char inst)
5934 BcResult *ptr, res, copy;
5938 s = bc_program_prep(&ptr, &num);
5941 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5942 copy.t = BC_RESULT_TEMP;
5943 bc_num_init(©.d.n, num->len);
5944 bc_num_copy(©.d.n, num);
5947 res.t = BC_RESULT_ONE;
5948 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5949 BC_INST_ASSIGN_PLUS :
5950 BC_INST_ASSIGN_MINUS;
5952 bc_vec_push(&G.prog.results, &res);
5953 bc_program_assign(inst);
5955 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5956 bc_vec_pop(&G.prog.results);
5957 bc_vec_push(&G.prog.results, ©);
5963 static BcStatus bc_program_call(char *code, size_t *idx)
5965 BcStatus s = BC_STATUS_SUCCESS;
5967 size_t i, nparams = bc_program_index(code, idx);
5974 ip.func = bc_program_index(code, idx);
5975 func = bc_vec_item(&G.prog.fns, ip.func);
5977 if (func->code.len == 0) {
5978 return bc_error("undefined function");
5980 if (nparams != func->nparams) {
5981 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5983 ip.len = G.prog.results.len - nparams;
5985 for (i = 0; i < nparams; ++i) {
5987 a = bc_vec_item(&func->autos, nparams - 1 - i);
5988 arg = bc_vec_top(&G.prog.results);
5990 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5991 return bc_error_variable_is_wrong_type();
5993 s = bc_program_copyToVar(a->name, a->idx);
5997 for (; i < func->autos.len; ++i) {
6000 a = bc_vec_item(&func->autos, i);
6001 v = bc_program_search(a->name, a->idx);
6004 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6005 bc_vec_push(v, ¶m.n);
6008 bc_array_init(¶m.v, true);
6009 bc_vec_push(v, ¶m.v);
6013 bc_vec_push(&G.prog.stack, &ip);
6015 return BC_STATUS_SUCCESS;
6018 static BcStatus bc_program_return(char inst)
6024 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6026 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6027 return bc_error_stack_has_too_few_elements();
6029 f = bc_vec_item(&G.prog.fns, ip->func);
6030 res.t = BC_RESULT_TEMP;
6032 if (inst == BC_INST_RET) {
6035 BcResult *operand = bc_vec_top(&G.prog.results);
6037 s = bc_program_num(operand, &num, false);
6039 bc_num_init(&res.d.n, num->len);
6040 bc_num_copy(&res.d.n, num);
6043 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6044 bc_num_zero(&res.d.n);
6047 // We need to pop arguments as well, so this takes that into account.
6048 for (i = 0; i < f->autos.len; ++i) {
6051 BcId *a = bc_vec_item(&f->autos, i);
6053 v = bc_program_search(a->name, a->idx);
6057 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6058 bc_vec_push(&G.prog.results, &res);
6059 bc_vec_pop(&G.prog.stack);
6061 return BC_STATUS_SUCCESS;
6065 static unsigned long bc_program_scale(BcNum *n)
6067 return (unsigned long) n->rdx;
6070 static unsigned long bc_program_len(BcNum *n)
6072 unsigned long len = n->len;
6075 if (n->rdx != n->len) return len;
6076 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6081 static BcStatus bc_program_builtin(char inst)
6087 bool len = inst == BC_INST_LENGTH;
6089 if (!BC_PROG_STACK(&G.prog.results, 1))
6090 return bc_error_stack_has_too_few_elements();
6091 opnd = bc_vec_top(&G.prog.results);
6093 s = bc_program_num(opnd, &num, false);
6097 if (!BC_PROG_NUM(opnd, num) && !len)
6098 return bc_error_variable_is_wrong_type();
6101 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6103 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6105 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6106 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6110 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6113 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6115 str = bc_vec_item(&G.prog.strs, idx);
6116 bc_num_ulong2num(&res.d.n, strlen(*str));
6120 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6121 bc_num_ulong2num(&res.d.n, f(num));
6124 bc_program_retire(&res, BC_RESULT_TEMP);
6130 static BcStatus bc_program_divmod(void)
6133 BcResult *opd1, *opd2, res, res2;
6134 BcNum *n1, *n2 = NULL;
6136 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6139 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6140 bc_num_init(&res2.d.n, n2->len);
6142 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6145 bc_program_binOpRetire(&res2);
6146 res.t = BC_RESULT_TEMP;
6147 bc_vec_push(&G.prog.results, &res);
6152 bc_num_free(&res2.d.n);
6153 bc_num_free(&res.d.n);
6157 static BcStatus bc_program_modexp(void)
6160 BcResult *r1, *r2, *r3, res;
6161 BcNum *n1, *n2, *n3;
6163 if (!BC_PROG_STACK(&G.prog.results, 3))
6164 return bc_error_stack_has_too_few_elements();
6165 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6168 r1 = bc_vec_item_rev(&G.prog.results, 2);
6169 s = bc_program_num(r1, &n1, false);
6171 if (!BC_PROG_NUM(r1, n1))
6172 return bc_error_variable_is_wrong_type();
6174 // Make sure that the values have their pointers updated, if necessary.
6175 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6177 if (r1->t == r2->t) {
6178 s = bc_program_num(r2, &n2, false);
6182 if (r1->t == r3->t) {
6183 s = bc_program_num(r3, &n3, false);
6188 bc_num_init(&res.d.n, n3->len);
6189 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6192 bc_vec_pop(&G.prog.results);
6193 bc_program_binOpRetire(&res);
6198 bc_num_free(&res.d.n);
6202 static void bc_program_stackLen(void)
6205 size_t len = G.prog.results.len;
6207 res.t = BC_RESULT_TEMP;
6209 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6210 bc_num_ulong2num(&res.d.n, len);
6211 bc_vec_push(&G.prog.results, &res);
6214 static BcStatus bc_program_asciify(void)
6218 BcNum *num = NULL, n;
6219 char *str, *str2, c;
6220 size_t len = G.prog.strs.len, idx;
6223 if (!BC_PROG_STACK(&G.prog.results, 1))
6224 return bc_error_stack_has_too_few_elements();
6225 r = bc_vec_top(&G.prog.results);
6227 s = bc_program_num(r, &num, false);
6230 if (BC_PROG_NUM(r, num)) {
6232 bc_num_init(&n, BC_NUM_DEF_SIZE);
6233 bc_num_copy(&n, num);
6234 bc_num_truncate(&n, n.rdx);
6236 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6237 if (s) goto num_err;
6238 s = bc_num_ulong(&n, &val);
6239 if (s) goto num_err;
6246 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6247 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6255 str2 = xstrdup(str);
6256 bc_program_addFunc(str2, &idx);
6258 if (idx != len + BC_PROG_REQ_FUNCS) {
6260 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6261 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6270 bc_vec_push(&G.prog.strs, &str);
6272 res.t = BC_RESULT_STR;
6274 bc_vec_pop(&G.prog.results);
6275 bc_vec_push(&G.prog.results, &res);
6277 return BC_STATUS_SUCCESS;
6284 static BcStatus bc_program_printStream(void)
6292 if (!BC_PROG_STACK(&G.prog.results, 1))
6293 return bc_error_stack_has_too_few_elements();
6294 r = bc_vec_top(&G.prog.results);
6296 s = bc_program_num(r, &n, false);
6299 if (BC_PROG_NUM(r, n))
6300 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6302 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6303 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6310 static BcStatus bc_program_nquit(void)
6317 s = bc_program_prep(&opnd, &num);
6319 s = bc_num_ulong(num, &val);
6322 bc_vec_pop(&G.prog.results);
6324 if (G.prog.stack.len < val)
6325 return bc_error_stack_has_too_few_elements();
6326 if (G.prog.stack.len == val)
6329 bc_vec_npop(&G.prog.stack, val);
6334 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6337 BcStatus s = BC_STATUS_SUCCESS;
6347 if (!BC_PROG_STACK(&G.prog.results, 1))
6348 return bc_error_stack_has_too_few_elements();
6350 r = bc_vec_top(&G.prog.results);
6354 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6356 if (code[*bgn] == BC_PARSE_STREND)
6359 else_name = bc_program_name(code, bgn);
6361 exec = r->d.n.len != 0;
6365 else if (else_name != NULL) {
6372 v = bc_program_search(name, true);
6379 if (!exec) goto exit;
6380 if (!BC_PROG_STR(n)) {
6381 s = bc_error_variable_is_wrong_type();
6389 if (r->t == BC_RESULT_STR)
6391 else if (r->t == BC_RESULT_VAR) {
6392 s = bc_program_num(r, &n, false);
6393 if (s || !BC_PROG_STR(n)) goto exit;
6400 fidx = sidx + BC_PROG_REQ_FUNCS;
6402 str = bc_vec_item(&G.prog.strs, sidx);
6403 f = bc_vec_item(&G.prog.fns, fidx);
6405 if (f->code.len == 0) {
6406 common_parse_init(&prs, fidx);
6407 s = bc_parse_text(&prs, *str);
6409 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6412 if (prs.l.t.t != BC_LEX_EOF) {
6413 s = bc_error_bad_expression();
6417 bc_parse_free(&prs);
6421 ip.len = G.prog.results.len;
6424 bc_vec_pop(&G.prog.results);
6425 bc_vec_push(&G.prog.stack, &ip);
6427 return BC_STATUS_SUCCESS;
6430 bc_parse_free(&prs);
6431 f = bc_vec_item(&G.prog.fns, fidx);
6432 bc_vec_pop_all(&f->code);
6434 bc_vec_pop(&G.prog.results);
6439 static void bc_program_pushGlobal(char inst)
6444 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6445 if (inst == BC_INST_IBASE)
6446 val = (unsigned long) G.prog.ib_t;
6447 else if (inst == BC_INST_SCALE)
6448 val = (unsigned long) G.prog.scale;
6450 val = (unsigned long) G.prog.ob_t;
6452 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6453 bc_num_ulong2num(&res.d.n, val);
6454 bc_vec_push(&G.prog.results, &res);
6457 static void bc_program_addFunc(char *name, size_t *idx)
6459 BcId entry, *entry_ptr;
6464 entry.idx = G.prog.fns.len;
6466 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6467 if (!inserted) free(name);
6469 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6470 *idx = entry_ptr->idx;
6474 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6476 // We need to reset these, so the function can be repopulated.
6478 bc_vec_pop_all(&func->autos);
6479 bc_vec_pop_all(&func->code);
6480 bc_vec_pop_all(&func->labels);
6484 bc_vec_push(&G.prog.fns, &f);
6488 // Called when parsing or execution detects a failure,
6489 // resets execution structures.
6490 static void bc_program_reset(void)
6495 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6496 bc_vec_pop_all(&G.prog.results);
6498 f = bc_vec_item(&G.prog.fns, 0);
6499 ip = bc_vec_top(&G.prog.stack);
6500 ip->idx = f->code.len;
6502 // If !tty, no need to check for ^C: we don't have ^C handler,
6503 // we would be killed by a signal and won't reach this place
6506 static BcStatus bc_program_exec(void)
6508 BcStatus s = BC_STATUS_SUCCESS;
6512 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6513 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6514 char *code = func->code.v;
6517 while (!s && ip->idx < func->code.len) {
6519 char inst = code[(ip->idx)++];
6524 case BC_INST_JUMP_ZERO:
6526 s = bc_program_prep(&ptr, &num);
6528 cond = !bc_num_cmp(num, &G.prog.zero);
6529 bc_vec_pop(&G.prog.results);
6535 idx = bc_program_index(code, &ip->idx);
6536 addr = bc_vec_item(&func->labels, idx);
6537 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6543 s = bc_program_call(code, &ip->idx);
6547 case BC_INST_INC_PRE:
6548 case BC_INST_DEC_PRE:
6549 case BC_INST_INC_POST:
6550 case BC_INST_DEC_POST:
6552 s = bc_program_incdec(inst);
6565 s = bc_program_return(inst);
6569 case BC_INST_BOOL_OR:
6570 case BC_INST_BOOL_AND:
6572 case BC_INST_REL_EQ:
6573 case BC_INST_REL_LE:
6574 case BC_INST_REL_GE:
6575 case BC_INST_REL_NE:
6576 case BC_INST_REL_LT:
6577 case BC_INST_REL_GT:
6579 s = bc_program_logical(inst);
6585 s = bc_program_read();
6591 s = bc_program_pushVar(code, &ip->idx, false, false);
6595 case BC_INST_ARRAY_ELEM:
6598 s = bc_program_pushArray(code, &ip->idx, inst);
6604 r.t = BC_RESULT_LAST;
6605 bc_vec_push(&G.prog.results, &r);
6613 bc_program_pushGlobal(inst);
6617 case BC_INST_SCALE_FUNC:
6618 case BC_INST_LENGTH:
6621 s = bc_program_builtin(inst);
6627 r.t = BC_RESULT_CONSTANT;
6628 r.d.id.idx = bc_program_index(code, &ip->idx);
6629 bc_vec_push(&G.prog.results, &r);
6635 if (!BC_PROG_STACK(&G.prog.results, 1))
6636 s = bc_error_stack_has_too_few_elements();
6638 bc_vec_pop(&G.prog.results);
6642 case BC_INST_POP_EXEC:
6644 bc_vec_pop(&G.prog.stack);
6649 case BC_INST_PRINT_POP:
6650 case BC_INST_PRINT_STR:
6652 s = bc_program_print(inst, 0);
6658 r.t = BC_RESULT_STR;
6659 r.d.id.idx = bc_program_index(code, &ip->idx);
6660 bc_vec_push(&G.prog.results, &r);
6665 case BC_INST_MULTIPLY:
6666 case BC_INST_DIVIDE:
6667 case BC_INST_MODULUS:
6671 s = bc_program_op(inst);
6675 case BC_INST_BOOL_NOT:
6677 s = bc_program_prep(&ptr, &num);
6680 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6681 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6682 bc_program_retire(&r, BC_RESULT_TEMP);
6689 s = bc_program_negate();
6694 case BC_INST_ASSIGN_POWER:
6695 case BC_INST_ASSIGN_MULTIPLY:
6696 case BC_INST_ASSIGN_DIVIDE:
6697 case BC_INST_ASSIGN_MODULUS:
6698 case BC_INST_ASSIGN_PLUS:
6699 case BC_INST_ASSIGN_MINUS:
6701 case BC_INST_ASSIGN:
6703 s = bc_program_assign(inst);
6707 case BC_INST_MODEXP:
6709 s = bc_program_modexp();
6713 case BC_INST_DIVMOD:
6715 s = bc_program_divmod();
6719 case BC_INST_EXECUTE:
6720 case BC_INST_EXEC_COND:
6722 cond = inst == BC_INST_EXEC_COND;
6723 s = bc_program_execStr(code, &ip->idx, cond);
6727 case BC_INST_PRINT_STACK:
6729 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6730 s = bc_program_print(BC_INST_PRINT, idx);
6734 case BC_INST_CLEAR_STACK:
6736 bc_vec_pop_all(&G.prog.results);
6740 case BC_INST_STACK_LEN:
6742 bc_program_stackLen();
6746 case BC_INST_DUPLICATE:
6748 if (!BC_PROG_STACK(&G.prog.results, 1))
6749 return bc_error_stack_has_too_few_elements();
6750 ptr = bc_vec_top(&G.prog.results);
6751 bc_result_copy(&r, ptr);
6752 bc_vec_push(&G.prog.results, &r);
6760 if (!BC_PROG_STACK(&G.prog.results, 2))
6761 return bc_error_stack_has_too_few_elements();
6763 ptr = bc_vec_item_rev(&G.prog.results, 0);
6764 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6765 memcpy(&r, ptr, sizeof(BcResult));
6766 memcpy(ptr, ptr2, sizeof(BcResult));
6767 memcpy(ptr2, &r, sizeof(BcResult));
6772 case BC_INST_ASCIIFY:
6774 s = bc_program_asciify();
6778 case BC_INST_PRINT_STREAM:
6780 s = bc_program_printStream();
6785 case BC_INST_PUSH_VAR:
6787 bool copy = inst == BC_INST_LOAD;
6788 s = bc_program_pushVar(code, &ip->idx, true, copy);
6792 case BC_INST_PUSH_TO_VAR:
6794 char *name = bc_program_name(code, &ip->idx);
6795 s = bc_program_copyToVar(name, true);
6802 if (G.prog.stack.len <= 2)
6804 bc_vec_npop(&G.prog.stack, 2);
6810 s = bc_program_nquit();
6816 if (s || G_interrupt) {
6821 // If the stack has changed, pointers may be invalid.
6822 ip = bc_vec_top(&G.prog.stack);
6823 func = bc_vec_item(&G.prog.fns, ip->func);
6824 code = func->code.v;
6830 static void bc_vm_info(void)
6832 printf("%s "BB_VER"\n"
6833 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6834 "Report bugs at: https://github.com/gavinhoward/bc\n"
6835 "This is free software with ABSOLUTELY NO WARRANTY\n"
6840 static void bc_vm_envArgs(void)
6842 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6845 char *env_args = getenv(bc_args_env_name), *buf;
6847 if (!env_args) return;
6849 G.env_args = xstrdup(env_args);
6852 bc_vec_init(&v, sizeof(char *), NULL);
6853 bc_vec_push(&v, &bc_args_env_name);
6856 if (!isspace(*buf)) {
6857 bc_vec_push(&v, &buf);
6858 while (*buf != 0 && !isspace(*buf)) ++buf;
6859 if (*buf != 0) (*(buf++)) = '\0';
6865 bc_args((int) v.len, (char **) v.v);
6871 static size_t bc_vm_envLen(const char *var)
6873 char *lenv = getenv(var);
6874 size_t i, len = BC_NUM_PRINT_WIDTH;
6877 if (!lenv) return len;
6881 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6883 len = (size_t) atoi(lenv) - 1;
6884 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6887 len = BC_NUM_PRINT_WIDTH;
6892 static BcStatus bc_vm_process(const char *text)
6894 BcStatus s = bc_parse_text(&G.prs, text);
6898 while (G.prs.l.t.t != BC_LEX_EOF) {
6899 s = G.prs.parse(&G.prs);
6903 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6904 s = bc_program_exec();
6913 static BcStatus bc_vm_file(const char *file)
6915 const char *sv_file;
6921 data = bc_read_file(file);
6922 if (!data) return bc_error_fmt("file '%s' is not text", file);
6924 sv_file = G.prog.file;
6926 bc_lex_file(&G.prs.l);
6927 s = bc_vm_process(data);
6930 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6931 ip = bc_vec_item(&G.prog.stack, 0);
6933 if (main_func->code.len < ip->idx)
6934 s = bc_error_fmt("file '%s' is not executable", file);
6937 G.prog.file = sv_file;
6942 static BcStatus bc_vm_stdin(void)
6946 size_t len, i, str = 0;
6947 bool comment = false;
6950 bc_lex_file(&G.prs.l);
6952 bc_char_vec_init(&buffer);
6953 bc_char_vec_init(&buf);
6954 bc_vec_pushZeroByte(&buffer);
6956 // This loop is complex because the vm tries not to send any lines that end
6957 // with a backslash to the parser. The reason for that is because the parser
6958 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6959 // case, and for strings and comments, the parser will expect more stuff.
6960 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6962 char *string = buf.v;
6967 if (str && buf.v[0] == G.send)
6969 else if (buf.v[0] == G.sbgn)
6972 else if (len > 1 || comment) {
6974 for (i = 0; i < len; ++i) {
6976 bool notend = len > i + 1;
6979 if (i - 1 > len || string[i - 1] != '\\') {
6980 if (G.sbgn == G.send)
6982 else if (c == G.send)
6984 else if (c == G.sbgn)
6988 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6992 else if (c == '*' && notend && comment && string[i + 1] == '/')
6996 if (str || comment || string[len - 2] == '\\') {
6997 bc_vec_concat(&buffer, buf.v);
7002 bc_vec_concat(&buffer, buf.v);
7003 s = bc_vm_process(buffer.v);
7006 fputs("ready for more input\n", stderr);
7009 bc_vec_pop_all(&buffer);
7013 s = bc_error("string end could not be found");
7016 s = bc_error("comment end could not be found");
7020 bc_vec_free(&buffer);
7025 static const char bc_lib[] = {
7028 "\n" "auto b,s,n,r,d,i,p,f,v"
7037 "\n" "scale=scale(x)+1"
7047 "\n" "for(i=2;v!=0;++i){"
7053 "\n" "while((d--)!=0)r*=r"
7056 "\n" "if(n!=0)return(1/r)"
7060 "\n" "auto b,s,r,p,a,q,i,v"
7064 "\n" "r=(1-10^scale)/1"
7075 "\n" "while(x<=0.5){"
7079 "\n" "r=a=(x-1)/(x+1)"
7082 "\n" "for(i=3;v!=0;i+=2){"
7093 "\n" "auto b,s,r,n,a,q,i"
7097 "\n" "scale=1.1*s+2"
7106 "\n" "if(q%2!=0)x=-x"
7110 "\n" "for(i=3;a!=0;i+=2){"
7111 "\n" "a*=q/(i*(i-1))"
7116 "\n" "if(n!=0)return(-r/1)"
7125 "\n" "x=s(2*a(1)+x)"
7131 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7140 "\n" "if(scale<65){"
7141 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7145 "\n" "if(scale<65){"
7146 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7157 "\n" "x=(x-.2)/(1+.2*x)"
7162 "\n" "for(i=3;t!=0;i+=2){"
7169 "\n" "return((m*a+r)/n)"
7171 "\n" "define j(n,x){"
7172 "\n" "auto b,s,o,a,i,v,f"
7180 "\n" "if(n%2==1)o=1"
7183 "\n" "for(i=2;i<=n;++i)a*=i"
7185 "\n" "a=(x^n)/2^n/a"
7188 "\n" "scale=scale+length(a)-scale(a)"
7189 "\n" "for(i=1;v!=0;++i){"
7190 "\n" "v=v*f/i/(n+i)"
7196 "\n" "return(a*r/1)"
7201 static BcStatus bc_vm_exec(void)
7203 BcStatus s = BC_STATUS_SUCCESS;
7207 if (option_mask32 & BC_FLAG_L) {
7209 // We know that internal library is not buggy,
7210 // thus error checking is normally disabled.
7211 # define DEBUG_LIB 0
7212 bc_lex_file(&G.prs.l);
7213 s = bc_parse_text(&G.prs, bc_lib);
7214 if (DEBUG_LIB && s) return s;
7216 while (G.prs.l.t.t != BC_LEX_EOF) {
7217 s = G.prs.parse(&G.prs);
7218 if (DEBUG_LIB && s) return s;
7220 s = bc_program_exec();
7221 if (DEBUG_LIB && s) return s;
7225 for (i = 0; !s && i < G.files.len; ++i)
7226 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7229 fputs("ready for more input\n", stderr);
7232 if (IS_BC || !G.files.len)
7234 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7235 s = bc_vm_process("");
7240 #if ENABLE_FEATURE_CLEAN_UP
7241 static void bc_program_free()
7243 bc_num_free(&G.prog.ib);
7244 bc_num_free(&G.prog.ob);
7245 bc_num_free(&G.prog.hexb);
7247 bc_num_free(&G.prog.strmb);
7249 bc_vec_free(&G.prog.fns);
7250 bc_vec_free(&G.prog.fn_map);
7251 bc_vec_free(&G.prog.vars);
7252 bc_vec_free(&G.prog.var_map);
7253 bc_vec_free(&G.prog.arrs);
7254 bc_vec_free(&G.prog.arr_map);
7255 bc_vec_free(&G.prog.strs);
7256 bc_vec_free(&G.prog.consts);
7257 bc_vec_free(&G.prog.results);
7258 bc_vec_free(&G.prog.stack);
7259 bc_num_free(&G.prog.last);
7260 bc_num_free(&G.prog.zero);
7261 bc_num_free(&G.prog.one);
7264 static void bc_vm_free(void)
7266 bc_vec_free(&G.files);
7268 bc_parse_free(&G.prs);
7273 static void bc_program_init(size_t line_len)
7278 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7279 memset(&ip, 0, sizeof(BcInstPtr));
7281 /* G.prog.nchars = G.prog.scale = 0; - already is */
7282 G.prog.len = line_len;
7284 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7285 bc_num_ten(&G.prog.ib);
7288 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7289 bc_num_ten(&G.prog.ob);
7292 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7293 bc_num_ten(&G.prog.hexb);
7294 G.prog.hexb.num[0] = 6;
7297 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7298 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7301 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7302 bc_num_zero(&G.prog.last);
7304 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7305 bc_num_zero(&G.prog.zero);
7307 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7308 bc_num_one(&G.prog.one);
7310 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7311 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7313 bc_program_addFunc(xstrdup("(main)"), &idx);
7314 bc_program_addFunc(xstrdup("(read)"), &idx);
7316 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7317 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7319 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7320 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7322 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7323 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7324 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7325 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7326 bc_vec_push(&G.prog.stack, &ip);
7329 static void bc_vm_init(const char *env_len)
7331 size_t len = bc_vm_envLen(env_len);
7333 bc_vec_init(&G.files, sizeof(char *), NULL);
7339 bc_program_init(len);
7341 bc_parse_init(&G.prs, BC_PROG_MAIN);
7343 dc_parse_init(&G.prs, BC_PROG_MAIN);
7347 static BcStatus bc_vm_run(int argc, char *argv[],
7348 const char *env_len)
7352 bc_vm_init(env_len);
7353 bc_args(argc, argv);
7355 G.ttyin = isatty(0);
7358 #if ENABLE_FEATURE_BC_SIGNALS
7359 // With SA_RESTART, most system calls will restart
7360 // (IOW: they won't fail with EINTR).
7361 // In particular, this means ^C won't cause
7362 // stdout to get into "error state" if SIGINT hits
7363 // within write() syscall.
7364 // The downside is that ^C while line input is taken
7365 // will only be handled after [Enter] since read()
7366 // from stdin is not interrupted by ^C either,
7367 // it restarts, thus fgetc() does not return on ^C.
7368 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7370 // Without SA_RESTART, this exhibits a bug:
7371 // "while (1) print 1" and try ^C-ing it.
7372 // Intermittently, instead of returning to input line,
7373 // you'll get "output error: Interrupted system call"
7375 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7377 if (!(option_mask32 & BC_FLAG_Q))
7382 #if ENABLE_FEATURE_CLEAN_UP
7389 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7390 int bc_main(int argc, char **argv)
7393 G.sbgn = G.send = '"';
7395 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7400 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7401 int dc_main(int argc, char **argv)
7407 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");