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)
793 #define G (*ptr_to_globals)
794 #define INIT_G() do { \
795 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
797 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
798 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
799 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
800 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
803 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
805 static void bc_vm_info(void);
809 // This is an array that corresponds to token types. An entry is
810 // true if the token is valid in an expression, false otherwise.
811 static const bool bc_parse_exprs[] = {
812 false, false, true, true, true, true, true, true, true, true, true, true,
813 true, true, true, true, true, true, true, true, true, true, true, true,
814 true, true, true, false, false, true, true, false, false, false, false,
815 false, false, false, true, true, false, false, false, false, false, false,
816 false, true, false, true, true, true, true, false, false, true, false, true,
820 // This is an array of data for operators that correspond to token types.
821 static const BcOp bc_parse_ops[] = {
822 { 0, false }, { 0, false },
825 { 3, true }, { 3, true }, { 3, true },
826 { 4, true }, { 4, true },
827 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
829 { 7, true }, { 7, true },
830 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
831 { 5, false }, { 5, false },
834 // These identify what tokens can come after expressions in certain cases.
835 static const BcParseNext bc_parse_next_expr =
836 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
837 static const BcParseNext bc_parse_next_param =
838 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
839 static const BcParseNext bc_parse_next_print =
840 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
841 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
842 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
843 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
844 static const BcParseNext bc_parse_next_read =
845 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
849 static const BcLexType dc_lex_regs[] = {
850 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
851 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
852 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
856 static const BcLexType dc_lex_tokens[] = {
857 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
858 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
859 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
860 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
861 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
862 BC_LEX_INVALID, BC_LEX_INVALID,
863 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
864 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
867 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
868 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
869 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
871 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
872 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
873 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
874 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
875 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
876 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
877 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
878 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
879 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
880 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
884 static const BcInst dc_parse_insts[] = {
885 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
886 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
887 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
888 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
889 BC_INST_INVALID, BC_INST_INVALID,
890 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
891 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
894 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
895 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_INVALID, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
899 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
900 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
902 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
903 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
904 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
905 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
906 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
907 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
911 static const BcNumBinaryOp bc_program_ops[] = {
912 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
915 static void fflush_and_check(void)
918 if (ferror(stdout) || ferror(stderr))
919 bb_perror_msg_and_die("output error");
922 static void quit(void) NORETURN;
923 static void quit(void)
926 bb_perror_msg_and_die("input error");
931 static NOINLINE int bc_error_fmt(const char *fmt, ...)
938 applet_name = G.prog.file;
941 bb_verror_msg(fmt, p, NULL);
947 return BC_STATUS_FAILURE;
950 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
955 // Are non-POSIX constructs totally ok?
956 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
957 return BC_STATUS_SUCCESS; // yes
961 applet_name = G.prog.file;
964 bb_verror_msg(fmt, p, NULL);
968 // Do we treat non-POSIX constructs as errors?
969 if (!(option_mask32 & BC_FLAG_S))
970 return BC_STATUS_SUCCESS; // no, it's a warning
973 return BC_STATUS_FAILURE;
976 // We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
977 // This idiom begs for tail-call optimization, but for it to work,
978 // function must not have calller-cleaned parameters on stack.
979 // Unfortunately, vararg functions do exactly that on most arches.
980 // Thus, these shims for the cases when we have no PARAMS:
981 static int bc_error(const char *msg)
983 return bc_error_fmt("%s", msg);
985 static int bc_posix_error(const char *msg)
987 return bc_posix_error_fmt("%s", msg);
989 static int bc_error_bad_character(char c)
991 return bc_error_fmt("bad character '%c'", c);
993 static int bc_error_bad_expression(void)
995 return bc_error("bad expression");
997 static int bc_error_bad_token(void)
999 return bc_error("bad token");
1001 static int bc_error_stack_has_too_few_elements(void)
1003 return bc_error("stack has too few elements");
1005 static int bc_error_variable_is_wrong_type(void)
1007 return bc_error("variable is wrong type");
1009 static int bc_error_nested_read_call(void)
1011 return bc_error("read() call inside of a read() call");
1014 static void bc_vec_grow(BcVec *v, size_t n)
1016 size_t cap = v->cap * 2;
1017 while (cap < v->len + n) cap *= 2;
1018 v->v = xrealloc(v->v, v->size * cap);
1022 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1025 v->cap = BC_VEC_START_CAP;
1028 v->v = xmalloc(esize * BC_VEC_START_CAP);
1031 static void bc_char_vec_init(BcVec *v)
1033 bc_vec_init(v, sizeof(char), NULL);
1036 static void bc_vec_expand(BcVec *v, size_t req)
1039 v->v = xrealloc(v->v, v->size * req);
1044 static void bc_vec_npop(BcVec *v, size_t n)
1049 size_t len = v->len - n;
1050 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1054 static void bc_vec_pop_all(BcVec *v)
1056 bc_vec_npop(v, v->len);
1059 static void bc_vec_push(BcVec *v, const void *data)
1061 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1062 memmove(v->v + (v->size * v->len), data, v->size);
1066 static void bc_vec_pushByte(BcVec *v, char data)
1068 bc_vec_push(v, &data);
1071 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1074 bc_vec_push(v, data);
1079 if (v->len == v->cap) bc_vec_grow(v, 1);
1081 ptr = v->v + v->size * idx;
1083 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1084 memmove(ptr, data, v->size);
1088 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1091 bc_vec_expand(v, len + 1);
1092 memcpy(v->v, str, len);
1095 bc_vec_pushByte(v, '\0');
1098 static void bc_vec_concat(BcVec *v, const char *str)
1102 if (v->len == 0) bc_vec_pushByte(v, '\0');
1104 len = v->len + strlen(str);
1106 if (v->cap < len) bc_vec_grow(v, len - v->len);
1112 static void *bc_vec_item(const BcVec *v, size_t idx)
1114 return v->v + v->size * idx;
1117 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1119 return v->v + v->size * (v->len - idx - 1);
1122 static void bc_vec_free(void *vec)
1124 BcVec *v = (BcVec *) vec;
1129 static size_t bc_map_find(const BcVec *v, const void *ptr)
1131 size_t low = 0, high = v->len;
1133 while (low < high) {
1135 size_t mid = (low + high) / 2;
1136 BcId *id = bc_vec_item(v, mid);
1137 int result = bc_id_cmp(ptr, id);
1141 else if (result < 0)
1150 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1152 size_t n = *i = bc_map_find(v, ptr);
1155 bc_vec_push(v, ptr);
1156 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1157 return 0; // "was not inserted"
1159 bc_vec_pushAt(v, ptr, n);
1160 return 1; // "was inserted"
1163 static size_t bc_map_index(const BcVec *v, const void *ptr)
1165 size_t i = bc_map_find(v, ptr);
1166 if (i >= v->len) return BC_VEC_INVALID_IDX;
1167 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1170 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1179 bc_vec_pop_all(vec);
1182 #if ENABLE_FEATURE_BC_SIGNALS
1183 if (bb_got_signal) { // ^C was pressed
1185 bb_got_signal = 0; // resets G_interrupt to zero
1187 ? "\ninterrupt (type \"quit\" to exit)\n"
1188 : "\ninterrupt (type \"q\" to exit)\n"
1192 if (G.ttyin && !G_posix)
1193 fputs(prompt, stderr);
1195 #if ENABLE_FEATURE_BC_SIGNALS
1201 #if ENABLE_FEATURE_BC_SIGNALS
1202 // Both conditions appear simultaneously, check both just in case
1203 if (errno == EINTR || bb_got_signal) {
1210 quit(); // this emits error message
1212 // Note: EOF does not append '\n', therefore:
1213 // printf 'print 123\n' | bc - works
1214 // printf 'print 123' | bc - fails (syntax error)
1218 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1221 // Bad chars on this line, ignore entire line
1222 bc_error_fmt("illegal character 0x%02x", i);
1226 bc_vec_push(vec, &c);
1227 } while (i != '\n');
1228 } while (bad_chars);
1230 bc_vec_pushByte(vec, '\0');
1232 return BC_STATUS_SUCCESS;
1235 static char* bc_read_file(const char *path)
1238 size_t size = ((size_t) -1);
1241 buf = xmalloc_open_read_close(path, &size);
1243 for (i = 0; i < size; ++i) {
1245 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1257 static void bc_args(int argc, char **argv)
1263 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1264 opts = getopt32long(argv, "xwvsqli",
1265 "extended-register\0" No_argument "x"
1266 "warn\0" No_argument "w"
1267 "version\0" No_argument "v"
1268 "standard\0" No_argument "s"
1269 "quiet\0" No_argument "q"
1270 "mathlib\0" No_argument "l"
1271 "interactive\0" No_argument "i"
1274 opts = getopt32(argv, "xwvsqli");
1276 if (getenv("POSIXLY_CORRECT"))
1277 option_mask32 |= BC_FLAG_S;
1279 if (opts & BC_FLAG_V) bc_vm_info();
1280 // should not be necessary, getopt32() handles this??
1281 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1283 for (i = optind; i < argc; ++i)
1284 bc_vec_push(&G.files, argv + i);
1287 static void bc_num_setToZero(BcNum *n, size_t scale)
1294 static void bc_num_zero(BcNum *n)
1296 bc_num_setToZero(n, 0);
1299 static void bc_num_one(BcNum *n)
1301 bc_num_setToZero(n, 0);
1306 static void bc_num_ten(BcNum *n)
1308 bc_num_setToZero(n, 0);
1314 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1318 for (i = 0; i < len; ++i) {
1319 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1326 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1330 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1331 return BC_NUM_NEG(i + 1, c < 0);
1334 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1336 size_t i, min, a_int, b_int, diff;
1337 BcDig *max_num, *min_num;
1338 bool a_max, neg = false;
1341 if (a == b) return 0;
1342 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1343 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1353 a_int = BC_NUM_INT(a);
1354 b_int = BC_NUM_INT(b);
1356 a_max = (a->rdx > b->rdx);
1358 if (a_int != 0) return (ssize_t) a_int;
1362 diff = a->rdx - b->rdx;
1363 max_num = a->num + diff;
1368 diff = b->rdx - a->rdx;
1369 max_num = b->num + diff;
1373 cmp = bc_num_compare(max_num, min_num, b_int + min);
1374 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1376 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1377 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1383 static void bc_num_truncate(BcNum *n, size_t places)
1385 if (places == 0) return;
1391 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1395 static void bc_num_extend(BcNum *n, size_t places)
1397 size_t len = n->len + places;
1401 if (n->cap < len) bc_num_expand(n, len);
1403 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1404 memset(n->num, 0, sizeof(BcDig) * places);
1411 static void bc_num_clean(BcNum *n)
1413 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1416 else if (n->len < n->rdx)
1420 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1423 bc_num_extend(n, scale - n->rdx);
1425 bc_num_truncate(n, n->rdx - scale);
1428 if (n->len != 0) n->neg = !neg1 != !neg2;
1431 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1436 b->len = n->len - idx;
1438 a->rdx = b->rdx = 0;
1440 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1441 memcpy(a->num, n->num, idx * sizeof(BcDig));
1452 static BcStatus bc_num_shift(BcNum *n, size_t places)
1454 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1455 if (places + n->len > BC_MAX_NUM)
1456 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1458 if (n->rdx >= places)
1461 bc_num_extend(n, places - n->rdx);
1467 return BC_STATUS_SUCCESS;
1470 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1479 return bc_num_div(&one, a, b, scale);
1482 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1484 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1485 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1488 // Because this function doesn't need to use scale (per the bc spec),
1489 // I am hijacking it to say whether it's doing an add or a subtract.
1493 if (sub && c->len) c->neg = !c->neg;
1494 return BC_STATUS_SUCCESS;
1496 else if (b->len == 0) {
1498 return BC_STATUS_SUCCESS;
1502 c->rdx = BC_MAX(a->rdx, b->rdx);
1503 min_rdx = BC_MIN(a->rdx, b->rdx);
1506 if (a->rdx > b->rdx) {
1507 diff = a->rdx - b->rdx;
1509 ptr_a = a->num + diff;
1513 diff = b->rdx - a->rdx;
1516 ptr_b = b->num + diff;
1519 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1522 a_int = BC_NUM_INT(a);
1523 b_int = BC_NUM_INT(b);
1525 if (a_int > b_int) {
1536 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1537 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1539 ptr_c[i] = (BcDig)(in % 10);
1542 for (; i < max + min_rdx; ++i, ++c->len) {
1543 in = ((int) ptr[i]) + carry;
1545 ptr_c[i] = (BcDig)(in % 10);
1548 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1550 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1553 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1556 BcNum *minuend, *subtrahend;
1558 bool aneg, bneg, neg;
1560 // Because this function doesn't need to use scale (per the bc spec),
1561 // I am hijacking it to say whether it's doing an add or a subtract.
1565 if (sub && c->len) c->neg = !c->neg;
1566 return BC_STATUS_SUCCESS;
1568 else if (b->len == 0) {
1570 return BC_STATUS_SUCCESS;
1575 a->neg = b->neg = false;
1577 cmp = bc_num_cmp(a, b);
1583 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1584 return BC_STATUS_SUCCESS;
1593 if (sub) neg = !neg;
1598 bc_num_copy(c, minuend);
1601 if (c->rdx < subtrahend->rdx) {
1602 bc_num_extend(c, subtrahend->rdx - c->rdx);
1606 start = c->rdx - subtrahend->rdx;
1608 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1612 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1615 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1620 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1621 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1622 bool aone = BC_NUM_ONE(a);
1624 if (a->len == 0 || b->len == 0) {
1626 return BC_STATUS_SUCCESS;
1628 else if (aone || BC_NUM_ONE(b)) {
1629 bc_num_copy(c, aone ? b : a);
1630 return BC_STATUS_SUCCESS;
1633 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1634 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1636 bc_num_expand(c, a->len + b->len + 1);
1638 memset(c->num, 0, sizeof(BcDig) * c->cap);
1639 c->len = carry = len = 0;
1641 for (i = 0; i < b->len; ++i) {
1643 for (j = 0; j < a->len; ++j) {
1644 int in = (int) c->num[i + j];
1645 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1647 c->num[i + j] = (BcDig)(in % 10);
1650 c->num[i + j] += (BcDig) carry;
1651 len = BC_MAX(len, i + j + !!carry);
1657 return BC_STATUS_SUCCESS;
1660 bc_num_init(&l1, max);
1661 bc_num_init(&h1, max);
1662 bc_num_init(&l2, max);
1663 bc_num_init(&h2, max);
1664 bc_num_init(&m1, max);
1665 bc_num_init(&m2, max);
1666 bc_num_init(&z0, max);
1667 bc_num_init(&z1, max);
1668 bc_num_init(&z2, max);
1669 bc_num_init(&temp, max + max);
1671 bc_num_split(a, max2, &l1, &h1);
1672 bc_num_split(b, max2, &l2, &h2);
1674 s = bc_num_add(&h1, &l1, &m1, 0);
1676 s = bc_num_add(&h2, &l2, &m2, 0);
1679 s = bc_num_k(&h1, &h2, &z0);
1681 s = bc_num_k(&m1, &m2, &z1);
1683 s = bc_num_k(&l1, &l2, &z2);
1686 s = bc_num_sub(&z1, &z0, &temp, 0);
1688 s = bc_num_sub(&temp, &z2, &z1, 0);
1691 s = bc_num_shift(&z0, max2 * 2);
1693 s = bc_num_shift(&z1, max2);
1695 s = bc_num_add(&z0, &z1, &temp, 0);
1697 s = bc_num_add(&temp, &z2, c, 0);
1713 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1717 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1719 scale = BC_MAX(scale, a->rdx);
1720 scale = BC_MAX(scale, b->rdx);
1721 scale = BC_MIN(a->rdx + b->rdx, scale);
1722 maxrdx = BC_MAX(maxrdx, scale);
1724 bc_num_init(&cpa, a->len);
1725 bc_num_init(&cpb, b->len);
1727 bc_num_copy(&cpa, a);
1728 bc_num_copy(&cpb, b);
1729 cpa.neg = cpb.neg = false;
1731 s = bc_num_shift(&cpa, maxrdx);
1733 s = bc_num_shift(&cpb, maxrdx);
1735 s = bc_num_k(&cpa, &cpb, c);
1739 bc_num_expand(c, c->len + maxrdx);
1741 if (c->len < maxrdx) {
1742 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1747 bc_num_retireMul(c, scale, a->neg, b->neg);
1755 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1757 BcStatus s = BC_STATUS_SUCCESS;
1764 return bc_error("divide by zero");
1765 else if (a->len == 0) {
1766 bc_num_setToZero(c, scale);
1767 return BC_STATUS_SUCCESS;
1769 else if (BC_NUM_ONE(b)) {
1771 bc_num_retireMul(c, scale, a->neg, b->neg);
1772 return BC_STATUS_SUCCESS;
1775 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1776 bc_num_copy(&cp, a);
1780 bc_num_expand(&cp, len + 2);
1781 bc_num_extend(&cp, len - cp.len);
1784 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1786 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1788 if (b->rdx == b->len) {
1789 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1793 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1795 // We want an extra zero in front to make things simpler.
1796 cp.num[cp.len++] = 0;
1799 bc_num_expand(c, cp.len);
1802 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1807 for (i = end - 1; !s && i < end; --i) {
1809 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1810 bc_num_subArrays(n, p, len);
1814 bc_num_retireMul(c, scale, a->neg, b->neg);
1817 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1820 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1821 BcNum *restrict d, size_t scale, size_t ts)
1828 return bc_error("divide by zero");
1831 bc_num_setToZero(d, ts);
1832 return BC_STATUS_SUCCESS;
1835 bc_num_init(&temp, d->cap);
1836 bc_num_d(a, b, c, scale);
1838 if (scale != 0) scale = ts;
1840 s = bc_num_m(c, b, &temp, scale);
1842 s = bc_num_sub(a, &temp, d, scale);
1845 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1848 bc_num_retireMul(d, ts, a->neg, b->neg);
1856 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1860 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1862 bc_num_init(&c1, len);
1863 s = bc_num_r(a, b, &c1, c, scale, ts);
1869 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1871 BcStatus s = BC_STATUS_SUCCESS;
1874 size_t i, powrdx, resrdx;
1877 if (b->rdx) return bc_error("non integer number");
1881 return BC_STATUS_SUCCESS;
1883 else if (a->len == 0) {
1884 bc_num_setToZero(c, scale);
1885 return BC_STATUS_SUCCESS;
1887 else if (BC_NUM_ONE(b)) {
1891 s = bc_num_inv(a, c, scale);
1898 s = bc_num_ulong(b, &pow);
1901 bc_num_init(©, a->len);
1902 bc_num_copy(©, a);
1904 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1908 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1910 s = bc_num_mul(©, ©, ©, powrdx);
1912 // It is too slow to handle ^C only after entire "2^1000000" completes
1914 s = BC_STATUS_FAILURE;
1919 bc_num_copy(c, ©);
1921 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1924 s = bc_num_mul(©, ©, ©, powrdx);
1929 s = bc_num_mul(c, ©, c, resrdx);
1932 // It is too slow to handle ^C only after entire "2^1000000" completes
1934 s = BC_STATUS_FAILURE;
1940 s = bc_num_inv(c, c, scale);
1944 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1946 // We can't use bc_num_clean() here.
1947 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1948 if (zero) bc_num_setToZero(c, scale);
1955 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1956 BcNumBinaryOp op, size_t req)
1959 BcNum num2, *ptr_a, *ptr_b;
1964 memcpy(ptr_a, c, sizeof(BcNum));
1973 memcpy(ptr_b, c, sizeof(BcNum));
1981 bc_num_init(c, req);
1983 bc_num_expand(c, req);
1985 s = op(ptr_a, ptr_b, c, scale);
1987 if (init) bc_num_free(&num2);
1992 static bool bc_num_strValid(const char *val, size_t base)
1995 bool small, radix = false;
1996 size_t i, len = strlen(val);
1998 if (!len) return true;
2001 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2003 for (i = 0; i < len; ++i) {
2009 if (radix) return false;
2015 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2022 static void bc_num_parseDecimal(BcNum *n, const char *val)
2028 for (i = 0; val[i] == '0'; ++i);
2035 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2036 bc_num_expand(n, len);
2039 ptr = strchr(val, '.');
2043 n->rdx = (size_t)((val + len) - (ptr + 1));
2046 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2047 n->num[n->len] = val[i] - '0';
2051 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2054 BcNum temp, mult, result;
2058 size_t i, digits, len = strlen(val);
2062 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2065 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2066 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2068 for (i = 0; i < len; ++i) {
2071 if (c == '.') break;
2073 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2075 s = bc_num_mul(n, base, &mult, 0);
2076 if (s) goto int_err;
2077 bc_num_ulong2num(&temp, v);
2078 s = bc_num_add(&mult, &temp, n, 0);
2079 if (s) goto int_err;
2084 if (c == 0) goto int_err;
2087 bc_num_init(&result, base->len);
2088 bc_num_zero(&result);
2091 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2096 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2098 s = bc_num_mul(&result, base, &result, 0);
2100 bc_num_ulong2num(&temp, v);
2101 s = bc_num_add(&result, &temp, &result, 0);
2103 s = bc_num_mul(&mult, base, &mult, 0);
2107 s = bc_num_div(&result, &mult, &result, digits);
2109 s = bc_num_add(n, &result, n, digits);
2113 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2119 bc_num_free(&result);
2125 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2127 if (*nchars == line_len - 1) {
2135 static void bc_num_printChar(size_t num, size_t width, bool radix,
2136 size_t *nchars, size_t line_len)
2138 (void) radix, (void) line_len;
2139 bb_putchar((char) num);
2140 *nchars = *nchars + width;
2144 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2145 size_t *nchars, size_t line_len)
2149 bc_num_printNewline(nchars, line_len);
2150 bb_putchar(radix ? '.' : ' ');
2153 bc_num_printNewline(nchars, line_len);
2154 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2157 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2159 bc_num_printNewline(nchars, line_len);
2162 bb_putchar(((char) dig) + '0');
2166 static void bc_num_printHex(size_t num, size_t width, bool radix,
2167 size_t *nchars, size_t line_len)
2170 bc_num_printNewline(nchars, line_len);
2175 bc_num_printNewline(nchars, line_len);
2176 bb_putchar(bb_hexdigits_upcase[num]);
2177 *nchars = *nchars + width;
2180 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2182 size_t i, rdx = n->rdx - 1;
2184 if (n->neg) bb_putchar('-');
2185 (*nchars) += n->neg;
2187 for (i = n->len - 1; i < n->len; --i)
2188 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2191 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2192 size_t *nchars, size_t len, BcNumDigitOp print)
2196 BcNum intp, fracp, digit, frac_len;
2197 unsigned long dig, *ptr;
2202 print(0, width, false, nchars, len);
2203 return BC_STATUS_SUCCESS;
2206 bc_vec_init(&stack, sizeof(long), NULL);
2207 bc_num_init(&intp, n->len);
2208 bc_num_init(&fracp, n->rdx);
2209 bc_num_init(&digit, width);
2210 bc_num_init(&frac_len, BC_NUM_INT(n));
2211 bc_num_copy(&intp, n);
2212 bc_num_one(&frac_len);
2214 bc_num_truncate(&intp, intp.rdx);
2215 s = bc_num_sub(n, &intp, &fracp, 0);
2218 while (intp.len != 0) {
2219 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2221 s = bc_num_ulong(&digit, &dig);
2223 bc_vec_push(&stack, &dig);
2226 for (i = 0; i < stack.len; ++i) {
2227 ptr = bc_vec_item_rev(&stack, i);
2228 print(*ptr, width, false, nchars, len);
2231 if (!n->rdx) goto err;
2233 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2234 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2236 s = bc_num_ulong(&fracp, &dig);
2238 bc_num_ulong2num(&intp, dig);
2239 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2241 print(dig, width, radix, nchars, len);
2242 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2247 bc_num_free(&frac_len);
2248 bc_num_free(&digit);
2249 bc_num_free(&fracp);
2251 bc_vec_free(&stack);
2255 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2256 size_t *nchars, size_t line_len)
2263 if (neg) bb_putchar('-');
2268 if (base_t <= BC_NUM_MAX_IBASE) {
2270 print = bc_num_printHex;
2273 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2274 print = bc_num_printDigits;
2277 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2284 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2286 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2290 static void bc_num_init(BcNum *n, size_t req)
2292 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2293 memset(n, 0, sizeof(BcNum));
2294 n->num = xmalloc(req);
2298 static void bc_num_expand(BcNum *n, size_t req)
2300 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2302 n->num = xrealloc(n->num, req);
2307 static void bc_num_free(void *num)
2309 free(((BcNum *) num)->num);
2312 static void bc_num_copy(BcNum *d, BcNum *s)
2315 bc_num_expand(d, s->cap);
2319 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2323 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2326 if (!bc_num_strValid(val, base_t))
2327 return bc_error("bad number string");
2330 bc_num_parseDecimal(n, val);
2332 bc_num_parseBase(n, val, base);
2334 return BC_STATUS_SUCCESS;
2337 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2338 size_t *nchars, size_t line_len)
2340 BcStatus s = BC_STATUS_SUCCESS;
2342 bc_num_printNewline(nchars, line_len);
2348 else if (base_t == 10)
2349 bc_num_printDecimal(n, nchars, line_len);
2351 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2361 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2366 if (n->neg) return bc_error("negative number");
2368 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2370 unsigned long prev = *result, powprev = pow;
2372 *result += ((unsigned long) n->num[i]) * pow;
2375 if (*result < prev || pow < powprev)
2376 return bc_error("overflow");
2379 return BC_STATUS_SUCCESS;
2382 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2390 if (val == 0) return;
2392 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2393 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2396 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2398 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2400 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2403 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2405 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2407 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2410 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2412 size_t req = BC_NUM_MREQ(a, b, scale);
2413 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2416 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2418 size_t req = BC_NUM_MREQ(a, b, scale);
2419 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2422 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2424 size_t req = BC_NUM_MREQ(a, b, scale);
2425 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2428 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2430 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2433 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2436 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2437 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2438 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2440 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2441 bc_num_expand(b, req);
2444 bc_num_setToZero(b, scale);
2445 return BC_STATUS_SUCCESS;
2448 return bc_error("negative number");
2449 else if (BC_NUM_ONE(a)) {
2451 bc_num_extend(b, scale);
2452 return BC_STATUS_SUCCESS;
2455 scale = BC_MAX(scale, a->rdx) + 1;
2456 len = a->len + scale;
2458 bc_num_init(&num1, len);
2459 bc_num_init(&num2, len);
2460 bc_num_init(&half, BC_NUM_DEF_SIZE);
2466 bc_num_init(&f, len);
2467 bc_num_init(&fprime, len);
2473 pow = BC_NUM_INT(a);
2482 pow -= 2 - (pow & 1);
2484 bc_num_extend(x0, pow);
2486 // Make sure to move the radix back.
2490 x0->rdx = digs = digs1 = 0;
2492 len = BC_NUM_INT(x0) + resrdx - 1;
2494 while (cmp != 0 || digs < len) {
2496 s = bc_num_div(a, x0, &f, resrdx);
2498 s = bc_num_add(x0, &f, &fprime, resrdx);
2500 s = bc_num_mul(&fprime, &half, x1, resrdx);
2503 cmp = bc_num_cmp(x1, x0);
2504 digs = x1->len - (unsigned long long) llabs(cmp);
2506 if (cmp == cmp2 && digs == digs1)
2511 resrdx += times > 4;
2524 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2527 bc_num_free(&fprime);
2535 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2541 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2544 memcpy(&num2, c, sizeof(BcNum));
2546 bc_num_init(c, len);
2551 bc_num_expand(c, len);
2554 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2556 if (init) bc_num_free(&num2);
2562 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2565 BcNum base, exp, two, temp;
2568 return bc_error("divide by zero");
2569 if (a->rdx || b->rdx || c->rdx)
2570 return bc_error("non integer number");
2572 return bc_error("negative number");
2574 bc_num_expand(d, c->len);
2575 bc_num_init(&base, c->len);
2576 bc_num_init(&exp, b->len);
2577 bc_num_init(&two, BC_NUM_DEF_SIZE);
2578 bc_num_init(&temp, b->len);
2584 s = bc_num_rem(a, c, &base, 0);
2586 bc_num_copy(&exp, b);
2588 while (exp.len != 0) {
2590 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2593 if (BC_NUM_ONE(&temp)) {
2594 s = bc_num_mul(d, &base, &temp, 0);
2596 s = bc_num_rem(&temp, c, d, 0);
2600 s = bc_num_mul(&base, &base, &temp, 0);
2602 s = bc_num_rem(&temp, c, &base, 0);
2615 static int bc_id_cmp(const void *e1, const void *e2)
2617 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2620 static void bc_id_free(void *id)
2622 free(((BcId *) id)->name);
2625 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2630 for (i = 0; i < f->autos.len; ++i) {
2631 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2632 return bc_error("function parameter or auto var has the same name as another");
2638 bc_vec_push(&f->autos, &a);
2640 return BC_STATUS_SUCCESS;
2643 static void bc_func_init(BcFunc *f)
2645 bc_char_vec_init(&f->code);
2646 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2647 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2651 static void bc_func_free(void *func)
2653 BcFunc *f = (BcFunc *) func;
2654 bc_vec_free(&f->code);
2655 bc_vec_free(&f->autos);
2656 bc_vec_free(&f->labels);
2659 static void bc_array_init(BcVec *a, bool nums)
2662 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2664 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2665 bc_array_expand(a, 1);
2668 static void bc_array_copy(BcVec *d, const BcVec *s)
2673 bc_vec_expand(d, s->cap);
2676 for (i = 0; i < s->len; ++i) {
2677 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2678 bc_num_init(dnum, snum->len);
2679 bc_num_copy(dnum, snum);
2683 static void bc_array_expand(BcVec *a, size_t len)
2687 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2688 while (len > a->len) {
2689 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2690 bc_vec_push(a, &data.n);
2694 while (len > a->len) {
2695 bc_array_init(&data.v, true);
2696 bc_vec_push(a, &data.v);
2701 static void bc_string_free(void *string)
2703 free(*((char **) string));
2707 static void bc_result_copy(BcResult *d, BcResult *src)
2713 case BC_RESULT_TEMP:
2714 case BC_RESULT_IBASE:
2715 case BC_RESULT_SCALE:
2716 case BC_RESULT_OBASE:
2718 bc_num_init(&d->d.n, src->d.n.len);
2719 bc_num_copy(&d->d.n, &src->d.n);
2724 case BC_RESULT_ARRAY:
2725 case BC_RESULT_ARRAY_ELEM:
2727 d->d.id.name = xstrdup(src->d.id.name);
2731 case BC_RESULT_CONSTANT:
2732 case BC_RESULT_LAST:
2736 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2743 static void bc_result_free(void *result)
2745 BcResult *r = (BcResult *) result;
2749 case BC_RESULT_TEMP:
2750 case BC_RESULT_IBASE:
2751 case BC_RESULT_SCALE:
2752 case BC_RESULT_OBASE:
2754 bc_num_free(&r->d.n);
2759 case BC_RESULT_ARRAY:
2760 case BC_RESULT_ARRAY_ELEM:
2774 static void bc_lex_lineComment(BcLex *l)
2776 l->t.t = BC_LEX_WHITESPACE;
2777 while (l->i < l->len && l->buf[l->i++] != '\n');
2781 static void bc_lex_whitespace(BcLex *l)
2784 l->t.t = BC_LEX_WHITESPACE;
2785 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2788 static BcStatus bc_lex_number(BcLex *l, char start)
2790 const char *buf = l->buf + l->i;
2791 size_t len, hits = 0, bslashes = 0, i = 0, j;
2793 bool last_pt, pt = start == '.';
2796 l->t.t = BC_LEX_NUMBER;
2798 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2799 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2813 len = i + !last_pt - bslashes * 2;
2814 if (len > BC_MAX_NUM)
2815 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2817 bc_vec_pop_all(&l->t.v);
2818 bc_vec_expand(&l->t.v, len + 1);
2819 bc_vec_push(&l->t.v, &start);
2821 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2825 // If we have hit a backslash, skip it. We don't have
2826 // to check for a newline because it's guaranteed.
2827 if (hits < bslashes && c == '\\') {
2833 bc_vec_push(&l->t.v, &c);
2836 bc_vec_pushByte(&l->t.v, '\0');
2839 return BC_STATUS_SUCCESS;
2842 static BcStatus bc_lex_name(BcLex *l)
2845 const char *buf = l->buf + l->i - 1;
2848 l->t.t = BC_LEX_NAME;
2850 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2852 if (i > BC_MAX_STRING)
2853 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2854 bc_vec_string(&l->t.v, i, buf);
2856 // Increment the index. We minus 1 because it has already been incremented.
2859 return BC_STATUS_SUCCESS;
2862 static void bc_lex_init(BcLex *l, BcLexNext next)
2865 bc_char_vec_init(&l->t.v);
2868 static void bc_lex_free(BcLex *l)
2870 bc_vec_free(&l->t.v);
2873 static void bc_lex_file(BcLex *l)
2879 static BcStatus bc_lex_next(BcLex *l)
2884 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2886 l->line += l->newline;
2887 l->t.t = BC_LEX_EOF;
2889 l->newline = (l->i == l->len);
2890 if (l->newline) return BC_STATUS_SUCCESS;
2892 // Loop until failure or we don't have whitespace. This
2893 // is so the parser doesn't get inundated with whitespace.
2896 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2901 static BcStatus bc_lex_text(BcLex *l, const char *text)
2905 l->len = strlen(text);
2906 l->t.t = l->t.last = BC_LEX_INVALID;
2907 return bc_lex_next(l);
2911 static BcStatus bc_lex_identifier(BcLex *l)
2915 const char *buf = l->buf + l->i - 1;
2917 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2918 const char *keyword8 = bc_lex_kws[i].name8;
2920 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2922 if (j == 8) goto match;
2924 if (keyword8[j] != '\0')
2927 // buf starts with keyword bc_lex_kws[i]
2928 l->t.t = BC_LEX_KEY_1st_keyword + i;
2929 if ((1 << i) & POSIX_KWORD_MASK) {
2930 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
2934 // We minus 1 because the index has already been incremented.
2936 return BC_STATUS_SUCCESS;
2943 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2948 static BcStatus bc_lex_string(BcLex *l)
2950 size_t len, nls = 0, i = l->i;
2953 l->t.t = BC_LEX_STR;
2955 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2959 return bc_error("string end could not be found");
2963 if (len > BC_MAX_STRING)
2964 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2965 bc_vec_string(&l->t.v, len, l->buf + l->i);
2970 return BC_STATUS_SUCCESS;
2973 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2975 if (l->buf[l->i] == '=') {
2983 static BcStatus bc_lex_comment(BcLex *l)
2986 const char *buf = l->buf;
2988 l->t.t = BC_LEX_WHITESPACE;
3001 return bc_error("comment end could not be found");
3010 return BC_STATUS_SUCCESS;
3013 static BcStatus bc_lex_token(BcLex *l)
3015 BcStatus s = BC_STATUS_SUCCESS;
3016 char c = l->buf[l->i++], c2;
3018 // This is the workhorse of the lexer.
3025 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3035 bc_lex_whitespace(l);
3041 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3043 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3044 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3053 s = bc_lex_string(l);
3059 s = bc_posix_error("POSIX does not allow '#' script comments");
3062 bc_lex_lineComment(l);
3069 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3078 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3082 l->t.t = BC_LEX_OP_BOOL_AND;
3085 l->t.t = BC_LEX_INVALID;
3086 s = bc_error_bad_character('&');
3095 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3101 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3110 l->t.t = BC_LEX_OP_INC;
3113 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3119 l->t.t = BC_LEX_COMMA;
3128 l->t.t = BC_LEX_OP_DEC;
3131 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3137 if (isdigit(l->buf[l->i]))
3138 s = bc_lex_number(l, c);
3140 l->t.t = BC_LEX_KEY_LAST;
3141 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3150 s = bc_lex_comment(l);
3152 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3173 s = bc_lex_number(l, c);
3179 l->t.t = BC_LEX_SCOLON;
3185 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3191 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3197 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3204 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3210 if (l->buf[l->i] == '\n') {
3211 l->t.t = BC_LEX_WHITESPACE;
3215 s = bc_error_bad_character(c);
3221 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3252 s = bc_lex_identifier(l);
3259 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3268 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3272 l->t.t = BC_LEX_OP_BOOL_OR;
3275 l->t.t = BC_LEX_INVALID;
3276 s = bc_error_bad_character(c);
3284 l->t.t = BC_LEX_INVALID;
3285 s = bc_error_bad_character(c);
3295 static BcStatus dc_lex_register(BcLex *l)
3297 BcStatus s = BC_STATUS_SUCCESS;
3299 if (isspace(l->buf[l->i - 1])) {
3300 bc_lex_whitespace(l);
3303 s = bc_error("extended register");
3308 bc_vec_pop_all(&l->t.v);
3309 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3310 bc_vec_pushByte(&l->t.v, '\0');
3311 l->t.t = BC_LEX_NAME;
3317 static BcStatus dc_lex_string(BcLex *l)
3319 size_t depth = 1, nls = 0, i = l->i;
3322 l->t.t = BC_LEX_STR;
3323 bc_vec_pop_all(&l->t.v);
3325 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3327 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3328 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3331 if (depth) bc_vec_push(&l->t.v, &c);
3336 return bc_error("string end could not be found");
3339 bc_vec_pushByte(&l->t.v, '\0');
3340 if (i - l->i > BC_MAX_STRING)
3341 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3346 return BC_STATUS_SUCCESS;
3349 static BcStatus dc_lex_token(BcLex *l)
3351 BcStatus s = BC_STATUS_SUCCESS;
3352 char c = l->buf[l->i++], c2;
3355 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3356 if (l->t.last == dc_lex_regs[i])
3357 return dc_lex_register(l);
3360 if (c >= '%' && c <= '~' &&
3361 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3366 // This is the workhorse of the lexer.
3371 l->t.t = BC_LEX_EOF;
3382 l->newline = (c == '\n');
3383 bc_lex_whitespace(l);
3392 l->t.t = BC_LEX_OP_REL_NE;
3394 l->t.t = BC_LEX_OP_REL_LE;
3396 l->t.t = BC_LEX_OP_REL_GE;
3398 return bc_error_bad_character(c);
3406 bc_lex_lineComment(l);
3412 if (isdigit(l->buf[l->i]))
3413 s = bc_lex_number(l, c);
3415 s = bc_error_bad_character(c);
3436 s = bc_lex_number(l, c);
3442 s = dc_lex_string(l);
3448 l->t.t = BC_LEX_INVALID;
3449 s = bc_error_bad_character(c);
3458 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3460 bc_program_addFunc(name, idx);
3461 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3464 static void bc_parse_pushName(BcParse *p, char *name)
3466 size_t i = 0, len = strlen(name);
3468 for (; i < len; ++i) bc_parse_push(p, name[i]);
3469 bc_parse_push(p, BC_PARSE_STREND);
3474 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3476 unsigned char amt, i, nums[sizeof(size_t)];
3478 for (amt = 0; idx; ++amt) {
3479 nums[amt] = (char) idx;
3480 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3483 bc_parse_push(p, amt);
3484 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3487 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3489 char *num = xstrdup(p->l.t.v.v);
3490 size_t idx = G.prog.consts.len;
3492 bc_vec_push(&G.prog.consts, &num);
3494 bc_parse_push(p, BC_INST_NUM);
3495 bc_parse_pushIndex(p, idx);
3498 (*prev) = BC_INST_NUM;
3501 static BcStatus bc_parse_text(BcParse *p, const char *text)
3505 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3507 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3508 p->l.t.t = BC_LEX_INVALID;
3511 if (!BC_PARSE_CAN_EXEC(p))
3512 return bc_error("file is not executable");
3515 return bc_lex_text(&p->l, text);
3518 // Called when bc/dc_parse_parse() detects a failure,
3519 // resets parsing structures.
3520 static void bc_parse_reset(BcParse *p)
3522 if (p->fidx != BC_PROG_MAIN) {
3523 p->func->nparams = 0;
3524 bc_vec_pop_all(&p->func->code);
3525 bc_vec_pop_all(&p->func->autos);
3526 bc_vec_pop_all(&p->func->labels);
3528 bc_parse_updateFunc(p, BC_PROG_MAIN);
3532 p->l.t.t = BC_LEX_EOF;
3533 p->auto_part = (p->nbraces = 0);
3535 bc_vec_npop(&p->flags, p->flags.len - 1);
3536 bc_vec_pop_all(&p->exits);
3537 bc_vec_pop_all(&p->conds);
3538 bc_vec_pop_all(&p->ops);
3543 static void bc_parse_free(BcParse *p)
3545 bc_vec_free(&p->flags);
3546 bc_vec_free(&p->exits);
3547 bc_vec_free(&p->conds);
3548 bc_vec_free(&p->ops);
3552 static void bc_parse_create(BcParse *p, size_t func,
3553 BcParseParse parse, BcLexNext next)
3555 memset(p, 0, sizeof(BcParse));
3557 bc_lex_init(&p->l, next);
3558 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3559 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3560 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3561 bc_vec_pushByte(&p->flags, 0);
3562 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3565 // p->auto_part = p->nbraces = 0; - already is
3566 bc_parse_updateFunc(p, func);
3570 static BcStatus bc_parse_else(BcParse *p);
3571 static BcStatus bc_parse_stmt(BcParse *p);
3573 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3574 size_t *nexprs, bool next)
3576 BcStatus s = BC_STATUS_SUCCESS;
3578 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3579 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3581 while (p->ops.len > start) {
3583 t = BC_PARSE_TOP_OP(p);
3584 if (t == BC_LEX_LPAREN) break;
3586 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3587 if (l >= r && (l != r || !left)) break;
3589 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3590 bc_vec_pop(&p->ops);
3591 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3594 bc_vec_push(&p->ops, &type);
3595 if (next) s = bc_lex_next(&p->l);
3600 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3604 if (p->ops.len <= ops_bgn)
3605 return bc_error_bad_expression();
3606 top = BC_PARSE_TOP_OP(p);
3608 while (top != BC_LEX_LPAREN) {
3610 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3612 bc_vec_pop(&p->ops);
3613 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3615 if (p->ops.len <= ops_bgn)
3616 return bc_error_bad_expression();
3617 top = BC_PARSE_TOP_OP(p);
3620 bc_vec_pop(&p->ops);
3622 return bc_lex_next(&p->l);
3625 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3631 s = bc_lex_next(&p->l);
3634 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3636 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3637 s = bc_parse_expr(p, flags, bc_parse_next_param);
3640 comma = p->l.t.t == BC_LEX_COMMA;
3642 s = bc_lex_next(&p->l);
3647 if (comma) return bc_error_bad_token();
3648 bc_parse_push(p, BC_INST_CALL);
3649 bc_parse_pushIndex(p, nparams);
3651 return BC_STATUS_SUCCESS;
3654 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3657 BcId entry, *entry_ptr;
3662 s = bc_parse_params(p, flags);
3665 if (p->l.t.t != BC_LEX_RPAREN) {
3666 s = bc_error_bad_token();
3670 idx = bc_map_index(&G.prog.fn_map, &entry);
3672 if (idx == BC_VEC_INVALID_IDX) {
3673 name = xstrdup(entry.name);
3674 bc_parse_addFunc(p, name, &idx);
3675 idx = bc_map_index(&G.prog.fn_map, &entry);
3681 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3682 bc_parse_pushIndex(p, entry_ptr->idx);
3684 return bc_lex_next(&p->l);
3691 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3696 name = xstrdup(p->l.t.v.v);
3697 s = bc_lex_next(&p->l);
3700 if (p->l.t.t == BC_LEX_LBRACKET) {
3702 s = bc_lex_next(&p->l);
3705 if (p->l.t.t == BC_LEX_RBRACKET) {
3707 if (!(flags & BC_PARSE_ARRAY)) {
3708 s = bc_error_bad_expression();
3712 *type = BC_INST_ARRAY;
3716 *type = BC_INST_ARRAY_ELEM;
3718 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3719 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3723 s = bc_lex_next(&p->l);
3725 bc_parse_push(p, *type);
3726 bc_parse_pushName(p, name);
3728 else if (p->l.t.t == BC_LEX_LPAREN) {
3730 if (flags & BC_PARSE_NOCALL) {
3731 s = bc_error_bad_token();
3735 *type = BC_INST_CALL;
3736 s = bc_parse_call(p, name, flags);
3739 *type = BC_INST_VAR;
3740 bc_parse_push(p, BC_INST_VAR);
3741 bc_parse_pushName(p, name);
3751 static BcStatus bc_parse_read(BcParse *p)
3755 s = bc_lex_next(&p->l);
3757 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3759 s = bc_lex_next(&p->l);
3761 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3763 bc_parse_push(p, BC_INST_READ);
3765 return bc_lex_next(&p->l);
3768 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3773 s = bc_lex_next(&p->l);
3775 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3777 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3779 s = bc_lex_next(&p->l);
3782 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3785 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3787 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3788 bc_parse_push(p, *prev);
3790 return bc_lex_next(&p->l);
3793 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3797 s = bc_lex_next(&p->l);
3800 if (p->l.t.t != BC_LEX_LPAREN) {
3801 *type = BC_INST_SCALE;
3802 bc_parse_push(p, BC_INST_SCALE);
3803 return BC_STATUS_SUCCESS;
3806 *type = BC_INST_SCALE_FUNC;
3807 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3809 s = bc_lex_next(&p->l);
3812 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3814 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3815 bc_parse_push(p, BC_INST_SCALE_FUNC);
3817 return bc_lex_next(&p->l);
3820 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3821 size_t *nexprs, uint8_t flags)
3826 BcInst etype = *prev;
3828 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3829 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3830 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3832 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3833 bc_parse_push(p, inst);
3834 s = bc_lex_next(&p->l);
3838 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3841 s = bc_lex_next(&p->l);
3845 // Because we parse the next part of the expression
3846 // right here, we need to increment this.
3847 *nexprs = *nexprs + 1;
3853 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3857 case BC_LEX_KEY_IBASE:
3858 case BC_LEX_KEY_LAST:
3859 case BC_LEX_KEY_OBASE:
3861 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3862 s = bc_lex_next(&p->l);
3866 case BC_LEX_KEY_SCALE:
3868 s = bc_lex_next(&p->l);
3870 if (p->l.t.t == BC_LEX_LPAREN)
3871 s = bc_error_bad_token();
3873 bc_parse_push(p, BC_INST_SCALE);
3879 s = bc_error_bad_token();
3884 if (!s) bc_parse_push(p, inst);
3890 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3891 bool rparen, size_t *nexprs)
3895 BcInst etype = *prev;
3897 s = bc_lex_next(&p->l);
3900 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3901 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3904 *prev = BC_PARSE_TOKEN_INST(type);
3906 // We can just push onto the op stack because this is the largest
3907 // precedence operator that gets pushed. Inc/dec does not.
3908 if (type != BC_LEX_OP_MINUS)
3909 bc_vec_push(&p->ops, &type);
3911 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3916 static BcStatus bc_parse_string(BcParse *p, char inst)
3918 char *str = xstrdup(p->l.t.v.v);
3920 bc_parse_push(p, BC_INST_STR);
3921 bc_parse_pushIndex(p, G.prog.strs.len);
3922 bc_vec_push(&G.prog.strs, &str);
3923 bc_parse_push(p, inst);
3925 return bc_lex_next(&p->l);
3928 static BcStatus bc_parse_print(BcParse *p)
3934 s = bc_lex_next(&p->l);
3939 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3940 return bc_error("bad print statement");
3942 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3944 if (type == BC_LEX_STR)
3945 s = bc_parse_string(p, BC_INST_PRINT_POP);
3947 s = bc_parse_expr(p, 0, bc_parse_next_print);
3949 bc_parse_push(p, BC_INST_PRINT_POP);
3954 comma = p->l.t.t == BC_LEX_COMMA;
3955 if (comma) s = bc_lex_next(&p->l);
3960 if (comma) return bc_error_bad_token();
3962 return bc_lex_next(&p->l);
3965 static BcStatus bc_parse_return(BcParse *p)
3971 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
3973 s = bc_lex_next(&p->l);
3977 paren = t == BC_LEX_LPAREN;
3979 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3980 bc_parse_push(p, BC_INST_RET0);
3983 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3984 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3987 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3988 bc_parse_push(p, BC_INST_RET0);
3989 s = bc_lex_next(&p->l);
3993 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3994 s = bc_posix_error("POSIX requires parentheses around return expressions");
3998 bc_parse_push(p, BC_INST_RET);
4004 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4006 BcStatus s = BC_STATUS_SUCCESS;
4008 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4009 return bc_error_bad_token();
4013 if (p->l.t.t == BC_LEX_RBRACE) {
4014 if (!p->nbraces) return bc_error_bad_token();
4016 s = bc_lex_next(&p->l);
4020 return bc_error_bad_token();
4023 if (BC_PARSE_IF(p)) {
4027 while (p->l.t.t == BC_LEX_NLINE) {
4028 s = bc_lex_next(&p->l);
4032 bc_vec_pop(&p->flags);
4034 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4035 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4037 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4039 else if (BC_PARSE_ELSE(p)) {
4044 bc_vec_pop(&p->flags);
4046 ip = bc_vec_top(&p->exits);
4047 label = bc_vec_item(&p->func->labels, ip->idx);
4048 *label = p->func->code.len;
4050 bc_vec_pop(&p->exits);
4052 else if (BC_PARSE_FUNC_INNER(p)) {
4053 bc_parse_push(p, BC_INST_RET0);
4054 bc_parse_updateFunc(p, BC_PROG_MAIN);
4055 bc_vec_pop(&p->flags);
4059 BcInstPtr *ip = bc_vec_top(&p->exits);
4060 size_t *label = bc_vec_top(&p->conds);
4062 bc_parse_push(p, BC_INST_JUMP);
4063 bc_parse_pushIndex(p, *label);
4065 label = bc_vec_item(&p->func->labels, ip->idx);
4066 *label = p->func->code.len;
4068 bc_vec_pop(&p->flags);
4069 bc_vec_pop(&p->exits);
4070 bc_vec_pop(&p->conds);
4076 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4078 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4079 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4080 flags |= BC_PARSE_FLAG_BODY;
4081 bc_vec_push(&p->flags, &flags);
4084 static void bc_parse_noElse(BcParse *p)
4088 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4090 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4092 ip = bc_vec_top(&p->exits);
4093 label = bc_vec_item(&p->func->labels, ip->idx);
4094 *label = p->func->code.len;
4096 bc_vec_pop(&p->exits);
4099 static BcStatus bc_parse_if(BcParse *p)
4104 s = bc_lex_next(&p->l);
4106 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4108 s = bc_lex_next(&p->l);
4110 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4112 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4114 s = bc_lex_next(&p->l);
4116 bc_parse_push(p, BC_INST_JUMP_ZERO);
4118 ip.idx = p->func->labels.len;
4119 ip.func = ip.len = 0;
4121 bc_parse_pushIndex(p, ip.idx);
4122 bc_vec_push(&p->exits, &ip);
4123 bc_vec_push(&p->func->labels, &ip.idx);
4124 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4126 return BC_STATUS_SUCCESS;
4129 static BcStatus bc_parse_else(BcParse *p)
4133 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4135 ip.idx = p->func->labels.len;
4136 ip.func = ip.len = 0;
4138 bc_parse_push(p, BC_INST_JUMP);
4139 bc_parse_pushIndex(p, ip.idx);
4143 bc_vec_push(&p->exits, &ip);
4144 bc_vec_push(&p->func->labels, &ip.idx);
4145 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4147 return bc_lex_next(&p->l);
4150 static BcStatus bc_parse_while(BcParse *p)
4155 s = bc_lex_next(&p->l);
4157 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4158 s = bc_lex_next(&p->l);
4161 ip.idx = p->func->labels.len;
4163 bc_vec_push(&p->func->labels, &p->func->code.len);
4164 bc_vec_push(&p->conds, &ip.idx);
4166 ip.idx = p->func->labels.len;
4170 bc_vec_push(&p->exits, &ip);
4171 bc_vec_push(&p->func->labels, &ip.idx);
4173 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4175 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4176 s = bc_lex_next(&p->l);
4179 bc_parse_push(p, BC_INST_JUMP_ZERO);
4180 bc_parse_pushIndex(p, ip.idx);
4181 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4183 return BC_STATUS_SUCCESS;
4186 static BcStatus bc_parse_for(BcParse *p)
4190 size_t cond_idx, exit_idx, body_idx, update_idx;
4192 s = bc_lex_next(&p->l);
4194 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4195 s = bc_lex_next(&p->l);
4198 if (p->l.t.t != BC_LEX_SCOLON)
4199 s = bc_parse_expr(p, 0, bc_parse_next_for);
4201 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4204 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4205 s = bc_lex_next(&p->l);
4208 cond_idx = p->func->labels.len;
4209 update_idx = cond_idx + 1;
4210 body_idx = update_idx + 1;
4211 exit_idx = body_idx + 1;
4213 bc_vec_push(&p->func->labels, &p->func->code.len);
4215 if (p->l.t.t != BC_LEX_SCOLON)
4216 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4218 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4221 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4223 s = bc_lex_next(&p->l);
4226 bc_parse_push(p, BC_INST_JUMP_ZERO);
4227 bc_parse_pushIndex(p, exit_idx);
4228 bc_parse_push(p, BC_INST_JUMP);
4229 bc_parse_pushIndex(p, body_idx);
4231 ip.idx = p->func->labels.len;
4233 bc_vec_push(&p->conds, &update_idx);
4234 bc_vec_push(&p->func->labels, &p->func->code.len);
4236 if (p->l.t.t != BC_LEX_RPAREN)
4237 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4239 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4243 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4244 bc_parse_push(p, BC_INST_JUMP);
4245 bc_parse_pushIndex(p, cond_idx);
4246 bc_vec_push(&p->func->labels, &p->func->code.len);
4252 bc_vec_push(&p->exits, &ip);
4253 bc_vec_push(&p->func->labels, &ip.idx);
4255 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4257 return BC_STATUS_SUCCESS;
4260 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4266 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4268 if (type == BC_LEX_KEY_BREAK) {
4270 if (p->exits.len == 0) return bc_error_bad_token();
4272 i = p->exits.len - 1;
4273 ip = bc_vec_item(&p->exits, i);
4275 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4276 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4281 i = *((size_t *) bc_vec_top(&p->conds));
4283 bc_parse_push(p, BC_INST_JUMP);
4284 bc_parse_pushIndex(p, i);
4286 s = bc_lex_next(&p->l);
4289 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4290 return bc_error_bad_token();
4292 return bc_lex_next(&p->l);
4295 static BcStatus bc_parse_func(BcParse *p)
4298 bool var, comma = false;
4302 s = bc_lex_next(&p->l);
4304 if (p->l.t.t != BC_LEX_NAME)
4305 return bc_error("bad function definition");
4307 name = xstrdup(p->l.t.v.v);
4308 bc_parse_addFunc(p, name, &p->fidx);
4310 s = bc_lex_next(&p->l);
4312 if (p->l.t.t != BC_LEX_LPAREN)
4313 return bc_error("bad function definition");
4314 s = bc_lex_next(&p->l);
4317 while (p->l.t.t != BC_LEX_RPAREN) {
4319 if (p->l.t.t != BC_LEX_NAME)
4320 return bc_error("bad function definition");
4324 name = xstrdup(p->l.t.v.v);
4325 s = bc_lex_next(&p->l);
4328 var = p->l.t.t != BC_LEX_LBRACKET;
4332 s = bc_lex_next(&p->l);
4335 if (p->l.t.t != BC_LEX_RBRACKET) {
4336 s = bc_error("bad function definition");
4340 s = bc_lex_next(&p->l);
4344 comma = p->l.t.t == BC_LEX_COMMA;
4346 s = bc_lex_next(&p->l);
4350 s = bc_func_insert(p->func, name, var);
4354 if (comma) return bc_error("bad function definition");
4356 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4357 bc_parse_startBody(p, flags);
4359 s = bc_lex_next(&p->l);
4362 if (p->l.t.t != BC_LEX_LBRACE)
4363 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4372 static BcStatus bc_parse_auto(BcParse *p)
4375 bool comma, var, one;
4378 if (!p->auto_part) return bc_error_bad_token();
4379 s = bc_lex_next(&p->l);
4382 p->auto_part = comma = false;
4383 one = p->l.t.t == BC_LEX_NAME;
4385 while (p->l.t.t == BC_LEX_NAME) {
4387 name = xstrdup(p->l.t.v.v);
4388 s = bc_lex_next(&p->l);
4391 var = p->l.t.t != BC_LEX_LBRACKET;
4394 s = bc_lex_next(&p->l);
4397 if (p->l.t.t != BC_LEX_RBRACKET) {
4398 s = bc_error("bad function definition");
4402 s = bc_lex_next(&p->l);
4406 comma = p->l.t.t == BC_LEX_COMMA;
4408 s = bc_lex_next(&p->l);
4412 s = bc_func_insert(p->func, name, var);
4416 if (comma) return bc_error("bad function definition");
4417 if (!one) return bc_error("no auto variable found");
4419 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4420 return bc_error_bad_token();
4422 return bc_lex_next(&p->l);
4429 static BcStatus bc_parse_body(BcParse *p, bool brace)
4431 BcStatus s = BC_STATUS_SUCCESS;
4432 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4434 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4436 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4438 if (!brace) return bc_error_bad_token();
4439 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4441 if (!p->auto_part) {
4442 s = bc_parse_auto(p);
4446 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4449 s = bc_parse_stmt(p);
4450 if (!s && !brace) s = bc_parse_endBody(p, false);
4456 static BcStatus bc_parse_stmt(BcParse *p)
4458 BcStatus s = BC_STATUS_SUCCESS;
4464 return bc_lex_next(&p->l);
4467 case BC_LEX_KEY_ELSE:
4469 p->auto_part = false;
4475 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4478 s = bc_lex_next(&p->l);
4481 return bc_parse_body(p, true);
4484 case BC_LEX_KEY_AUTO:
4486 return bc_parse_auto(p);
4491 p->auto_part = false;
4493 if (BC_PARSE_IF_END(p)) {
4495 return BC_STATUS_SUCCESS;
4497 else if (BC_PARSE_BODY(p))
4498 return bc_parse_body(p, false);
4508 case BC_LEX_OP_MINUS:
4509 case BC_LEX_OP_BOOL_NOT:
4513 case BC_LEX_KEY_IBASE:
4514 case BC_LEX_KEY_LAST:
4515 case BC_LEX_KEY_LENGTH:
4516 case BC_LEX_KEY_OBASE:
4517 case BC_LEX_KEY_READ:
4518 case BC_LEX_KEY_SCALE:
4519 case BC_LEX_KEY_SQRT:
4521 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4525 case BC_LEX_KEY_ELSE:
4527 s = bc_parse_else(p);
4533 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4539 s = bc_parse_endBody(p, true);
4545 s = bc_parse_string(p, BC_INST_PRINT_STR);
4549 case BC_LEX_KEY_BREAK:
4550 case BC_LEX_KEY_CONTINUE:
4552 s = bc_parse_loopExit(p, p->l.t.t);
4556 case BC_LEX_KEY_FOR:
4558 s = bc_parse_for(p);
4562 case BC_LEX_KEY_HALT:
4564 bc_parse_push(p, BC_INST_HALT);
4565 s = bc_lex_next(&p->l);
4575 case BC_LEX_KEY_LIMITS:
4577 // "limits" is a compile-time command,
4578 // the output is produced at _parse time_.
4579 s = bc_lex_next(&p->l);
4581 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4582 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4583 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4584 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4585 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4586 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4587 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4588 printf("Number of vars = %lu\n", BC_MAX_VARS);
4592 case BC_LEX_KEY_PRINT:
4594 s = bc_parse_print(p);
4598 case BC_LEX_KEY_QUIT:
4600 // "quit" is a compile-time command. For example,
4601 // "if (0 == 1) quit" terminates when parsing the statement,
4602 // not when it is executed
4606 case BC_LEX_KEY_RETURN:
4608 s = bc_parse_return(p);
4612 case BC_LEX_KEY_WHILE:
4614 s = bc_parse_while(p);
4620 s = bc_error_bad_token();
4628 static BcStatus bc_parse_parse(BcParse *p)
4632 if (p->l.t.t == BC_LEX_EOF)
4633 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4634 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4635 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4636 s = bc_parse_func(p);
4639 s = bc_parse_stmt(p);
4641 if (s || G_interrupt) {
4643 s = BC_STATUS_FAILURE;
4649 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4651 BcStatus s = BC_STATUS_SUCCESS;
4652 BcInst prev = BC_INST_PRINT;
4653 BcLexType top, t = p->l.t.t;
4654 size_t nexprs = 0, ops_bgn = p->ops.len;
4655 uint32_t i, nparens, nrelops;
4656 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4658 paren_first = p->l.t.t == BC_LEX_LPAREN;
4659 nparens = nrelops = 0;
4660 paren_expr = rprn = done = get_token = assign = false;
4663 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4669 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4670 rprn = get_token = bin_last = false;
4674 case BC_LEX_OP_MINUS:
4676 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4677 rprn = get_token = false;
4678 bin_last = prev == BC_INST_MINUS;
4682 case BC_LEX_OP_ASSIGN_POWER:
4683 case BC_LEX_OP_ASSIGN_MULTIPLY:
4684 case BC_LEX_OP_ASSIGN_DIVIDE:
4685 case BC_LEX_OP_ASSIGN_MODULUS:
4686 case BC_LEX_OP_ASSIGN_PLUS:
4687 case BC_LEX_OP_ASSIGN_MINUS:
4688 case BC_LEX_OP_ASSIGN:
4690 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4691 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4692 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4694 s = bc_error("bad assignment:"
4695 " left side must be scale,"
4696 " ibase, obase, last, var,"
4703 case BC_LEX_OP_POWER:
4704 case BC_LEX_OP_MULTIPLY:
4705 case BC_LEX_OP_DIVIDE:
4706 case BC_LEX_OP_MODULUS:
4707 case BC_LEX_OP_PLUS:
4708 case BC_LEX_OP_REL_EQ:
4709 case BC_LEX_OP_REL_LE:
4710 case BC_LEX_OP_REL_GE:
4711 case BC_LEX_OP_REL_NE:
4712 case BC_LEX_OP_REL_LT:
4713 case BC_LEX_OP_REL_GT:
4714 case BC_LEX_OP_BOOL_NOT:
4715 case BC_LEX_OP_BOOL_OR:
4716 case BC_LEX_OP_BOOL_AND:
4718 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4719 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4721 return bc_error_bad_expression();
4724 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4725 prev = BC_PARSE_TOKEN_INST(t);
4726 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4727 rprn = get_token = false;
4728 bin_last = t != BC_LEX_OP_BOOL_NOT;
4735 if (BC_PARSE_LEAF(prev, rprn))
4736 return bc_error_bad_expression();
4738 paren_expr = rprn = bin_last = false;
4740 bc_vec_push(&p->ops, &t);
4747 if (bin_last || prev == BC_INST_BOOL_NOT)
4748 return bc_error_bad_expression();
4751 s = BC_STATUS_SUCCESS;
4756 else if (!paren_expr)
4757 return BC_STATUS_PARSE_EMPTY_EXP;
4760 paren_expr = rprn = true;
4761 get_token = bin_last = false;
4763 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4770 if (BC_PARSE_LEAF(prev, rprn))
4771 return bc_error_bad_expression();
4773 rprn = get_token = bin_last = false;
4774 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4782 if (BC_PARSE_LEAF(prev, rprn))
4783 return bc_error_bad_expression();
4784 bc_parse_number(p, &prev, &nexprs);
4785 paren_expr = get_token = true;
4786 rprn = bin_last = false;
4791 case BC_LEX_KEY_IBASE:
4792 case BC_LEX_KEY_LAST:
4793 case BC_LEX_KEY_OBASE:
4795 if (BC_PARSE_LEAF(prev, rprn))
4796 return bc_error_bad_expression();
4797 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4798 bc_parse_push(p, (char) prev);
4800 paren_expr = get_token = true;
4801 rprn = bin_last = false;
4807 case BC_LEX_KEY_LENGTH:
4808 case BC_LEX_KEY_SQRT:
4810 if (BC_PARSE_LEAF(prev, rprn))
4811 return bc_error_bad_expression();
4812 s = bc_parse_builtin(p, t, flags, &prev);
4814 rprn = get_token = bin_last = false;
4820 case BC_LEX_KEY_READ:
4822 if (BC_PARSE_LEAF(prev, rprn))
4823 return bc_error_bad_expression();
4824 else if (flags & BC_PARSE_NOREAD)
4825 s = bc_error_nested_read_call();
4827 s = bc_parse_read(p);
4830 rprn = get_token = bin_last = false;
4832 prev = BC_INST_READ;
4837 case BC_LEX_KEY_SCALE:
4839 if (BC_PARSE_LEAF(prev, rprn))
4840 return bc_error_bad_expression();
4841 s = bc_parse_scale(p, &prev, flags);
4843 rprn = get_token = bin_last = false;
4845 prev = BC_INST_SCALE;
4852 s = bc_error_bad_token();
4857 if (!s && get_token) s = bc_lex_next(&p->l);
4861 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4863 while (p->ops.len > ops_bgn) {
4865 top = BC_PARSE_TOP_OP(p);
4866 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4868 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4869 return bc_error_bad_expression();
4871 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4873 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4874 bc_vec_pop(&p->ops);
4877 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4878 return bc_error_bad_expression();
4880 for (i = 0; i < next.len; ++i)
4881 if (t == next.tokens[i])
4883 return bc_error_bad_expression();
4886 if (!(flags & BC_PARSE_REL) && nrelops) {
4887 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4890 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4891 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4895 if (flags & BC_PARSE_PRINT) {
4896 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4897 bc_parse_push(p, BC_INST_POP);
4903 static void bc_parse_init(BcParse *p, size_t func)
4905 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4908 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4910 return bc_parse_expr(p, flags, bc_parse_next_read);
4915 static BcStatus dc_parse_register(BcParse *p)
4920 s = bc_lex_next(&p->l);
4922 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4924 name = xstrdup(p->l.t.v.v);
4925 bc_parse_pushName(p, name);
4930 static BcStatus dc_parse_string(BcParse *p)
4932 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4933 size_t idx, len = G.prog.strs.len;
4935 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4938 str = xstrdup(p->l.t.v.v);
4939 bc_parse_push(p, BC_INST_STR);
4940 bc_parse_pushIndex(p, len);
4941 bc_vec_push(&G.prog.strs, &str);
4942 bc_parse_addFunc(p, name, &idx);
4944 return bc_lex_next(&p->l);
4947 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4951 bc_parse_push(p, inst);
4953 s = dc_parse_register(p);
4958 bc_parse_push(p, BC_INST_SWAP);
4959 bc_parse_push(p, BC_INST_ASSIGN);
4960 bc_parse_push(p, BC_INST_POP);
4963 return bc_lex_next(&p->l);
4966 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4970 bc_parse_push(p, inst);
4971 bc_parse_push(p, BC_INST_EXEC_COND);
4973 s = dc_parse_register(p);
4976 s = bc_lex_next(&p->l);
4979 if (p->l.t.t == BC_LEX_ELSE) {
4980 s = dc_parse_register(p);
4982 s = bc_lex_next(&p->l);
4985 bc_parse_push(p, BC_PARSE_STREND);
4990 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4992 BcStatus s = BC_STATUS_SUCCESS;
4995 bool assign, get_token = false;
4999 case BC_LEX_OP_REL_EQ:
5000 case BC_LEX_OP_REL_LE:
5001 case BC_LEX_OP_REL_GE:
5002 case BC_LEX_OP_REL_NE:
5003 case BC_LEX_OP_REL_LT:
5004 case BC_LEX_OP_REL_GT:
5006 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5013 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5019 s = dc_parse_string(p);
5026 if (t == BC_LEX_NEG) {
5027 s = bc_lex_next(&p->l);
5029 if (p->l.t.t != BC_LEX_NUMBER)
5030 return bc_error_bad_token();
5033 bc_parse_number(p, &prev, &p->nbraces);
5035 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5041 case BC_LEX_KEY_READ:
5043 if (flags & BC_PARSE_NOREAD)
5044 s = bc_error_nested_read_call();
5046 bc_parse_push(p, BC_INST_READ);
5051 case BC_LEX_OP_ASSIGN:
5052 case BC_LEX_STORE_PUSH:
5054 assign = t == BC_LEX_OP_ASSIGN;
5055 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5056 s = dc_parse_mem(p, inst, true, assign);
5061 case BC_LEX_LOAD_POP:
5063 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5064 s = dc_parse_mem(p, inst, true, false);
5068 case BC_LEX_STORE_IBASE:
5069 case BC_LEX_STORE_SCALE:
5070 case BC_LEX_STORE_OBASE:
5072 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5073 s = dc_parse_mem(p, inst, false, true);
5079 s = bc_error_bad_token();
5085 if (!s && get_token) s = bc_lex_next(&p->l);
5090 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5092 BcStatus s = BC_STATUS_SUCCESS;
5096 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5098 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5100 inst = dc_parse_insts[t];
5102 if (inst != BC_INST_INVALID) {
5103 bc_parse_push(p, inst);
5104 s = bc_lex_next(&p->l);
5107 s = dc_parse_token(p, t, flags);
5110 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5111 bc_parse_push(p, BC_INST_POP_EXEC);
5116 static BcStatus dc_parse_parse(BcParse *p)
5120 if (p->l.t.t == BC_LEX_EOF)
5121 s = bc_error("end of file");
5123 s = dc_parse_expr(p, 0);
5125 if (s || G_interrupt) {
5127 s = BC_STATUS_FAILURE;
5133 static void dc_parse_init(BcParse *p, size_t func)
5135 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5139 static void common_parse_init(BcParse *p, size_t func)
5142 bc_parse_init(p, func);
5144 dc_parse_init(p, func);
5148 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5151 return bc_parse_expression(p, flags);
5153 return dc_parse_expr(p, flags);
5157 static BcVec* bc_program_search(char *id, bool var)
5165 v = var ? &G.prog.vars : &G.prog.arrs;
5166 map = var ? &G.prog.var_map : &G.prog.arr_map;
5170 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5173 bc_array_init(&data.v, var);
5174 bc_vec_push(v, &data.v);
5177 ptr = bc_vec_item(map, i);
5178 if (new) ptr->name = xstrdup(e.name);
5179 return bc_vec_item(v, ptr->idx);
5182 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5184 BcStatus s = BC_STATUS_SUCCESS;
5189 case BC_RESULT_TEMP:
5190 case BC_RESULT_IBASE:
5191 case BC_RESULT_SCALE:
5192 case BC_RESULT_OBASE:
5198 case BC_RESULT_CONSTANT:
5200 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5201 size_t base_t, len = strlen(*str);
5204 bc_num_init(&r->d.n, len);
5206 hex = hex && len == 1;
5207 base = hex ? &G.prog.hexb : &G.prog.ib;
5208 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5209 s = bc_num_parse(&r->d.n, *str, base, base_t);
5212 bc_num_free(&r->d.n);
5217 r->t = BC_RESULT_TEMP;
5223 case BC_RESULT_ARRAY:
5224 case BC_RESULT_ARRAY_ELEM:
5228 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5230 if (r->t == BC_RESULT_ARRAY_ELEM) {
5232 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5233 *num = bc_vec_item(v, r->d.id.idx);
5236 *num = bc_vec_top(v);
5241 case BC_RESULT_LAST:
5243 *num = &G.prog.last;
5257 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5258 BcResult **r, BcNum **rn, bool assign)
5262 BcResultType lt, rt;
5264 if (!BC_PROG_STACK(&G.prog.results, 2))
5265 return bc_error_stack_has_too_few_elements();
5267 *r = bc_vec_item_rev(&G.prog.results, 0);
5268 *l = bc_vec_item_rev(&G.prog.results, 1);
5272 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5274 s = bc_program_num(*l, ln, false);
5276 s = bc_program_num(*r, rn, hex);
5279 // We run this again under these conditions in case any vector has been
5280 // reallocated out from under the BcNums or arrays we had.
5281 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5282 s = bc_program_num(*l, ln, false);
5286 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5287 return bc_error_variable_is_wrong_type();
5288 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5289 return bc_error_variable_is_wrong_type();
5294 static void bc_program_binOpRetire(BcResult *r)
5296 r->t = BC_RESULT_TEMP;
5297 bc_vec_pop(&G.prog.results);
5298 bc_vec_pop(&G.prog.results);
5299 bc_vec_push(&G.prog.results, r);
5302 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5306 if (!BC_PROG_STACK(&G.prog.results, 1))
5307 return bc_error_stack_has_too_few_elements();
5308 *r = bc_vec_top(&G.prog.results);
5310 s = bc_program_num(*r, n, false);
5313 if (!BC_PROG_NUM((*r), (*n)))
5314 return bc_error_variable_is_wrong_type();
5319 static void bc_program_retire(BcResult *r, BcResultType t)
5322 bc_vec_pop(&G.prog.results);
5323 bc_vec_push(&G.prog.results, r);
5326 static BcStatus bc_program_op(char inst)
5329 BcResult *opd1, *opd2, res;
5330 BcNum *n1, *n2 = NULL;
5332 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5334 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5336 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5338 bc_program_binOpRetire(&res);
5343 bc_num_free(&res.d.n);
5347 static BcStatus bc_program_read(void)
5349 const char *sv_file;
5355 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5357 for (i = 0; i < G.prog.stack.len; ++i) {
5358 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5359 if (ip_ptr->func == BC_PROG_READ)
5360 return bc_error_nested_read_call();
5363 bc_vec_pop_all(&f->code);
5364 bc_char_vec_init(&buf);
5366 sv_file = G.prog.file;
5369 s = bc_read_line(&buf, "read> ");
5372 common_parse_init(&parse, BC_PROG_READ);
5373 bc_lex_file(&parse.l);
5375 s = bc_parse_text(&parse, buf.v);
5376 if (s) goto exec_err;
5377 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5378 if (s) goto exec_err;
5380 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5381 s = bc_error("bad read() expression");
5385 ip.func = BC_PROG_READ;
5387 ip.len = G.prog.results.len;
5389 // Update this pointer, just in case.
5390 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5392 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5393 bc_vec_push(&G.prog.stack, &ip);
5396 G.prog.file = sv_file;
5397 bc_parse_free(&parse);
5403 static size_t bc_program_index(char *code, size_t *bgn)
5405 char amt = code[(*bgn)++], i = 0;
5408 for (; i < amt; ++i, ++(*bgn))
5409 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5414 static char *bc_program_name(char *code, size_t *bgn)
5417 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5419 s = xmalloc(ptr - str + 1);
5422 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5430 static void bc_program_printString(const char *str, size_t *nchars)
5432 size_t i, len = strlen(str);
5441 for (i = 0; i < len; ++i, ++(*nchars)) {
5445 if (c != '\\' || i == len - 1)
5505 // Just print the backslash and following character.
5516 static BcStatus bc_program_print(char inst, size_t idx)
5518 BcStatus s = BC_STATUS_SUCCESS;
5523 bool pop = inst != BC_INST_PRINT;
5525 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5526 return bc_error_stack_has_too_few_elements();
5528 r = bc_vec_item_rev(&G.prog.results, idx);
5529 s = bc_program_num(r, &num, false);
5532 if (BC_PROG_NUM(r, num)) {
5533 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5534 if (!s) bc_num_copy(&G.prog.last, num);
5538 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5539 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5541 if (inst == BC_INST_PRINT_STR) {
5542 for (i = 0, len = strlen(str); i < len; ++i) {
5545 if (c == '\n') G.prog.nchars = SIZE_MAX;
5550 bc_program_printString(str, &G.prog.nchars);
5551 if (inst == BC_INST_PRINT) bb_putchar('\n');
5555 if (!s && pop) bc_vec_pop(&G.prog.results);
5560 static BcStatus bc_program_negate(void)
5566 s = bc_program_prep(&ptr, &num);
5569 bc_num_init(&res.d.n, num->len);
5570 bc_num_copy(&res.d.n, num);
5571 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5573 bc_program_retire(&res, BC_RESULT_TEMP);
5578 static BcStatus bc_program_logical(char inst)
5581 BcResult *opd1, *opd2, res;
5586 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5588 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5590 if (inst == BC_INST_BOOL_AND)
5591 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5592 else if (inst == BC_INST_BOOL_OR)
5593 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5596 cmp = bc_num_cmp(n1, n2);
5600 case BC_INST_REL_EQ:
5606 case BC_INST_REL_LE:
5612 case BC_INST_REL_GE:
5618 case BC_INST_REL_NE:
5624 case BC_INST_REL_LT:
5630 case BC_INST_REL_GT:
5638 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5640 bc_program_binOpRetire(&res);
5646 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5652 memset(&n2, 0, sizeof(BcNum));
5653 n2.rdx = res.d.id.idx = r->d.id.idx;
5654 res.t = BC_RESULT_STR;
5657 if (!BC_PROG_STACK(&G.prog.results, 2))
5658 return bc_error_stack_has_too_few_elements();
5660 bc_vec_pop(&G.prog.results);
5663 bc_vec_pop(&G.prog.results);
5665 bc_vec_push(&G.prog.results, &res);
5666 bc_vec_push(v, &n2);
5668 return BC_STATUS_SUCCESS;
5672 static BcStatus bc_program_copyToVar(char *name, bool var)
5679 if (!BC_PROG_STACK(&G.prog.results, 1))
5680 return bc_error_stack_has_too_few_elements();
5682 ptr = bc_vec_top(&G.prog.results);
5683 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5684 return bc_error_variable_is_wrong_type();
5685 v = bc_program_search(name, var);
5688 if (ptr->t == BC_RESULT_STR && !var)
5689 return bc_error_variable_is_wrong_type();
5690 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5693 s = bc_program_num(ptr, &n, false);
5696 // Do this once more to make sure that pointers were not invalidated.
5697 v = bc_program_search(name, var);
5700 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5701 bc_num_copy(&r.d.n, n);
5704 bc_array_init(&r.d.v, true);
5705 bc_array_copy(&r.d.v, (BcVec *) n);
5708 bc_vec_push(v, &r.d);
5709 bc_vec_pop(&G.prog.results);
5714 static BcStatus bc_program_assign(char inst)
5717 BcResult *left, *right, res;
5718 BcNum *l = NULL, *r = NULL;
5719 unsigned long val, max;
5720 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5722 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5725 ib = left->t == BC_RESULT_IBASE;
5726 sc = left->t == BC_RESULT_SCALE;
5730 if (right->t == BC_RESULT_STR) {
5734 if (left->t != BC_RESULT_VAR)
5735 return bc_error_variable_is_wrong_type();
5736 v = bc_program_search(left->d.id.name, true);
5738 return bc_program_assignStr(right, v, false);
5742 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5743 return bc_error("bad assignment:"
5744 " left side must be scale,"
5745 " ibase, obase, last, var,"
5750 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5751 return bc_error("divide by zero");
5756 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5763 if (ib || sc || left->t == BC_RESULT_OBASE) {
5764 static const char *const msg[] = {
5765 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5766 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5767 "?1", //BC_RESULT_LAST
5768 "?2", //BC_RESULT_CONSTANT
5769 "?3", //BC_RESULT_ONE
5770 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5774 s = bc_num_ulong(l, &val);
5777 s = left->t - BC_RESULT_IBASE;
5780 ptr = &G.prog.scale;
5783 if (val < BC_NUM_MIN_BASE)
5784 return bc_error(msg[s]);
5785 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5786 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5790 return bc_error(msg[s]);
5792 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5794 *ptr = (size_t) val;
5795 s = BC_STATUS_SUCCESS;
5798 bc_num_init(&res.d.n, l->len);
5799 bc_num_copy(&res.d.n, l);
5800 bc_program_binOpRetire(&res);
5806 #define bc_program_pushVar(code, bgn, pop, copy) \
5807 bc_program_pushVar(code, bgn)
5808 // for bc, 'pop' and 'copy' are always false
5810 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5811 bool pop, bool copy)
5813 BcStatus s = BC_STATUS_SUCCESS;
5815 char *name = bc_program_name(code, bgn);
5817 r.t = BC_RESULT_VAR;
5822 BcVec *v = bc_program_search(name, true);
5823 BcNum *num = bc_vec_top(v);
5827 if (!BC_PROG_STACK(v, 2 - copy)) {
5829 return bc_error_stack_has_too_few_elements();
5835 if (!BC_PROG_STR(num)) {
5837 r.t = BC_RESULT_TEMP;
5839 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5840 bc_num_copy(&r.d.n, num);
5843 r.t = BC_RESULT_STR;
5844 r.d.id.idx = num->rdx;
5847 if (!copy) bc_vec_pop(v);
5852 bc_vec_push(&G.prog.results, &r);
5857 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5860 BcStatus s = BC_STATUS_SUCCESS;
5864 r.d.id.name = bc_program_name(code, bgn);
5866 if (inst == BC_INST_ARRAY) {
5867 r.t = BC_RESULT_ARRAY;
5868 bc_vec_push(&G.prog.results, &r);
5875 s = bc_program_prep(&operand, &num);
5877 s = bc_num_ulong(num, &temp);
5880 if (temp > BC_MAX_DIM) {
5881 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5885 r.d.id.idx = (size_t) temp;
5886 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5890 if (s) free(r.d.id.name);
5895 static BcStatus bc_program_incdec(char inst)
5898 BcResult *ptr, res, copy;
5902 s = bc_program_prep(&ptr, &num);
5905 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5906 copy.t = BC_RESULT_TEMP;
5907 bc_num_init(©.d.n, num->len);
5908 bc_num_copy(©.d.n, num);
5911 res.t = BC_RESULT_ONE;
5912 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5913 BC_INST_ASSIGN_PLUS :
5914 BC_INST_ASSIGN_MINUS;
5916 bc_vec_push(&G.prog.results, &res);
5917 bc_program_assign(inst);
5919 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5920 bc_vec_pop(&G.prog.results);
5921 bc_vec_push(&G.prog.results, ©);
5927 static BcStatus bc_program_call(char *code, size_t *idx)
5929 BcStatus s = BC_STATUS_SUCCESS;
5931 size_t i, nparams = bc_program_index(code, idx);
5938 ip.func = bc_program_index(code, idx);
5939 func = bc_vec_item(&G.prog.fns, ip.func);
5941 if (func->code.len == 0) {
5942 return bc_error("undefined function");
5944 if (nparams != func->nparams) {
5945 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5947 ip.len = G.prog.results.len - nparams;
5949 for (i = 0; i < nparams; ++i) {
5951 a = bc_vec_item(&func->autos, nparams - 1 - i);
5952 arg = bc_vec_top(&G.prog.results);
5954 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5955 return bc_error_variable_is_wrong_type();
5957 s = bc_program_copyToVar(a->name, a->idx);
5961 for (; i < func->autos.len; ++i) {
5964 a = bc_vec_item(&func->autos, i);
5965 v = bc_program_search(a->name, a->idx);
5968 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5969 bc_vec_push(v, ¶m.n);
5972 bc_array_init(¶m.v, true);
5973 bc_vec_push(v, ¶m.v);
5977 bc_vec_push(&G.prog.stack, &ip);
5979 return BC_STATUS_SUCCESS;
5982 static BcStatus bc_program_return(char inst)
5988 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5990 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5991 return bc_error_stack_has_too_few_elements();
5993 f = bc_vec_item(&G.prog.fns, ip->func);
5994 res.t = BC_RESULT_TEMP;
5996 if (inst == BC_INST_RET) {
5999 BcResult *operand = bc_vec_top(&G.prog.results);
6001 s = bc_program_num(operand, &num, false);
6003 bc_num_init(&res.d.n, num->len);
6004 bc_num_copy(&res.d.n, num);
6007 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6008 bc_num_zero(&res.d.n);
6011 // We need to pop arguments as well, so this takes that into account.
6012 for (i = 0; i < f->autos.len; ++i) {
6015 BcId *a = bc_vec_item(&f->autos, i);
6017 v = bc_program_search(a->name, a->idx);
6021 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6022 bc_vec_push(&G.prog.results, &res);
6023 bc_vec_pop(&G.prog.stack);
6025 return BC_STATUS_SUCCESS;
6029 static unsigned long bc_program_scale(BcNum *n)
6031 return (unsigned long) n->rdx;
6034 static unsigned long bc_program_len(BcNum *n)
6036 unsigned long len = n->len;
6039 if (n->rdx != n->len) return len;
6040 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6045 static BcStatus bc_program_builtin(char inst)
6051 bool len = inst == BC_INST_LENGTH;
6053 if (!BC_PROG_STACK(&G.prog.results, 1))
6054 return bc_error_stack_has_too_few_elements();
6055 opnd = bc_vec_top(&G.prog.results);
6057 s = bc_program_num(opnd, &num, false);
6061 if (!BC_PROG_NUM(opnd, num) && !len)
6062 return bc_error_variable_is_wrong_type();
6065 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6067 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6069 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6070 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6074 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6077 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6079 str = bc_vec_item(&G.prog.strs, idx);
6080 bc_num_ulong2num(&res.d.n, strlen(*str));
6084 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6085 bc_num_ulong2num(&res.d.n, f(num));
6088 bc_program_retire(&res, BC_RESULT_TEMP);
6094 static BcStatus bc_program_divmod(void)
6097 BcResult *opd1, *opd2, res, res2;
6098 BcNum *n1, *n2 = NULL;
6100 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6103 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6104 bc_num_init(&res2.d.n, n2->len);
6106 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6109 bc_program_binOpRetire(&res2);
6110 res.t = BC_RESULT_TEMP;
6111 bc_vec_push(&G.prog.results, &res);
6116 bc_num_free(&res2.d.n);
6117 bc_num_free(&res.d.n);
6121 static BcStatus bc_program_modexp(void)
6124 BcResult *r1, *r2, *r3, res;
6125 BcNum *n1, *n2, *n3;
6127 if (!BC_PROG_STACK(&G.prog.results, 3))
6128 return bc_error_stack_has_too_few_elements();
6129 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6132 r1 = bc_vec_item_rev(&G.prog.results, 2);
6133 s = bc_program_num(r1, &n1, false);
6135 if (!BC_PROG_NUM(r1, n1))
6136 return bc_error_variable_is_wrong_type();
6138 // Make sure that the values have their pointers updated, if necessary.
6139 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6141 if (r1->t == r2->t) {
6142 s = bc_program_num(r2, &n2, false);
6146 if (r1->t == r3->t) {
6147 s = bc_program_num(r3, &n3, false);
6152 bc_num_init(&res.d.n, n3->len);
6153 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6156 bc_vec_pop(&G.prog.results);
6157 bc_program_binOpRetire(&res);
6162 bc_num_free(&res.d.n);
6166 static void bc_program_stackLen(void)
6169 size_t len = G.prog.results.len;
6171 res.t = BC_RESULT_TEMP;
6173 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6174 bc_num_ulong2num(&res.d.n, len);
6175 bc_vec_push(&G.prog.results, &res);
6178 static BcStatus bc_program_asciify(void)
6182 BcNum *num = NULL, n;
6183 char *str, *str2, c;
6184 size_t len = G.prog.strs.len, idx;
6187 if (!BC_PROG_STACK(&G.prog.results, 1))
6188 return bc_error_stack_has_too_few_elements();
6189 r = bc_vec_top(&G.prog.results);
6191 s = bc_program_num(r, &num, false);
6194 if (BC_PROG_NUM(r, num)) {
6196 bc_num_init(&n, BC_NUM_DEF_SIZE);
6197 bc_num_copy(&n, num);
6198 bc_num_truncate(&n, n.rdx);
6200 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6201 if (s) goto num_err;
6202 s = bc_num_ulong(&n, &val);
6203 if (s) goto num_err;
6210 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6211 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6219 str2 = xstrdup(str);
6220 bc_program_addFunc(str2, &idx);
6222 if (idx != len + BC_PROG_REQ_FUNCS) {
6224 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6225 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6234 bc_vec_push(&G.prog.strs, &str);
6236 res.t = BC_RESULT_STR;
6238 bc_vec_pop(&G.prog.results);
6239 bc_vec_push(&G.prog.results, &res);
6241 return BC_STATUS_SUCCESS;
6248 static BcStatus bc_program_printStream(void)
6256 if (!BC_PROG_STACK(&G.prog.results, 1))
6257 return bc_error_stack_has_too_few_elements();
6258 r = bc_vec_top(&G.prog.results);
6260 s = bc_program_num(r, &n, false);
6263 if (BC_PROG_NUM(r, n))
6264 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6266 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6267 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6274 static BcStatus bc_program_nquit(void)
6281 s = bc_program_prep(&opnd, &num);
6283 s = bc_num_ulong(num, &val);
6286 bc_vec_pop(&G.prog.results);
6288 if (G.prog.stack.len < val)
6289 return bc_error_stack_has_too_few_elements();
6290 if (G.prog.stack.len == val)
6293 bc_vec_npop(&G.prog.stack, val);
6298 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6301 BcStatus s = BC_STATUS_SUCCESS;
6311 if (!BC_PROG_STACK(&G.prog.results, 1))
6312 return bc_error_stack_has_too_few_elements();
6314 r = bc_vec_top(&G.prog.results);
6318 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6320 if (code[*bgn] == BC_PARSE_STREND)
6323 else_name = bc_program_name(code, bgn);
6325 exec = r->d.n.len != 0;
6329 else if (else_name != NULL) {
6336 v = bc_program_search(name, true);
6343 if (!exec) goto exit;
6344 if (!BC_PROG_STR(n)) {
6345 s = bc_error_variable_is_wrong_type();
6353 if (r->t == BC_RESULT_STR)
6355 else if (r->t == BC_RESULT_VAR) {
6356 s = bc_program_num(r, &n, false);
6357 if (s || !BC_PROG_STR(n)) goto exit;
6364 fidx = sidx + BC_PROG_REQ_FUNCS;
6366 str = bc_vec_item(&G.prog.strs, sidx);
6367 f = bc_vec_item(&G.prog.fns, fidx);
6369 if (f->code.len == 0) {
6370 common_parse_init(&prs, fidx);
6371 s = bc_parse_text(&prs, *str);
6373 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6376 if (prs.l.t.t != BC_LEX_EOF) {
6377 s = bc_error_bad_expression();
6381 bc_parse_free(&prs);
6385 ip.len = G.prog.results.len;
6388 bc_vec_pop(&G.prog.results);
6389 bc_vec_push(&G.prog.stack, &ip);
6391 return BC_STATUS_SUCCESS;
6394 bc_parse_free(&prs);
6395 f = bc_vec_item(&G.prog.fns, fidx);
6396 bc_vec_pop_all(&f->code);
6398 bc_vec_pop(&G.prog.results);
6403 static void bc_program_pushGlobal(char inst)
6408 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6409 if (inst == BC_INST_IBASE)
6410 val = (unsigned long) G.prog.ib_t;
6411 else if (inst == BC_INST_SCALE)
6412 val = (unsigned long) G.prog.scale;
6414 val = (unsigned long) G.prog.ob_t;
6416 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6417 bc_num_ulong2num(&res.d.n, val);
6418 bc_vec_push(&G.prog.results, &res);
6421 static void bc_program_addFunc(char *name, size_t *idx)
6423 BcId entry, *entry_ptr;
6428 entry.idx = G.prog.fns.len;
6430 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6431 if (!inserted) free(name);
6433 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6434 *idx = entry_ptr->idx;
6438 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6440 // We need to reset these, so the function can be repopulated.
6442 bc_vec_pop_all(&func->autos);
6443 bc_vec_pop_all(&func->code);
6444 bc_vec_pop_all(&func->labels);
6448 bc_vec_push(&G.prog.fns, &f);
6452 // Called when parsing or execution detects a failure,
6453 // resets execution structures.
6454 static void bc_program_reset(void)
6459 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6460 bc_vec_pop_all(&G.prog.results);
6462 f = bc_vec_item(&G.prog.fns, 0);
6463 ip = bc_vec_top(&G.prog.stack);
6464 ip->idx = f->code.len;
6466 // If !tty, no need to check for ^C: we don't have ^C handler,
6467 // we would be killed by a signal and won't reach this place
6470 static BcStatus bc_program_exec(void)
6472 BcStatus s = BC_STATUS_SUCCESS;
6476 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6477 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6478 char *code = func->code.v;
6481 while (!s && ip->idx < func->code.len) {
6483 char inst = code[(ip->idx)++];
6488 case BC_INST_JUMP_ZERO:
6490 s = bc_program_prep(&ptr, &num);
6492 cond = !bc_num_cmp(num, &G.prog.zero);
6493 bc_vec_pop(&G.prog.results);
6499 idx = bc_program_index(code, &ip->idx);
6500 addr = bc_vec_item(&func->labels, idx);
6501 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6507 s = bc_program_call(code, &ip->idx);
6511 case BC_INST_INC_PRE:
6512 case BC_INST_DEC_PRE:
6513 case BC_INST_INC_POST:
6514 case BC_INST_DEC_POST:
6516 s = bc_program_incdec(inst);
6529 s = bc_program_return(inst);
6533 case BC_INST_BOOL_OR:
6534 case BC_INST_BOOL_AND:
6536 case BC_INST_REL_EQ:
6537 case BC_INST_REL_LE:
6538 case BC_INST_REL_GE:
6539 case BC_INST_REL_NE:
6540 case BC_INST_REL_LT:
6541 case BC_INST_REL_GT:
6543 s = bc_program_logical(inst);
6549 s = bc_program_read();
6555 s = bc_program_pushVar(code, &ip->idx, false, false);
6559 case BC_INST_ARRAY_ELEM:
6562 s = bc_program_pushArray(code, &ip->idx, inst);
6568 r.t = BC_RESULT_LAST;
6569 bc_vec_push(&G.prog.results, &r);
6577 bc_program_pushGlobal(inst);
6581 case BC_INST_SCALE_FUNC:
6582 case BC_INST_LENGTH:
6585 s = bc_program_builtin(inst);
6591 r.t = BC_RESULT_CONSTANT;
6592 r.d.id.idx = bc_program_index(code, &ip->idx);
6593 bc_vec_push(&G.prog.results, &r);
6599 if (!BC_PROG_STACK(&G.prog.results, 1))
6600 s = bc_error_stack_has_too_few_elements();
6602 bc_vec_pop(&G.prog.results);
6606 case BC_INST_POP_EXEC:
6608 bc_vec_pop(&G.prog.stack);
6613 case BC_INST_PRINT_POP:
6614 case BC_INST_PRINT_STR:
6616 s = bc_program_print(inst, 0);
6622 r.t = BC_RESULT_STR;
6623 r.d.id.idx = bc_program_index(code, &ip->idx);
6624 bc_vec_push(&G.prog.results, &r);
6629 case BC_INST_MULTIPLY:
6630 case BC_INST_DIVIDE:
6631 case BC_INST_MODULUS:
6635 s = bc_program_op(inst);
6639 case BC_INST_BOOL_NOT:
6641 s = bc_program_prep(&ptr, &num);
6644 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6645 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6646 bc_program_retire(&r, BC_RESULT_TEMP);
6653 s = bc_program_negate();
6658 case BC_INST_ASSIGN_POWER:
6659 case BC_INST_ASSIGN_MULTIPLY:
6660 case BC_INST_ASSIGN_DIVIDE:
6661 case BC_INST_ASSIGN_MODULUS:
6662 case BC_INST_ASSIGN_PLUS:
6663 case BC_INST_ASSIGN_MINUS:
6665 case BC_INST_ASSIGN:
6667 s = bc_program_assign(inst);
6671 case BC_INST_MODEXP:
6673 s = bc_program_modexp();
6677 case BC_INST_DIVMOD:
6679 s = bc_program_divmod();
6683 case BC_INST_EXECUTE:
6684 case BC_INST_EXEC_COND:
6686 cond = inst == BC_INST_EXEC_COND;
6687 s = bc_program_execStr(code, &ip->idx, cond);
6691 case BC_INST_PRINT_STACK:
6693 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6694 s = bc_program_print(BC_INST_PRINT, idx);
6698 case BC_INST_CLEAR_STACK:
6700 bc_vec_pop_all(&G.prog.results);
6704 case BC_INST_STACK_LEN:
6706 bc_program_stackLen();
6710 case BC_INST_DUPLICATE:
6712 if (!BC_PROG_STACK(&G.prog.results, 1))
6713 return bc_error_stack_has_too_few_elements();
6714 ptr = bc_vec_top(&G.prog.results);
6715 bc_result_copy(&r, ptr);
6716 bc_vec_push(&G.prog.results, &r);
6724 if (!BC_PROG_STACK(&G.prog.results, 2))
6725 return bc_error_stack_has_too_few_elements();
6727 ptr = bc_vec_item_rev(&G.prog.results, 0);
6728 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6729 memcpy(&r, ptr, sizeof(BcResult));
6730 memcpy(ptr, ptr2, sizeof(BcResult));
6731 memcpy(ptr2, &r, sizeof(BcResult));
6736 case BC_INST_ASCIIFY:
6738 s = bc_program_asciify();
6742 case BC_INST_PRINT_STREAM:
6744 s = bc_program_printStream();
6749 case BC_INST_PUSH_VAR:
6751 bool copy = inst == BC_INST_LOAD;
6752 s = bc_program_pushVar(code, &ip->idx, true, copy);
6756 case BC_INST_PUSH_TO_VAR:
6758 char *name = bc_program_name(code, &ip->idx);
6759 s = bc_program_copyToVar(name, true);
6766 if (G.prog.stack.len <= 2)
6768 bc_vec_npop(&G.prog.stack, 2);
6774 s = bc_program_nquit();
6780 if (s || G_interrupt) {
6785 // If the stack has changed, pointers may be invalid.
6786 ip = bc_vec_top(&G.prog.stack);
6787 func = bc_vec_item(&G.prog.fns, ip->func);
6788 code = func->code.v;
6794 static void bc_vm_info(void)
6796 printf("%s "BB_VER"\n"
6797 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6798 "Report bugs at: https://github.com/gavinhoward/bc\n"
6799 "This is free software with ABSOLUTELY NO WARRANTY\n"
6804 static void bc_vm_envArgs(void)
6806 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6809 char *env_args = getenv(bc_args_env_name), *buf;
6811 if (!env_args) return;
6813 G.env_args = xstrdup(env_args);
6816 bc_vec_init(&v, sizeof(char *), NULL);
6817 bc_vec_push(&v, &bc_args_env_name);
6820 if (!isspace(*buf)) {
6821 bc_vec_push(&v, &buf);
6822 while (*buf != 0 && !isspace(*buf)) ++buf;
6823 if (*buf != 0) (*(buf++)) = '\0';
6829 bc_args((int) v.len, (char **) v.v);
6835 static size_t bc_vm_envLen(const char *var)
6837 char *lenv = getenv(var);
6838 size_t i, len = BC_NUM_PRINT_WIDTH;
6841 if (!lenv) return len;
6845 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6847 len = (size_t) atoi(lenv) - 1;
6848 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6851 len = BC_NUM_PRINT_WIDTH;
6856 static BcStatus bc_vm_process(const char *text)
6858 BcStatus s = bc_parse_text(&G.prs, text);
6862 while (G.prs.l.t.t != BC_LEX_EOF) {
6863 s = G.prs.parse(&G.prs);
6867 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6868 s = bc_program_exec();
6877 static BcStatus bc_vm_file(const char *file)
6879 const char *sv_file;
6885 data = bc_read_file(file);
6886 if (!data) return bc_error_fmt("file '%s' is not text", file);
6888 sv_file = G.prog.file;
6890 bc_lex_file(&G.prs.l);
6891 s = bc_vm_process(data);
6894 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6895 ip = bc_vec_item(&G.prog.stack, 0);
6897 if (main_func->code.len < ip->idx)
6898 s = bc_error_fmt("file '%s' is not executable", file);
6901 G.prog.file = sv_file;
6906 static BcStatus bc_vm_stdin(void)
6910 size_t len, i, str = 0;
6911 bool comment = false;
6914 bc_lex_file(&G.prs.l);
6916 bc_char_vec_init(&buffer);
6917 bc_char_vec_init(&buf);
6918 bc_vec_pushByte(&buffer, '\0');
6920 // This loop is complex because the vm tries not to send any lines that end
6921 // with a backslash to the parser. The reason for that is because the parser
6922 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6923 // case, and for strings and comments, the parser will expect more stuff.
6924 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6926 char *string = buf.v;
6931 if (str && buf.v[0] == G.send)
6933 else if (buf.v[0] == G.sbgn)
6936 else if (len > 1 || comment) {
6938 for (i = 0; i < len; ++i) {
6940 bool notend = len > i + 1;
6943 if (i - 1 > len || string[i - 1] != '\\') {
6944 if (G.sbgn == G.send)
6946 else if (c == G.send)
6948 else if (c == G.sbgn)
6952 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6956 else if (c == '*' && notend && comment && string[i + 1] == '/')
6960 if (str || comment || string[len - 2] == '\\') {
6961 bc_vec_concat(&buffer, buf.v);
6966 bc_vec_concat(&buffer, buf.v);
6967 s = bc_vm_process(buffer.v);
6970 fputs("ready for more input\n", stderr);
6973 bc_vec_pop_all(&buffer);
6977 s = bc_error("string end could not be found");
6980 s = bc_error("comment end could not be found");
6984 bc_vec_free(&buffer);
6989 static const char bc_lib[] = {
6992 "\n" "auto b,s,n,r,d,i,p,f,v"
7001 "\n" "scale=scale(x)+1"
7011 "\n" "for(i=2;v!=0;++i){"
7017 "\n" "while((d--)!=0)r*=r"
7020 "\n" "if(n!=0)return(1/r)"
7024 "\n" "auto b,s,r,p,a,q,i,v"
7028 "\n" "r=(1-10^scale)/1"
7039 "\n" "while(x<=0.5){"
7043 "\n" "r=a=(x-1)/(x+1)"
7046 "\n" "for(i=3;v!=0;i+=2){"
7057 "\n" "auto b,s,r,n,a,q,i"
7061 "\n" "scale=1.1*s+2"
7070 "\n" "if(q%2!=0)x=-x"
7074 "\n" "for(i=3;a!=0;i+=2){"
7075 "\n" "a*=q/(i*(i-1))"
7080 "\n" "if(n!=0)return(-r/1)"
7089 "\n" "x=s(2*a(1)+x)"
7095 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7104 "\n" "if(scale<65){"
7105 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7109 "\n" "if(scale<65){"
7110 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7121 "\n" "x=(x-.2)/(1+.2*x)"
7126 "\n" "for(i=3;t!=0;i+=2){"
7133 "\n" "return((m*a+r)/n)"
7135 "\n" "define j(n,x){"
7136 "\n" "auto b,s,o,a,i,v,f"
7144 "\n" "if(n%2==1)o=1"
7147 "\n" "for(i=2;i<=n;++i)a*=i"
7149 "\n" "a=(x^n)/2^n/a"
7152 "\n" "scale=scale+length(a)-scale(a)"
7153 "\n" "for(i=1;v!=0;++i){"
7154 "\n" "v=v*f/i/(n+i)"
7160 "\n" "return(a*r/1)"
7165 static BcStatus bc_vm_exec(void)
7167 BcStatus s = BC_STATUS_SUCCESS;
7171 if (option_mask32 & BC_FLAG_L) {
7173 // We know that internal library is not buggy,
7174 // thus error checking is normally disabled.
7175 # define DEBUG_LIB 0
7176 bc_lex_file(&G.prs.l);
7177 s = bc_parse_text(&G.prs, bc_lib);
7178 if (DEBUG_LIB && s) return s;
7180 while (G.prs.l.t.t != BC_LEX_EOF) {
7181 s = G.prs.parse(&G.prs);
7182 if (DEBUG_LIB && s) return s;
7184 s = bc_program_exec();
7185 if (DEBUG_LIB && s) return s;
7189 for (i = 0; !s && i < G.files.len; ++i)
7190 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7193 fputs("ready for more input\n", stderr);
7196 if (IS_BC || !G.files.len)
7198 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7199 s = bc_vm_process("");
7204 #if ENABLE_FEATURE_CLEAN_UP
7205 static void bc_program_free()
7207 bc_num_free(&G.prog.ib);
7208 bc_num_free(&G.prog.ob);
7209 bc_num_free(&G.prog.hexb);
7211 bc_num_free(&G.prog.strmb);
7213 bc_vec_free(&G.prog.fns);
7214 bc_vec_free(&G.prog.fn_map);
7215 bc_vec_free(&G.prog.vars);
7216 bc_vec_free(&G.prog.var_map);
7217 bc_vec_free(&G.prog.arrs);
7218 bc_vec_free(&G.prog.arr_map);
7219 bc_vec_free(&G.prog.strs);
7220 bc_vec_free(&G.prog.consts);
7221 bc_vec_free(&G.prog.results);
7222 bc_vec_free(&G.prog.stack);
7223 bc_num_free(&G.prog.last);
7224 bc_num_free(&G.prog.zero);
7225 bc_num_free(&G.prog.one);
7228 static void bc_vm_free(void)
7230 bc_vec_free(&G.files);
7232 bc_parse_free(&G.prs);
7237 static void bc_program_init(size_t line_len)
7242 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7243 memset(&ip, 0, sizeof(BcInstPtr));
7245 /* G.prog.nchars = G.prog.scale = 0; - already is */
7246 G.prog.len = line_len;
7248 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7249 bc_num_ten(&G.prog.ib);
7252 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7253 bc_num_ten(&G.prog.ob);
7256 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7257 bc_num_ten(&G.prog.hexb);
7258 G.prog.hexb.num[0] = 6;
7261 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7262 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7265 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7266 bc_num_zero(&G.prog.last);
7268 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7269 bc_num_zero(&G.prog.zero);
7271 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7272 bc_num_one(&G.prog.one);
7274 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7275 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7277 bc_program_addFunc(xstrdup("(main)"), &idx);
7278 bc_program_addFunc(xstrdup("(read)"), &idx);
7280 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7281 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7283 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7284 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7286 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7287 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7288 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7289 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7290 bc_vec_push(&G.prog.stack, &ip);
7293 static void bc_vm_init(const char *env_len)
7295 size_t len = bc_vm_envLen(env_len);
7297 bc_vec_init(&G.files, sizeof(char *), NULL);
7303 bc_program_init(len);
7305 bc_parse_init(&G.prs, BC_PROG_MAIN);
7307 dc_parse_init(&G.prs, BC_PROG_MAIN);
7311 static BcStatus bc_vm_run(int argc, char *argv[],
7312 const char *env_len)
7316 bc_vm_init(env_len);
7317 bc_args(argc, argv);
7319 G.ttyin = isatty(0);
7322 #if ENABLE_FEATURE_BC_SIGNALS
7323 // With SA_RESTART, most system calls will restart
7324 // (IOW: they won't fail with EINTR).
7325 // In particular, this means ^C won't cause
7326 // stdout to get into "error state" if SIGINT hits
7327 // within write() syscall.
7328 // The downside is that ^C while line input is taken
7329 // will only be handled after [Enter] since read()
7330 // from stdin is not interrupted by ^C either,
7331 // it restarts, thus fgetc() does not return on ^C.
7332 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7334 // Without SA_RESTART, this exhibits a bug:
7335 // "while (1) print 1" and try ^C-ing it.
7336 // Intermittently, instead of returning to input line,
7337 // you'll get "output error: Interrupted system call"
7339 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7341 if (!(option_mask32 & BC_FLAG_Q))
7346 #if ENABLE_FEATURE_CLEAN_UP
7353 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7354 int bc_main(int argc, char **argv)
7357 G.sbgn = G.send = '"';
7359 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7364 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7365 int dc_main(int argc, char **argv)
7371 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");