1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 typedef signed char BcDig;
194 typedef struct BcNum {
202 #define BC_NUM_MIN_BASE ((unsigned long) 2)
203 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
204 #define BC_NUM_DEF_SIZE (16)
205 #define BC_NUM_PRINT_WIDTH (69)
207 #define BC_NUM_KARATSUBA_LEN (32)
209 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212 #define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214 #define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
217 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
220 static void bc_num_init(BcNum *n, size_t req);
221 static void bc_num_expand(BcNum *n, size_t req);
222 static void bc_num_copy(BcNum *d, BcNum *s);
223 static void bc_num_free(void *num);
225 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
226 static void bc_num_ulong2num(BcNum *n, unsigned long val);
228 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 typedef enum BcInst {
268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
273 BC_INST_ASSIGN_MINUS,
319 BC_INST_PRINT_STREAM,
334 BC_INST_INVALID = -1,
339 typedef struct BcId {
344 typedef struct BcFunc {
351 typedef enum BcResultType {
356 BC_RESULT_ARRAY_ELEM,
365 // These are between to calculate ibase, obase, and last from instructions.
373 typedef union BcResultData {
379 typedef struct BcResult {
384 typedef struct BcInstPtr {
390 static void bc_array_expand(BcVec *a, size_t len);
391 static int bc_id_cmp(const void *e1, const void *e2);
393 // BC_LEX_NEG is not used in lexing; it is only for parsing.
394 typedef enum BcLexType {
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
500 // must match order of BC_LEX_KEY_foo etc above
502 struct BcLexKeyword {
505 #define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507 static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
563 typedef BcStatus (*BcLexNext)(struct BcLex *);
565 typedef struct BcLex {
583 #define BC_PARSE_STREND ((char) UCHAR_MAX)
585 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
586 #define bc_parse_updateFunc(p, f) \
587 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
589 #define BC_PARSE_REL (1 << 0)
590 #define BC_PARSE_PRINT (1 << 1)
591 #define BC_PARSE_NOCALL (1 << 2)
592 #define BC_PARSE_NOREAD (1 << 3)
593 #define BC_PARSE_ARRAY (1 << 4)
595 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
596 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
599 #define BC_PARSE_FUNC_INNER(parse) \
600 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602 #define BC_PARSE_FLAG_FUNC (1 << 1)
603 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605 #define BC_PARSE_FLAG_BODY (1 << 2)
606 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608 #define BC_PARSE_FLAG_LOOP (1 << 3)
609 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
612 #define BC_PARSE_LOOP_INNER(parse) \
613 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615 #define BC_PARSE_FLAG_IF (1 << 5)
616 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618 #define BC_PARSE_FLAG_ELSE (1 << 6)
619 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621 #define BC_PARSE_FLAG_IF_END (1 << 7)
622 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624 #define BC_PARSE_CAN_EXEC(parse) \
625 (!(BC_PARSE_TOP_FLAG(parse) & \
626 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
627 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
628 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630 typedef struct BcOp {
635 typedef struct BcParseNext {
640 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
641 #define BC_PARSE_NEXT(a, ...) \
643 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
650 typedef BcStatus (*BcParseParse)(struct BcParse *);
652 typedef struct BcParse {
675 static BcStatus bc_lex_token(BcLex *l);
677 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
678 #define BC_PARSE_LEAF(p, rparen) \
679 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
680 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682 // We can calculate the conversion between tokens and exprs by subtracting the
683 // position of the first operator in the lex enum and adding the position of the
684 // first in the expr enum. Note: This only works for binary operators.
685 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
693 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695 static BcStatus dc_lex_token(BcLex *l);
697 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
701 typedef struct BcProgram {
742 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744 #define BC_PROG_MAIN (0)
745 #define BC_PROG_READ (1)
748 #define BC_PROG_REQ_FUNCS (2)
751 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
752 #define BC_PROG_NUM(r, n) \
753 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757 static void bc_program_addFunc(char *name, size_t *idx);
758 static void bc_program_reset(void);
760 #define BC_FLAG_X (1 << 0)
761 #define BC_FLAG_W (1 << 1)
762 #define BC_FLAG_V (1 << 2)
763 #define BC_FLAG_S (1 << 3)
764 #define BC_FLAG_Q (1 << 4)
765 #define BC_FLAG_L (1 << 5)
766 #define BC_FLAG_I (1 << 6)
768 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
769 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771 #define BC_MAX_OBASE ((unsigned) 999)
772 #define BC_MAX_DIM ((unsigned) INT_MAX)
773 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
774 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
775 #define BC_MAX_NAME BC_MAX_STRING
776 #define BC_MAX_NUM BC_MAX_STRING
777 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
778 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
789 // For error messages. Can be set to current parsed line,
790 // or [TODO] to current executing line (can be before last parsed one)
797 #define G (*ptr_to_globals)
798 #define INIT_G() do { \
799 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
801 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
802 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
803 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
804 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
807 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
809 static void bc_vm_info(void);
813 // This is an array that corresponds to token types. An entry is
814 // true if the token is valid in an expression, false otherwise.
815 static const bool bc_parse_exprs[] = {
816 false, false, true, true, true, true, true, true, true, true, true, true,
817 true, true, true, true, true, true, true, true, true, true, true, true,
818 true, true, true, false, false, true, true, false, false, false, false,
819 false, false, false, true, true, false, false, false, false, false, false,
820 false, true, false, true, true, true, true, false, false, true, false, true,
824 // This is an array of data for operators that correspond to token types.
825 static const BcOp bc_parse_ops[] = {
826 { 0, false }, { 0, false },
829 { 3, true }, { 3, true }, { 3, true },
830 { 4, true }, { 4, true },
831 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
833 { 7, true }, { 7, true },
834 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
835 { 5, false }, { 5, false },
838 // These identify what tokens can come after expressions in certain cases.
839 static const BcParseNext bc_parse_next_expr =
840 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
841 static const BcParseNext bc_parse_next_param =
842 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
843 static const BcParseNext bc_parse_next_print =
844 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
845 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
846 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
847 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
848 static const BcParseNext bc_parse_next_read =
849 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
853 static const BcLexType dc_lex_regs[] = {
854 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
855 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
856 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
860 static const BcLexType dc_lex_tokens[] = {
861 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
862 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
863 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
864 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
868 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
871 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
872 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
873 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
875 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
877 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
878 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
880 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
881 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
882 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
883 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
884 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
888 static const BcInst dc_parse_insts[] = {
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
890 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
891 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
899 BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
904 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
906 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
908 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
909 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
911 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
915 static const BcNumBinaryOp bc_program_ops[] = {
916 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
919 static void fflush_and_check(void)
922 if (ferror(stdout) || ferror(stderr))
923 bb_perror_msg_and_die("output error");
926 static void quit(void) NORETURN;
927 static void quit(void)
930 bb_perror_msg_and_die("input error");
935 static void bc_verror_msg(const char *fmt, va_list p)
937 const char *sv = sv; /* for compiler */
940 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
942 bb_verror_msg(fmt, p, NULL);
944 free((char*)applet_name);
949 static NOINLINE int bc_error_fmt(const char *fmt, ...)
954 bc_verror_msg(fmt, p);
959 return BC_STATUS_FAILURE;
962 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
966 // Are non-POSIX constructs totally ok?
967 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
968 return BC_STATUS_SUCCESS; // yes
971 bc_verror_msg(fmt, p);
974 // Do we treat non-POSIX constructs as errors?
975 if (!(option_mask32 & BC_FLAG_S))
976 return BC_STATUS_SUCCESS; // no, it's a warning
979 return BC_STATUS_FAILURE;
982 // We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
983 // This idiom begs for tail-call optimization, but for it to work,
984 // function must not have calller-cleaned parameters on stack.
985 // Unfortunately, vararg functions do exactly that on most arches.
986 // Thus, these shims for the cases when we have no PARAMS:
987 static int bc_error(const char *msg)
989 return bc_error_fmt("%s", msg);
991 static int bc_posix_error(const char *msg)
993 return bc_posix_error_fmt("%s", msg);
995 static int bc_POSIX_does_not_allow(const char *msg)
997 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
999 static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1001 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1003 static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1005 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1007 static int bc_error_bad_character(char c)
1009 return bc_error_fmt("bad character '%c'", c);
1011 static int bc_error_bad_expression(void)
1013 return bc_error("bad expression");
1015 static int bc_error_bad_token(void)
1017 return bc_error("bad token");
1019 static int bc_error_stack_has_too_few_elements(void)
1021 return bc_error("stack has too few elements");
1023 static int bc_error_variable_is_wrong_type(void)
1025 return bc_error("variable is wrong type");
1027 static int bc_error_nested_read_call(void)
1029 return bc_error("read() call inside of a read() call");
1032 static void bc_vec_grow(BcVec *v, size_t n)
1034 size_t cap = v->cap * 2;
1035 while (cap < v->len + n) cap *= 2;
1036 v->v = xrealloc(v->v, v->size * cap);
1040 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1043 v->cap = BC_VEC_START_CAP;
1046 v->v = xmalloc(esize * BC_VEC_START_CAP);
1049 static void bc_char_vec_init(BcVec *v)
1051 bc_vec_init(v, sizeof(char), NULL);
1054 static void bc_vec_expand(BcVec *v, size_t req)
1057 v->v = xrealloc(v->v, v->size * req);
1062 static void bc_vec_npop(BcVec *v, size_t n)
1067 size_t len = v->len - n;
1068 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1072 static void bc_vec_pop_all(BcVec *v)
1074 bc_vec_npop(v, v->len);
1077 static void bc_vec_push(BcVec *v, const void *data)
1079 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1080 memmove(v->v + (v->size * v->len), data, v->size);
1084 static void bc_vec_pushByte(BcVec *v, char data)
1086 bc_vec_push(v, &data);
1089 static void bc_vec_pushZeroByte(BcVec *v)
1091 //bc_vec_pushByte(v, '\0');
1093 bc_vec_push(v, &const_int_0);
1096 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1099 bc_vec_push(v, data);
1104 if (v->len == v->cap) bc_vec_grow(v, 1);
1106 ptr = v->v + v->size * idx;
1108 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1109 memmove(ptr, data, v->size);
1113 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1116 bc_vec_expand(v, len + 1);
1117 memcpy(v->v, str, len);
1120 bc_vec_pushZeroByte(v);
1123 static void bc_vec_concat(BcVec *v, const char *str)
1127 if (v->len == 0) bc_vec_pushZeroByte(v);
1129 len = v->len + strlen(str);
1131 if (v->cap < len) bc_vec_grow(v, len - v->len);
1137 static void *bc_vec_item(const BcVec *v, size_t idx)
1139 return v->v + v->size * idx;
1142 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1144 return v->v + v->size * (v->len - idx - 1);
1147 static void bc_vec_free(void *vec)
1149 BcVec *v = (BcVec *) vec;
1154 static size_t bc_map_find(const BcVec *v, const void *ptr)
1156 size_t low = 0, high = v->len;
1158 while (low < high) {
1160 size_t mid = (low + high) / 2;
1161 BcId *id = bc_vec_item(v, mid);
1162 int result = bc_id_cmp(ptr, id);
1166 else if (result < 0)
1175 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1177 size_t n = *i = bc_map_find(v, ptr);
1180 bc_vec_push(v, ptr);
1181 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1182 return 0; // "was not inserted"
1184 bc_vec_pushAt(v, ptr, n);
1185 return 1; // "was inserted"
1188 static size_t bc_map_index(const BcVec *v, const void *ptr)
1190 size_t i = bc_map_find(v, ptr);
1191 if (i >= v->len) return BC_VEC_INVALID_IDX;
1192 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1195 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1203 bc_vec_pop_all(vec);
1206 #if ENABLE_FEATURE_BC_SIGNALS
1207 if (bb_got_signal) { // ^C was pressed
1209 bb_got_signal = 0; // resets G_interrupt to zero
1211 ? "\ninterrupt (type \"quit\" to exit)\n"
1212 : "\ninterrupt (type \"q\" to exit)\n"
1216 if (G.ttyin && !G_posix)
1217 fputs(prompt, stderr);
1219 #if ENABLE_FEATURE_BC_SIGNALS
1225 #if ENABLE_FEATURE_BC_SIGNALS
1226 // Both conditions appear simultaneously, check both just in case
1227 if (errno == EINTR || bb_got_signal) {
1234 quit(); // this emits error message
1236 // Note: EOF does not append '\n', therefore:
1237 // printf 'print 123\n' | bc - works
1238 // printf 'print 123' | bc - fails (syntax error)
1242 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1245 // Bad chars on this line, ignore entire line
1246 bc_error_fmt("illegal character 0x%02x", i);
1249 bc_vec_pushByte(vec, (char)i);
1250 } while (i != '\n');
1251 } while (bad_chars);
1253 bc_vec_pushZeroByte(vec);
1255 return BC_STATUS_SUCCESS;
1258 static char* bc_read_file(const char *path)
1261 size_t size = ((size_t) -1);
1264 buf = xmalloc_open_read_close(path, &size);
1266 for (i = 0; i < size; ++i) {
1268 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1280 static void bc_args(int argc, char **argv)
1286 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1287 opts = getopt32long(argv, "xwvsqli",
1288 "extended-register\0" No_argument "x"
1289 "warn\0" No_argument "w"
1290 "version\0" No_argument "v"
1291 "standard\0" No_argument "s"
1292 "quiet\0" No_argument "q"
1293 "mathlib\0" No_argument "l"
1294 "interactive\0" No_argument "i"
1297 opts = getopt32(argv, "xwvsqli");
1299 if (getenv("POSIXLY_CORRECT"))
1300 option_mask32 |= BC_FLAG_S;
1302 if (opts & BC_FLAG_V) bc_vm_info();
1303 // should not be necessary, getopt32() handles this??
1304 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1306 for (i = optind; i < argc; ++i)
1307 bc_vec_push(&G.files, argv + i);
1310 static void bc_num_setToZero(BcNum *n, size_t scale)
1317 static void bc_num_zero(BcNum *n)
1319 bc_num_setToZero(n, 0);
1322 static void bc_num_one(BcNum *n)
1324 bc_num_setToZero(n, 0);
1329 static void bc_num_ten(BcNum *n)
1331 bc_num_setToZero(n, 0);
1337 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1341 for (i = 0; i < len; ++i) {
1342 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1349 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1353 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1354 return BC_NUM_NEG(i + 1, c < 0);
1357 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1359 size_t i, min, a_int, b_int, diff;
1360 BcDig *max_num, *min_num;
1361 bool a_max, neg = false;
1364 if (a == b) return 0;
1365 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1366 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1376 a_int = BC_NUM_INT(a);
1377 b_int = BC_NUM_INT(b);
1379 a_max = (a->rdx > b->rdx);
1381 if (a_int != 0) return (ssize_t) a_int;
1385 diff = a->rdx - b->rdx;
1386 max_num = a->num + diff;
1391 diff = b->rdx - a->rdx;
1392 max_num = b->num + diff;
1396 cmp = bc_num_compare(max_num, min_num, b_int + min);
1397 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1399 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1400 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1406 static void bc_num_truncate(BcNum *n, size_t places)
1408 if (places == 0) return;
1414 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1418 static void bc_num_extend(BcNum *n, size_t places)
1420 size_t len = n->len + places;
1424 if (n->cap < len) bc_num_expand(n, len);
1426 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1427 memset(n->num, 0, sizeof(BcDig) * places);
1434 static void bc_num_clean(BcNum *n)
1436 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1439 else if (n->len < n->rdx)
1443 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1446 bc_num_extend(n, scale - n->rdx);
1448 bc_num_truncate(n, n->rdx - scale);
1451 if (n->len != 0) n->neg = !neg1 != !neg2;
1454 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1459 b->len = n->len - idx;
1461 a->rdx = b->rdx = 0;
1463 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1464 memcpy(a->num, n->num, idx * sizeof(BcDig));
1475 static BcStatus bc_num_shift(BcNum *n, size_t places)
1477 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1478 if (places + n->len > BC_MAX_NUM)
1479 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1481 if (n->rdx >= places)
1484 bc_num_extend(n, places - n->rdx);
1490 return BC_STATUS_SUCCESS;
1493 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1502 return bc_num_div(&one, a, b, scale);
1505 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1507 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1508 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1511 // Because this function doesn't need to use scale (per the bc spec),
1512 // I am hijacking it to say whether it's doing an add or a subtract.
1516 if (sub && c->len) c->neg = !c->neg;
1517 return BC_STATUS_SUCCESS;
1519 else if (b->len == 0) {
1521 return BC_STATUS_SUCCESS;
1525 c->rdx = BC_MAX(a->rdx, b->rdx);
1526 min_rdx = BC_MIN(a->rdx, b->rdx);
1529 if (a->rdx > b->rdx) {
1530 diff = a->rdx - b->rdx;
1532 ptr_a = a->num + diff;
1536 diff = b->rdx - a->rdx;
1539 ptr_b = b->num + diff;
1542 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1545 a_int = BC_NUM_INT(a);
1546 b_int = BC_NUM_INT(b);
1548 if (a_int > b_int) {
1559 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1560 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1562 ptr_c[i] = (BcDig)(in % 10);
1565 for (; i < max + min_rdx; ++i, ++c->len) {
1566 in = ((int) ptr[i]) + carry;
1568 ptr_c[i] = (BcDig)(in % 10);
1571 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1573 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1576 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1579 BcNum *minuend, *subtrahend;
1581 bool aneg, bneg, neg;
1583 // Because this function doesn't need to use scale (per the bc spec),
1584 // I am hijacking it to say whether it's doing an add or a subtract.
1588 if (sub && c->len) c->neg = !c->neg;
1589 return BC_STATUS_SUCCESS;
1591 else if (b->len == 0) {
1593 return BC_STATUS_SUCCESS;
1598 a->neg = b->neg = false;
1600 cmp = bc_num_cmp(a, b);
1606 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1607 return BC_STATUS_SUCCESS;
1616 if (sub) neg = !neg;
1621 bc_num_copy(c, minuend);
1624 if (c->rdx < subtrahend->rdx) {
1625 bc_num_extend(c, subtrahend->rdx - c->rdx);
1629 start = c->rdx - subtrahend->rdx;
1631 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1635 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1638 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1643 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1644 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1645 bool aone = BC_NUM_ONE(a);
1647 if (a->len == 0 || b->len == 0) {
1649 return BC_STATUS_SUCCESS;
1651 else if (aone || BC_NUM_ONE(b)) {
1652 bc_num_copy(c, aone ? b : a);
1653 return BC_STATUS_SUCCESS;
1656 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1657 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1659 bc_num_expand(c, a->len + b->len + 1);
1661 memset(c->num, 0, sizeof(BcDig) * c->cap);
1662 c->len = carry = len = 0;
1664 for (i = 0; i < b->len; ++i) {
1666 for (j = 0; j < a->len; ++j) {
1667 int in = (int) c->num[i + j];
1668 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1670 c->num[i + j] = (BcDig)(in % 10);
1673 c->num[i + j] += (BcDig) carry;
1674 len = BC_MAX(len, i + j + !!carry);
1680 return BC_STATUS_SUCCESS;
1683 bc_num_init(&l1, max);
1684 bc_num_init(&h1, max);
1685 bc_num_init(&l2, max);
1686 bc_num_init(&h2, max);
1687 bc_num_init(&m1, max);
1688 bc_num_init(&m2, max);
1689 bc_num_init(&z0, max);
1690 bc_num_init(&z1, max);
1691 bc_num_init(&z2, max);
1692 bc_num_init(&temp, max + max);
1694 bc_num_split(a, max2, &l1, &h1);
1695 bc_num_split(b, max2, &l2, &h2);
1697 s = bc_num_add(&h1, &l1, &m1, 0);
1699 s = bc_num_add(&h2, &l2, &m2, 0);
1702 s = bc_num_k(&h1, &h2, &z0);
1704 s = bc_num_k(&m1, &m2, &z1);
1706 s = bc_num_k(&l1, &l2, &z2);
1709 s = bc_num_sub(&z1, &z0, &temp, 0);
1711 s = bc_num_sub(&temp, &z2, &z1, 0);
1714 s = bc_num_shift(&z0, max2 * 2);
1716 s = bc_num_shift(&z1, max2);
1718 s = bc_num_add(&z0, &z1, &temp, 0);
1720 s = bc_num_add(&temp, &z2, c, 0);
1736 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1740 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1742 scale = BC_MAX(scale, a->rdx);
1743 scale = BC_MAX(scale, b->rdx);
1744 scale = BC_MIN(a->rdx + b->rdx, scale);
1745 maxrdx = BC_MAX(maxrdx, scale);
1747 bc_num_init(&cpa, a->len);
1748 bc_num_init(&cpb, b->len);
1750 bc_num_copy(&cpa, a);
1751 bc_num_copy(&cpb, b);
1752 cpa.neg = cpb.neg = false;
1754 s = bc_num_shift(&cpa, maxrdx);
1756 s = bc_num_shift(&cpb, maxrdx);
1758 s = bc_num_k(&cpa, &cpb, c);
1762 bc_num_expand(c, c->len + maxrdx);
1764 if (c->len < maxrdx) {
1765 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1770 bc_num_retireMul(c, scale, a->neg, b->neg);
1778 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1780 BcStatus s = BC_STATUS_SUCCESS;
1787 return bc_error("divide by zero");
1788 else if (a->len == 0) {
1789 bc_num_setToZero(c, scale);
1790 return BC_STATUS_SUCCESS;
1792 else if (BC_NUM_ONE(b)) {
1794 bc_num_retireMul(c, scale, a->neg, b->neg);
1795 return BC_STATUS_SUCCESS;
1798 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1799 bc_num_copy(&cp, a);
1803 bc_num_expand(&cp, len + 2);
1804 bc_num_extend(&cp, len - cp.len);
1807 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1809 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1811 if (b->rdx == b->len) {
1812 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1816 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1818 // We want an extra zero in front to make things simpler.
1819 cp.num[cp.len++] = 0;
1822 bc_num_expand(c, cp.len);
1825 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1830 for (i = end - 1; !s && i < end; --i) {
1832 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1833 bc_num_subArrays(n, p, len);
1837 bc_num_retireMul(c, scale, a->neg, b->neg);
1840 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1843 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1844 BcNum *restrict d, size_t scale, size_t ts)
1851 return bc_error("divide by zero");
1854 bc_num_setToZero(d, ts);
1855 return BC_STATUS_SUCCESS;
1858 bc_num_init(&temp, d->cap);
1859 bc_num_d(a, b, c, scale);
1861 if (scale != 0) scale = ts;
1863 s = bc_num_m(c, b, &temp, scale);
1865 s = bc_num_sub(a, &temp, d, scale);
1868 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1871 bc_num_retireMul(d, ts, a->neg, b->neg);
1879 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1883 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1885 bc_num_init(&c1, len);
1886 s = bc_num_r(a, b, &c1, c, scale, ts);
1892 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1894 BcStatus s = BC_STATUS_SUCCESS;
1897 size_t i, powrdx, resrdx;
1900 if (b->rdx) return bc_error("non integer number");
1904 return BC_STATUS_SUCCESS;
1906 else if (a->len == 0) {
1907 bc_num_setToZero(c, scale);
1908 return BC_STATUS_SUCCESS;
1910 else if (BC_NUM_ONE(b)) {
1914 s = bc_num_inv(a, c, scale);
1921 s = bc_num_ulong(b, &pow);
1924 bc_num_init(©, a->len);
1925 bc_num_copy(©, a);
1927 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1931 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1933 s = bc_num_mul(©, ©, ©, powrdx);
1935 // It is too slow to handle ^C only after entire "2^1000000" completes
1937 s = BC_STATUS_FAILURE;
1942 bc_num_copy(c, ©);
1944 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1947 s = bc_num_mul(©, ©, ©, powrdx);
1952 s = bc_num_mul(c, ©, c, resrdx);
1955 // It is too slow to handle ^C only after entire "2^1000000" completes
1957 s = BC_STATUS_FAILURE;
1963 s = bc_num_inv(c, c, scale);
1967 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1969 // We can't use bc_num_clean() here.
1970 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1971 if (zero) bc_num_setToZero(c, scale);
1978 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1979 BcNumBinaryOp op, size_t req)
1982 BcNum num2, *ptr_a, *ptr_b;
1987 memcpy(ptr_a, c, sizeof(BcNum));
1996 memcpy(ptr_b, c, sizeof(BcNum));
2004 bc_num_init(c, req);
2006 bc_num_expand(c, req);
2008 s = op(ptr_a, ptr_b, c, scale);
2010 if (init) bc_num_free(&num2);
2015 static bool bc_num_strValid(const char *val, size_t base)
2018 bool small, radix = false;
2019 size_t i, len = strlen(val);
2021 if (!len) return true;
2024 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2026 for (i = 0; i < len; ++i) {
2032 if (radix) return false;
2038 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2045 static void bc_num_parseDecimal(BcNum *n, const char *val)
2051 for (i = 0; val[i] == '0'; ++i);
2058 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2059 bc_num_expand(n, len);
2062 ptr = strchr(val, '.');
2066 n->rdx = (size_t)((val + len) - (ptr + 1));
2069 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2070 n->num[n->len] = val[i] - '0';
2074 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2077 BcNum temp, mult, result;
2081 size_t i, digits, len = strlen(val);
2085 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2088 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2089 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2091 for (i = 0; i < len; ++i) {
2094 if (c == '.') break;
2096 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2098 s = bc_num_mul(n, base, &mult, 0);
2099 if (s) goto int_err;
2100 bc_num_ulong2num(&temp, v);
2101 s = bc_num_add(&mult, &temp, n, 0);
2102 if (s) goto int_err;
2107 if (c == 0) goto int_err;
2110 bc_num_init(&result, base->len);
2111 bc_num_zero(&result);
2114 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2119 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2121 s = bc_num_mul(&result, base, &result, 0);
2123 bc_num_ulong2num(&temp, v);
2124 s = bc_num_add(&result, &temp, &result, 0);
2126 s = bc_num_mul(&mult, base, &mult, 0);
2130 s = bc_num_div(&result, &mult, &result, digits);
2132 s = bc_num_add(n, &result, n, digits);
2136 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2142 bc_num_free(&result);
2148 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2150 if (*nchars == line_len - 1) {
2158 static void bc_num_printChar(size_t num, size_t width, bool radix,
2159 size_t *nchars, size_t line_len)
2161 (void) radix, (void) line_len;
2162 bb_putchar((char) num);
2163 *nchars = *nchars + width;
2167 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2168 size_t *nchars, size_t line_len)
2172 bc_num_printNewline(nchars, line_len);
2173 bb_putchar(radix ? '.' : ' ');
2176 bc_num_printNewline(nchars, line_len);
2177 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2180 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2182 bc_num_printNewline(nchars, line_len);
2185 bb_putchar(((char) dig) + '0');
2189 static void bc_num_printHex(size_t num, size_t width, bool radix,
2190 size_t *nchars, size_t line_len)
2193 bc_num_printNewline(nchars, line_len);
2198 bc_num_printNewline(nchars, line_len);
2199 bb_putchar(bb_hexdigits_upcase[num]);
2200 *nchars = *nchars + width;
2203 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2205 size_t i, rdx = n->rdx - 1;
2207 if (n->neg) bb_putchar('-');
2208 (*nchars) += n->neg;
2210 for (i = n->len - 1; i < n->len; --i)
2211 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2214 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2215 size_t *nchars, size_t len, BcNumDigitOp print)
2219 BcNum intp, fracp, digit, frac_len;
2220 unsigned long dig, *ptr;
2225 print(0, width, false, nchars, len);
2226 return BC_STATUS_SUCCESS;
2229 bc_vec_init(&stack, sizeof(long), NULL);
2230 bc_num_init(&intp, n->len);
2231 bc_num_init(&fracp, n->rdx);
2232 bc_num_init(&digit, width);
2233 bc_num_init(&frac_len, BC_NUM_INT(n));
2234 bc_num_copy(&intp, n);
2235 bc_num_one(&frac_len);
2237 bc_num_truncate(&intp, intp.rdx);
2238 s = bc_num_sub(n, &intp, &fracp, 0);
2241 while (intp.len != 0) {
2242 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2244 s = bc_num_ulong(&digit, &dig);
2246 bc_vec_push(&stack, &dig);
2249 for (i = 0; i < stack.len; ++i) {
2250 ptr = bc_vec_item_rev(&stack, i);
2251 print(*ptr, width, false, nchars, len);
2254 if (!n->rdx) goto err;
2256 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2257 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2259 s = bc_num_ulong(&fracp, &dig);
2261 bc_num_ulong2num(&intp, dig);
2262 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2264 print(dig, width, radix, nchars, len);
2265 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2270 bc_num_free(&frac_len);
2271 bc_num_free(&digit);
2272 bc_num_free(&fracp);
2274 bc_vec_free(&stack);
2278 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2279 size_t *nchars, size_t line_len)
2286 if (neg) bb_putchar('-');
2291 if (base_t <= BC_NUM_MAX_IBASE) {
2293 print = bc_num_printHex;
2296 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2297 print = bc_num_printDigits;
2300 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2307 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2309 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2313 static void bc_num_init(BcNum *n, size_t req)
2315 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2316 memset(n, 0, sizeof(BcNum));
2317 n->num = xmalloc(req);
2321 static void bc_num_expand(BcNum *n, size_t req)
2323 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2325 n->num = xrealloc(n->num, req);
2330 static void bc_num_free(void *num)
2332 free(((BcNum *) num)->num);
2335 static void bc_num_copy(BcNum *d, BcNum *s)
2338 bc_num_expand(d, s->cap);
2342 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2346 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2349 if (!bc_num_strValid(val, base_t))
2350 return bc_error("bad number string");
2353 bc_num_parseDecimal(n, val);
2355 bc_num_parseBase(n, val, base);
2357 return BC_STATUS_SUCCESS;
2360 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2361 size_t *nchars, size_t line_len)
2363 BcStatus s = BC_STATUS_SUCCESS;
2365 bc_num_printNewline(nchars, line_len);
2371 else if (base_t == 10)
2372 bc_num_printDecimal(n, nchars, line_len);
2374 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2384 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2389 if (n->neg) return bc_error("negative number");
2391 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2393 unsigned long prev = *result, powprev = pow;
2395 *result += ((unsigned long) n->num[i]) * pow;
2398 if (*result < prev || pow < powprev)
2399 return bc_error("overflow");
2402 return BC_STATUS_SUCCESS;
2405 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2413 if (val == 0) return;
2415 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2416 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2419 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2421 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2423 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2426 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2428 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2430 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2433 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2435 size_t req = BC_NUM_MREQ(a, b, scale);
2436 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2439 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2441 size_t req = BC_NUM_MREQ(a, b, scale);
2442 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2445 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2447 size_t req = BC_NUM_MREQ(a, b, scale);
2448 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2451 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2453 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2456 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2459 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2460 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2461 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2463 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2464 bc_num_expand(b, req);
2467 bc_num_setToZero(b, scale);
2468 return BC_STATUS_SUCCESS;
2471 return bc_error("negative number");
2472 else if (BC_NUM_ONE(a)) {
2474 bc_num_extend(b, scale);
2475 return BC_STATUS_SUCCESS;
2478 scale = BC_MAX(scale, a->rdx) + 1;
2479 len = a->len + scale;
2481 bc_num_init(&num1, len);
2482 bc_num_init(&num2, len);
2483 bc_num_init(&half, BC_NUM_DEF_SIZE);
2489 bc_num_init(&f, len);
2490 bc_num_init(&fprime, len);
2496 pow = BC_NUM_INT(a);
2505 pow -= 2 - (pow & 1);
2507 bc_num_extend(x0, pow);
2509 // Make sure to move the radix back.
2513 x0->rdx = digs = digs1 = 0;
2515 len = BC_NUM_INT(x0) + resrdx - 1;
2517 while (cmp != 0 || digs < len) {
2519 s = bc_num_div(a, x0, &f, resrdx);
2521 s = bc_num_add(x0, &f, &fprime, resrdx);
2523 s = bc_num_mul(&fprime, &half, x1, resrdx);
2526 cmp = bc_num_cmp(x1, x0);
2527 digs = x1->len - (unsigned long long) llabs(cmp);
2529 if (cmp == cmp2 && digs == digs1)
2534 resrdx += times > 4;
2547 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2550 bc_num_free(&fprime);
2558 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2564 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2567 memcpy(&num2, c, sizeof(BcNum));
2569 bc_num_init(c, len);
2574 bc_num_expand(c, len);
2577 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2579 if (init) bc_num_free(&num2);
2585 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2588 BcNum base, exp, two, temp;
2591 return bc_error("divide by zero");
2592 if (a->rdx || b->rdx || c->rdx)
2593 return bc_error("non integer number");
2595 return bc_error("negative number");
2597 bc_num_expand(d, c->len);
2598 bc_num_init(&base, c->len);
2599 bc_num_init(&exp, b->len);
2600 bc_num_init(&two, BC_NUM_DEF_SIZE);
2601 bc_num_init(&temp, b->len);
2607 s = bc_num_rem(a, c, &base, 0);
2609 bc_num_copy(&exp, b);
2611 while (exp.len != 0) {
2613 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2616 if (BC_NUM_ONE(&temp)) {
2617 s = bc_num_mul(d, &base, &temp, 0);
2619 s = bc_num_rem(&temp, c, d, 0);
2623 s = bc_num_mul(&base, &base, &temp, 0);
2625 s = bc_num_rem(&temp, c, &base, 0);
2638 static int bc_id_cmp(const void *e1, const void *e2)
2640 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2643 static void bc_id_free(void *id)
2645 free(((BcId *) id)->name);
2648 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2653 for (i = 0; i < f->autos.len; ++i) {
2654 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2655 return bc_error("function parameter or auto var has the same name as another");
2661 bc_vec_push(&f->autos, &a);
2663 return BC_STATUS_SUCCESS;
2666 static void bc_func_init(BcFunc *f)
2668 bc_char_vec_init(&f->code);
2669 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2670 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2674 static void bc_func_free(void *func)
2676 BcFunc *f = (BcFunc *) func;
2677 bc_vec_free(&f->code);
2678 bc_vec_free(&f->autos);
2679 bc_vec_free(&f->labels);
2682 static void bc_array_init(BcVec *a, bool nums)
2685 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2687 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2688 bc_array_expand(a, 1);
2691 static void bc_array_copy(BcVec *d, const BcVec *s)
2696 bc_vec_expand(d, s->cap);
2699 for (i = 0; i < s->len; ++i) {
2700 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2701 bc_num_init(dnum, snum->len);
2702 bc_num_copy(dnum, snum);
2706 static void bc_array_expand(BcVec *a, size_t len)
2710 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2711 while (len > a->len) {
2712 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2713 bc_vec_push(a, &data.n);
2717 while (len > a->len) {
2718 bc_array_init(&data.v, true);
2719 bc_vec_push(a, &data.v);
2724 static void bc_string_free(void *string)
2726 free(*((char **) string));
2730 static void bc_result_copy(BcResult *d, BcResult *src)
2736 case BC_RESULT_TEMP:
2737 case BC_RESULT_IBASE:
2738 case BC_RESULT_SCALE:
2739 case BC_RESULT_OBASE:
2741 bc_num_init(&d->d.n, src->d.n.len);
2742 bc_num_copy(&d->d.n, &src->d.n);
2747 case BC_RESULT_ARRAY:
2748 case BC_RESULT_ARRAY_ELEM:
2750 d->d.id.name = xstrdup(src->d.id.name);
2754 case BC_RESULT_CONSTANT:
2755 case BC_RESULT_LAST:
2759 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2766 static void bc_result_free(void *result)
2768 BcResult *r = (BcResult *) result;
2772 case BC_RESULT_TEMP:
2773 case BC_RESULT_IBASE:
2774 case BC_RESULT_SCALE:
2775 case BC_RESULT_OBASE:
2777 bc_num_free(&r->d.n);
2782 case BC_RESULT_ARRAY:
2783 case BC_RESULT_ARRAY_ELEM:
2797 static void bc_lex_lineComment(BcLex *l)
2799 l->t.t = BC_LEX_WHITESPACE;
2800 while (l->i < l->len && l->buf[l->i++] != '\n');
2804 static void bc_lex_whitespace(BcLex *l)
2807 l->t.t = BC_LEX_WHITESPACE;
2808 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2811 static BcStatus bc_lex_number(BcLex *l, char start)
2813 const char *buf = l->buf + l->i;
2814 size_t len, hits = 0, bslashes = 0, i = 0, j;
2816 bool last_pt, pt = start == '.';
2819 l->t.t = BC_LEX_NUMBER;
2821 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2822 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2836 len = i + !last_pt - bslashes * 2;
2837 if (len > BC_MAX_NUM)
2838 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2840 bc_vec_pop_all(&l->t.v);
2841 bc_vec_expand(&l->t.v, len + 1);
2842 bc_vec_push(&l->t.v, &start);
2844 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2848 // If we have hit a backslash, skip it. We don't have
2849 // to check for a newline because it's guaranteed.
2850 if (hits < bslashes && c == '\\') {
2856 bc_vec_push(&l->t.v, &c);
2859 bc_vec_pushZeroByte(&l->t.v);
2862 return BC_STATUS_SUCCESS;
2865 static BcStatus bc_lex_name(BcLex *l)
2868 const char *buf = l->buf + l->i - 1;
2871 l->t.t = BC_LEX_NAME;
2873 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2875 if (i > BC_MAX_STRING)
2876 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2877 bc_vec_string(&l->t.v, i, buf);
2879 // Increment the index. We minus 1 because it has already been incremented.
2882 return BC_STATUS_SUCCESS;
2885 static void bc_lex_init(BcLex *l, BcLexNext next)
2888 bc_char_vec_init(&l->t.v);
2891 static void bc_lex_free(BcLex *l)
2893 bc_vec_free(&l->t.v);
2896 static void bc_lex_file(BcLex *l)
2898 G.err_line = l->line = 1;
2902 static BcStatus bc_lex_next(BcLex *l)
2907 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2909 l->line += l->newline;
2910 G.err_line = l->line;
2911 l->t.t = BC_LEX_EOF;
2913 l->newline = (l->i == l->len);
2914 if (l->newline) return BC_STATUS_SUCCESS;
2916 // Loop until failure or we don't have whitespace. This
2917 // is so the parser doesn't get inundated with whitespace.
2920 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2925 static BcStatus bc_lex_text(BcLex *l, const char *text)
2929 l->len = strlen(text);
2930 l->t.t = l->t.last = BC_LEX_INVALID;
2931 return bc_lex_next(l);
2935 static BcStatus bc_lex_identifier(BcLex *l)
2939 const char *buf = l->buf + l->i - 1;
2941 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2942 const char *keyword8 = bc_lex_kws[i].name8;
2944 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2946 if (j == 8) goto match;
2948 if (keyword8[j] != '\0')
2951 // buf starts with keyword bc_lex_kws[i]
2952 l->t.t = BC_LEX_KEY_1st_keyword + i;
2953 if (!((1 << i) & POSIX_KWORD_MASK)) {
2954 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
2958 // We minus 1 because the index has already been incremented.
2960 return BC_STATUS_SUCCESS;
2966 if (l->t.v.len > 2) {
2969 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
2971 unsigned len = strchrnul(buf, '\n') - buf;
2972 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
2978 static BcStatus bc_lex_string(BcLex *l)
2980 size_t len, nls = 0, i = l->i;
2983 l->t.t = BC_LEX_STR;
2985 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2989 return bc_error("string end could not be found");
2993 if (len > BC_MAX_STRING)
2994 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2995 bc_vec_string(&l->t.v, len, l->buf + l->i);
2999 G.err_line = l->line;
3001 return BC_STATUS_SUCCESS;
3004 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3006 if (l->buf[l->i] == '=') {
3014 static BcStatus bc_lex_comment(BcLex *l)
3017 const char *buf = l->buf;
3019 l->t.t = BC_LEX_WHITESPACE;
3032 return bc_error("comment end could not be found");
3040 G.err_line = l->line;
3042 return BC_STATUS_SUCCESS;
3045 static BcStatus bc_lex_token(BcLex *l)
3047 BcStatus s = BC_STATUS_SUCCESS;
3048 char c = l->buf[l->i++], c2;
3050 // This is the workhorse of the lexer.
3057 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3067 bc_lex_whitespace(l);
3073 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3075 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3076 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3085 s = bc_lex_string(l);
3091 s = bc_POSIX_does_not_allow("'#' script comments");
3094 bc_lex_lineComment(l);
3101 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3110 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3114 l->t.t = BC_LEX_OP_BOOL_AND;
3117 l->t.t = BC_LEX_INVALID;
3118 s = bc_error_bad_character('&');
3127 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3133 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3142 l->t.t = BC_LEX_OP_INC;
3145 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3151 l->t.t = BC_LEX_COMMA;
3160 l->t.t = BC_LEX_OP_DEC;
3163 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3169 if (isdigit(l->buf[l->i]))
3170 s = bc_lex_number(l, c);
3172 l->t.t = BC_LEX_KEY_LAST;
3173 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
3182 s = bc_lex_comment(l);
3184 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3205 s = bc_lex_number(l, c);
3211 l->t.t = BC_LEX_SCOLON;
3217 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3223 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3229 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3236 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3242 if (l->buf[l->i] == '\n') {
3243 l->t.t = BC_LEX_WHITESPACE;
3247 s = bc_error_bad_character(c);
3253 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3284 s = bc_lex_identifier(l);
3291 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3300 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3304 l->t.t = BC_LEX_OP_BOOL_OR;
3307 l->t.t = BC_LEX_INVALID;
3308 s = bc_error_bad_character(c);
3316 l->t.t = BC_LEX_INVALID;
3317 s = bc_error_bad_character(c);
3327 static BcStatus dc_lex_register(BcLex *l)
3329 BcStatus s = BC_STATUS_SUCCESS;
3331 if (isspace(l->buf[l->i - 1])) {
3332 bc_lex_whitespace(l);
3335 s = bc_error("extended register");
3340 bc_vec_pop_all(&l->t.v);
3341 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3342 bc_vec_pushZeroByte(&l->t.v);
3343 l->t.t = BC_LEX_NAME;
3349 static BcStatus dc_lex_string(BcLex *l)
3351 size_t depth = 1, nls = 0, i = l->i;
3354 l->t.t = BC_LEX_STR;
3355 bc_vec_pop_all(&l->t.v);
3357 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3359 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3360 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3363 if (depth) bc_vec_push(&l->t.v, &c);
3368 return bc_error("string end could not be found");
3371 bc_vec_pushZeroByte(&l->t.v);
3372 if (i - l->i > BC_MAX_STRING)
3373 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3377 G.err_line = l->line;
3379 return BC_STATUS_SUCCESS;
3382 static BcStatus dc_lex_token(BcLex *l)
3384 BcStatus s = BC_STATUS_SUCCESS;
3385 char c = l->buf[l->i++], c2;
3388 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3389 if (l->t.last == dc_lex_regs[i])
3390 return dc_lex_register(l);
3393 if (c >= '%' && c <= '~' &&
3394 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3399 // This is the workhorse of the lexer.
3404 l->t.t = BC_LEX_EOF;
3415 l->newline = (c == '\n');
3416 bc_lex_whitespace(l);
3425 l->t.t = BC_LEX_OP_REL_NE;
3427 l->t.t = BC_LEX_OP_REL_LE;
3429 l->t.t = BC_LEX_OP_REL_GE;
3431 return bc_error_bad_character(c);
3439 bc_lex_lineComment(l);
3445 if (isdigit(l->buf[l->i]))
3446 s = bc_lex_number(l, c);
3448 s = bc_error_bad_character(c);
3469 s = bc_lex_number(l, c);
3475 s = dc_lex_string(l);
3481 l->t.t = BC_LEX_INVALID;
3482 s = bc_error_bad_character(c);
3491 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3493 bc_program_addFunc(name, idx);
3494 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3497 static void bc_parse_pushName(BcParse *p, char *name)
3499 size_t i = 0, len = strlen(name);
3501 for (; i < len; ++i) bc_parse_push(p, name[i]);
3502 bc_parse_push(p, BC_PARSE_STREND);
3507 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3509 unsigned char amt, i, nums[sizeof(size_t)];
3511 for (amt = 0; idx; ++amt) {
3512 nums[amt] = (char) idx;
3513 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3516 bc_parse_push(p, amt);
3517 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3520 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3522 char *num = xstrdup(p->l.t.v.v);
3523 size_t idx = G.prog.consts.len;
3525 bc_vec_push(&G.prog.consts, &num);
3527 bc_parse_push(p, BC_INST_NUM);
3528 bc_parse_pushIndex(p, idx);
3531 (*prev) = BC_INST_NUM;
3534 static BcStatus bc_parse_text(BcParse *p, const char *text)
3538 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3540 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3541 p->l.t.t = BC_LEX_INVALID;
3544 if (!BC_PARSE_CAN_EXEC(p))
3545 return bc_error("file is not executable");
3548 return bc_lex_text(&p->l, text);
3551 // Called when bc/dc_parse_parse() detects a failure,
3552 // resets parsing structures.
3553 static void bc_parse_reset(BcParse *p)
3555 if (p->fidx != BC_PROG_MAIN) {
3556 p->func->nparams = 0;
3557 bc_vec_pop_all(&p->func->code);
3558 bc_vec_pop_all(&p->func->autos);
3559 bc_vec_pop_all(&p->func->labels);
3561 bc_parse_updateFunc(p, BC_PROG_MAIN);
3565 p->l.t.t = BC_LEX_EOF;
3566 p->auto_part = (p->nbraces = 0);
3568 bc_vec_npop(&p->flags, p->flags.len - 1);
3569 bc_vec_pop_all(&p->exits);
3570 bc_vec_pop_all(&p->conds);
3571 bc_vec_pop_all(&p->ops);
3576 static void bc_parse_free(BcParse *p)
3578 bc_vec_free(&p->flags);
3579 bc_vec_free(&p->exits);
3580 bc_vec_free(&p->conds);
3581 bc_vec_free(&p->ops);
3585 static void bc_parse_create(BcParse *p, size_t func,
3586 BcParseParse parse, BcLexNext next)
3588 memset(p, 0, sizeof(BcParse));
3590 bc_lex_init(&p->l, next);
3591 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3592 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3593 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3594 bc_vec_pushZeroByte(&p->flags);
3595 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3598 // p->auto_part = p->nbraces = 0; - already is
3599 bc_parse_updateFunc(p, func);
3603 static BcStatus bc_parse_else(BcParse *p);
3604 static BcStatus bc_parse_stmt(BcParse *p);
3606 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3607 size_t *nexprs, bool next)
3609 BcStatus s = BC_STATUS_SUCCESS;
3611 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3612 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3614 while (p->ops.len > start) {
3616 t = BC_PARSE_TOP_OP(p);
3617 if (t == BC_LEX_LPAREN) break;
3619 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3620 if (l >= r && (l != r || !left)) break;
3622 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3623 bc_vec_pop(&p->ops);
3624 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3627 bc_vec_push(&p->ops, &type);
3628 if (next) s = bc_lex_next(&p->l);
3633 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3637 if (p->ops.len <= ops_bgn)
3638 return bc_error_bad_expression();
3639 top = BC_PARSE_TOP_OP(p);
3641 while (top != BC_LEX_LPAREN) {
3643 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3645 bc_vec_pop(&p->ops);
3646 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3648 if (p->ops.len <= ops_bgn)
3649 return bc_error_bad_expression();
3650 top = BC_PARSE_TOP_OP(p);
3653 bc_vec_pop(&p->ops);
3655 return bc_lex_next(&p->l);
3658 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3664 s = bc_lex_next(&p->l);
3667 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3669 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3670 s = bc_parse_expr(p, flags, bc_parse_next_param);
3673 comma = p->l.t.t == BC_LEX_COMMA;
3675 s = bc_lex_next(&p->l);
3680 if (comma) return bc_error_bad_token();
3681 bc_parse_push(p, BC_INST_CALL);
3682 bc_parse_pushIndex(p, nparams);
3684 return BC_STATUS_SUCCESS;
3687 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3690 BcId entry, *entry_ptr;
3695 s = bc_parse_params(p, flags);
3698 if (p->l.t.t != BC_LEX_RPAREN) {
3699 s = bc_error_bad_token();
3703 idx = bc_map_index(&G.prog.fn_map, &entry);
3705 if (idx == BC_VEC_INVALID_IDX) {
3706 name = xstrdup(entry.name);
3707 bc_parse_addFunc(p, name, &idx);
3708 idx = bc_map_index(&G.prog.fn_map, &entry);
3714 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3715 bc_parse_pushIndex(p, entry_ptr->idx);
3717 return bc_lex_next(&p->l);
3724 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3729 name = xstrdup(p->l.t.v.v);
3730 s = bc_lex_next(&p->l);
3733 if (p->l.t.t == BC_LEX_LBRACKET) {
3735 s = bc_lex_next(&p->l);
3738 if (p->l.t.t == BC_LEX_RBRACKET) {
3740 if (!(flags & BC_PARSE_ARRAY)) {
3741 s = bc_error_bad_expression();
3745 *type = BC_INST_ARRAY;
3749 *type = BC_INST_ARRAY_ELEM;
3751 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3752 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3756 s = bc_lex_next(&p->l);
3758 bc_parse_push(p, *type);
3759 bc_parse_pushName(p, name);
3761 else if (p->l.t.t == BC_LEX_LPAREN) {
3763 if (flags & BC_PARSE_NOCALL) {
3764 s = bc_error_bad_token();
3768 *type = BC_INST_CALL;
3769 s = bc_parse_call(p, name, flags);
3772 *type = BC_INST_VAR;
3773 bc_parse_push(p, BC_INST_VAR);
3774 bc_parse_pushName(p, name);
3784 static BcStatus bc_parse_read(BcParse *p)
3788 s = bc_lex_next(&p->l);
3790 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3792 s = bc_lex_next(&p->l);
3794 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3796 bc_parse_push(p, BC_INST_READ);
3798 return bc_lex_next(&p->l);
3801 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3806 s = bc_lex_next(&p->l);
3808 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3810 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3812 s = bc_lex_next(&p->l);
3815 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3818 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3820 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3821 bc_parse_push(p, *prev);
3823 return bc_lex_next(&p->l);
3826 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3830 s = bc_lex_next(&p->l);
3833 if (p->l.t.t != BC_LEX_LPAREN) {
3834 *type = BC_INST_SCALE;
3835 bc_parse_push(p, BC_INST_SCALE);
3836 return BC_STATUS_SUCCESS;
3839 *type = BC_INST_SCALE_FUNC;
3840 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3842 s = bc_lex_next(&p->l);
3845 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3847 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3848 bc_parse_push(p, BC_INST_SCALE_FUNC);
3850 return bc_lex_next(&p->l);
3853 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3854 size_t *nexprs, uint8_t flags)
3859 BcInst etype = *prev;
3861 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3862 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3863 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3865 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3866 bc_parse_push(p, inst);
3867 s = bc_lex_next(&p->l);
3871 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3874 s = bc_lex_next(&p->l);
3878 // Because we parse the next part of the expression
3879 // right here, we need to increment this.
3880 *nexprs = *nexprs + 1;
3886 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3890 case BC_LEX_KEY_IBASE:
3891 case BC_LEX_KEY_LAST:
3892 case BC_LEX_KEY_OBASE:
3894 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3895 s = bc_lex_next(&p->l);
3899 case BC_LEX_KEY_SCALE:
3901 s = bc_lex_next(&p->l);
3903 if (p->l.t.t == BC_LEX_LPAREN)
3904 s = bc_error_bad_token();
3906 bc_parse_push(p, BC_INST_SCALE);
3912 s = bc_error_bad_token();
3917 if (!s) bc_parse_push(p, inst);
3923 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3924 bool rparen, size_t *nexprs)
3928 BcInst etype = *prev;
3930 s = bc_lex_next(&p->l);
3933 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3934 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3937 *prev = BC_PARSE_TOKEN_INST(type);
3939 // We can just push onto the op stack because this is the largest
3940 // precedence operator that gets pushed. Inc/dec does not.
3941 if (type != BC_LEX_OP_MINUS)
3942 bc_vec_push(&p->ops, &type);
3944 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3949 static BcStatus bc_parse_string(BcParse *p, char inst)
3951 char *str = xstrdup(p->l.t.v.v);
3953 bc_parse_push(p, BC_INST_STR);
3954 bc_parse_pushIndex(p, G.prog.strs.len);
3955 bc_vec_push(&G.prog.strs, &str);
3956 bc_parse_push(p, inst);
3958 return bc_lex_next(&p->l);
3961 static BcStatus bc_parse_print(BcParse *p)
3967 s = bc_lex_next(&p->l);
3972 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3973 return bc_error("bad print statement");
3975 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3977 if (type == BC_LEX_STR)
3978 s = bc_parse_string(p, BC_INST_PRINT_POP);
3980 s = bc_parse_expr(p, 0, bc_parse_next_print);
3982 bc_parse_push(p, BC_INST_PRINT_POP);
3987 comma = p->l.t.t == BC_LEX_COMMA;
3988 if (comma) s = bc_lex_next(&p->l);
3993 if (comma) return bc_error_bad_token();
3995 return bc_lex_next(&p->l);
3998 static BcStatus bc_parse_return(BcParse *p)
4004 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
4006 s = bc_lex_next(&p->l);
4010 paren = t == BC_LEX_LPAREN;
4012 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4013 bc_parse_push(p, BC_INST_RET0);
4016 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4017 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4020 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4021 bc_parse_push(p, BC_INST_RET0);
4022 s = bc_lex_next(&p->l);
4026 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4027 s = bc_posix_error("POSIX requires parentheses around return expressions");
4031 bc_parse_push(p, BC_INST_RET);
4037 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4039 BcStatus s = BC_STATUS_SUCCESS;
4041 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4042 return bc_error_bad_token();
4046 if (p->l.t.t == BC_LEX_RBRACE) {
4047 if (!p->nbraces) return bc_error_bad_token();
4049 s = bc_lex_next(&p->l);
4053 return bc_error_bad_token();
4056 if (BC_PARSE_IF(p)) {
4060 while (p->l.t.t == BC_LEX_NLINE) {
4061 s = bc_lex_next(&p->l);
4065 bc_vec_pop(&p->flags);
4067 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4068 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4070 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4072 else if (BC_PARSE_ELSE(p)) {
4077 bc_vec_pop(&p->flags);
4079 ip = bc_vec_top(&p->exits);
4080 label = bc_vec_item(&p->func->labels, ip->idx);
4081 *label = p->func->code.len;
4083 bc_vec_pop(&p->exits);
4085 else if (BC_PARSE_FUNC_INNER(p)) {
4086 bc_parse_push(p, BC_INST_RET0);
4087 bc_parse_updateFunc(p, BC_PROG_MAIN);
4088 bc_vec_pop(&p->flags);
4092 BcInstPtr *ip = bc_vec_top(&p->exits);
4093 size_t *label = bc_vec_top(&p->conds);
4095 bc_parse_push(p, BC_INST_JUMP);
4096 bc_parse_pushIndex(p, *label);
4098 label = bc_vec_item(&p->func->labels, ip->idx);
4099 *label = p->func->code.len;
4101 bc_vec_pop(&p->flags);
4102 bc_vec_pop(&p->exits);
4103 bc_vec_pop(&p->conds);
4109 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4111 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4112 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4113 flags |= BC_PARSE_FLAG_BODY;
4114 bc_vec_push(&p->flags, &flags);
4117 static void bc_parse_noElse(BcParse *p)
4121 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4123 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4125 ip = bc_vec_top(&p->exits);
4126 label = bc_vec_item(&p->func->labels, ip->idx);
4127 *label = p->func->code.len;
4129 bc_vec_pop(&p->exits);
4132 static BcStatus bc_parse_if(BcParse *p)
4137 s = bc_lex_next(&p->l);
4139 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4141 s = bc_lex_next(&p->l);
4143 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4145 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4147 s = bc_lex_next(&p->l);
4149 bc_parse_push(p, BC_INST_JUMP_ZERO);
4151 ip.idx = p->func->labels.len;
4152 ip.func = ip.len = 0;
4154 bc_parse_pushIndex(p, ip.idx);
4155 bc_vec_push(&p->exits, &ip);
4156 bc_vec_push(&p->func->labels, &ip.idx);
4157 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4159 return BC_STATUS_SUCCESS;
4162 static BcStatus bc_parse_else(BcParse *p)
4166 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4168 ip.idx = p->func->labels.len;
4169 ip.func = ip.len = 0;
4171 bc_parse_push(p, BC_INST_JUMP);
4172 bc_parse_pushIndex(p, ip.idx);
4176 bc_vec_push(&p->exits, &ip);
4177 bc_vec_push(&p->func->labels, &ip.idx);
4178 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4180 return bc_lex_next(&p->l);
4183 static BcStatus bc_parse_while(BcParse *p)
4188 s = bc_lex_next(&p->l);
4190 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4191 s = bc_lex_next(&p->l);
4194 ip.idx = p->func->labels.len;
4196 bc_vec_push(&p->func->labels, &p->func->code.len);
4197 bc_vec_push(&p->conds, &ip.idx);
4199 ip.idx = p->func->labels.len;
4203 bc_vec_push(&p->exits, &ip);
4204 bc_vec_push(&p->func->labels, &ip.idx);
4206 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4208 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4209 s = bc_lex_next(&p->l);
4212 bc_parse_push(p, BC_INST_JUMP_ZERO);
4213 bc_parse_pushIndex(p, ip.idx);
4214 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4216 return BC_STATUS_SUCCESS;
4219 static BcStatus bc_parse_for(BcParse *p)
4223 size_t cond_idx, exit_idx, body_idx, update_idx;
4225 s = bc_lex_next(&p->l);
4227 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4228 s = bc_lex_next(&p->l);
4231 if (p->l.t.t != BC_LEX_SCOLON)
4232 s = bc_parse_expr(p, 0, bc_parse_next_for);
4234 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4237 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4238 s = bc_lex_next(&p->l);
4241 cond_idx = p->func->labels.len;
4242 update_idx = cond_idx + 1;
4243 body_idx = update_idx + 1;
4244 exit_idx = body_idx + 1;
4246 bc_vec_push(&p->func->labels, &p->func->code.len);
4248 if (p->l.t.t != BC_LEX_SCOLON)
4249 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4251 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4254 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4256 s = bc_lex_next(&p->l);
4259 bc_parse_push(p, BC_INST_JUMP_ZERO);
4260 bc_parse_pushIndex(p, exit_idx);
4261 bc_parse_push(p, BC_INST_JUMP);
4262 bc_parse_pushIndex(p, body_idx);
4264 ip.idx = p->func->labels.len;
4266 bc_vec_push(&p->conds, &update_idx);
4267 bc_vec_push(&p->func->labels, &p->func->code.len);
4269 if (p->l.t.t != BC_LEX_RPAREN)
4270 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4272 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4276 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4277 bc_parse_push(p, BC_INST_JUMP);
4278 bc_parse_pushIndex(p, cond_idx);
4279 bc_vec_push(&p->func->labels, &p->func->code.len);
4285 bc_vec_push(&p->exits, &ip);
4286 bc_vec_push(&p->func->labels, &ip.idx);
4288 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4290 return BC_STATUS_SUCCESS;
4293 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4299 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4301 if (type == BC_LEX_KEY_BREAK) {
4303 if (p->exits.len == 0) return bc_error_bad_token();
4305 i = p->exits.len - 1;
4306 ip = bc_vec_item(&p->exits, i);
4308 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4309 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4314 i = *((size_t *) bc_vec_top(&p->conds));
4316 bc_parse_push(p, BC_INST_JUMP);
4317 bc_parse_pushIndex(p, i);
4319 s = bc_lex_next(&p->l);
4322 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4323 return bc_error_bad_token();
4325 return bc_lex_next(&p->l);
4328 static BcStatus bc_parse_func(BcParse *p)
4331 bool var, comma = false;
4335 s = bc_lex_next(&p->l);
4337 if (p->l.t.t != BC_LEX_NAME)
4338 return bc_error("bad function definition");
4340 name = xstrdup(p->l.t.v.v);
4341 bc_parse_addFunc(p, name, &p->fidx);
4343 s = bc_lex_next(&p->l);
4345 if (p->l.t.t != BC_LEX_LPAREN)
4346 return bc_error("bad function definition");
4347 s = bc_lex_next(&p->l);
4350 while (p->l.t.t != BC_LEX_RPAREN) {
4352 if (p->l.t.t != BC_LEX_NAME)
4353 return bc_error("bad function definition");
4357 name = xstrdup(p->l.t.v.v);
4358 s = bc_lex_next(&p->l);
4361 var = p->l.t.t != BC_LEX_LBRACKET;
4365 s = bc_lex_next(&p->l);
4368 if (p->l.t.t != BC_LEX_RBRACKET) {
4369 s = bc_error("bad function definition");
4373 s = bc_lex_next(&p->l);
4377 comma = p->l.t.t == BC_LEX_COMMA;
4379 s = bc_lex_next(&p->l);
4383 s = bc_func_insert(p->func, name, var);
4387 if (comma) return bc_error("bad function definition");
4389 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4390 bc_parse_startBody(p, flags);
4392 s = bc_lex_next(&p->l);
4395 if (p->l.t.t != BC_LEX_LBRACE)
4396 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4405 static BcStatus bc_parse_auto(BcParse *p)
4408 bool comma, var, one;
4411 if (!p->auto_part) return bc_error_bad_token();
4412 s = bc_lex_next(&p->l);
4415 p->auto_part = comma = false;
4416 one = p->l.t.t == BC_LEX_NAME;
4418 while (p->l.t.t == BC_LEX_NAME) {
4420 name = xstrdup(p->l.t.v.v);
4421 s = bc_lex_next(&p->l);
4424 var = p->l.t.t != BC_LEX_LBRACKET;
4427 s = bc_lex_next(&p->l);
4430 if (p->l.t.t != BC_LEX_RBRACKET) {
4431 s = bc_error("bad function definition");
4435 s = bc_lex_next(&p->l);
4439 comma = p->l.t.t == BC_LEX_COMMA;
4441 s = bc_lex_next(&p->l);
4445 s = bc_func_insert(p->func, name, var);
4449 if (comma) return bc_error("bad function definition");
4450 if (!one) return bc_error("no auto variable found");
4452 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4453 return bc_error_bad_token();
4455 return bc_lex_next(&p->l);
4462 static BcStatus bc_parse_body(BcParse *p, bool brace)
4464 BcStatus s = BC_STATUS_SUCCESS;
4465 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4467 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4469 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4471 if (!brace) return bc_error_bad_token();
4472 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4474 if (!p->auto_part) {
4475 s = bc_parse_auto(p);
4479 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4482 s = bc_parse_stmt(p);
4483 if (!s && !brace) s = bc_parse_endBody(p, false);
4489 static BcStatus bc_parse_stmt(BcParse *p)
4491 BcStatus s = BC_STATUS_SUCCESS;
4497 return bc_lex_next(&p->l);
4500 case BC_LEX_KEY_ELSE:
4502 p->auto_part = false;
4508 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4511 s = bc_lex_next(&p->l);
4514 return bc_parse_body(p, true);
4517 case BC_LEX_KEY_AUTO:
4519 return bc_parse_auto(p);
4524 p->auto_part = false;
4526 if (BC_PARSE_IF_END(p)) {
4528 return BC_STATUS_SUCCESS;
4530 else if (BC_PARSE_BODY(p))
4531 return bc_parse_body(p, false);
4541 case BC_LEX_OP_MINUS:
4542 case BC_LEX_OP_BOOL_NOT:
4546 case BC_LEX_KEY_IBASE:
4547 case BC_LEX_KEY_LAST:
4548 case BC_LEX_KEY_LENGTH:
4549 case BC_LEX_KEY_OBASE:
4550 case BC_LEX_KEY_READ:
4551 case BC_LEX_KEY_SCALE:
4552 case BC_LEX_KEY_SQRT:
4554 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4558 case BC_LEX_KEY_ELSE:
4560 s = bc_parse_else(p);
4566 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4572 s = bc_parse_endBody(p, true);
4578 s = bc_parse_string(p, BC_INST_PRINT_STR);
4582 case BC_LEX_KEY_BREAK:
4583 case BC_LEX_KEY_CONTINUE:
4585 s = bc_parse_loopExit(p, p->l.t.t);
4589 case BC_LEX_KEY_FOR:
4591 s = bc_parse_for(p);
4595 case BC_LEX_KEY_HALT:
4597 bc_parse_push(p, BC_INST_HALT);
4598 s = bc_lex_next(&p->l);
4608 case BC_LEX_KEY_LIMITS:
4610 // "limits" is a compile-time command,
4611 // the output is produced at _parse time_.
4612 s = bc_lex_next(&p->l);
4614 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4615 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4616 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4617 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4618 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4619 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4620 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4621 printf("Number of vars = %lu\n", BC_MAX_VARS);
4625 case BC_LEX_KEY_PRINT:
4627 s = bc_parse_print(p);
4631 case BC_LEX_KEY_QUIT:
4633 // "quit" is a compile-time command. For example,
4634 // "if (0 == 1) quit" terminates when parsing the statement,
4635 // not when it is executed
4639 case BC_LEX_KEY_RETURN:
4641 s = bc_parse_return(p);
4645 case BC_LEX_KEY_WHILE:
4647 s = bc_parse_while(p);
4653 s = bc_error_bad_token();
4661 static BcStatus bc_parse_parse(BcParse *p)
4665 if (p->l.t.t == BC_LEX_EOF)
4666 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4667 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4668 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4669 s = bc_parse_func(p);
4672 s = bc_parse_stmt(p);
4674 if (s || G_interrupt) {
4676 s = BC_STATUS_FAILURE;
4682 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4684 BcStatus s = BC_STATUS_SUCCESS;
4685 BcInst prev = BC_INST_PRINT;
4686 BcLexType top, t = p->l.t.t;
4687 size_t nexprs = 0, ops_bgn = p->ops.len;
4688 uint32_t i, nparens, nrelops;
4689 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4691 paren_first = p->l.t.t == BC_LEX_LPAREN;
4692 nparens = nrelops = 0;
4693 paren_expr = rprn = done = get_token = assign = false;
4696 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4702 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4703 rprn = get_token = bin_last = false;
4707 case BC_LEX_OP_MINUS:
4709 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4710 rprn = get_token = false;
4711 bin_last = prev == BC_INST_MINUS;
4715 case BC_LEX_OP_ASSIGN_POWER:
4716 case BC_LEX_OP_ASSIGN_MULTIPLY:
4717 case BC_LEX_OP_ASSIGN_DIVIDE:
4718 case BC_LEX_OP_ASSIGN_MODULUS:
4719 case BC_LEX_OP_ASSIGN_PLUS:
4720 case BC_LEX_OP_ASSIGN_MINUS:
4721 case BC_LEX_OP_ASSIGN:
4723 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4724 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4725 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4727 s = bc_error("bad assignment:"
4728 " left side must be scale,"
4729 " ibase, obase, last, var,"
4736 case BC_LEX_OP_POWER:
4737 case BC_LEX_OP_MULTIPLY:
4738 case BC_LEX_OP_DIVIDE:
4739 case BC_LEX_OP_MODULUS:
4740 case BC_LEX_OP_PLUS:
4741 case BC_LEX_OP_REL_EQ:
4742 case BC_LEX_OP_REL_LE:
4743 case BC_LEX_OP_REL_GE:
4744 case BC_LEX_OP_REL_NE:
4745 case BC_LEX_OP_REL_LT:
4746 case BC_LEX_OP_REL_GT:
4747 case BC_LEX_OP_BOOL_NOT:
4748 case BC_LEX_OP_BOOL_OR:
4749 case BC_LEX_OP_BOOL_AND:
4751 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4752 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4754 return bc_error_bad_expression();
4757 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4758 prev = BC_PARSE_TOKEN_INST(t);
4759 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4760 rprn = get_token = false;
4761 bin_last = t != BC_LEX_OP_BOOL_NOT;
4768 if (BC_PARSE_LEAF(prev, rprn))
4769 return bc_error_bad_expression();
4771 paren_expr = rprn = bin_last = false;
4773 bc_vec_push(&p->ops, &t);
4780 if (bin_last || prev == BC_INST_BOOL_NOT)
4781 return bc_error_bad_expression();
4784 s = BC_STATUS_SUCCESS;
4789 else if (!paren_expr)
4790 return BC_STATUS_PARSE_EMPTY_EXP;
4793 paren_expr = rprn = true;
4794 get_token = bin_last = false;
4796 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4803 if (BC_PARSE_LEAF(prev, rprn))
4804 return bc_error_bad_expression();
4806 rprn = get_token = bin_last = false;
4807 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4815 if (BC_PARSE_LEAF(prev, rprn))
4816 return bc_error_bad_expression();
4817 bc_parse_number(p, &prev, &nexprs);
4818 paren_expr = get_token = true;
4819 rprn = bin_last = false;
4824 case BC_LEX_KEY_IBASE:
4825 case BC_LEX_KEY_LAST:
4826 case BC_LEX_KEY_OBASE:
4828 if (BC_PARSE_LEAF(prev, rprn))
4829 return bc_error_bad_expression();
4830 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4831 bc_parse_push(p, (char) prev);
4833 paren_expr = get_token = true;
4834 rprn = bin_last = false;
4840 case BC_LEX_KEY_LENGTH:
4841 case BC_LEX_KEY_SQRT:
4843 if (BC_PARSE_LEAF(prev, rprn))
4844 return bc_error_bad_expression();
4845 s = bc_parse_builtin(p, t, flags, &prev);
4847 rprn = get_token = bin_last = false;
4853 case BC_LEX_KEY_READ:
4855 if (BC_PARSE_LEAF(prev, rprn))
4856 return bc_error_bad_expression();
4857 else if (flags & BC_PARSE_NOREAD)
4858 s = bc_error_nested_read_call();
4860 s = bc_parse_read(p);
4863 rprn = get_token = bin_last = false;
4865 prev = BC_INST_READ;
4870 case BC_LEX_KEY_SCALE:
4872 if (BC_PARSE_LEAF(prev, rprn))
4873 return bc_error_bad_expression();
4874 s = bc_parse_scale(p, &prev, flags);
4876 rprn = get_token = bin_last = false;
4878 prev = BC_INST_SCALE;
4885 s = bc_error_bad_token();
4890 if (!s && get_token) s = bc_lex_next(&p->l);
4894 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4896 while (p->ops.len > ops_bgn) {
4898 top = BC_PARSE_TOP_OP(p);
4899 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4901 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4902 return bc_error_bad_expression();
4904 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4906 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4907 bc_vec_pop(&p->ops);
4910 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4911 return bc_error_bad_expression();
4913 for (i = 0; i < next.len; ++i)
4914 if (t == next.tokens[i])
4916 return bc_error_bad_expression();
4919 if (!(flags & BC_PARSE_REL) && nrelops) {
4920 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4923 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4924 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4928 if (flags & BC_PARSE_PRINT) {
4929 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4930 bc_parse_push(p, BC_INST_POP);
4936 static void bc_parse_init(BcParse *p, size_t func)
4938 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4941 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4943 return bc_parse_expr(p, flags, bc_parse_next_read);
4948 static BcStatus dc_parse_register(BcParse *p)
4953 s = bc_lex_next(&p->l);
4955 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4957 name = xstrdup(p->l.t.v.v);
4958 bc_parse_pushName(p, name);
4963 static BcStatus dc_parse_string(BcParse *p)
4965 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4966 size_t idx, len = G.prog.strs.len;
4968 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4971 str = xstrdup(p->l.t.v.v);
4972 bc_parse_push(p, BC_INST_STR);
4973 bc_parse_pushIndex(p, len);
4974 bc_vec_push(&G.prog.strs, &str);
4975 bc_parse_addFunc(p, name, &idx);
4977 return bc_lex_next(&p->l);
4980 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4984 bc_parse_push(p, inst);
4986 s = dc_parse_register(p);
4991 bc_parse_push(p, BC_INST_SWAP);
4992 bc_parse_push(p, BC_INST_ASSIGN);
4993 bc_parse_push(p, BC_INST_POP);
4996 return bc_lex_next(&p->l);
4999 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5003 bc_parse_push(p, inst);
5004 bc_parse_push(p, BC_INST_EXEC_COND);
5006 s = dc_parse_register(p);
5009 s = bc_lex_next(&p->l);
5012 if (p->l.t.t == BC_LEX_ELSE) {
5013 s = dc_parse_register(p);
5015 s = bc_lex_next(&p->l);
5018 bc_parse_push(p, BC_PARSE_STREND);
5023 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5025 BcStatus s = BC_STATUS_SUCCESS;
5028 bool assign, get_token = false;
5032 case BC_LEX_OP_REL_EQ:
5033 case BC_LEX_OP_REL_LE:
5034 case BC_LEX_OP_REL_GE:
5035 case BC_LEX_OP_REL_NE:
5036 case BC_LEX_OP_REL_LT:
5037 case BC_LEX_OP_REL_GT:
5039 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5046 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5052 s = dc_parse_string(p);
5059 if (t == BC_LEX_NEG) {
5060 s = bc_lex_next(&p->l);
5062 if (p->l.t.t != BC_LEX_NUMBER)
5063 return bc_error_bad_token();
5066 bc_parse_number(p, &prev, &p->nbraces);
5068 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5074 case BC_LEX_KEY_READ:
5076 if (flags & BC_PARSE_NOREAD)
5077 s = bc_error_nested_read_call();
5079 bc_parse_push(p, BC_INST_READ);
5084 case BC_LEX_OP_ASSIGN:
5085 case BC_LEX_STORE_PUSH:
5087 assign = t == BC_LEX_OP_ASSIGN;
5088 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5089 s = dc_parse_mem(p, inst, true, assign);
5094 case BC_LEX_LOAD_POP:
5096 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5097 s = dc_parse_mem(p, inst, true, false);
5101 case BC_LEX_STORE_IBASE:
5102 case BC_LEX_STORE_SCALE:
5103 case BC_LEX_STORE_OBASE:
5105 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5106 s = dc_parse_mem(p, inst, false, true);
5112 s = bc_error_bad_token();
5118 if (!s && get_token) s = bc_lex_next(&p->l);
5123 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5125 BcStatus s = BC_STATUS_SUCCESS;
5129 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5131 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5133 inst = dc_parse_insts[t];
5135 if (inst != BC_INST_INVALID) {
5136 bc_parse_push(p, inst);
5137 s = bc_lex_next(&p->l);
5140 s = dc_parse_token(p, t, flags);
5143 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5144 bc_parse_push(p, BC_INST_POP_EXEC);
5149 static BcStatus dc_parse_parse(BcParse *p)
5153 if (p->l.t.t == BC_LEX_EOF)
5154 s = bc_error("end of file");
5156 s = dc_parse_expr(p, 0);
5158 if (s || G_interrupt) {
5160 s = BC_STATUS_FAILURE;
5166 static void dc_parse_init(BcParse *p, size_t func)
5168 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5172 static void common_parse_init(BcParse *p, size_t func)
5175 bc_parse_init(p, func);
5177 dc_parse_init(p, func);
5181 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5184 return bc_parse_expression(p, flags);
5186 return dc_parse_expr(p, flags);
5190 static BcVec* bc_program_search(char *id, bool var)
5198 v = var ? &G.prog.vars : &G.prog.arrs;
5199 map = var ? &G.prog.var_map : &G.prog.arr_map;
5203 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5206 bc_array_init(&data.v, var);
5207 bc_vec_push(v, &data.v);
5210 ptr = bc_vec_item(map, i);
5211 if (new) ptr->name = xstrdup(e.name);
5212 return bc_vec_item(v, ptr->idx);
5215 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5217 BcStatus s = BC_STATUS_SUCCESS;
5222 case BC_RESULT_TEMP:
5223 case BC_RESULT_IBASE:
5224 case BC_RESULT_SCALE:
5225 case BC_RESULT_OBASE:
5231 case BC_RESULT_CONSTANT:
5233 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5234 size_t base_t, len = strlen(*str);
5237 bc_num_init(&r->d.n, len);
5239 hex = hex && len == 1;
5240 base = hex ? &G.prog.hexb : &G.prog.ib;
5241 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5242 s = bc_num_parse(&r->d.n, *str, base, base_t);
5245 bc_num_free(&r->d.n);
5250 r->t = BC_RESULT_TEMP;
5256 case BC_RESULT_ARRAY:
5257 case BC_RESULT_ARRAY_ELEM:
5261 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5263 if (r->t == BC_RESULT_ARRAY_ELEM) {
5265 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5266 *num = bc_vec_item(v, r->d.id.idx);
5269 *num = bc_vec_top(v);
5274 case BC_RESULT_LAST:
5276 *num = &G.prog.last;
5290 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5291 BcResult **r, BcNum **rn, bool assign)
5295 BcResultType lt, rt;
5297 if (!BC_PROG_STACK(&G.prog.results, 2))
5298 return bc_error_stack_has_too_few_elements();
5300 *r = bc_vec_item_rev(&G.prog.results, 0);
5301 *l = bc_vec_item_rev(&G.prog.results, 1);
5305 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5307 s = bc_program_num(*l, ln, false);
5309 s = bc_program_num(*r, rn, hex);
5312 // We run this again under these conditions in case any vector has been
5313 // reallocated out from under the BcNums or arrays we had.
5314 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5315 s = bc_program_num(*l, ln, false);
5319 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5320 return bc_error_variable_is_wrong_type();
5321 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5322 return bc_error_variable_is_wrong_type();
5327 static void bc_program_binOpRetire(BcResult *r)
5329 r->t = BC_RESULT_TEMP;
5330 bc_vec_pop(&G.prog.results);
5331 bc_vec_pop(&G.prog.results);
5332 bc_vec_push(&G.prog.results, r);
5335 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5339 if (!BC_PROG_STACK(&G.prog.results, 1))
5340 return bc_error_stack_has_too_few_elements();
5341 *r = bc_vec_top(&G.prog.results);
5343 s = bc_program_num(*r, n, false);
5346 if (!BC_PROG_NUM((*r), (*n)))
5347 return bc_error_variable_is_wrong_type();
5352 static void bc_program_retire(BcResult *r, BcResultType t)
5355 bc_vec_pop(&G.prog.results);
5356 bc_vec_push(&G.prog.results, r);
5359 static BcStatus bc_program_op(char inst)
5362 BcResult *opd1, *opd2, res;
5363 BcNum *n1, *n2 = NULL;
5365 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5367 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5369 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5371 bc_program_binOpRetire(&res);
5376 bc_num_free(&res.d.n);
5380 static BcStatus bc_program_read(void)
5382 const char *sv_file;
5388 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5390 for (i = 0; i < G.prog.stack.len; ++i) {
5391 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5392 if (ip_ptr->func == BC_PROG_READ)
5393 return bc_error_nested_read_call();
5396 bc_vec_pop_all(&f->code);
5397 bc_char_vec_init(&buf);
5399 sv_file = G.prog.file;
5402 s = bc_read_line(&buf, "read> ");
5405 common_parse_init(&parse, BC_PROG_READ);
5406 bc_lex_file(&parse.l);
5408 s = bc_parse_text(&parse, buf.v);
5409 if (s) goto exec_err;
5410 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5411 if (s) goto exec_err;
5413 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5414 s = bc_error("bad read() expression");
5418 ip.func = BC_PROG_READ;
5420 ip.len = G.prog.results.len;
5422 // Update this pointer, just in case.
5423 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5425 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5426 bc_vec_push(&G.prog.stack, &ip);
5429 G.prog.file = sv_file;
5430 bc_parse_free(&parse);
5436 static size_t bc_program_index(char *code, size_t *bgn)
5438 char amt = code[(*bgn)++], i = 0;
5441 for (; i < amt; ++i, ++(*bgn))
5442 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5447 static char *bc_program_name(char *code, size_t *bgn)
5450 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5452 s = xmalloc(ptr - str + 1);
5455 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5463 static void bc_program_printString(const char *str, size_t *nchars)
5465 size_t i, len = strlen(str);
5474 for (i = 0; i < len; ++i, ++(*nchars)) {
5478 if (c != '\\' || i == len - 1)
5538 // Just print the backslash and following character.
5549 static BcStatus bc_program_print(char inst, size_t idx)
5551 BcStatus s = BC_STATUS_SUCCESS;
5556 bool pop = inst != BC_INST_PRINT;
5558 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5559 return bc_error_stack_has_too_few_elements();
5561 r = bc_vec_item_rev(&G.prog.results, idx);
5562 s = bc_program_num(r, &num, false);
5565 if (BC_PROG_NUM(r, num)) {
5566 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5567 if (!s) bc_num_copy(&G.prog.last, num);
5571 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5572 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5574 if (inst == BC_INST_PRINT_STR) {
5575 for (i = 0, len = strlen(str); i < len; ++i) {
5578 if (c == '\n') G.prog.nchars = SIZE_MAX;
5583 bc_program_printString(str, &G.prog.nchars);
5584 if (inst == BC_INST_PRINT) bb_putchar('\n');
5588 if (!s && pop) bc_vec_pop(&G.prog.results);
5593 static BcStatus bc_program_negate(void)
5599 s = bc_program_prep(&ptr, &num);
5602 bc_num_init(&res.d.n, num->len);
5603 bc_num_copy(&res.d.n, num);
5604 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5606 bc_program_retire(&res, BC_RESULT_TEMP);
5611 static BcStatus bc_program_logical(char inst)
5614 BcResult *opd1, *opd2, res;
5619 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5621 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5623 if (inst == BC_INST_BOOL_AND)
5624 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5625 else if (inst == BC_INST_BOOL_OR)
5626 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5629 cmp = bc_num_cmp(n1, n2);
5633 case BC_INST_REL_EQ:
5639 case BC_INST_REL_LE:
5645 case BC_INST_REL_GE:
5651 case BC_INST_REL_NE:
5657 case BC_INST_REL_LT:
5663 case BC_INST_REL_GT:
5671 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5673 bc_program_binOpRetire(&res);
5679 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5685 memset(&n2, 0, sizeof(BcNum));
5686 n2.rdx = res.d.id.idx = r->d.id.idx;
5687 res.t = BC_RESULT_STR;
5690 if (!BC_PROG_STACK(&G.prog.results, 2))
5691 return bc_error_stack_has_too_few_elements();
5693 bc_vec_pop(&G.prog.results);
5696 bc_vec_pop(&G.prog.results);
5698 bc_vec_push(&G.prog.results, &res);
5699 bc_vec_push(v, &n2);
5701 return BC_STATUS_SUCCESS;
5705 static BcStatus bc_program_copyToVar(char *name, bool var)
5712 if (!BC_PROG_STACK(&G.prog.results, 1))
5713 return bc_error_stack_has_too_few_elements();
5715 ptr = bc_vec_top(&G.prog.results);
5716 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5717 return bc_error_variable_is_wrong_type();
5718 v = bc_program_search(name, var);
5721 if (ptr->t == BC_RESULT_STR && !var)
5722 return bc_error_variable_is_wrong_type();
5723 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5726 s = bc_program_num(ptr, &n, false);
5729 // Do this once more to make sure that pointers were not invalidated.
5730 v = bc_program_search(name, var);
5733 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5734 bc_num_copy(&r.d.n, n);
5737 bc_array_init(&r.d.v, true);
5738 bc_array_copy(&r.d.v, (BcVec *) n);
5741 bc_vec_push(v, &r.d);
5742 bc_vec_pop(&G.prog.results);
5747 static BcStatus bc_program_assign(char inst)
5750 BcResult *left, *right, res;
5751 BcNum *l = NULL, *r = NULL;
5752 unsigned long val, max;
5753 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5755 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5758 ib = left->t == BC_RESULT_IBASE;
5759 sc = left->t == BC_RESULT_SCALE;
5763 if (right->t == BC_RESULT_STR) {
5767 if (left->t != BC_RESULT_VAR)
5768 return bc_error_variable_is_wrong_type();
5769 v = bc_program_search(left->d.id.name, true);
5771 return bc_program_assignStr(right, v, false);
5775 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5776 return bc_error("bad assignment:"
5777 " left side must be scale,"
5778 " ibase, obase, last, var,"
5783 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5784 return bc_error("divide by zero");
5789 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5796 if (ib || sc || left->t == BC_RESULT_OBASE) {
5797 static const char *const msg[] = {
5798 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5799 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5800 "?1", //BC_RESULT_LAST
5801 "?2", //BC_RESULT_CONSTANT
5802 "?3", //BC_RESULT_ONE
5803 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5807 s = bc_num_ulong(l, &val);
5810 s = left->t - BC_RESULT_IBASE;
5813 ptr = &G.prog.scale;
5816 if (val < BC_NUM_MIN_BASE)
5817 return bc_error(msg[s]);
5818 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5819 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5823 return bc_error(msg[s]);
5825 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5827 *ptr = (size_t) val;
5828 s = BC_STATUS_SUCCESS;
5831 bc_num_init(&res.d.n, l->len);
5832 bc_num_copy(&res.d.n, l);
5833 bc_program_binOpRetire(&res);
5839 #define bc_program_pushVar(code, bgn, pop, copy) \
5840 bc_program_pushVar(code, bgn)
5841 // for bc, 'pop' and 'copy' are always false
5843 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5844 bool pop, bool copy)
5846 BcStatus s = BC_STATUS_SUCCESS;
5848 char *name = bc_program_name(code, bgn);
5850 r.t = BC_RESULT_VAR;
5855 BcVec *v = bc_program_search(name, true);
5856 BcNum *num = bc_vec_top(v);
5860 if (!BC_PROG_STACK(v, 2 - copy)) {
5862 return bc_error_stack_has_too_few_elements();
5868 if (!BC_PROG_STR(num)) {
5870 r.t = BC_RESULT_TEMP;
5872 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5873 bc_num_copy(&r.d.n, num);
5876 r.t = BC_RESULT_STR;
5877 r.d.id.idx = num->rdx;
5880 if (!copy) bc_vec_pop(v);
5885 bc_vec_push(&G.prog.results, &r);
5890 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5893 BcStatus s = BC_STATUS_SUCCESS;
5897 r.d.id.name = bc_program_name(code, bgn);
5899 if (inst == BC_INST_ARRAY) {
5900 r.t = BC_RESULT_ARRAY;
5901 bc_vec_push(&G.prog.results, &r);
5908 s = bc_program_prep(&operand, &num);
5910 s = bc_num_ulong(num, &temp);
5913 if (temp > BC_MAX_DIM) {
5914 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5918 r.d.id.idx = (size_t) temp;
5919 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5923 if (s) free(r.d.id.name);
5928 static BcStatus bc_program_incdec(char inst)
5931 BcResult *ptr, res, copy;
5935 s = bc_program_prep(&ptr, &num);
5938 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5939 copy.t = BC_RESULT_TEMP;
5940 bc_num_init(©.d.n, num->len);
5941 bc_num_copy(©.d.n, num);
5944 res.t = BC_RESULT_ONE;
5945 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5946 BC_INST_ASSIGN_PLUS :
5947 BC_INST_ASSIGN_MINUS;
5949 bc_vec_push(&G.prog.results, &res);
5950 bc_program_assign(inst);
5952 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5953 bc_vec_pop(&G.prog.results);
5954 bc_vec_push(&G.prog.results, ©);
5960 static BcStatus bc_program_call(char *code, size_t *idx)
5962 BcStatus s = BC_STATUS_SUCCESS;
5964 size_t i, nparams = bc_program_index(code, idx);
5971 ip.func = bc_program_index(code, idx);
5972 func = bc_vec_item(&G.prog.fns, ip.func);
5974 if (func->code.len == 0) {
5975 return bc_error("undefined function");
5977 if (nparams != func->nparams) {
5978 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5980 ip.len = G.prog.results.len - nparams;
5982 for (i = 0; i < nparams; ++i) {
5984 a = bc_vec_item(&func->autos, nparams - 1 - i);
5985 arg = bc_vec_top(&G.prog.results);
5987 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5988 return bc_error_variable_is_wrong_type();
5990 s = bc_program_copyToVar(a->name, a->idx);
5994 for (; i < func->autos.len; ++i) {
5997 a = bc_vec_item(&func->autos, i);
5998 v = bc_program_search(a->name, a->idx);
6001 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6002 bc_vec_push(v, ¶m.n);
6005 bc_array_init(¶m.v, true);
6006 bc_vec_push(v, ¶m.v);
6010 bc_vec_push(&G.prog.stack, &ip);
6012 return BC_STATUS_SUCCESS;
6015 static BcStatus bc_program_return(char inst)
6021 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6023 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6024 return bc_error_stack_has_too_few_elements();
6026 f = bc_vec_item(&G.prog.fns, ip->func);
6027 res.t = BC_RESULT_TEMP;
6029 if (inst == BC_INST_RET) {
6032 BcResult *operand = bc_vec_top(&G.prog.results);
6034 s = bc_program_num(operand, &num, false);
6036 bc_num_init(&res.d.n, num->len);
6037 bc_num_copy(&res.d.n, num);
6040 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6041 bc_num_zero(&res.d.n);
6044 // We need to pop arguments as well, so this takes that into account.
6045 for (i = 0; i < f->autos.len; ++i) {
6048 BcId *a = bc_vec_item(&f->autos, i);
6050 v = bc_program_search(a->name, a->idx);
6054 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6055 bc_vec_push(&G.prog.results, &res);
6056 bc_vec_pop(&G.prog.stack);
6058 return BC_STATUS_SUCCESS;
6062 static unsigned long bc_program_scale(BcNum *n)
6064 return (unsigned long) n->rdx;
6067 static unsigned long bc_program_len(BcNum *n)
6069 unsigned long len = n->len;
6072 if (n->rdx != n->len) return len;
6073 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6078 static BcStatus bc_program_builtin(char inst)
6084 bool len = inst == BC_INST_LENGTH;
6086 if (!BC_PROG_STACK(&G.prog.results, 1))
6087 return bc_error_stack_has_too_few_elements();
6088 opnd = bc_vec_top(&G.prog.results);
6090 s = bc_program_num(opnd, &num, false);
6094 if (!BC_PROG_NUM(opnd, num) && !len)
6095 return bc_error_variable_is_wrong_type();
6098 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6100 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6102 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6103 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6107 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6110 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6112 str = bc_vec_item(&G.prog.strs, idx);
6113 bc_num_ulong2num(&res.d.n, strlen(*str));
6117 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6118 bc_num_ulong2num(&res.d.n, f(num));
6121 bc_program_retire(&res, BC_RESULT_TEMP);
6127 static BcStatus bc_program_divmod(void)
6130 BcResult *opd1, *opd2, res, res2;
6131 BcNum *n1, *n2 = NULL;
6133 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6136 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6137 bc_num_init(&res2.d.n, n2->len);
6139 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6142 bc_program_binOpRetire(&res2);
6143 res.t = BC_RESULT_TEMP;
6144 bc_vec_push(&G.prog.results, &res);
6149 bc_num_free(&res2.d.n);
6150 bc_num_free(&res.d.n);
6154 static BcStatus bc_program_modexp(void)
6157 BcResult *r1, *r2, *r3, res;
6158 BcNum *n1, *n2, *n3;
6160 if (!BC_PROG_STACK(&G.prog.results, 3))
6161 return bc_error_stack_has_too_few_elements();
6162 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6165 r1 = bc_vec_item_rev(&G.prog.results, 2);
6166 s = bc_program_num(r1, &n1, false);
6168 if (!BC_PROG_NUM(r1, n1))
6169 return bc_error_variable_is_wrong_type();
6171 // Make sure that the values have their pointers updated, if necessary.
6172 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6174 if (r1->t == r2->t) {
6175 s = bc_program_num(r2, &n2, false);
6179 if (r1->t == r3->t) {
6180 s = bc_program_num(r3, &n3, false);
6185 bc_num_init(&res.d.n, n3->len);
6186 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6189 bc_vec_pop(&G.prog.results);
6190 bc_program_binOpRetire(&res);
6195 bc_num_free(&res.d.n);
6199 static void bc_program_stackLen(void)
6202 size_t len = G.prog.results.len;
6204 res.t = BC_RESULT_TEMP;
6206 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6207 bc_num_ulong2num(&res.d.n, len);
6208 bc_vec_push(&G.prog.results, &res);
6211 static BcStatus bc_program_asciify(void)
6215 BcNum *num = NULL, n;
6216 char *str, *str2, c;
6217 size_t len = G.prog.strs.len, idx;
6220 if (!BC_PROG_STACK(&G.prog.results, 1))
6221 return bc_error_stack_has_too_few_elements();
6222 r = bc_vec_top(&G.prog.results);
6224 s = bc_program_num(r, &num, false);
6227 if (BC_PROG_NUM(r, num)) {
6229 bc_num_init(&n, BC_NUM_DEF_SIZE);
6230 bc_num_copy(&n, num);
6231 bc_num_truncate(&n, n.rdx);
6233 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6234 if (s) goto num_err;
6235 s = bc_num_ulong(&n, &val);
6236 if (s) goto num_err;
6243 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6244 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6252 str2 = xstrdup(str);
6253 bc_program_addFunc(str2, &idx);
6255 if (idx != len + BC_PROG_REQ_FUNCS) {
6257 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6258 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6267 bc_vec_push(&G.prog.strs, &str);
6269 res.t = BC_RESULT_STR;
6271 bc_vec_pop(&G.prog.results);
6272 bc_vec_push(&G.prog.results, &res);
6274 return BC_STATUS_SUCCESS;
6281 static BcStatus bc_program_printStream(void)
6289 if (!BC_PROG_STACK(&G.prog.results, 1))
6290 return bc_error_stack_has_too_few_elements();
6291 r = bc_vec_top(&G.prog.results);
6293 s = bc_program_num(r, &n, false);
6296 if (BC_PROG_NUM(r, n))
6297 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6299 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6300 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6307 static BcStatus bc_program_nquit(void)
6314 s = bc_program_prep(&opnd, &num);
6316 s = bc_num_ulong(num, &val);
6319 bc_vec_pop(&G.prog.results);
6321 if (G.prog.stack.len < val)
6322 return bc_error_stack_has_too_few_elements();
6323 if (G.prog.stack.len == val)
6326 bc_vec_npop(&G.prog.stack, val);
6331 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6334 BcStatus s = BC_STATUS_SUCCESS;
6344 if (!BC_PROG_STACK(&G.prog.results, 1))
6345 return bc_error_stack_has_too_few_elements();
6347 r = bc_vec_top(&G.prog.results);
6351 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6353 if (code[*bgn] == BC_PARSE_STREND)
6356 else_name = bc_program_name(code, bgn);
6358 exec = r->d.n.len != 0;
6362 else if (else_name != NULL) {
6369 v = bc_program_search(name, true);
6376 if (!exec) goto exit;
6377 if (!BC_PROG_STR(n)) {
6378 s = bc_error_variable_is_wrong_type();
6386 if (r->t == BC_RESULT_STR)
6388 else if (r->t == BC_RESULT_VAR) {
6389 s = bc_program_num(r, &n, false);
6390 if (s || !BC_PROG_STR(n)) goto exit;
6397 fidx = sidx + BC_PROG_REQ_FUNCS;
6399 str = bc_vec_item(&G.prog.strs, sidx);
6400 f = bc_vec_item(&G.prog.fns, fidx);
6402 if (f->code.len == 0) {
6403 common_parse_init(&prs, fidx);
6404 s = bc_parse_text(&prs, *str);
6406 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6409 if (prs.l.t.t != BC_LEX_EOF) {
6410 s = bc_error_bad_expression();
6414 bc_parse_free(&prs);
6418 ip.len = G.prog.results.len;
6421 bc_vec_pop(&G.prog.results);
6422 bc_vec_push(&G.prog.stack, &ip);
6424 return BC_STATUS_SUCCESS;
6427 bc_parse_free(&prs);
6428 f = bc_vec_item(&G.prog.fns, fidx);
6429 bc_vec_pop_all(&f->code);
6431 bc_vec_pop(&G.prog.results);
6436 static void bc_program_pushGlobal(char inst)
6441 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6442 if (inst == BC_INST_IBASE)
6443 val = (unsigned long) G.prog.ib_t;
6444 else if (inst == BC_INST_SCALE)
6445 val = (unsigned long) G.prog.scale;
6447 val = (unsigned long) G.prog.ob_t;
6449 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6450 bc_num_ulong2num(&res.d.n, val);
6451 bc_vec_push(&G.prog.results, &res);
6454 static void bc_program_addFunc(char *name, size_t *idx)
6456 BcId entry, *entry_ptr;
6461 entry.idx = G.prog.fns.len;
6463 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6464 if (!inserted) free(name);
6466 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6467 *idx = entry_ptr->idx;
6471 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6473 // We need to reset these, so the function can be repopulated.
6475 bc_vec_pop_all(&func->autos);
6476 bc_vec_pop_all(&func->code);
6477 bc_vec_pop_all(&func->labels);
6481 bc_vec_push(&G.prog.fns, &f);
6485 // Called when parsing or execution detects a failure,
6486 // resets execution structures.
6487 static void bc_program_reset(void)
6492 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6493 bc_vec_pop_all(&G.prog.results);
6495 f = bc_vec_item(&G.prog.fns, 0);
6496 ip = bc_vec_top(&G.prog.stack);
6497 ip->idx = f->code.len;
6499 // If !tty, no need to check for ^C: we don't have ^C handler,
6500 // we would be killed by a signal and won't reach this place
6503 static BcStatus bc_program_exec(void)
6505 BcStatus s = BC_STATUS_SUCCESS;
6509 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6510 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6511 char *code = func->code.v;
6514 while (!s && ip->idx < func->code.len) {
6516 char inst = code[(ip->idx)++];
6521 case BC_INST_JUMP_ZERO:
6523 s = bc_program_prep(&ptr, &num);
6525 cond = !bc_num_cmp(num, &G.prog.zero);
6526 bc_vec_pop(&G.prog.results);
6532 idx = bc_program_index(code, &ip->idx);
6533 addr = bc_vec_item(&func->labels, idx);
6534 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6540 s = bc_program_call(code, &ip->idx);
6544 case BC_INST_INC_PRE:
6545 case BC_INST_DEC_PRE:
6546 case BC_INST_INC_POST:
6547 case BC_INST_DEC_POST:
6549 s = bc_program_incdec(inst);
6562 s = bc_program_return(inst);
6566 case BC_INST_BOOL_OR:
6567 case BC_INST_BOOL_AND:
6569 case BC_INST_REL_EQ:
6570 case BC_INST_REL_LE:
6571 case BC_INST_REL_GE:
6572 case BC_INST_REL_NE:
6573 case BC_INST_REL_LT:
6574 case BC_INST_REL_GT:
6576 s = bc_program_logical(inst);
6582 s = bc_program_read();
6588 s = bc_program_pushVar(code, &ip->idx, false, false);
6592 case BC_INST_ARRAY_ELEM:
6595 s = bc_program_pushArray(code, &ip->idx, inst);
6601 r.t = BC_RESULT_LAST;
6602 bc_vec_push(&G.prog.results, &r);
6610 bc_program_pushGlobal(inst);
6614 case BC_INST_SCALE_FUNC:
6615 case BC_INST_LENGTH:
6618 s = bc_program_builtin(inst);
6624 r.t = BC_RESULT_CONSTANT;
6625 r.d.id.idx = bc_program_index(code, &ip->idx);
6626 bc_vec_push(&G.prog.results, &r);
6632 if (!BC_PROG_STACK(&G.prog.results, 1))
6633 s = bc_error_stack_has_too_few_elements();
6635 bc_vec_pop(&G.prog.results);
6639 case BC_INST_POP_EXEC:
6641 bc_vec_pop(&G.prog.stack);
6646 case BC_INST_PRINT_POP:
6647 case BC_INST_PRINT_STR:
6649 s = bc_program_print(inst, 0);
6655 r.t = BC_RESULT_STR;
6656 r.d.id.idx = bc_program_index(code, &ip->idx);
6657 bc_vec_push(&G.prog.results, &r);
6662 case BC_INST_MULTIPLY:
6663 case BC_INST_DIVIDE:
6664 case BC_INST_MODULUS:
6668 s = bc_program_op(inst);
6672 case BC_INST_BOOL_NOT:
6674 s = bc_program_prep(&ptr, &num);
6677 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6678 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6679 bc_program_retire(&r, BC_RESULT_TEMP);
6686 s = bc_program_negate();
6691 case BC_INST_ASSIGN_POWER:
6692 case BC_INST_ASSIGN_MULTIPLY:
6693 case BC_INST_ASSIGN_DIVIDE:
6694 case BC_INST_ASSIGN_MODULUS:
6695 case BC_INST_ASSIGN_PLUS:
6696 case BC_INST_ASSIGN_MINUS:
6698 case BC_INST_ASSIGN:
6700 s = bc_program_assign(inst);
6704 case BC_INST_MODEXP:
6706 s = bc_program_modexp();
6710 case BC_INST_DIVMOD:
6712 s = bc_program_divmod();
6716 case BC_INST_EXECUTE:
6717 case BC_INST_EXEC_COND:
6719 cond = inst == BC_INST_EXEC_COND;
6720 s = bc_program_execStr(code, &ip->idx, cond);
6724 case BC_INST_PRINT_STACK:
6726 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6727 s = bc_program_print(BC_INST_PRINT, idx);
6731 case BC_INST_CLEAR_STACK:
6733 bc_vec_pop_all(&G.prog.results);
6737 case BC_INST_STACK_LEN:
6739 bc_program_stackLen();
6743 case BC_INST_DUPLICATE:
6745 if (!BC_PROG_STACK(&G.prog.results, 1))
6746 return bc_error_stack_has_too_few_elements();
6747 ptr = bc_vec_top(&G.prog.results);
6748 bc_result_copy(&r, ptr);
6749 bc_vec_push(&G.prog.results, &r);
6757 if (!BC_PROG_STACK(&G.prog.results, 2))
6758 return bc_error_stack_has_too_few_elements();
6760 ptr = bc_vec_item_rev(&G.prog.results, 0);
6761 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6762 memcpy(&r, ptr, sizeof(BcResult));
6763 memcpy(ptr, ptr2, sizeof(BcResult));
6764 memcpy(ptr2, &r, sizeof(BcResult));
6769 case BC_INST_ASCIIFY:
6771 s = bc_program_asciify();
6775 case BC_INST_PRINT_STREAM:
6777 s = bc_program_printStream();
6782 case BC_INST_PUSH_VAR:
6784 bool copy = inst == BC_INST_LOAD;
6785 s = bc_program_pushVar(code, &ip->idx, true, copy);
6789 case BC_INST_PUSH_TO_VAR:
6791 char *name = bc_program_name(code, &ip->idx);
6792 s = bc_program_copyToVar(name, true);
6799 if (G.prog.stack.len <= 2)
6801 bc_vec_npop(&G.prog.stack, 2);
6807 s = bc_program_nquit();
6813 if (s || G_interrupt) {
6818 // If the stack has changed, pointers may be invalid.
6819 ip = bc_vec_top(&G.prog.stack);
6820 func = bc_vec_item(&G.prog.fns, ip->func);
6821 code = func->code.v;
6827 static void bc_vm_info(void)
6829 printf("%s "BB_VER"\n"
6830 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6831 "Report bugs at: https://github.com/gavinhoward/bc\n"
6832 "This is free software with ABSOLUTELY NO WARRANTY\n"
6837 static void bc_vm_envArgs(void)
6839 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6842 char *env_args = getenv(bc_args_env_name), *buf;
6844 if (!env_args) return;
6846 G.env_args = xstrdup(env_args);
6849 bc_vec_init(&v, sizeof(char *), NULL);
6850 bc_vec_push(&v, &bc_args_env_name);
6853 if (!isspace(*buf)) {
6854 bc_vec_push(&v, &buf);
6855 while (*buf != 0 && !isspace(*buf)) ++buf;
6856 if (*buf != 0) (*(buf++)) = '\0';
6862 bc_args((int) v.len, (char **) v.v);
6868 static size_t bc_vm_envLen(const char *var)
6870 char *lenv = getenv(var);
6871 size_t i, len = BC_NUM_PRINT_WIDTH;
6874 if (!lenv) return len;
6878 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6880 len = (size_t) atoi(lenv) - 1;
6881 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6884 len = BC_NUM_PRINT_WIDTH;
6889 static BcStatus bc_vm_process(const char *text)
6891 BcStatus s = bc_parse_text(&G.prs, text);
6895 while (G.prs.l.t.t != BC_LEX_EOF) {
6896 s = G.prs.parse(&G.prs);
6900 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6901 s = bc_program_exec();
6910 static BcStatus bc_vm_file(const char *file)
6912 const char *sv_file;
6918 data = bc_read_file(file);
6919 if (!data) return bc_error_fmt("file '%s' is not text", file);
6921 sv_file = G.prog.file;
6923 bc_lex_file(&G.prs.l);
6924 s = bc_vm_process(data);
6927 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6928 ip = bc_vec_item(&G.prog.stack, 0);
6930 if (main_func->code.len < ip->idx)
6931 s = bc_error_fmt("file '%s' is not executable", file);
6934 G.prog.file = sv_file;
6939 static BcStatus bc_vm_stdin(void)
6943 size_t len, i, str = 0;
6944 bool comment = false;
6947 bc_lex_file(&G.prs.l);
6949 bc_char_vec_init(&buffer);
6950 bc_char_vec_init(&buf);
6951 bc_vec_pushZeroByte(&buffer);
6953 // This loop is complex because the vm tries not to send any lines that end
6954 // with a backslash to the parser. The reason for that is because the parser
6955 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6956 // case, and for strings and comments, the parser will expect more stuff.
6957 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6959 char *string = buf.v;
6964 if (str && buf.v[0] == G.send)
6966 else if (buf.v[0] == G.sbgn)
6969 else if (len > 1 || comment) {
6971 for (i = 0; i < len; ++i) {
6973 bool notend = len > i + 1;
6976 if (i - 1 > len || string[i - 1] != '\\') {
6977 if (G.sbgn == G.send)
6979 else if (c == G.send)
6981 else if (c == G.sbgn)
6985 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6989 else if (c == '*' && notend && comment && string[i + 1] == '/')
6993 if (str || comment || string[len - 2] == '\\') {
6994 bc_vec_concat(&buffer, buf.v);
6999 bc_vec_concat(&buffer, buf.v);
7000 s = bc_vm_process(buffer.v);
7003 fputs("ready for more input\n", stderr);
7006 bc_vec_pop_all(&buffer);
7010 s = bc_error("string end could not be found");
7013 s = bc_error("comment end could not be found");
7017 bc_vec_free(&buffer);
7022 static const char bc_lib[] = {
7025 "\n" "auto b,s,n,r,d,i,p,f,v"
7034 "\n" "scale=scale(x)+1"
7044 "\n" "for(i=2;v!=0;++i){"
7050 "\n" "while((d--)!=0)r*=r"
7053 "\n" "if(n!=0)return(1/r)"
7057 "\n" "auto b,s,r,p,a,q,i,v"
7061 "\n" "r=(1-10^scale)/1"
7072 "\n" "while(x<=0.5){"
7076 "\n" "r=a=(x-1)/(x+1)"
7079 "\n" "for(i=3;v!=0;i+=2){"
7090 "\n" "auto b,s,r,n,a,q,i"
7094 "\n" "scale=1.1*s+2"
7103 "\n" "if(q%2!=0)x=-x"
7107 "\n" "for(i=3;a!=0;i+=2){"
7108 "\n" "a*=q/(i*(i-1))"
7113 "\n" "if(n!=0)return(-r/1)"
7122 "\n" "x=s(2*a(1)+x)"
7128 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7137 "\n" "if(scale<65){"
7138 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7142 "\n" "if(scale<65){"
7143 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7154 "\n" "x=(x-.2)/(1+.2*x)"
7159 "\n" "for(i=3;t!=0;i+=2){"
7166 "\n" "return((m*a+r)/n)"
7168 "\n" "define j(n,x){"
7169 "\n" "auto b,s,o,a,i,v,f"
7177 "\n" "if(n%2==1)o=1"
7180 "\n" "for(i=2;i<=n;++i)a*=i"
7182 "\n" "a=(x^n)/2^n/a"
7185 "\n" "scale=scale+length(a)-scale(a)"
7186 "\n" "for(i=1;v!=0;++i){"
7187 "\n" "v=v*f/i/(n+i)"
7193 "\n" "return(a*r/1)"
7198 static BcStatus bc_vm_exec(void)
7200 BcStatus s = BC_STATUS_SUCCESS;
7204 if (option_mask32 & BC_FLAG_L) {
7206 // We know that internal library is not buggy,
7207 // thus error checking is normally disabled.
7208 # define DEBUG_LIB 0
7209 bc_lex_file(&G.prs.l);
7210 s = bc_parse_text(&G.prs, bc_lib);
7211 if (DEBUG_LIB && s) return s;
7213 while (G.prs.l.t.t != BC_LEX_EOF) {
7214 s = G.prs.parse(&G.prs);
7215 if (DEBUG_LIB && s) return s;
7217 s = bc_program_exec();
7218 if (DEBUG_LIB && s) return s;
7222 for (i = 0; !s && i < G.files.len; ++i)
7223 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7226 fputs("ready for more input\n", stderr);
7229 if (IS_BC || !G.files.len)
7231 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7232 s = bc_vm_process("");
7237 #if ENABLE_FEATURE_CLEAN_UP
7238 static void bc_program_free()
7240 bc_num_free(&G.prog.ib);
7241 bc_num_free(&G.prog.ob);
7242 bc_num_free(&G.prog.hexb);
7244 bc_num_free(&G.prog.strmb);
7246 bc_vec_free(&G.prog.fns);
7247 bc_vec_free(&G.prog.fn_map);
7248 bc_vec_free(&G.prog.vars);
7249 bc_vec_free(&G.prog.var_map);
7250 bc_vec_free(&G.prog.arrs);
7251 bc_vec_free(&G.prog.arr_map);
7252 bc_vec_free(&G.prog.strs);
7253 bc_vec_free(&G.prog.consts);
7254 bc_vec_free(&G.prog.results);
7255 bc_vec_free(&G.prog.stack);
7256 bc_num_free(&G.prog.last);
7257 bc_num_free(&G.prog.zero);
7258 bc_num_free(&G.prog.one);
7261 static void bc_vm_free(void)
7263 bc_vec_free(&G.files);
7265 bc_parse_free(&G.prs);
7270 static void bc_program_init(size_t line_len)
7275 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7276 memset(&ip, 0, sizeof(BcInstPtr));
7278 /* G.prog.nchars = G.prog.scale = 0; - already is */
7279 G.prog.len = line_len;
7281 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7282 bc_num_ten(&G.prog.ib);
7285 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7286 bc_num_ten(&G.prog.ob);
7289 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7290 bc_num_ten(&G.prog.hexb);
7291 G.prog.hexb.num[0] = 6;
7294 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7295 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7298 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7299 bc_num_zero(&G.prog.last);
7301 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7302 bc_num_zero(&G.prog.zero);
7304 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7305 bc_num_one(&G.prog.one);
7307 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7308 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7310 bc_program_addFunc(xstrdup("(main)"), &idx);
7311 bc_program_addFunc(xstrdup("(read)"), &idx);
7313 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7314 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7316 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7317 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7319 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7320 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7321 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7322 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7323 bc_vec_push(&G.prog.stack, &ip);
7326 static void bc_vm_init(const char *env_len)
7328 size_t len = bc_vm_envLen(env_len);
7330 bc_vec_init(&G.files, sizeof(char *), NULL);
7336 bc_program_init(len);
7338 bc_parse_init(&G.prs, BC_PROG_MAIN);
7340 dc_parse_init(&G.prs, BC_PROG_MAIN);
7344 static BcStatus bc_vm_run(int argc, char *argv[],
7345 const char *env_len)
7349 bc_vm_init(env_len);
7350 bc_args(argc, argv);
7352 G.ttyin = isatty(0);
7355 #if ENABLE_FEATURE_BC_SIGNALS
7356 // With SA_RESTART, most system calls will restart
7357 // (IOW: they won't fail with EINTR).
7358 // In particular, this means ^C won't cause
7359 // stdout to get into "error state" if SIGINT hits
7360 // within write() syscall.
7361 // The downside is that ^C while line input is taken
7362 // will only be handled after [Enter] since read()
7363 // from stdin is not interrupted by ^C either,
7364 // it restarts, thus fgetc() does not return on ^C.
7365 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7367 // Without SA_RESTART, this exhibits a bug:
7368 // "while (1) print 1" and try ^C-ing it.
7369 // Intermittently, instead of returning to input line,
7370 // you'll get "output error: Interrupted system call"
7372 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7374 if (!(option_mask32 & BC_FLAG_Q))
7379 #if ENABLE_FEATURE_CLEAN_UP
7386 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7387 int bc_main(int argc, char **argv)
7390 G.sbgn = G.send = '"';
7392 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7397 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7398 int dc_main(int argc, char **argv)
7404 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");