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_pushZeroByte(BcVec *v)
1073 //bc_vec_pushByte(v, '\0');
1075 bc_vec_push(v, &const_int_0);
1078 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1081 bc_vec_push(v, data);
1086 if (v->len == v->cap) bc_vec_grow(v, 1);
1088 ptr = v->v + v->size * idx;
1090 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1091 memmove(ptr, data, v->size);
1095 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1098 bc_vec_expand(v, len + 1);
1099 memcpy(v->v, str, len);
1102 bc_vec_pushZeroByte(v);
1105 static void bc_vec_concat(BcVec *v, const char *str)
1109 if (v->len == 0) bc_vec_pushZeroByte(v);
1111 len = v->len + strlen(str);
1113 if (v->cap < len) bc_vec_grow(v, len - v->len);
1119 static void *bc_vec_item(const BcVec *v, size_t idx)
1121 return v->v + v->size * idx;
1124 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1126 return v->v + v->size * (v->len - idx - 1);
1129 static void bc_vec_free(void *vec)
1131 BcVec *v = (BcVec *) vec;
1136 static size_t bc_map_find(const BcVec *v, const void *ptr)
1138 size_t low = 0, high = v->len;
1140 while (low < high) {
1142 size_t mid = (low + high) / 2;
1143 BcId *id = bc_vec_item(v, mid);
1144 int result = bc_id_cmp(ptr, id);
1148 else if (result < 0)
1157 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1159 size_t n = *i = bc_map_find(v, ptr);
1162 bc_vec_push(v, ptr);
1163 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1164 return 0; // "was not inserted"
1166 bc_vec_pushAt(v, ptr, n);
1167 return 1; // "was inserted"
1170 static size_t bc_map_index(const BcVec *v, const void *ptr)
1172 size_t i = bc_map_find(v, ptr);
1173 if (i >= v->len) return BC_VEC_INVALID_IDX;
1174 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1177 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1185 bc_vec_pop_all(vec);
1188 #if ENABLE_FEATURE_BC_SIGNALS
1189 if (bb_got_signal) { // ^C was pressed
1191 bb_got_signal = 0; // resets G_interrupt to zero
1193 ? "\ninterrupt (type \"quit\" to exit)\n"
1194 : "\ninterrupt (type \"q\" to exit)\n"
1198 if (G.ttyin && !G_posix)
1199 fputs(prompt, stderr);
1201 #if ENABLE_FEATURE_BC_SIGNALS
1207 #if ENABLE_FEATURE_BC_SIGNALS
1208 // Both conditions appear simultaneously, check both just in case
1209 if (errno == EINTR || bb_got_signal) {
1216 quit(); // this emits error message
1218 // Note: EOF does not append '\n', therefore:
1219 // printf 'print 123\n' | bc - works
1220 // printf 'print 123' | bc - fails (syntax error)
1224 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1227 // Bad chars on this line, ignore entire line
1228 bc_error_fmt("illegal character 0x%02x", i);
1231 bc_vec_pushByte(vec, (char)i);
1232 } while (i != '\n');
1233 } while (bad_chars);
1235 bc_vec_pushZeroByte(vec);
1237 return BC_STATUS_SUCCESS;
1240 static char* bc_read_file(const char *path)
1243 size_t size = ((size_t) -1);
1246 buf = xmalloc_open_read_close(path, &size);
1248 for (i = 0; i < size; ++i) {
1250 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1262 static void bc_args(int argc, char **argv)
1268 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1269 opts = getopt32long(argv, "xwvsqli",
1270 "extended-register\0" No_argument "x"
1271 "warn\0" No_argument "w"
1272 "version\0" No_argument "v"
1273 "standard\0" No_argument "s"
1274 "quiet\0" No_argument "q"
1275 "mathlib\0" No_argument "l"
1276 "interactive\0" No_argument "i"
1279 opts = getopt32(argv, "xwvsqli");
1281 if (getenv("POSIXLY_CORRECT"))
1282 option_mask32 |= BC_FLAG_S;
1284 if (opts & BC_FLAG_V) bc_vm_info();
1285 // should not be necessary, getopt32() handles this??
1286 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1288 for (i = optind; i < argc; ++i)
1289 bc_vec_push(&G.files, argv + i);
1292 static void bc_num_setToZero(BcNum *n, size_t scale)
1299 static void bc_num_zero(BcNum *n)
1301 bc_num_setToZero(n, 0);
1304 static void bc_num_one(BcNum *n)
1306 bc_num_setToZero(n, 0);
1311 static void bc_num_ten(BcNum *n)
1313 bc_num_setToZero(n, 0);
1319 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1323 for (i = 0; i < len; ++i) {
1324 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1331 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1335 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1336 return BC_NUM_NEG(i + 1, c < 0);
1339 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1341 size_t i, min, a_int, b_int, diff;
1342 BcDig *max_num, *min_num;
1343 bool a_max, neg = false;
1346 if (a == b) return 0;
1347 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1348 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1358 a_int = BC_NUM_INT(a);
1359 b_int = BC_NUM_INT(b);
1361 a_max = (a->rdx > b->rdx);
1363 if (a_int != 0) return (ssize_t) a_int;
1367 diff = a->rdx - b->rdx;
1368 max_num = a->num + diff;
1373 diff = b->rdx - a->rdx;
1374 max_num = b->num + diff;
1378 cmp = bc_num_compare(max_num, min_num, b_int + min);
1379 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1381 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1382 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1388 static void bc_num_truncate(BcNum *n, size_t places)
1390 if (places == 0) return;
1396 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1400 static void bc_num_extend(BcNum *n, size_t places)
1402 size_t len = n->len + places;
1406 if (n->cap < len) bc_num_expand(n, len);
1408 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1409 memset(n->num, 0, sizeof(BcDig) * places);
1416 static void bc_num_clean(BcNum *n)
1418 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1421 else if (n->len < n->rdx)
1425 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1428 bc_num_extend(n, scale - n->rdx);
1430 bc_num_truncate(n, n->rdx - scale);
1433 if (n->len != 0) n->neg = !neg1 != !neg2;
1436 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1441 b->len = n->len - idx;
1443 a->rdx = b->rdx = 0;
1445 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1446 memcpy(a->num, n->num, idx * sizeof(BcDig));
1457 static BcStatus bc_num_shift(BcNum *n, size_t places)
1459 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1460 if (places + n->len > BC_MAX_NUM)
1461 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1463 if (n->rdx >= places)
1466 bc_num_extend(n, places - n->rdx);
1472 return BC_STATUS_SUCCESS;
1475 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1484 return bc_num_div(&one, a, b, scale);
1487 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1489 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1490 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1493 // Because this function doesn't need to use scale (per the bc spec),
1494 // I am hijacking it to say whether it's doing an add or a subtract.
1498 if (sub && c->len) c->neg = !c->neg;
1499 return BC_STATUS_SUCCESS;
1501 else if (b->len == 0) {
1503 return BC_STATUS_SUCCESS;
1507 c->rdx = BC_MAX(a->rdx, b->rdx);
1508 min_rdx = BC_MIN(a->rdx, b->rdx);
1511 if (a->rdx > b->rdx) {
1512 diff = a->rdx - b->rdx;
1514 ptr_a = a->num + diff;
1518 diff = b->rdx - a->rdx;
1521 ptr_b = b->num + diff;
1524 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1527 a_int = BC_NUM_INT(a);
1528 b_int = BC_NUM_INT(b);
1530 if (a_int > b_int) {
1541 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1542 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1544 ptr_c[i] = (BcDig)(in % 10);
1547 for (; i < max + min_rdx; ++i, ++c->len) {
1548 in = ((int) ptr[i]) + carry;
1550 ptr_c[i] = (BcDig)(in % 10);
1553 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1555 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1558 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1561 BcNum *minuend, *subtrahend;
1563 bool aneg, bneg, neg;
1565 // Because this function doesn't need to use scale (per the bc spec),
1566 // I am hijacking it to say whether it's doing an add or a subtract.
1570 if (sub && c->len) c->neg = !c->neg;
1571 return BC_STATUS_SUCCESS;
1573 else if (b->len == 0) {
1575 return BC_STATUS_SUCCESS;
1580 a->neg = b->neg = false;
1582 cmp = bc_num_cmp(a, b);
1588 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1589 return BC_STATUS_SUCCESS;
1598 if (sub) neg = !neg;
1603 bc_num_copy(c, minuend);
1606 if (c->rdx < subtrahend->rdx) {
1607 bc_num_extend(c, subtrahend->rdx - c->rdx);
1611 start = c->rdx - subtrahend->rdx;
1613 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1617 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1620 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1625 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1626 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1627 bool aone = BC_NUM_ONE(a);
1629 if (a->len == 0 || b->len == 0) {
1631 return BC_STATUS_SUCCESS;
1633 else if (aone || BC_NUM_ONE(b)) {
1634 bc_num_copy(c, aone ? b : a);
1635 return BC_STATUS_SUCCESS;
1638 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1639 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1641 bc_num_expand(c, a->len + b->len + 1);
1643 memset(c->num, 0, sizeof(BcDig) * c->cap);
1644 c->len = carry = len = 0;
1646 for (i = 0; i < b->len; ++i) {
1648 for (j = 0; j < a->len; ++j) {
1649 int in = (int) c->num[i + j];
1650 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1652 c->num[i + j] = (BcDig)(in % 10);
1655 c->num[i + j] += (BcDig) carry;
1656 len = BC_MAX(len, i + j + !!carry);
1662 return BC_STATUS_SUCCESS;
1665 bc_num_init(&l1, max);
1666 bc_num_init(&h1, max);
1667 bc_num_init(&l2, max);
1668 bc_num_init(&h2, max);
1669 bc_num_init(&m1, max);
1670 bc_num_init(&m2, max);
1671 bc_num_init(&z0, max);
1672 bc_num_init(&z1, max);
1673 bc_num_init(&z2, max);
1674 bc_num_init(&temp, max + max);
1676 bc_num_split(a, max2, &l1, &h1);
1677 bc_num_split(b, max2, &l2, &h2);
1679 s = bc_num_add(&h1, &l1, &m1, 0);
1681 s = bc_num_add(&h2, &l2, &m2, 0);
1684 s = bc_num_k(&h1, &h2, &z0);
1686 s = bc_num_k(&m1, &m2, &z1);
1688 s = bc_num_k(&l1, &l2, &z2);
1691 s = bc_num_sub(&z1, &z0, &temp, 0);
1693 s = bc_num_sub(&temp, &z2, &z1, 0);
1696 s = bc_num_shift(&z0, max2 * 2);
1698 s = bc_num_shift(&z1, max2);
1700 s = bc_num_add(&z0, &z1, &temp, 0);
1702 s = bc_num_add(&temp, &z2, c, 0);
1718 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1722 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1724 scale = BC_MAX(scale, a->rdx);
1725 scale = BC_MAX(scale, b->rdx);
1726 scale = BC_MIN(a->rdx + b->rdx, scale);
1727 maxrdx = BC_MAX(maxrdx, scale);
1729 bc_num_init(&cpa, a->len);
1730 bc_num_init(&cpb, b->len);
1732 bc_num_copy(&cpa, a);
1733 bc_num_copy(&cpb, b);
1734 cpa.neg = cpb.neg = false;
1736 s = bc_num_shift(&cpa, maxrdx);
1738 s = bc_num_shift(&cpb, maxrdx);
1740 s = bc_num_k(&cpa, &cpb, c);
1744 bc_num_expand(c, c->len + maxrdx);
1746 if (c->len < maxrdx) {
1747 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1752 bc_num_retireMul(c, scale, a->neg, b->neg);
1760 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1762 BcStatus s = BC_STATUS_SUCCESS;
1769 return bc_error("divide by zero");
1770 else if (a->len == 0) {
1771 bc_num_setToZero(c, scale);
1772 return BC_STATUS_SUCCESS;
1774 else if (BC_NUM_ONE(b)) {
1776 bc_num_retireMul(c, scale, a->neg, b->neg);
1777 return BC_STATUS_SUCCESS;
1780 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1781 bc_num_copy(&cp, a);
1785 bc_num_expand(&cp, len + 2);
1786 bc_num_extend(&cp, len - cp.len);
1789 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1791 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1793 if (b->rdx == b->len) {
1794 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1798 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1800 // We want an extra zero in front to make things simpler.
1801 cp.num[cp.len++] = 0;
1804 bc_num_expand(c, cp.len);
1807 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1812 for (i = end - 1; !s && i < end; --i) {
1814 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1815 bc_num_subArrays(n, p, len);
1819 bc_num_retireMul(c, scale, a->neg, b->neg);
1822 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1825 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1826 BcNum *restrict d, size_t scale, size_t ts)
1833 return bc_error("divide by zero");
1836 bc_num_setToZero(d, ts);
1837 return BC_STATUS_SUCCESS;
1840 bc_num_init(&temp, d->cap);
1841 bc_num_d(a, b, c, scale);
1843 if (scale != 0) scale = ts;
1845 s = bc_num_m(c, b, &temp, scale);
1847 s = bc_num_sub(a, &temp, d, scale);
1850 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1853 bc_num_retireMul(d, ts, a->neg, b->neg);
1861 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1865 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1867 bc_num_init(&c1, len);
1868 s = bc_num_r(a, b, &c1, c, scale, ts);
1874 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1876 BcStatus s = BC_STATUS_SUCCESS;
1879 size_t i, powrdx, resrdx;
1882 if (b->rdx) return bc_error("non integer number");
1886 return BC_STATUS_SUCCESS;
1888 else if (a->len == 0) {
1889 bc_num_setToZero(c, scale);
1890 return BC_STATUS_SUCCESS;
1892 else if (BC_NUM_ONE(b)) {
1896 s = bc_num_inv(a, c, scale);
1903 s = bc_num_ulong(b, &pow);
1906 bc_num_init(©, a->len);
1907 bc_num_copy(©, a);
1909 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1913 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1915 s = bc_num_mul(©, ©, ©, powrdx);
1917 // It is too slow to handle ^C only after entire "2^1000000" completes
1919 s = BC_STATUS_FAILURE;
1924 bc_num_copy(c, ©);
1926 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1929 s = bc_num_mul(©, ©, ©, powrdx);
1934 s = bc_num_mul(c, ©, c, resrdx);
1937 // It is too slow to handle ^C only after entire "2^1000000" completes
1939 s = BC_STATUS_FAILURE;
1945 s = bc_num_inv(c, c, scale);
1949 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1951 // We can't use bc_num_clean() here.
1952 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1953 if (zero) bc_num_setToZero(c, scale);
1960 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1961 BcNumBinaryOp op, size_t req)
1964 BcNum num2, *ptr_a, *ptr_b;
1969 memcpy(ptr_a, c, sizeof(BcNum));
1978 memcpy(ptr_b, c, sizeof(BcNum));
1986 bc_num_init(c, req);
1988 bc_num_expand(c, req);
1990 s = op(ptr_a, ptr_b, c, scale);
1992 if (init) bc_num_free(&num2);
1997 static bool bc_num_strValid(const char *val, size_t base)
2000 bool small, radix = false;
2001 size_t i, len = strlen(val);
2003 if (!len) return true;
2006 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2008 for (i = 0; i < len; ++i) {
2014 if (radix) return false;
2020 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2027 static void bc_num_parseDecimal(BcNum *n, const char *val)
2033 for (i = 0; val[i] == '0'; ++i);
2040 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2041 bc_num_expand(n, len);
2044 ptr = strchr(val, '.');
2048 n->rdx = (size_t)((val + len) - (ptr + 1));
2051 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2052 n->num[n->len] = val[i] - '0';
2056 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2059 BcNum temp, mult, result;
2063 size_t i, digits, len = strlen(val);
2067 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2070 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2071 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2073 for (i = 0; i < len; ++i) {
2076 if (c == '.') break;
2078 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2080 s = bc_num_mul(n, base, &mult, 0);
2081 if (s) goto int_err;
2082 bc_num_ulong2num(&temp, v);
2083 s = bc_num_add(&mult, &temp, n, 0);
2084 if (s) goto int_err;
2089 if (c == 0) goto int_err;
2092 bc_num_init(&result, base->len);
2093 bc_num_zero(&result);
2096 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2101 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2103 s = bc_num_mul(&result, base, &result, 0);
2105 bc_num_ulong2num(&temp, v);
2106 s = bc_num_add(&result, &temp, &result, 0);
2108 s = bc_num_mul(&mult, base, &mult, 0);
2112 s = bc_num_div(&result, &mult, &result, digits);
2114 s = bc_num_add(n, &result, n, digits);
2118 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2124 bc_num_free(&result);
2130 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2132 if (*nchars == line_len - 1) {
2140 static void bc_num_printChar(size_t num, size_t width, bool radix,
2141 size_t *nchars, size_t line_len)
2143 (void) radix, (void) line_len;
2144 bb_putchar((char) num);
2145 *nchars = *nchars + width;
2149 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2150 size_t *nchars, size_t line_len)
2154 bc_num_printNewline(nchars, line_len);
2155 bb_putchar(radix ? '.' : ' ');
2158 bc_num_printNewline(nchars, line_len);
2159 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2162 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2164 bc_num_printNewline(nchars, line_len);
2167 bb_putchar(((char) dig) + '0');
2171 static void bc_num_printHex(size_t num, size_t width, bool radix,
2172 size_t *nchars, size_t line_len)
2175 bc_num_printNewline(nchars, line_len);
2180 bc_num_printNewline(nchars, line_len);
2181 bb_putchar(bb_hexdigits_upcase[num]);
2182 *nchars = *nchars + width;
2185 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2187 size_t i, rdx = n->rdx - 1;
2189 if (n->neg) bb_putchar('-');
2190 (*nchars) += n->neg;
2192 for (i = n->len - 1; i < n->len; --i)
2193 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2196 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2197 size_t *nchars, size_t len, BcNumDigitOp print)
2201 BcNum intp, fracp, digit, frac_len;
2202 unsigned long dig, *ptr;
2207 print(0, width, false, nchars, len);
2208 return BC_STATUS_SUCCESS;
2211 bc_vec_init(&stack, sizeof(long), NULL);
2212 bc_num_init(&intp, n->len);
2213 bc_num_init(&fracp, n->rdx);
2214 bc_num_init(&digit, width);
2215 bc_num_init(&frac_len, BC_NUM_INT(n));
2216 bc_num_copy(&intp, n);
2217 bc_num_one(&frac_len);
2219 bc_num_truncate(&intp, intp.rdx);
2220 s = bc_num_sub(n, &intp, &fracp, 0);
2223 while (intp.len != 0) {
2224 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2226 s = bc_num_ulong(&digit, &dig);
2228 bc_vec_push(&stack, &dig);
2231 for (i = 0; i < stack.len; ++i) {
2232 ptr = bc_vec_item_rev(&stack, i);
2233 print(*ptr, width, false, nchars, len);
2236 if (!n->rdx) goto err;
2238 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2239 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2241 s = bc_num_ulong(&fracp, &dig);
2243 bc_num_ulong2num(&intp, dig);
2244 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2246 print(dig, width, radix, nchars, len);
2247 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2252 bc_num_free(&frac_len);
2253 bc_num_free(&digit);
2254 bc_num_free(&fracp);
2256 bc_vec_free(&stack);
2260 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2261 size_t *nchars, size_t line_len)
2268 if (neg) bb_putchar('-');
2273 if (base_t <= BC_NUM_MAX_IBASE) {
2275 print = bc_num_printHex;
2278 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2279 print = bc_num_printDigits;
2282 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2289 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2291 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2295 static void bc_num_init(BcNum *n, size_t req)
2297 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2298 memset(n, 0, sizeof(BcNum));
2299 n->num = xmalloc(req);
2303 static void bc_num_expand(BcNum *n, size_t req)
2305 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2307 n->num = xrealloc(n->num, req);
2312 static void bc_num_free(void *num)
2314 free(((BcNum *) num)->num);
2317 static void bc_num_copy(BcNum *d, BcNum *s)
2320 bc_num_expand(d, s->cap);
2324 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2328 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2331 if (!bc_num_strValid(val, base_t))
2332 return bc_error("bad number string");
2335 bc_num_parseDecimal(n, val);
2337 bc_num_parseBase(n, val, base);
2339 return BC_STATUS_SUCCESS;
2342 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2343 size_t *nchars, size_t line_len)
2345 BcStatus s = BC_STATUS_SUCCESS;
2347 bc_num_printNewline(nchars, line_len);
2353 else if (base_t == 10)
2354 bc_num_printDecimal(n, nchars, line_len);
2356 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2366 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2371 if (n->neg) return bc_error("negative number");
2373 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2375 unsigned long prev = *result, powprev = pow;
2377 *result += ((unsigned long) n->num[i]) * pow;
2380 if (*result < prev || pow < powprev)
2381 return bc_error("overflow");
2384 return BC_STATUS_SUCCESS;
2387 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2395 if (val == 0) return;
2397 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2398 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2401 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2403 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2405 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2408 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2410 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2412 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2415 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2417 size_t req = BC_NUM_MREQ(a, b, scale);
2418 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2421 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2423 size_t req = BC_NUM_MREQ(a, b, scale);
2424 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2427 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2429 size_t req = BC_NUM_MREQ(a, b, scale);
2430 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2433 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2435 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2438 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2441 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2442 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2443 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2445 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2446 bc_num_expand(b, req);
2449 bc_num_setToZero(b, scale);
2450 return BC_STATUS_SUCCESS;
2453 return bc_error("negative number");
2454 else if (BC_NUM_ONE(a)) {
2456 bc_num_extend(b, scale);
2457 return BC_STATUS_SUCCESS;
2460 scale = BC_MAX(scale, a->rdx) + 1;
2461 len = a->len + scale;
2463 bc_num_init(&num1, len);
2464 bc_num_init(&num2, len);
2465 bc_num_init(&half, BC_NUM_DEF_SIZE);
2471 bc_num_init(&f, len);
2472 bc_num_init(&fprime, len);
2478 pow = BC_NUM_INT(a);
2487 pow -= 2 - (pow & 1);
2489 bc_num_extend(x0, pow);
2491 // Make sure to move the radix back.
2495 x0->rdx = digs = digs1 = 0;
2497 len = BC_NUM_INT(x0) + resrdx - 1;
2499 while (cmp != 0 || digs < len) {
2501 s = bc_num_div(a, x0, &f, resrdx);
2503 s = bc_num_add(x0, &f, &fprime, resrdx);
2505 s = bc_num_mul(&fprime, &half, x1, resrdx);
2508 cmp = bc_num_cmp(x1, x0);
2509 digs = x1->len - (unsigned long long) llabs(cmp);
2511 if (cmp == cmp2 && digs == digs1)
2516 resrdx += times > 4;
2529 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2532 bc_num_free(&fprime);
2540 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2546 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2549 memcpy(&num2, c, sizeof(BcNum));
2551 bc_num_init(c, len);
2556 bc_num_expand(c, len);
2559 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2561 if (init) bc_num_free(&num2);
2567 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2570 BcNum base, exp, two, temp;
2573 return bc_error("divide by zero");
2574 if (a->rdx || b->rdx || c->rdx)
2575 return bc_error("non integer number");
2577 return bc_error("negative number");
2579 bc_num_expand(d, c->len);
2580 bc_num_init(&base, c->len);
2581 bc_num_init(&exp, b->len);
2582 bc_num_init(&two, BC_NUM_DEF_SIZE);
2583 bc_num_init(&temp, b->len);
2589 s = bc_num_rem(a, c, &base, 0);
2591 bc_num_copy(&exp, b);
2593 while (exp.len != 0) {
2595 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2598 if (BC_NUM_ONE(&temp)) {
2599 s = bc_num_mul(d, &base, &temp, 0);
2601 s = bc_num_rem(&temp, c, d, 0);
2605 s = bc_num_mul(&base, &base, &temp, 0);
2607 s = bc_num_rem(&temp, c, &base, 0);
2620 static int bc_id_cmp(const void *e1, const void *e2)
2622 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2625 static void bc_id_free(void *id)
2627 free(((BcId *) id)->name);
2630 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2635 for (i = 0; i < f->autos.len; ++i) {
2636 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2637 return bc_error("function parameter or auto var has the same name as another");
2643 bc_vec_push(&f->autos, &a);
2645 return BC_STATUS_SUCCESS;
2648 static void bc_func_init(BcFunc *f)
2650 bc_char_vec_init(&f->code);
2651 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2652 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2656 static void bc_func_free(void *func)
2658 BcFunc *f = (BcFunc *) func;
2659 bc_vec_free(&f->code);
2660 bc_vec_free(&f->autos);
2661 bc_vec_free(&f->labels);
2664 static void bc_array_init(BcVec *a, bool nums)
2667 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2669 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2670 bc_array_expand(a, 1);
2673 static void bc_array_copy(BcVec *d, const BcVec *s)
2678 bc_vec_expand(d, s->cap);
2681 for (i = 0; i < s->len; ++i) {
2682 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2683 bc_num_init(dnum, snum->len);
2684 bc_num_copy(dnum, snum);
2688 static void bc_array_expand(BcVec *a, size_t len)
2692 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2693 while (len > a->len) {
2694 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2695 bc_vec_push(a, &data.n);
2699 while (len > a->len) {
2700 bc_array_init(&data.v, true);
2701 bc_vec_push(a, &data.v);
2706 static void bc_string_free(void *string)
2708 free(*((char **) string));
2712 static void bc_result_copy(BcResult *d, BcResult *src)
2718 case BC_RESULT_TEMP:
2719 case BC_RESULT_IBASE:
2720 case BC_RESULT_SCALE:
2721 case BC_RESULT_OBASE:
2723 bc_num_init(&d->d.n, src->d.n.len);
2724 bc_num_copy(&d->d.n, &src->d.n);
2729 case BC_RESULT_ARRAY:
2730 case BC_RESULT_ARRAY_ELEM:
2732 d->d.id.name = xstrdup(src->d.id.name);
2736 case BC_RESULT_CONSTANT:
2737 case BC_RESULT_LAST:
2741 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2748 static void bc_result_free(void *result)
2750 BcResult *r = (BcResult *) result;
2754 case BC_RESULT_TEMP:
2755 case BC_RESULT_IBASE:
2756 case BC_RESULT_SCALE:
2757 case BC_RESULT_OBASE:
2759 bc_num_free(&r->d.n);
2764 case BC_RESULT_ARRAY:
2765 case BC_RESULT_ARRAY_ELEM:
2779 static void bc_lex_lineComment(BcLex *l)
2781 l->t.t = BC_LEX_WHITESPACE;
2782 while (l->i < l->len && l->buf[l->i++] != '\n');
2786 static void bc_lex_whitespace(BcLex *l)
2789 l->t.t = BC_LEX_WHITESPACE;
2790 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2793 static BcStatus bc_lex_number(BcLex *l, char start)
2795 const char *buf = l->buf + l->i;
2796 size_t len, hits = 0, bslashes = 0, i = 0, j;
2798 bool last_pt, pt = start == '.';
2801 l->t.t = BC_LEX_NUMBER;
2803 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2804 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2818 len = i + !last_pt - bslashes * 2;
2819 if (len > BC_MAX_NUM)
2820 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2822 bc_vec_pop_all(&l->t.v);
2823 bc_vec_expand(&l->t.v, len + 1);
2824 bc_vec_push(&l->t.v, &start);
2826 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2830 // If we have hit a backslash, skip it. We don't have
2831 // to check for a newline because it's guaranteed.
2832 if (hits < bslashes && c == '\\') {
2838 bc_vec_push(&l->t.v, &c);
2841 bc_vec_pushZeroByte(&l->t.v);
2844 return BC_STATUS_SUCCESS;
2847 static BcStatus bc_lex_name(BcLex *l)
2850 const char *buf = l->buf + l->i - 1;
2853 l->t.t = BC_LEX_NAME;
2855 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2857 if (i > BC_MAX_STRING)
2858 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2859 bc_vec_string(&l->t.v, i, buf);
2861 // Increment the index. We minus 1 because it has already been incremented.
2864 return BC_STATUS_SUCCESS;
2867 static void bc_lex_init(BcLex *l, BcLexNext next)
2870 bc_char_vec_init(&l->t.v);
2873 static void bc_lex_free(BcLex *l)
2875 bc_vec_free(&l->t.v);
2878 static void bc_lex_file(BcLex *l)
2884 static BcStatus bc_lex_next(BcLex *l)
2889 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2891 l->line += l->newline;
2892 l->t.t = BC_LEX_EOF;
2894 l->newline = (l->i == l->len);
2895 if (l->newline) return BC_STATUS_SUCCESS;
2897 // Loop until failure or we don't have whitespace. This
2898 // is so the parser doesn't get inundated with whitespace.
2901 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2906 static BcStatus bc_lex_text(BcLex *l, const char *text)
2910 l->len = strlen(text);
2911 l->t.t = l->t.last = BC_LEX_INVALID;
2912 return bc_lex_next(l);
2916 static BcStatus bc_lex_identifier(BcLex *l)
2920 const char *buf = l->buf + l->i - 1;
2922 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2923 const char *keyword8 = bc_lex_kws[i].name8;
2925 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2927 if (j == 8) goto match;
2929 if (keyword8[j] != '\0')
2932 // buf starts with keyword bc_lex_kws[i]
2933 l->t.t = BC_LEX_KEY_1st_keyword + i;
2934 if ((1 << i) & POSIX_KWORD_MASK) {
2935 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
2939 // We minus 1 because the index has already been incremented.
2941 return BC_STATUS_SUCCESS;
2948 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2953 static BcStatus bc_lex_string(BcLex *l)
2955 size_t len, nls = 0, i = l->i;
2958 l->t.t = BC_LEX_STR;
2960 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2964 return bc_error("string end could not be found");
2968 if (len > BC_MAX_STRING)
2969 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2970 bc_vec_string(&l->t.v, len, l->buf + l->i);
2975 return BC_STATUS_SUCCESS;
2978 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2980 if (l->buf[l->i] == '=') {
2988 static BcStatus bc_lex_comment(BcLex *l)
2991 const char *buf = l->buf;
2993 l->t.t = BC_LEX_WHITESPACE;
3006 return bc_error("comment end could not be found");
3015 return BC_STATUS_SUCCESS;
3018 static BcStatus bc_lex_token(BcLex *l)
3020 BcStatus s = BC_STATUS_SUCCESS;
3021 char c = l->buf[l->i++], c2;
3023 // This is the workhorse of the lexer.
3030 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3040 bc_lex_whitespace(l);
3046 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3048 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3049 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3058 s = bc_lex_string(l);
3064 s = bc_posix_error("POSIX does not allow '#' script comments");
3067 bc_lex_lineComment(l);
3074 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3083 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3087 l->t.t = BC_LEX_OP_BOOL_AND;
3090 l->t.t = BC_LEX_INVALID;
3091 s = bc_error_bad_character('&');
3100 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3106 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3115 l->t.t = BC_LEX_OP_INC;
3118 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3124 l->t.t = BC_LEX_COMMA;
3133 l->t.t = BC_LEX_OP_DEC;
3136 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3142 if (isdigit(l->buf[l->i]))
3143 s = bc_lex_number(l, c);
3145 l->t.t = BC_LEX_KEY_LAST;
3146 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3155 s = bc_lex_comment(l);
3157 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3178 s = bc_lex_number(l, c);
3184 l->t.t = BC_LEX_SCOLON;
3190 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3196 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3202 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3209 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3215 if (l->buf[l->i] == '\n') {
3216 l->t.t = BC_LEX_WHITESPACE;
3220 s = bc_error_bad_character(c);
3226 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3257 s = bc_lex_identifier(l);
3264 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3273 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3277 l->t.t = BC_LEX_OP_BOOL_OR;
3280 l->t.t = BC_LEX_INVALID;
3281 s = bc_error_bad_character(c);
3289 l->t.t = BC_LEX_INVALID;
3290 s = bc_error_bad_character(c);
3300 static BcStatus dc_lex_register(BcLex *l)
3302 BcStatus s = BC_STATUS_SUCCESS;
3304 if (isspace(l->buf[l->i - 1])) {
3305 bc_lex_whitespace(l);
3308 s = bc_error("extended register");
3313 bc_vec_pop_all(&l->t.v);
3314 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3315 bc_vec_pushZeroByte(&l->t.v);
3316 l->t.t = BC_LEX_NAME;
3322 static BcStatus dc_lex_string(BcLex *l)
3324 size_t depth = 1, nls = 0, i = l->i;
3327 l->t.t = BC_LEX_STR;
3328 bc_vec_pop_all(&l->t.v);
3330 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3332 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3333 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3336 if (depth) bc_vec_push(&l->t.v, &c);
3341 return bc_error("string end could not be found");
3344 bc_vec_pushZeroByte(&l->t.v);
3345 if (i - l->i > BC_MAX_STRING)
3346 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3351 return BC_STATUS_SUCCESS;
3354 static BcStatus dc_lex_token(BcLex *l)
3356 BcStatus s = BC_STATUS_SUCCESS;
3357 char c = l->buf[l->i++], c2;
3360 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3361 if (l->t.last == dc_lex_regs[i])
3362 return dc_lex_register(l);
3365 if (c >= '%' && c <= '~' &&
3366 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3371 // This is the workhorse of the lexer.
3376 l->t.t = BC_LEX_EOF;
3387 l->newline = (c == '\n');
3388 bc_lex_whitespace(l);
3397 l->t.t = BC_LEX_OP_REL_NE;
3399 l->t.t = BC_LEX_OP_REL_LE;
3401 l->t.t = BC_LEX_OP_REL_GE;
3403 return bc_error_bad_character(c);
3411 bc_lex_lineComment(l);
3417 if (isdigit(l->buf[l->i]))
3418 s = bc_lex_number(l, c);
3420 s = bc_error_bad_character(c);
3441 s = bc_lex_number(l, c);
3447 s = dc_lex_string(l);
3453 l->t.t = BC_LEX_INVALID;
3454 s = bc_error_bad_character(c);
3463 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3465 bc_program_addFunc(name, idx);
3466 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3469 static void bc_parse_pushName(BcParse *p, char *name)
3471 size_t i = 0, len = strlen(name);
3473 for (; i < len; ++i) bc_parse_push(p, name[i]);
3474 bc_parse_push(p, BC_PARSE_STREND);
3479 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3481 unsigned char amt, i, nums[sizeof(size_t)];
3483 for (amt = 0; idx; ++amt) {
3484 nums[amt] = (char) idx;
3485 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3488 bc_parse_push(p, amt);
3489 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3492 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3494 char *num = xstrdup(p->l.t.v.v);
3495 size_t idx = G.prog.consts.len;
3497 bc_vec_push(&G.prog.consts, &num);
3499 bc_parse_push(p, BC_INST_NUM);
3500 bc_parse_pushIndex(p, idx);
3503 (*prev) = BC_INST_NUM;
3506 static BcStatus bc_parse_text(BcParse *p, const char *text)
3510 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3512 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3513 p->l.t.t = BC_LEX_INVALID;
3516 if (!BC_PARSE_CAN_EXEC(p))
3517 return bc_error("file is not executable");
3520 return bc_lex_text(&p->l, text);
3523 // Called when bc/dc_parse_parse() detects a failure,
3524 // resets parsing structures.
3525 static void bc_parse_reset(BcParse *p)
3527 if (p->fidx != BC_PROG_MAIN) {
3528 p->func->nparams = 0;
3529 bc_vec_pop_all(&p->func->code);
3530 bc_vec_pop_all(&p->func->autos);
3531 bc_vec_pop_all(&p->func->labels);
3533 bc_parse_updateFunc(p, BC_PROG_MAIN);
3537 p->l.t.t = BC_LEX_EOF;
3538 p->auto_part = (p->nbraces = 0);
3540 bc_vec_npop(&p->flags, p->flags.len - 1);
3541 bc_vec_pop_all(&p->exits);
3542 bc_vec_pop_all(&p->conds);
3543 bc_vec_pop_all(&p->ops);
3548 static void bc_parse_free(BcParse *p)
3550 bc_vec_free(&p->flags);
3551 bc_vec_free(&p->exits);
3552 bc_vec_free(&p->conds);
3553 bc_vec_free(&p->ops);
3557 static void bc_parse_create(BcParse *p, size_t func,
3558 BcParseParse parse, BcLexNext next)
3560 memset(p, 0, sizeof(BcParse));
3562 bc_lex_init(&p->l, next);
3563 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3564 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3565 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3566 bc_vec_pushZeroByte(&p->flags);
3567 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3570 // p->auto_part = p->nbraces = 0; - already is
3571 bc_parse_updateFunc(p, func);
3575 static BcStatus bc_parse_else(BcParse *p);
3576 static BcStatus bc_parse_stmt(BcParse *p);
3578 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3579 size_t *nexprs, bool next)
3581 BcStatus s = BC_STATUS_SUCCESS;
3583 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3584 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3586 while (p->ops.len > start) {
3588 t = BC_PARSE_TOP_OP(p);
3589 if (t == BC_LEX_LPAREN) break;
3591 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3592 if (l >= r && (l != r || !left)) break;
3594 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3595 bc_vec_pop(&p->ops);
3596 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3599 bc_vec_push(&p->ops, &type);
3600 if (next) s = bc_lex_next(&p->l);
3605 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3609 if (p->ops.len <= ops_bgn)
3610 return bc_error_bad_expression();
3611 top = BC_PARSE_TOP_OP(p);
3613 while (top != BC_LEX_LPAREN) {
3615 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3617 bc_vec_pop(&p->ops);
3618 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3620 if (p->ops.len <= ops_bgn)
3621 return bc_error_bad_expression();
3622 top = BC_PARSE_TOP_OP(p);
3625 bc_vec_pop(&p->ops);
3627 return bc_lex_next(&p->l);
3630 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3636 s = bc_lex_next(&p->l);
3639 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3641 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3642 s = bc_parse_expr(p, flags, bc_parse_next_param);
3645 comma = p->l.t.t == BC_LEX_COMMA;
3647 s = bc_lex_next(&p->l);
3652 if (comma) return bc_error_bad_token();
3653 bc_parse_push(p, BC_INST_CALL);
3654 bc_parse_pushIndex(p, nparams);
3656 return BC_STATUS_SUCCESS;
3659 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3662 BcId entry, *entry_ptr;
3667 s = bc_parse_params(p, flags);
3670 if (p->l.t.t != BC_LEX_RPAREN) {
3671 s = bc_error_bad_token();
3675 idx = bc_map_index(&G.prog.fn_map, &entry);
3677 if (idx == BC_VEC_INVALID_IDX) {
3678 name = xstrdup(entry.name);
3679 bc_parse_addFunc(p, name, &idx);
3680 idx = bc_map_index(&G.prog.fn_map, &entry);
3686 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3687 bc_parse_pushIndex(p, entry_ptr->idx);
3689 return bc_lex_next(&p->l);
3696 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3701 name = xstrdup(p->l.t.v.v);
3702 s = bc_lex_next(&p->l);
3705 if (p->l.t.t == BC_LEX_LBRACKET) {
3707 s = bc_lex_next(&p->l);
3710 if (p->l.t.t == BC_LEX_RBRACKET) {
3712 if (!(flags & BC_PARSE_ARRAY)) {
3713 s = bc_error_bad_expression();
3717 *type = BC_INST_ARRAY;
3721 *type = BC_INST_ARRAY_ELEM;
3723 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3724 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3728 s = bc_lex_next(&p->l);
3730 bc_parse_push(p, *type);
3731 bc_parse_pushName(p, name);
3733 else if (p->l.t.t == BC_LEX_LPAREN) {
3735 if (flags & BC_PARSE_NOCALL) {
3736 s = bc_error_bad_token();
3740 *type = BC_INST_CALL;
3741 s = bc_parse_call(p, name, flags);
3744 *type = BC_INST_VAR;
3745 bc_parse_push(p, BC_INST_VAR);
3746 bc_parse_pushName(p, name);
3756 static BcStatus bc_parse_read(BcParse *p)
3760 s = bc_lex_next(&p->l);
3762 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3764 s = bc_lex_next(&p->l);
3766 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3768 bc_parse_push(p, BC_INST_READ);
3770 return bc_lex_next(&p->l);
3773 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3778 s = bc_lex_next(&p->l);
3780 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3782 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3784 s = bc_lex_next(&p->l);
3787 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3790 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3792 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3793 bc_parse_push(p, *prev);
3795 return bc_lex_next(&p->l);
3798 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3802 s = bc_lex_next(&p->l);
3805 if (p->l.t.t != BC_LEX_LPAREN) {
3806 *type = BC_INST_SCALE;
3807 bc_parse_push(p, BC_INST_SCALE);
3808 return BC_STATUS_SUCCESS;
3811 *type = BC_INST_SCALE_FUNC;
3812 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3814 s = bc_lex_next(&p->l);
3817 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3819 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3820 bc_parse_push(p, BC_INST_SCALE_FUNC);
3822 return bc_lex_next(&p->l);
3825 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3826 size_t *nexprs, uint8_t flags)
3831 BcInst etype = *prev;
3833 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3834 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3835 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3837 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3838 bc_parse_push(p, inst);
3839 s = bc_lex_next(&p->l);
3843 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3846 s = bc_lex_next(&p->l);
3850 // Because we parse the next part of the expression
3851 // right here, we need to increment this.
3852 *nexprs = *nexprs + 1;
3858 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3862 case BC_LEX_KEY_IBASE:
3863 case BC_LEX_KEY_LAST:
3864 case BC_LEX_KEY_OBASE:
3866 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3867 s = bc_lex_next(&p->l);
3871 case BC_LEX_KEY_SCALE:
3873 s = bc_lex_next(&p->l);
3875 if (p->l.t.t == BC_LEX_LPAREN)
3876 s = bc_error_bad_token();
3878 bc_parse_push(p, BC_INST_SCALE);
3884 s = bc_error_bad_token();
3889 if (!s) bc_parse_push(p, inst);
3895 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3896 bool rparen, size_t *nexprs)
3900 BcInst etype = *prev;
3902 s = bc_lex_next(&p->l);
3905 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3906 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3909 *prev = BC_PARSE_TOKEN_INST(type);
3911 // We can just push onto the op stack because this is the largest
3912 // precedence operator that gets pushed. Inc/dec does not.
3913 if (type != BC_LEX_OP_MINUS)
3914 bc_vec_push(&p->ops, &type);
3916 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3921 static BcStatus bc_parse_string(BcParse *p, char inst)
3923 char *str = xstrdup(p->l.t.v.v);
3925 bc_parse_push(p, BC_INST_STR);
3926 bc_parse_pushIndex(p, G.prog.strs.len);
3927 bc_vec_push(&G.prog.strs, &str);
3928 bc_parse_push(p, inst);
3930 return bc_lex_next(&p->l);
3933 static BcStatus bc_parse_print(BcParse *p)
3939 s = bc_lex_next(&p->l);
3944 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3945 return bc_error("bad print statement");
3947 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3949 if (type == BC_LEX_STR)
3950 s = bc_parse_string(p, BC_INST_PRINT_POP);
3952 s = bc_parse_expr(p, 0, bc_parse_next_print);
3954 bc_parse_push(p, BC_INST_PRINT_POP);
3959 comma = p->l.t.t == BC_LEX_COMMA;
3960 if (comma) s = bc_lex_next(&p->l);
3965 if (comma) return bc_error_bad_token();
3967 return bc_lex_next(&p->l);
3970 static BcStatus bc_parse_return(BcParse *p)
3976 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
3978 s = bc_lex_next(&p->l);
3982 paren = t == BC_LEX_LPAREN;
3984 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3985 bc_parse_push(p, BC_INST_RET0);
3988 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3989 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3992 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3993 bc_parse_push(p, BC_INST_RET0);
3994 s = bc_lex_next(&p->l);
3998 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3999 s = bc_posix_error("POSIX requires parentheses around return expressions");
4003 bc_parse_push(p, BC_INST_RET);
4009 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4011 BcStatus s = BC_STATUS_SUCCESS;
4013 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4014 return bc_error_bad_token();
4018 if (p->l.t.t == BC_LEX_RBRACE) {
4019 if (!p->nbraces) return bc_error_bad_token();
4021 s = bc_lex_next(&p->l);
4025 return bc_error_bad_token();
4028 if (BC_PARSE_IF(p)) {
4032 while (p->l.t.t == BC_LEX_NLINE) {
4033 s = bc_lex_next(&p->l);
4037 bc_vec_pop(&p->flags);
4039 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4040 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4042 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4044 else if (BC_PARSE_ELSE(p)) {
4049 bc_vec_pop(&p->flags);
4051 ip = bc_vec_top(&p->exits);
4052 label = bc_vec_item(&p->func->labels, ip->idx);
4053 *label = p->func->code.len;
4055 bc_vec_pop(&p->exits);
4057 else if (BC_PARSE_FUNC_INNER(p)) {
4058 bc_parse_push(p, BC_INST_RET0);
4059 bc_parse_updateFunc(p, BC_PROG_MAIN);
4060 bc_vec_pop(&p->flags);
4064 BcInstPtr *ip = bc_vec_top(&p->exits);
4065 size_t *label = bc_vec_top(&p->conds);
4067 bc_parse_push(p, BC_INST_JUMP);
4068 bc_parse_pushIndex(p, *label);
4070 label = bc_vec_item(&p->func->labels, ip->idx);
4071 *label = p->func->code.len;
4073 bc_vec_pop(&p->flags);
4074 bc_vec_pop(&p->exits);
4075 bc_vec_pop(&p->conds);
4081 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4083 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4084 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4085 flags |= BC_PARSE_FLAG_BODY;
4086 bc_vec_push(&p->flags, &flags);
4089 static void bc_parse_noElse(BcParse *p)
4093 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4095 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4097 ip = bc_vec_top(&p->exits);
4098 label = bc_vec_item(&p->func->labels, ip->idx);
4099 *label = p->func->code.len;
4101 bc_vec_pop(&p->exits);
4104 static BcStatus bc_parse_if(BcParse *p)
4109 s = bc_lex_next(&p->l);
4111 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4113 s = bc_lex_next(&p->l);
4115 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4117 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4119 s = bc_lex_next(&p->l);
4121 bc_parse_push(p, BC_INST_JUMP_ZERO);
4123 ip.idx = p->func->labels.len;
4124 ip.func = ip.len = 0;
4126 bc_parse_pushIndex(p, ip.idx);
4127 bc_vec_push(&p->exits, &ip);
4128 bc_vec_push(&p->func->labels, &ip.idx);
4129 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4131 return BC_STATUS_SUCCESS;
4134 static BcStatus bc_parse_else(BcParse *p)
4138 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4140 ip.idx = p->func->labels.len;
4141 ip.func = ip.len = 0;
4143 bc_parse_push(p, BC_INST_JUMP);
4144 bc_parse_pushIndex(p, ip.idx);
4148 bc_vec_push(&p->exits, &ip);
4149 bc_vec_push(&p->func->labels, &ip.idx);
4150 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4152 return bc_lex_next(&p->l);
4155 static BcStatus bc_parse_while(BcParse *p)
4160 s = bc_lex_next(&p->l);
4162 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4163 s = bc_lex_next(&p->l);
4166 ip.idx = p->func->labels.len;
4168 bc_vec_push(&p->func->labels, &p->func->code.len);
4169 bc_vec_push(&p->conds, &ip.idx);
4171 ip.idx = p->func->labels.len;
4175 bc_vec_push(&p->exits, &ip);
4176 bc_vec_push(&p->func->labels, &ip.idx);
4178 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4180 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4181 s = bc_lex_next(&p->l);
4184 bc_parse_push(p, BC_INST_JUMP_ZERO);
4185 bc_parse_pushIndex(p, ip.idx);
4186 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4188 return BC_STATUS_SUCCESS;
4191 static BcStatus bc_parse_for(BcParse *p)
4195 size_t cond_idx, exit_idx, body_idx, update_idx;
4197 s = bc_lex_next(&p->l);
4199 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4200 s = bc_lex_next(&p->l);
4203 if (p->l.t.t != BC_LEX_SCOLON)
4204 s = bc_parse_expr(p, 0, bc_parse_next_for);
4206 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4209 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4210 s = bc_lex_next(&p->l);
4213 cond_idx = p->func->labels.len;
4214 update_idx = cond_idx + 1;
4215 body_idx = update_idx + 1;
4216 exit_idx = body_idx + 1;
4218 bc_vec_push(&p->func->labels, &p->func->code.len);
4220 if (p->l.t.t != BC_LEX_SCOLON)
4221 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4223 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4226 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4228 s = bc_lex_next(&p->l);
4231 bc_parse_push(p, BC_INST_JUMP_ZERO);
4232 bc_parse_pushIndex(p, exit_idx);
4233 bc_parse_push(p, BC_INST_JUMP);
4234 bc_parse_pushIndex(p, body_idx);
4236 ip.idx = p->func->labels.len;
4238 bc_vec_push(&p->conds, &update_idx);
4239 bc_vec_push(&p->func->labels, &p->func->code.len);
4241 if (p->l.t.t != BC_LEX_RPAREN)
4242 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4244 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4248 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4249 bc_parse_push(p, BC_INST_JUMP);
4250 bc_parse_pushIndex(p, cond_idx);
4251 bc_vec_push(&p->func->labels, &p->func->code.len);
4257 bc_vec_push(&p->exits, &ip);
4258 bc_vec_push(&p->func->labels, &ip.idx);
4260 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4262 return BC_STATUS_SUCCESS;
4265 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4271 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4273 if (type == BC_LEX_KEY_BREAK) {
4275 if (p->exits.len == 0) return bc_error_bad_token();
4277 i = p->exits.len - 1;
4278 ip = bc_vec_item(&p->exits, i);
4280 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4281 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4286 i = *((size_t *) bc_vec_top(&p->conds));
4288 bc_parse_push(p, BC_INST_JUMP);
4289 bc_parse_pushIndex(p, i);
4291 s = bc_lex_next(&p->l);
4294 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4295 return bc_error_bad_token();
4297 return bc_lex_next(&p->l);
4300 static BcStatus bc_parse_func(BcParse *p)
4303 bool var, comma = false;
4307 s = bc_lex_next(&p->l);
4309 if (p->l.t.t != BC_LEX_NAME)
4310 return bc_error("bad function definition");
4312 name = xstrdup(p->l.t.v.v);
4313 bc_parse_addFunc(p, name, &p->fidx);
4315 s = bc_lex_next(&p->l);
4317 if (p->l.t.t != BC_LEX_LPAREN)
4318 return bc_error("bad function definition");
4319 s = bc_lex_next(&p->l);
4322 while (p->l.t.t != BC_LEX_RPAREN) {
4324 if (p->l.t.t != BC_LEX_NAME)
4325 return bc_error("bad function definition");
4329 name = xstrdup(p->l.t.v.v);
4330 s = bc_lex_next(&p->l);
4333 var = p->l.t.t != BC_LEX_LBRACKET;
4337 s = bc_lex_next(&p->l);
4340 if (p->l.t.t != BC_LEX_RBRACKET) {
4341 s = bc_error("bad function definition");
4345 s = bc_lex_next(&p->l);
4349 comma = p->l.t.t == BC_LEX_COMMA;
4351 s = bc_lex_next(&p->l);
4355 s = bc_func_insert(p->func, name, var);
4359 if (comma) return bc_error("bad function definition");
4361 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4362 bc_parse_startBody(p, flags);
4364 s = bc_lex_next(&p->l);
4367 if (p->l.t.t != BC_LEX_LBRACE)
4368 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4377 static BcStatus bc_parse_auto(BcParse *p)
4380 bool comma, var, one;
4383 if (!p->auto_part) return bc_error_bad_token();
4384 s = bc_lex_next(&p->l);
4387 p->auto_part = comma = false;
4388 one = p->l.t.t == BC_LEX_NAME;
4390 while (p->l.t.t == BC_LEX_NAME) {
4392 name = xstrdup(p->l.t.v.v);
4393 s = bc_lex_next(&p->l);
4396 var = p->l.t.t != BC_LEX_LBRACKET;
4399 s = bc_lex_next(&p->l);
4402 if (p->l.t.t != BC_LEX_RBRACKET) {
4403 s = bc_error("bad function definition");
4407 s = bc_lex_next(&p->l);
4411 comma = p->l.t.t == BC_LEX_COMMA;
4413 s = bc_lex_next(&p->l);
4417 s = bc_func_insert(p->func, name, var);
4421 if (comma) return bc_error("bad function definition");
4422 if (!one) return bc_error("no auto variable found");
4424 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4425 return bc_error_bad_token();
4427 return bc_lex_next(&p->l);
4434 static BcStatus bc_parse_body(BcParse *p, bool brace)
4436 BcStatus s = BC_STATUS_SUCCESS;
4437 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4439 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4441 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4443 if (!brace) return bc_error_bad_token();
4444 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4446 if (!p->auto_part) {
4447 s = bc_parse_auto(p);
4451 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4454 s = bc_parse_stmt(p);
4455 if (!s && !brace) s = bc_parse_endBody(p, false);
4461 static BcStatus bc_parse_stmt(BcParse *p)
4463 BcStatus s = BC_STATUS_SUCCESS;
4469 return bc_lex_next(&p->l);
4472 case BC_LEX_KEY_ELSE:
4474 p->auto_part = false;
4480 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4483 s = bc_lex_next(&p->l);
4486 return bc_parse_body(p, true);
4489 case BC_LEX_KEY_AUTO:
4491 return bc_parse_auto(p);
4496 p->auto_part = false;
4498 if (BC_PARSE_IF_END(p)) {
4500 return BC_STATUS_SUCCESS;
4502 else if (BC_PARSE_BODY(p))
4503 return bc_parse_body(p, false);
4513 case BC_LEX_OP_MINUS:
4514 case BC_LEX_OP_BOOL_NOT:
4518 case BC_LEX_KEY_IBASE:
4519 case BC_LEX_KEY_LAST:
4520 case BC_LEX_KEY_LENGTH:
4521 case BC_LEX_KEY_OBASE:
4522 case BC_LEX_KEY_READ:
4523 case BC_LEX_KEY_SCALE:
4524 case BC_LEX_KEY_SQRT:
4526 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4530 case BC_LEX_KEY_ELSE:
4532 s = bc_parse_else(p);
4538 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4544 s = bc_parse_endBody(p, true);
4550 s = bc_parse_string(p, BC_INST_PRINT_STR);
4554 case BC_LEX_KEY_BREAK:
4555 case BC_LEX_KEY_CONTINUE:
4557 s = bc_parse_loopExit(p, p->l.t.t);
4561 case BC_LEX_KEY_FOR:
4563 s = bc_parse_for(p);
4567 case BC_LEX_KEY_HALT:
4569 bc_parse_push(p, BC_INST_HALT);
4570 s = bc_lex_next(&p->l);
4580 case BC_LEX_KEY_LIMITS:
4582 // "limits" is a compile-time command,
4583 // the output is produced at _parse time_.
4584 s = bc_lex_next(&p->l);
4586 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4587 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4588 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4589 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4590 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4591 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4592 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4593 printf("Number of vars = %lu\n", BC_MAX_VARS);
4597 case BC_LEX_KEY_PRINT:
4599 s = bc_parse_print(p);
4603 case BC_LEX_KEY_QUIT:
4605 // "quit" is a compile-time command. For example,
4606 // "if (0 == 1) quit" terminates when parsing the statement,
4607 // not when it is executed
4611 case BC_LEX_KEY_RETURN:
4613 s = bc_parse_return(p);
4617 case BC_LEX_KEY_WHILE:
4619 s = bc_parse_while(p);
4625 s = bc_error_bad_token();
4633 static BcStatus bc_parse_parse(BcParse *p)
4637 if (p->l.t.t == BC_LEX_EOF)
4638 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4639 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4640 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4641 s = bc_parse_func(p);
4644 s = bc_parse_stmt(p);
4646 if (s || G_interrupt) {
4648 s = BC_STATUS_FAILURE;
4654 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4656 BcStatus s = BC_STATUS_SUCCESS;
4657 BcInst prev = BC_INST_PRINT;
4658 BcLexType top, t = p->l.t.t;
4659 size_t nexprs = 0, ops_bgn = p->ops.len;
4660 uint32_t i, nparens, nrelops;
4661 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4663 paren_first = p->l.t.t == BC_LEX_LPAREN;
4664 nparens = nrelops = 0;
4665 paren_expr = rprn = done = get_token = assign = false;
4668 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4674 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4675 rprn = get_token = bin_last = false;
4679 case BC_LEX_OP_MINUS:
4681 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4682 rprn = get_token = false;
4683 bin_last = prev == BC_INST_MINUS;
4687 case BC_LEX_OP_ASSIGN_POWER:
4688 case BC_LEX_OP_ASSIGN_MULTIPLY:
4689 case BC_LEX_OP_ASSIGN_DIVIDE:
4690 case BC_LEX_OP_ASSIGN_MODULUS:
4691 case BC_LEX_OP_ASSIGN_PLUS:
4692 case BC_LEX_OP_ASSIGN_MINUS:
4693 case BC_LEX_OP_ASSIGN:
4695 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4696 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4697 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4699 s = bc_error("bad assignment:"
4700 " left side must be scale,"
4701 " ibase, obase, last, var,"
4708 case BC_LEX_OP_POWER:
4709 case BC_LEX_OP_MULTIPLY:
4710 case BC_LEX_OP_DIVIDE:
4711 case BC_LEX_OP_MODULUS:
4712 case BC_LEX_OP_PLUS:
4713 case BC_LEX_OP_REL_EQ:
4714 case BC_LEX_OP_REL_LE:
4715 case BC_LEX_OP_REL_GE:
4716 case BC_LEX_OP_REL_NE:
4717 case BC_LEX_OP_REL_LT:
4718 case BC_LEX_OP_REL_GT:
4719 case BC_LEX_OP_BOOL_NOT:
4720 case BC_LEX_OP_BOOL_OR:
4721 case BC_LEX_OP_BOOL_AND:
4723 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4724 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4726 return bc_error_bad_expression();
4729 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4730 prev = BC_PARSE_TOKEN_INST(t);
4731 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4732 rprn = get_token = false;
4733 bin_last = t != BC_LEX_OP_BOOL_NOT;
4740 if (BC_PARSE_LEAF(prev, rprn))
4741 return bc_error_bad_expression();
4743 paren_expr = rprn = bin_last = false;
4745 bc_vec_push(&p->ops, &t);
4752 if (bin_last || prev == BC_INST_BOOL_NOT)
4753 return bc_error_bad_expression();
4756 s = BC_STATUS_SUCCESS;
4761 else if (!paren_expr)
4762 return BC_STATUS_PARSE_EMPTY_EXP;
4765 paren_expr = rprn = true;
4766 get_token = bin_last = false;
4768 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4775 if (BC_PARSE_LEAF(prev, rprn))
4776 return bc_error_bad_expression();
4778 rprn = get_token = bin_last = false;
4779 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4787 if (BC_PARSE_LEAF(prev, rprn))
4788 return bc_error_bad_expression();
4789 bc_parse_number(p, &prev, &nexprs);
4790 paren_expr = get_token = true;
4791 rprn = bin_last = false;
4796 case BC_LEX_KEY_IBASE:
4797 case BC_LEX_KEY_LAST:
4798 case BC_LEX_KEY_OBASE:
4800 if (BC_PARSE_LEAF(prev, rprn))
4801 return bc_error_bad_expression();
4802 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4803 bc_parse_push(p, (char) prev);
4805 paren_expr = get_token = true;
4806 rprn = bin_last = false;
4812 case BC_LEX_KEY_LENGTH:
4813 case BC_LEX_KEY_SQRT:
4815 if (BC_PARSE_LEAF(prev, rprn))
4816 return bc_error_bad_expression();
4817 s = bc_parse_builtin(p, t, flags, &prev);
4819 rprn = get_token = bin_last = false;
4825 case BC_LEX_KEY_READ:
4827 if (BC_PARSE_LEAF(prev, rprn))
4828 return bc_error_bad_expression();
4829 else if (flags & BC_PARSE_NOREAD)
4830 s = bc_error_nested_read_call();
4832 s = bc_parse_read(p);
4835 rprn = get_token = bin_last = false;
4837 prev = BC_INST_READ;
4842 case BC_LEX_KEY_SCALE:
4844 if (BC_PARSE_LEAF(prev, rprn))
4845 return bc_error_bad_expression();
4846 s = bc_parse_scale(p, &prev, flags);
4848 rprn = get_token = bin_last = false;
4850 prev = BC_INST_SCALE;
4857 s = bc_error_bad_token();
4862 if (!s && get_token) s = bc_lex_next(&p->l);
4866 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4868 while (p->ops.len > ops_bgn) {
4870 top = BC_PARSE_TOP_OP(p);
4871 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4873 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4874 return bc_error_bad_expression();
4876 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4878 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4879 bc_vec_pop(&p->ops);
4882 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4883 return bc_error_bad_expression();
4885 for (i = 0; i < next.len; ++i)
4886 if (t == next.tokens[i])
4888 return bc_error_bad_expression();
4891 if (!(flags & BC_PARSE_REL) && nrelops) {
4892 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4895 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4896 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4900 if (flags & BC_PARSE_PRINT) {
4901 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4902 bc_parse_push(p, BC_INST_POP);
4908 static void bc_parse_init(BcParse *p, size_t func)
4910 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4913 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4915 return bc_parse_expr(p, flags, bc_parse_next_read);
4920 static BcStatus dc_parse_register(BcParse *p)
4925 s = bc_lex_next(&p->l);
4927 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4929 name = xstrdup(p->l.t.v.v);
4930 bc_parse_pushName(p, name);
4935 static BcStatus dc_parse_string(BcParse *p)
4937 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4938 size_t idx, len = G.prog.strs.len;
4940 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4943 str = xstrdup(p->l.t.v.v);
4944 bc_parse_push(p, BC_INST_STR);
4945 bc_parse_pushIndex(p, len);
4946 bc_vec_push(&G.prog.strs, &str);
4947 bc_parse_addFunc(p, name, &idx);
4949 return bc_lex_next(&p->l);
4952 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4956 bc_parse_push(p, inst);
4958 s = dc_parse_register(p);
4963 bc_parse_push(p, BC_INST_SWAP);
4964 bc_parse_push(p, BC_INST_ASSIGN);
4965 bc_parse_push(p, BC_INST_POP);
4968 return bc_lex_next(&p->l);
4971 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4975 bc_parse_push(p, inst);
4976 bc_parse_push(p, BC_INST_EXEC_COND);
4978 s = dc_parse_register(p);
4981 s = bc_lex_next(&p->l);
4984 if (p->l.t.t == BC_LEX_ELSE) {
4985 s = dc_parse_register(p);
4987 s = bc_lex_next(&p->l);
4990 bc_parse_push(p, BC_PARSE_STREND);
4995 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4997 BcStatus s = BC_STATUS_SUCCESS;
5000 bool assign, get_token = false;
5004 case BC_LEX_OP_REL_EQ:
5005 case BC_LEX_OP_REL_LE:
5006 case BC_LEX_OP_REL_GE:
5007 case BC_LEX_OP_REL_NE:
5008 case BC_LEX_OP_REL_LT:
5009 case BC_LEX_OP_REL_GT:
5011 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5018 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5024 s = dc_parse_string(p);
5031 if (t == BC_LEX_NEG) {
5032 s = bc_lex_next(&p->l);
5034 if (p->l.t.t != BC_LEX_NUMBER)
5035 return bc_error_bad_token();
5038 bc_parse_number(p, &prev, &p->nbraces);
5040 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5046 case BC_LEX_KEY_READ:
5048 if (flags & BC_PARSE_NOREAD)
5049 s = bc_error_nested_read_call();
5051 bc_parse_push(p, BC_INST_READ);
5056 case BC_LEX_OP_ASSIGN:
5057 case BC_LEX_STORE_PUSH:
5059 assign = t == BC_LEX_OP_ASSIGN;
5060 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5061 s = dc_parse_mem(p, inst, true, assign);
5066 case BC_LEX_LOAD_POP:
5068 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5069 s = dc_parse_mem(p, inst, true, false);
5073 case BC_LEX_STORE_IBASE:
5074 case BC_LEX_STORE_SCALE:
5075 case BC_LEX_STORE_OBASE:
5077 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5078 s = dc_parse_mem(p, inst, false, true);
5084 s = bc_error_bad_token();
5090 if (!s && get_token) s = bc_lex_next(&p->l);
5095 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5097 BcStatus s = BC_STATUS_SUCCESS;
5101 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5103 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5105 inst = dc_parse_insts[t];
5107 if (inst != BC_INST_INVALID) {
5108 bc_parse_push(p, inst);
5109 s = bc_lex_next(&p->l);
5112 s = dc_parse_token(p, t, flags);
5115 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5116 bc_parse_push(p, BC_INST_POP_EXEC);
5121 static BcStatus dc_parse_parse(BcParse *p)
5125 if (p->l.t.t == BC_LEX_EOF)
5126 s = bc_error("end of file");
5128 s = dc_parse_expr(p, 0);
5130 if (s || G_interrupt) {
5132 s = BC_STATUS_FAILURE;
5138 static void dc_parse_init(BcParse *p, size_t func)
5140 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5144 static void common_parse_init(BcParse *p, size_t func)
5147 bc_parse_init(p, func);
5149 dc_parse_init(p, func);
5153 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5156 return bc_parse_expression(p, flags);
5158 return dc_parse_expr(p, flags);
5162 static BcVec* bc_program_search(char *id, bool var)
5170 v = var ? &G.prog.vars : &G.prog.arrs;
5171 map = var ? &G.prog.var_map : &G.prog.arr_map;
5175 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5178 bc_array_init(&data.v, var);
5179 bc_vec_push(v, &data.v);
5182 ptr = bc_vec_item(map, i);
5183 if (new) ptr->name = xstrdup(e.name);
5184 return bc_vec_item(v, ptr->idx);
5187 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5189 BcStatus s = BC_STATUS_SUCCESS;
5194 case BC_RESULT_TEMP:
5195 case BC_RESULT_IBASE:
5196 case BC_RESULT_SCALE:
5197 case BC_RESULT_OBASE:
5203 case BC_RESULT_CONSTANT:
5205 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5206 size_t base_t, len = strlen(*str);
5209 bc_num_init(&r->d.n, len);
5211 hex = hex && len == 1;
5212 base = hex ? &G.prog.hexb : &G.prog.ib;
5213 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5214 s = bc_num_parse(&r->d.n, *str, base, base_t);
5217 bc_num_free(&r->d.n);
5222 r->t = BC_RESULT_TEMP;
5228 case BC_RESULT_ARRAY:
5229 case BC_RESULT_ARRAY_ELEM:
5233 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5235 if (r->t == BC_RESULT_ARRAY_ELEM) {
5237 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5238 *num = bc_vec_item(v, r->d.id.idx);
5241 *num = bc_vec_top(v);
5246 case BC_RESULT_LAST:
5248 *num = &G.prog.last;
5262 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5263 BcResult **r, BcNum **rn, bool assign)
5267 BcResultType lt, rt;
5269 if (!BC_PROG_STACK(&G.prog.results, 2))
5270 return bc_error_stack_has_too_few_elements();
5272 *r = bc_vec_item_rev(&G.prog.results, 0);
5273 *l = bc_vec_item_rev(&G.prog.results, 1);
5277 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5279 s = bc_program_num(*l, ln, false);
5281 s = bc_program_num(*r, rn, hex);
5284 // We run this again under these conditions in case any vector has been
5285 // reallocated out from under the BcNums or arrays we had.
5286 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5287 s = bc_program_num(*l, ln, false);
5291 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5292 return bc_error_variable_is_wrong_type();
5293 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5294 return bc_error_variable_is_wrong_type();
5299 static void bc_program_binOpRetire(BcResult *r)
5301 r->t = BC_RESULT_TEMP;
5302 bc_vec_pop(&G.prog.results);
5303 bc_vec_pop(&G.prog.results);
5304 bc_vec_push(&G.prog.results, r);
5307 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5311 if (!BC_PROG_STACK(&G.prog.results, 1))
5312 return bc_error_stack_has_too_few_elements();
5313 *r = bc_vec_top(&G.prog.results);
5315 s = bc_program_num(*r, n, false);
5318 if (!BC_PROG_NUM((*r), (*n)))
5319 return bc_error_variable_is_wrong_type();
5324 static void bc_program_retire(BcResult *r, BcResultType t)
5327 bc_vec_pop(&G.prog.results);
5328 bc_vec_push(&G.prog.results, r);
5331 static BcStatus bc_program_op(char inst)
5334 BcResult *opd1, *opd2, res;
5335 BcNum *n1, *n2 = NULL;
5337 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5339 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5341 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5343 bc_program_binOpRetire(&res);
5348 bc_num_free(&res.d.n);
5352 static BcStatus bc_program_read(void)
5354 const char *sv_file;
5360 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5362 for (i = 0; i < G.prog.stack.len; ++i) {
5363 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5364 if (ip_ptr->func == BC_PROG_READ)
5365 return bc_error_nested_read_call();
5368 bc_vec_pop_all(&f->code);
5369 bc_char_vec_init(&buf);
5371 sv_file = G.prog.file;
5374 s = bc_read_line(&buf, "read> ");
5377 common_parse_init(&parse, BC_PROG_READ);
5378 bc_lex_file(&parse.l);
5380 s = bc_parse_text(&parse, buf.v);
5381 if (s) goto exec_err;
5382 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5383 if (s) goto exec_err;
5385 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5386 s = bc_error("bad read() expression");
5390 ip.func = BC_PROG_READ;
5392 ip.len = G.prog.results.len;
5394 // Update this pointer, just in case.
5395 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5397 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5398 bc_vec_push(&G.prog.stack, &ip);
5401 G.prog.file = sv_file;
5402 bc_parse_free(&parse);
5408 static size_t bc_program_index(char *code, size_t *bgn)
5410 char amt = code[(*bgn)++], i = 0;
5413 for (; i < amt; ++i, ++(*bgn))
5414 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5419 static char *bc_program_name(char *code, size_t *bgn)
5422 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5424 s = xmalloc(ptr - str + 1);
5427 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5435 static void bc_program_printString(const char *str, size_t *nchars)
5437 size_t i, len = strlen(str);
5446 for (i = 0; i < len; ++i, ++(*nchars)) {
5450 if (c != '\\' || i == len - 1)
5510 // Just print the backslash and following character.
5521 static BcStatus bc_program_print(char inst, size_t idx)
5523 BcStatus s = BC_STATUS_SUCCESS;
5528 bool pop = inst != BC_INST_PRINT;
5530 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5531 return bc_error_stack_has_too_few_elements();
5533 r = bc_vec_item_rev(&G.prog.results, idx);
5534 s = bc_program_num(r, &num, false);
5537 if (BC_PROG_NUM(r, num)) {
5538 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5539 if (!s) bc_num_copy(&G.prog.last, num);
5543 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5544 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5546 if (inst == BC_INST_PRINT_STR) {
5547 for (i = 0, len = strlen(str); i < len; ++i) {
5550 if (c == '\n') G.prog.nchars = SIZE_MAX;
5555 bc_program_printString(str, &G.prog.nchars);
5556 if (inst == BC_INST_PRINT) bb_putchar('\n');
5560 if (!s && pop) bc_vec_pop(&G.prog.results);
5565 static BcStatus bc_program_negate(void)
5571 s = bc_program_prep(&ptr, &num);
5574 bc_num_init(&res.d.n, num->len);
5575 bc_num_copy(&res.d.n, num);
5576 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5578 bc_program_retire(&res, BC_RESULT_TEMP);
5583 static BcStatus bc_program_logical(char inst)
5586 BcResult *opd1, *opd2, res;
5591 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5593 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5595 if (inst == BC_INST_BOOL_AND)
5596 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5597 else if (inst == BC_INST_BOOL_OR)
5598 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5601 cmp = bc_num_cmp(n1, n2);
5605 case BC_INST_REL_EQ:
5611 case BC_INST_REL_LE:
5617 case BC_INST_REL_GE:
5623 case BC_INST_REL_NE:
5629 case BC_INST_REL_LT:
5635 case BC_INST_REL_GT:
5643 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5645 bc_program_binOpRetire(&res);
5651 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5657 memset(&n2, 0, sizeof(BcNum));
5658 n2.rdx = res.d.id.idx = r->d.id.idx;
5659 res.t = BC_RESULT_STR;
5662 if (!BC_PROG_STACK(&G.prog.results, 2))
5663 return bc_error_stack_has_too_few_elements();
5665 bc_vec_pop(&G.prog.results);
5668 bc_vec_pop(&G.prog.results);
5670 bc_vec_push(&G.prog.results, &res);
5671 bc_vec_push(v, &n2);
5673 return BC_STATUS_SUCCESS;
5677 static BcStatus bc_program_copyToVar(char *name, bool var)
5684 if (!BC_PROG_STACK(&G.prog.results, 1))
5685 return bc_error_stack_has_too_few_elements();
5687 ptr = bc_vec_top(&G.prog.results);
5688 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5689 return bc_error_variable_is_wrong_type();
5690 v = bc_program_search(name, var);
5693 if (ptr->t == BC_RESULT_STR && !var)
5694 return bc_error_variable_is_wrong_type();
5695 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5698 s = bc_program_num(ptr, &n, false);
5701 // Do this once more to make sure that pointers were not invalidated.
5702 v = bc_program_search(name, var);
5705 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5706 bc_num_copy(&r.d.n, n);
5709 bc_array_init(&r.d.v, true);
5710 bc_array_copy(&r.d.v, (BcVec *) n);
5713 bc_vec_push(v, &r.d);
5714 bc_vec_pop(&G.prog.results);
5719 static BcStatus bc_program_assign(char inst)
5722 BcResult *left, *right, res;
5723 BcNum *l = NULL, *r = NULL;
5724 unsigned long val, max;
5725 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5727 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5730 ib = left->t == BC_RESULT_IBASE;
5731 sc = left->t == BC_RESULT_SCALE;
5735 if (right->t == BC_RESULT_STR) {
5739 if (left->t != BC_RESULT_VAR)
5740 return bc_error_variable_is_wrong_type();
5741 v = bc_program_search(left->d.id.name, true);
5743 return bc_program_assignStr(right, v, false);
5747 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5748 return bc_error("bad assignment:"
5749 " left side must be scale,"
5750 " ibase, obase, last, var,"
5755 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5756 return bc_error("divide by zero");
5761 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5768 if (ib || sc || left->t == BC_RESULT_OBASE) {
5769 static const char *const msg[] = {
5770 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5771 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5772 "?1", //BC_RESULT_LAST
5773 "?2", //BC_RESULT_CONSTANT
5774 "?3", //BC_RESULT_ONE
5775 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5779 s = bc_num_ulong(l, &val);
5782 s = left->t - BC_RESULT_IBASE;
5785 ptr = &G.prog.scale;
5788 if (val < BC_NUM_MIN_BASE)
5789 return bc_error(msg[s]);
5790 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5791 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5795 return bc_error(msg[s]);
5797 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5799 *ptr = (size_t) val;
5800 s = BC_STATUS_SUCCESS;
5803 bc_num_init(&res.d.n, l->len);
5804 bc_num_copy(&res.d.n, l);
5805 bc_program_binOpRetire(&res);
5811 #define bc_program_pushVar(code, bgn, pop, copy) \
5812 bc_program_pushVar(code, bgn)
5813 // for bc, 'pop' and 'copy' are always false
5815 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5816 bool pop, bool copy)
5818 BcStatus s = BC_STATUS_SUCCESS;
5820 char *name = bc_program_name(code, bgn);
5822 r.t = BC_RESULT_VAR;
5827 BcVec *v = bc_program_search(name, true);
5828 BcNum *num = bc_vec_top(v);
5832 if (!BC_PROG_STACK(v, 2 - copy)) {
5834 return bc_error_stack_has_too_few_elements();
5840 if (!BC_PROG_STR(num)) {
5842 r.t = BC_RESULT_TEMP;
5844 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5845 bc_num_copy(&r.d.n, num);
5848 r.t = BC_RESULT_STR;
5849 r.d.id.idx = num->rdx;
5852 if (!copy) bc_vec_pop(v);
5857 bc_vec_push(&G.prog.results, &r);
5862 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5865 BcStatus s = BC_STATUS_SUCCESS;
5869 r.d.id.name = bc_program_name(code, bgn);
5871 if (inst == BC_INST_ARRAY) {
5872 r.t = BC_RESULT_ARRAY;
5873 bc_vec_push(&G.prog.results, &r);
5880 s = bc_program_prep(&operand, &num);
5882 s = bc_num_ulong(num, &temp);
5885 if (temp > BC_MAX_DIM) {
5886 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5890 r.d.id.idx = (size_t) temp;
5891 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5895 if (s) free(r.d.id.name);
5900 static BcStatus bc_program_incdec(char inst)
5903 BcResult *ptr, res, copy;
5907 s = bc_program_prep(&ptr, &num);
5910 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5911 copy.t = BC_RESULT_TEMP;
5912 bc_num_init(©.d.n, num->len);
5913 bc_num_copy(©.d.n, num);
5916 res.t = BC_RESULT_ONE;
5917 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5918 BC_INST_ASSIGN_PLUS :
5919 BC_INST_ASSIGN_MINUS;
5921 bc_vec_push(&G.prog.results, &res);
5922 bc_program_assign(inst);
5924 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5925 bc_vec_pop(&G.prog.results);
5926 bc_vec_push(&G.prog.results, ©);
5932 static BcStatus bc_program_call(char *code, size_t *idx)
5934 BcStatus s = BC_STATUS_SUCCESS;
5936 size_t i, nparams = bc_program_index(code, idx);
5943 ip.func = bc_program_index(code, idx);
5944 func = bc_vec_item(&G.prog.fns, ip.func);
5946 if (func->code.len == 0) {
5947 return bc_error("undefined function");
5949 if (nparams != func->nparams) {
5950 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5952 ip.len = G.prog.results.len - nparams;
5954 for (i = 0; i < nparams; ++i) {
5956 a = bc_vec_item(&func->autos, nparams - 1 - i);
5957 arg = bc_vec_top(&G.prog.results);
5959 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5960 return bc_error_variable_is_wrong_type();
5962 s = bc_program_copyToVar(a->name, a->idx);
5966 for (; i < func->autos.len; ++i) {
5969 a = bc_vec_item(&func->autos, i);
5970 v = bc_program_search(a->name, a->idx);
5973 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5974 bc_vec_push(v, ¶m.n);
5977 bc_array_init(¶m.v, true);
5978 bc_vec_push(v, ¶m.v);
5982 bc_vec_push(&G.prog.stack, &ip);
5984 return BC_STATUS_SUCCESS;
5987 static BcStatus bc_program_return(char inst)
5993 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5995 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5996 return bc_error_stack_has_too_few_elements();
5998 f = bc_vec_item(&G.prog.fns, ip->func);
5999 res.t = BC_RESULT_TEMP;
6001 if (inst == BC_INST_RET) {
6004 BcResult *operand = bc_vec_top(&G.prog.results);
6006 s = bc_program_num(operand, &num, false);
6008 bc_num_init(&res.d.n, num->len);
6009 bc_num_copy(&res.d.n, num);
6012 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6013 bc_num_zero(&res.d.n);
6016 // We need to pop arguments as well, so this takes that into account.
6017 for (i = 0; i < f->autos.len; ++i) {
6020 BcId *a = bc_vec_item(&f->autos, i);
6022 v = bc_program_search(a->name, a->idx);
6026 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6027 bc_vec_push(&G.prog.results, &res);
6028 bc_vec_pop(&G.prog.stack);
6030 return BC_STATUS_SUCCESS;
6034 static unsigned long bc_program_scale(BcNum *n)
6036 return (unsigned long) n->rdx;
6039 static unsigned long bc_program_len(BcNum *n)
6041 unsigned long len = n->len;
6044 if (n->rdx != n->len) return len;
6045 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6050 static BcStatus bc_program_builtin(char inst)
6056 bool len = inst == BC_INST_LENGTH;
6058 if (!BC_PROG_STACK(&G.prog.results, 1))
6059 return bc_error_stack_has_too_few_elements();
6060 opnd = bc_vec_top(&G.prog.results);
6062 s = bc_program_num(opnd, &num, false);
6066 if (!BC_PROG_NUM(opnd, num) && !len)
6067 return bc_error_variable_is_wrong_type();
6070 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6072 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6074 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6075 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6079 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6082 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6084 str = bc_vec_item(&G.prog.strs, idx);
6085 bc_num_ulong2num(&res.d.n, strlen(*str));
6089 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6090 bc_num_ulong2num(&res.d.n, f(num));
6093 bc_program_retire(&res, BC_RESULT_TEMP);
6099 static BcStatus bc_program_divmod(void)
6102 BcResult *opd1, *opd2, res, res2;
6103 BcNum *n1, *n2 = NULL;
6105 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6108 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6109 bc_num_init(&res2.d.n, n2->len);
6111 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6114 bc_program_binOpRetire(&res2);
6115 res.t = BC_RESULT_TEMP;
6116 bc_vec_push(&G.prog.results, &res);
6121 bc_num_free(&res2.d.n);
6122 bc_num_free(&res.d.n);
6126 static BcStatus bc_program_modexp(void)
6129 BcResult *r1, *r2, *r3, res;
6130 BcNum *n1, *n2, *n3;
6132 if (!BC_PROG_STACK(&G.prog.results, 3))
6133 return bc_error_stack_has_too_few_elements();
6134 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6137 r1 = bc_vec_item_rev(&G.prog.results, 2);
6138 s = bc_program_num(r1, &n1, false);
6140 if (!BC_PROG_NUM(r1, n1))
6141 return bc_error_variable_is_wrong_type();
6143 // Make sure that the values have their pointers updated, if necessary.
6144 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6146 if (r1->t == r2->t) {
6147 s = bc_program_num(r2, &n2, false);
6151 if (r1->t == r3->t) {
6152 s = bc_program_num(r3, &n3, false);
6157 bc_num_init(&res.d.n, n3->len);
6158 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6161 bc_vec_pop(&G.prog.results);
6162 bc_program_binOpRetire(&res);
6167 bc_num_free(&res.d.n);
6171 static void bc_program_stackLen(void)
6174 size_t len = G.prog.results.len;
6176 res.t = BC_RESULT_TEMP;
6178 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6179 bc_num_ulong2num(&res.d.n, len);
6180 bc_vec_push(&G.prog.results, &res);
6183 static BcStatus bc_program_asciify(void)
6187 BcNum *num = NULL, n;
6188 char *str, *str2, c;
6189 size_t len = G.prog.strs.len, idx;
6192 if (!BC_PROG_STACK(&G.prog.results, 1))
6193 return bc_error_stack_has_too_few_elements();
6194 r = bc_vec_top(&G.prog.results);
6196 s = bc_program_num(r, &num, false);
6199 if (BC_PROG_NUM(r, num)) {
6201 bc_num_init(&n, BC_NUM_DEF_SIZE);
6202 bc_num_copy(&n, num);
6203 bc_num_truncate(&n, n.rdx);
6205 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6206 if (s) goto num_err;
6207 s = bc_num_ulong(&n, &val);
6208 if (s) goto num_err;
6215 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6216 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6224 str2 = xstrdup(str);
6225 bc_program_addFunc(str2, &idx);
6227 if (idx != len + BC_PROG_REQ_FUNCS) {
6229 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6230 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6239 bc_vec_push(&G.prog.strs, &str);
6241 res.t = BC_RESULT_STR;
6243 bc_vec_pop(&G.prog.results);
6244 bc_vec_push(&G.prog.results, &res);
6246 return BC_STATUS_SUCCESS;
6253 static BcStatus bc_program_printStream(void)
6261 if (!BC_PROG_STACK(&G.prog.results, 1))
6262 return bc_error_stack_has_too_few_elements();
6263 r = bc_vec_top(&G.prog.results);
6265 s = bc_program_num(r, &n, false);
6268 if (BC_PROG_NUM(r, n))
6269 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6271 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6272 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6279 static BcStatus bc_program_nquit(void)
6286 s = bc_program_prep(&opnd, &num);
6288 s = bc_num_ulong(num, &val);
6291 bc_vec_pop(&G.prog.results);
6293 if (G.prog.stack.len < val)
6294 return bc_error_stack_has_too_few_elements();
6295 if (G.prog.stack.len == val)
6298 bc_vec_npop(&G.prog.stack, val);
6303 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6306 BcStatus s = BC_STATUS_SUCCESS;
6316 if (!BC_PROG_STACK(&G.prog.results, 1))
6317 return bc_error_stack_has_too_few_elements();
6319 r = bc_vec_top(&G.prog.results);
6323 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6325 if (code[*bgn] == BC_PARSE_STREND)
6328 else_name = bc_program_name(code, bgn);
6330 exec = r->d.n.len != 0;
6334 else if (else_name != NULL) {
6341 v = bc_program_search(name, true);
6348 if (!exec) goto exit;
6349 if (!BC_PROG_STR(n)) {
6350 s = bc_error_variable_is_wrong_type();
6358 if (r->t == BC_RESULT_STR)
6360 else if (r->t == BC_RESULT_VAR) {
6361 s = bc_program_num(r, &n, false);
6362 if (s || !BC_PROG_STR(n)) goto exit;
6369 fidx = sidx + BC_PROG_REQ_FUNCS;
6371 str = bc_vec_item(&G.prog.strs, sidx);
6372 f = bc_vec_item(&G.prog.fns, fidx);
6374 if (f->code.len == 0) {
6375 common_parse_init(&prs, fidx);
6376 s = bc_parse_text(&prs, *str);
6378 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6381 if (prs.l.t.t != BC_LEX_EOF) {
6382 s = bc_error_bad_expression();
6386 bc_parse_free(&prs);
6390 ip.len = G.prog.results.len;
6393 bc_vec_pop(&G.prog.results);
6394 bc_vec_push(&G.prog.stack, &ip);
6396 return BC_STATUS_SUCCESS;
6399 bc_parse_free(&prs);
6400 f = bc_vec_item(&G.prog.fns, fidx);
6401 bc_vec_pop_all(&f->code);
6403 bc_vec_pop(&G.prog.results);
6408 static void bc_program_pushGlobal(char inst)
6413 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6414 if (inst == BC_INST_IBASE)
6415 val = (unsigned long) G.prog.ib_t;
6416 else if (inst == BC_INST_SCALE)
6417 val = (unsigned long) G.prog.scale;
6419 val = (unsigned long) G.prog.ob_t;
6421 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6422 bc_num_ulong2num(&res.d.n, val);
6423 bc_vec_push(&G.prog.results, &res);
6426 static void bc_program_addFunc(char *name, size_t *idx)
6428 BcId entry, *entry_ptr;
6433 entry.idx = G.prog.fns.len;
6435 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6436 if (!inserted) free(name);
6438 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6439 *idx = entry_ptr->idx;
6443 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6445 // We need to reset these, so the function can be repopulated.
6447 bc_vec_pop_all(&func->autos);
6448 bc_vec_pop_all(&func->code);
6449 bc_vec_pop_all(&func->labels);
6453 bc_vec_push(&G.prog.fns, &f);
6457 // Called when parsing or execution detects a failure,
6458 // resets execution structures.
6459 static void bc_program_reset(void)
6464 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6465 bc_vec_pop_all(&G.prog.results);
6467 f = bc_vec_item(&G.prog.fns, 0);
6468 ip = bc_vec_top(&G.prog.stack);
6469 ip->idx = f->code.len;
6471 // If !tty, no need to check for ^C: we don't have ^C handler,
6472 // we would be killed by a signal and won't reach this place
6475 static BcStatus bc_program_exec(void)
6477 BcStatus s = BC_STATUS_SUCCESS;
6481 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6482 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6483 char *code = func->code.v;
6486 while (!s && ip->idx < func->code.len) {
6488 char inst = code[(ip->idx)++];
6493 case BC_INST_JUMP_ZERO:
6495 s = bc_program_prep(&ptr, &num);
6497 cond = !bc_num_cmp(num, &G.prog.zero);
6498 bc_vec_pop(&G.prog.results);
6504 idx = bc_program_index(code, &ip->idx);
6505 addr = bc_vec_item(&func->labels, idx);
6506 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6512 s = bc_program_call(code, &ip->idx);
6516 case BC_INST_INC_PRE:
6517 case BC_INST_DEC_PRE:
6518 case BC_INST_INC_POST:
6519 case BC_INST_DEC_POST:
6521 s = bc_program_incdec(inst);
6534 s = bc_program_return(inst);
6538 case BC_INST_BOOL_OR:
6539 case BC_INST_BOOL_AND:
6541 case BC_INST_REL_EQ:
6542 case BC_INST_REL_LE:
6543 case BC_INST_REL_GE:
6544 case BC_INST_REL_NE:
6545 case BC_INST_REL_LT:
6546 case BC_INST_REL_GT:
6548 s = bc_program_logical(inst);
6554 s = bc_program_read();
6560 s = bc_program_pushVar(code, &ip->idx, false, false);
6564 case BC_INST_ARRAY_ELEM:
6567 s = bc_program_pushArray(code, &ip->idx, inst);
6573 r.t = BC_RESULT_LAST;
6574 bc_vec_push(&G.prog.results, &r);
6582 bc_program_pushGlobal(inst);
6586 case BC_INST_SCALE_FUNC:
6587 case BC_INST_LENGTH:
6590 s = bc_program_builtin(inst);
6596 r.t = BC_RESULT_CONSTANT;
6597 r.d.id.idx = bc_program_index(code, &ip->idx);
6598 bc_vec_push(&G.prog.results, &r);
6604 if (!BC_PROG_STACK(&G.prog.results, 1))
6605 s = bc_error_stack_has_too_few_elements();
6607 bc_vec_pop(&G.prog.results);
6611 case BC_INST_POP_EXEC:
6613 bc_vec_pop(&G.prog.stack);
6618 case BC_INST_PRINT_POP:
6619 case BC_INST_PRINT_STR:
6621 s = bc_program_print(inst, 0);
6627 r.t = BC_RESULT_STR;
6628 r.d.id.idx = bc_program_index(code, &ip->idx);
6629 bc_vec_push(&G.prog.results, &r);
6634 case BC_INST_MULTIPLY:
6635 case BC_INST_DIVIDE:
6636 case BC_INST_MODULUS:
6640 s = bc_program_op(inst);
6644 case BC_INST_BOOL_NOT:
6646 s = bc_program_prep(&ptr, &num);
6649 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6650 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6651 bc_program_retire(&r, BC_RESULT_TEMP);
6658 s = bc_program_negate();
6663 case BC_INST_ASSIGN_POWER:
6664 case BC_INST_ASSIGN_MULTIPLY:
6665 case BC_INST_ASSIGN_DIVIDE:
6666 case BC_INST_ASSIGN_MODULUS:
6667 case BC_INST_ASSIGN_PLUS:
6668 case BC_INST_ASSIGN_MINUS:
6670 case BC_INST_ASSIGN:
6672 s = bc_program_assign(inst);
6676 case BC_INST_MODEXP:
6678 s = bc_program_modexp();
6682 case BC_INST_DIVMOD:
6684 s = bc_program_divmod();
6688 case BC_INST_EXECUTE:
6689 case BC_INST_EXEC_COND:
6691 cond = inst == BC_INST_EXEC_COND;
6692 s = bc_program_execStr(code, &ip->idx, cond);
6696 case BC_INST_PRINT_STACK:
6698 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6699 s = bc_program_print(BC_INST_PRINT, idx);
6703 case BC_INST_CLEAR_STACK:
6705 bc_vec_pop_all(&G.prog.results);
6709 case BC_INST_STACK_LEN:
6711 bc_program_stackLen();
6715 case BC_INST_DUPLICATE:
6717 if (!BC_PROG_STACK(&G.prog.results, 1))
6718 return bc_error_stack_has_too_few_elements();
6719 ptr = bc_vec_top(&G.prog.results);
6720 bc_result_copy(&r, ptr);
6721 bc_vec_push(&G.prog.results, &r);
6729 if (!BC_PROG_STACK(&G.prog.results, 2))
6730 return bc_error_stack_has_too_few_elements();
6732 ptr = bc_vec_item_rev(&G.prog.results, 0);
6733 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6734 memcpy(&r, ptr, sizeof(BcResult));
6735 memcpy(ptr, ptr2, sizeof(BcResult));
6736 memcpy(ptr2, &r, sizeof(BcResult));
6741 case BC_INST_ASCIIFY:
6743 s = bc_program_asciify();
6747 case BC_INST_PRINT_STREAM:
6749 s = bc_program_printStream();
6754 case BC_INST_PUSH_VAR:
6756 bool copy = inst == BC_INST_LOAD;
6757 s = bc_program_pushVar(code, &ip->idx, true, copy);
6761 case BC_INST_PUSH_TO_VAR:
6763 char *name = bc_program_name(code, &ip->idx);
6764 s = bc_program_copyToVar(name, true);
6771 if (G.prog.stack.len <= 2)
6773 bc_vec_npop(&G.prog.stack, 2);
6779 s = bc_program_nquit();
6785 if (s || G_interrupt) {
6790 // If the stack has changed, pointers may be invalid.
6791 ip = bc_vec_top(&G.prog.stack);
6792 func = bc_vec_item(&G.prog.fns, ip->func);
6793 code = func->code.v;
6799 static void bc_vm_info(void)
6801 printf("%s "BB_VER"\n"
6802 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6803 "Report bugs at: https://github.com/gavinhoward/bc\n"
6804 "This is free software with ABSOLUTELY NO WARRANTY\n"
6809 static void bc_vm_envArgs(void)
6811 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6814 char *env_args = getenv(bc_args_env_name), *buf;
6816 if (!env_args) return;
6818 G.env_args = xstrdup(env_args);
6821 bc_vec_init(&v, sizeof(char *), NULL);
6822 bc_vec_push(&v, &bc_args_env_name);
6825 if (!isspace(*buf)) {
6826 bc_vec_push(&v, &buf);
6827 while (*buf != 0 && !isspace(*buf)) ++buf;
6828 if (*buf != 0) (*(buf++)) = '\0';
6834 bc_args((int) v.len, (char **) v.v);
6840 static size_t bc_vm_envLen(const char *var)
6842 char *lenv = getenv(var);
6843 size_t i, len = BC_NUM_PRINT_WIDTH;
6846 if (!lenv) return len;
6850 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6852 len = (size_t) atoi(lenv) - 1;
6853 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6856 len = BC_NUM_PRINT_WIDTH;
6861 static BcStatus bc_vm_process(const char *text)
6863 BcStatus s = bc_parse_text(&G.prs, text);
6867 while (G.prs.l.t.t != BC_LEX_EOF) {
6868 s = G.prs.parse(&G.prs);
6872 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6873 s = bc_program_exec();
6882 static BcStatus bc_vm_file(const char *file)
6884 const char *sv_file;
6890 data = bc_read_file(file);
6891 if (!data) return bc_error_fmt("file '%s' is not text", file);
6893 sv_file = G.prog.file;
6895 bc_lex_file(&G.prs.l);
6896 s = bc_vm_process(data);
6899 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6900 ip = bc_vec_item(&G.prog.stack, 0);
6902 if (main_func->code.len < ip->idx)
6903 s = bc_error_fmt("file '%s' is not executable", file);
6906 G.prog.file = sv_file;
6911 static BcStatus bc_vm_stdin(void)
6915 size_t len, i, str = 0;
6916 bool comment = false;
6919 bc_lex_file(&G.prs.l);
6921 bc_char_vec_init(&buffer);
6922 bc_char_vec_init(&buf);
6923 bc_vec_pushZeroByte(&buffer);
6925 // This loop is complex because the vm tries not to send any lines that end
6926 // with a backslash to the parser. The reason for that is because the parser
6927 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6928 // case, and for strings and comments, the parser will expect more stuff.
6929 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6931 char *string = buf.v;
6936 if (str && buf.v[0] == G.send)
6938 else if (buf.v[0] == G.sbgn)
6941 else if (len > 1 || comment) {
6943 for (i = 0; i < len; ++i) {
6945 bool notend = len > i + 1;
6948 if (i - 1 > len || string[i - 1] != '\\') {
6949 if (G.sbgn == G.send)
6951 else if (c == G.send)
6953 else if (c == G.sbgn)
6957 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6961 else if (c == '*' && notend && comment && string[i + 1] == '/')
6965 if (str || comment || string[len - 2] == '\\') {
6966 bc_vec_concat(&buffer, buf.v);
6971 bc_vec_concat(&buffer, buf.v);
6972 s = bc_vm_process(buffer.v);
6975 fputs("ready for more input\n", stderr);
6978 bc_vec_pop_all(&buffer);
6982 s = bc_error("string end could not be found");
6985 s = bc_error("comment end could not be found");
6989 bc_vec_free(&buffer);
6994 static const char bc_lib[] = {
6997 "\n" "auto b,s,n,r,d,i,p,f,v"
7006 "\n" "scale=scale(x)+1"
7016 "\n" "for(i=2;v!=0;++i){"
7022 "\n" "while((d--)!=0)r*=r"
7025 "\n" "if(n!=0)return(1/r)"
7029 "\n" "auto b,s,r,p,a,q,i,v"
7033 "\n" "r=(1-10^scale)/1"
7044 "\n" "while(x<=0.5){"
7048 "\n" "r=a=(x-1)/(x+1)"
7051 "\n" "for(i=3;v!=0;i+=2){"
7062 "\n" "auto b,s,r,n,a,q,i"
7066 "\n" "scale=1.1*s+2"
7075 "\n" "if(q%2!=0)x=-x"
7079 "\n" "for(i=3;a!=0;i+=2){"
7080 "\n" "a*=q/(i*(i-1))"
7085 "\n" "if(n!=0)return(-r/1)"
7094 "\n" "x=s(2*a(1)+x)"
7100 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7109 "\n" "if(scale<65){"
7110 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7114 "\n" "if(scale<65){"
7115 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7126 "\n" "x=(x-.2)/(1+.2*x)"
7131 "\n" "for(i=3;t!=0;i+=2){"
7138 "\n" "return((m*a+r)/n)"
7140 "\n" "define j(n,x){"
7141 "\n" "auto b,s,o,a,i,v,f"
7149 "\n" "if(n%2==1)o=1"
7152 "\n" "for(i=2;i<=n;++i)a*=i"
7154 "\n" "a=(x^n)/2^n/a"
7157 "\n" "scale=scale+length(a)-scale(a)"
7158 "\n" "for(i=1;v!=0;++i){"
7159 "\n" "v=v*f/i/(n+i)"
7165 "\n" "return(a*r/1)"
7170 static BcStatus bc_vm_exec(void)
7172 BcStatus s = BC_STATUS_SUCCESS;
7176 if (option_mask32 & BC_FLAG_L) {
7178 // We know that internal library is not buggy,
7179 // thus error checking is normally disabled.
7180 # define DEBUG_LIB 0
7181 bc_lex_file(&G.prs.l);
7182 s = bc_parse_text(&G.prs, bc_lib);
7183 if (DEBUG_LIB && s) return s;
7185 while (G.prs.l.t.t != BC_LEX_EOF) {
7186 s = G.prs.parse(&G.prs);
7187 if (DEBUG_LIB && s) return s;
7189 s = bc_program_exec();
7190 if (DEBUG_LIB && s) return s;
7194 for (i = 0; !s && i < G.files.len; ++i)
7195 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7198 fputs("ready for more input\n", stderr);
7201 if (IS_BC || !G.files.len)
7203 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7204 s = bc_vm_process("");
7209 #if ENABLE_FEATURE_CLEAN_UP
7210 static void bc_program_free()
7212 bc_num_free(&G.prog.ib);
7213 bc_num_free(&G.prog.ob);
7214 bc_num_free(&G.prog.hexb);
7216 bc_num_free(&G.prog.strmb);
7218 bc_vec_free(&G.prog.fns);
7219 bc_vec_free(&G.prog.fn_map);
7220 bc_vec_free(&G.prog.vars);
7221 bc_vec_free(&G.prog.var_map);
7222 bc_vec_free(&G.prog.arrs);
7223 bc_vec_free(&G.prog.arr_map);
7224 bc_vec_free(&G.prog.strs);
7225 bc_vec_free(&G.prog.consts);
7226 bc_vec_free(&G.prog.results);
7227 bc_vec_free(&G.prog.stack);
7228 bc_num_free(&G.prog.last);
7229 bc_num_free(&G.prog.zero);
7230 bc_num_free(&G.prog.one);
7233 static void bc_vm_free(void)
7235 bc_vec_free(&G.files);
7237 bc_parse_free(&G.prs);
7242 static void bc_program_init(size_t line_len)
7247 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7248 memset(&ip, 0, sizeof(BcInstPtr));
7250 /* G.prog.nchars = G.prog.scale = 0; - already is */
7251 G.prog.len = line_len;
7253 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7254 bc_num_ten(&G.prog.ib);
7257 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7258 bc_num_ten(&G.prog.ob);
7261 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7262 bc_num_ten(&G.prog.hexb);
7263 G.prog.hexb.num[0] = 6;
7266 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7267 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7270 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7271 bc_num_zero(&G.prog.last);
7273 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7274 bc_num_zero(&G.prog.zero);
7276 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7277 bc_num_one(&G.prog.one);
7279 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7280 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7282 bc_program_addFunc(xstrdup("(main)"), &idx);
7283 bc_program_addFunc(xstrdup("(read)"), &idx);
7285 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7286 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7288 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7289 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7291 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7292 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7293 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7294 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7295 bc_vec_push(&G.prog.stack, &ip);
7298 static void bc_vm_init(const char *env_len)
7300 size_t len = bc_vm_envLen(env_len);
7302 bc_vec_init(&G.files, sizeof(char *), NULL);
7308 bc_program_init(len);
7310 bc_parse_init(&G.prs, BC_PROG_MAIN);
7312 dc_parse_init(&G.prs, BC_PROG_MAIN);
7316 static BcStatus bc_vm_run(int argc, char *argv[],
7317 const char *env_len)
7321 bc_vm_init(env_len);
7322 bc_args(argc, argv);
7324 G.ttyin = isatty(0);
7327 #if ENABLE_FEATURE_BC_SIGNALS
7328 // With SA_RESTART, most system calls will restart
7329 // (IOW: they won't fail with EINTR).
7330 // In particular, this means ^C won't cause
7331 // stdout to get into "error state" if SIGINT hits
7332 // within write() syscall.
7333 // The downside is that ^C while line input is taken
7334 // will only be handled after [Enter] since read()
7335 // from stdin is not interrupted by ^C either,
7336 // it restarts, thus fgetc() does not return on ^C.
7337 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7339 // Without SA_RESTART, this exhibits a bug:
7340 // "while (1) print 1" and try ^C-ing it.
7341 // Intermittently, instead of returning to input line,
7342 // you'll get "output error: Interrupted system call"
7344 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7346 if (!(option_mask32 & BC_FLAG_Q))
7351 #if ENABLE_FEATURE_CLEAN_UP
7358 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7359 int bc_main(int argc, char **argv)
7362 G.sbgn = G.send = '"';
7364 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7369 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7370 int dc_main(int argc, char **argv)
7376 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");