1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 typedef signed char BcDig;
194 typedef struct BcNum {
202 #define BC_NUM_MIN_BASE ((unsigned long) 2)
203 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
204 #define BC_NUM_DEF_SIZE (16)
205 #define BC_NUM_PRINT_WIDTH (69)
207 #define BC_NUM_KARATSUBA_LEN (32)
209 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212 #define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214 #define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
217 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
220 static void bc_num_init(BcNum *n, size_t req);
221 static void bc_num_expand(BcNum *n, size_t req);
222 static void bc_num_copy(BcNum *d, BcNum *s);
223 static void bc_num_free(void *num);
225 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
226 static void bc_num_ulong2num(BcNum *n, unsigned long val);
228 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 typedef enum BcInst {
268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
273 BC_INST_ASSIGN_MINUS,
319 BC_INST_PRINT_STREAM,
334 BC_INST_INVALID = -1,
339 typedef struct BcId {
344 typedef struct BcFunc {
351 typedef enum BcResultType {
356 BC_RESULT_ARRAY_ELEM,
365 // These are between to calculate ibase, obase, and last from instructions.
373 typedef union BcResultData {
379 typedef struct BcResult {
384 typedef struct BcInstPtr {
390 static void bc_array_expand(BcVec *a, size_t len);
391 static int bc_id_cmp(const void *e1, const void *e2);
393 // BC_LEX_NEG is not used in lexing; it is only for parsing.
394 typedef enum BcLexType {
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
500 // must match order of BC_LEX_KEY_foo etc above
502 struct BcLexKeyword {
505 #define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507 static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
563 typedef BcStatus (*BcLexNext)(struct BcLex *);
565 typedef struct BcLex {
583 #define BC_PARSE_STREND ((char) UCHAR_MAX)
585 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
586 #define bc_parse_updateFunc(p, f) \
587 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
589 #define BC_PARSE_REL (1 << 0)
590 #define BC_PARSE_PRINT (1 << 1)
591 #define BC_PARSE_NOCALL (1 << 2)
592 #define BC_PARSE_NOREAD (1 << 3)
593 #define BC_PARSE_ARRAY (1 << 4)
595 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
596 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
599 #define BC_PARSE_FUNC_INNER(parse) \
600 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602 #define BC_PARSE_FLAG_FUNC (1 << 1)
603 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605 #define BC_PARSE_FLAG_BODY (1 << 2)
606 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608 #define BC_PARSE_FLAG_LOOP (1 << 3)
609 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
612 #define BC_PARSE_LOOP_INNER(parse) \
613 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615 #define BC_PARSE_FLAG_IF (1 << 5)
616 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618 #define BC_PARSE_FLAG_ELSE (1 << 6)
619 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621 #define BC_PARSE_FLAG_IF_END (1 << 7)
622 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624 #define BC_PARSE_CAN_EXEC(parse) \
625 (!(BC_PARSE_TOP_FLAG(parse) & \
626 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
627 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
628 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630 typedef struct BcOp {
635 typedef struct BcParseNext {
640 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
641 #define BC_PARSE_NEXT(a, ...) \
643 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
650 typedef BcStatus (*BcParseParse)(struct BcParse *);
652 typedef struct BcParse {
675 static BcStatus bc_lex_token(BcLex *l);
677 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
678 #define BC_PARSE_LEAF(p, rparen) \
679 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
680 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682 // We can calculate the conversion between tokens and exprs by subtracting the
683 // position of the first operator in the lex enum and adding the position of the
684 // first in the expr enum. Note: This only works for binary operators.
685 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
693 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695 static BcStatus dc_lex_token(BcLex *l);
697 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
701 typedef struct BcProgram {
742 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744 #define BC_PROG_MAIN (0)
745 #define BC_PROG_READ (1)
748 #define BC_PROG_REQ_FUNCS (2)
751 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
752 #define BC_PROG_NUM(r, n) \
753 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757 static void bc_program_addFunc(char *name, size_t *idx);
758 static void bc_program_reset(void);
760 #define BC_FLAG_X (1 << 0)
761 #define BC_FLAG_W (1 << 1)
762 #define BC_FLAG_V (1 << 2)
763 #define BC_FLAG_S (1 << 3)
764 #define BC_FLAG_Q (1 << 4)
765 #define BC_FLAG_L (1 << 5)
766 #define BC_FLAG_I (1 << 6)
768 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
769 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771 #define BC_MAX_OBASE ((unsigned) 999)
772 #define BC_MAX_DIM ((unsigned) INT_MAX)
773 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
774 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
775 #define BC_MAX_NAME BC_MAX_STRING
776 #define BC_MAX_NUM BC_MAX_STRING
777 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
778 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
789 // For error messages. Can be set to current parsed line,
790 // or [TODO] to current executing line (can be before last parsed one)
797 #define G (*ptr_to_globals)
798 #define INIT_G() do { \
799 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
801 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
802 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
803 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
804 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
807 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
809 static void bc_vm_info(void);
813 // This is an array that corresponds to token types. An entry is
814 // true if the token is valid in an expression, false otherwise.
815 static const bool bc_parse_exprs[] = {
816 false, false, true, true, true, true, true, true, true, true, true, true,
817 true, true, true, true, true, true, true, true, true, true, true, true,
818 true, true, true, false, false, true, true, false, false, false, false,
819 false, false, false, true, true, false, false, false, false, false, false,
820 false, true, false, true, true, true, true, false, false, true, false, true,
824 // This is an array of data for operators that correspond to token types.
825 static const BcOp bc_parse_ops[] = {
826 { 0, false }, { 0, false },
829 { 3, true }, { 3, true }, { 3, true },
830 { 4, true }, { 4, true },
831 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
833 { 7, true }, { 7, true },
834 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
835 { 5, false }, { 5, false },
838 // These identify what tokens can come after expressions in certain cases.
839 static const BcParseNext bc_parse_next_expr =
840 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
841 static const BcParseNext bc_parse_next_param =
842 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
843 static const BcParseNext bc_parse_next_print =
844 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
845 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
846 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
847 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
848 static const BcParseNext bc_parse_next_read =
849 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
853 static const BcLexType dc_lex_regs[] = {
854 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
855 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
856 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
860 static const BcLexType dc_lex_tokens[] = {
861 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
862 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
863 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
864 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
868 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
871 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
872 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
873 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
875 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
877 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
878 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
880 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
881 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
882 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
883 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
884 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
888 static const BcInst dc_parse_insts[] = {
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
890 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
891 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
899 BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
904 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
906 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
908 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
909 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
911 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
915 static const BcNumBinaryOp bc_program_ops[] = {
916 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
919 static void fflush_and_check(void)
922 if (ferror(stdout) || ferror(stderr))
923 bb_perror_msg_and_die("output error");
926 static void quit(void) NORETURN;
927 static void quit(void)
930 bb_perror_msg_and_die("input error");
935 static void bc_verror_msg(const char *fmt, va_list p)
937 const char *sv = sv; /* for compiler */
940 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
942 bb_verror_msg(fmt, p, NULL);
944 free((char*)applet_name);
949 static NOINLINE int bc_error_fmt(const char *fmt, ...)
954 bc_verror_msg(fmt, p);
959 return BC_STATUS_FAILURE;
962 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
966 // Are non-POSIX constructs totally ok?
967 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
968 return BC_STATUS_SUCCESS; // yes
971 bc_verror_msg(fmt, p);
974 // Do we treat non-POSIX constructs as errors?
975 if (!(option_mask32 & BC_FLAG_S))
976 return BC_STATUS_SUCCESS; // no, it's a warning
979 return BC_STATUS_FAILURE;
982 // We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
983 // This idiom begs for tail-call optimization, but for it to work,
984 // function must not have calller-cleaned parameters on stack.
985 // Unfortunately, vararg functions do exactly that on most arches.
986 // Thus, these shims for the cases when we have no PARAMS:
987 static int bc_error(const char *msg)
989 return bc_error_fmt("%s", msg);
991 static int bc_posix_error(const char *msg)
993 return bc_posix_error_fmt("%s", msg);
995 static int bc_POSIX_does_not_allow(const char *msg)
997 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
999 static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1001 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1003 static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1005 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1007 static int bc_error_bad_character(char c)
1009 return bc_error_fmt("bad character '%c'", c);
1011 static int bc_error_bad_expression(void)
1013 return bc_error("bad expression");
1015 static int bc_error_bad_token(void)
1017 return bc_error("bad token");
1019 static int bc_error_stack_has_too_few_elements(void)
1021 return bc_error("stack has too few elements");
1023 static int bc_error_variable_is_wrong_type(void)
1025 return bc_error("variable is wrong type");
1027 static int bc_error_nested_read_call(void)
1029 return bc_error("read() call inside of a read() call");
1032 static void bc_vec_grow(BcVec *v, size_t n)
1034 size_t cap = v->cap * 2;
1035 while (cap < v->len + n) cap *= 2;
1036 v->v = xrealloc(v->v, v->size * cap);
1040 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1043 v->cap = BC_VEC_START_CAP;
1046 v->v = xmalloc(esize * BC_VEC_START_CAP);
1049 static void bc_char_vec_init(BcVec *v)
1051 bc_vec_init(v, sizeof(char), NULL);
1054 static void bc_vec_expand(BcVec *v, size_t req)
1057 v->v = xrealloc(v->v, v->size * req);
1062 static void bc_vec_npop(BcVec *v, size_t n)
1067 size_t len = v->len - n;
1068 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1072 static void bc_vec_pop_all(BcVec *v)
1074 bc_vec_npop(v, v->len);
1077 static void bc_vec_push(BcVec *v, const void *data)
1079 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1080 memmove(v->v + (v->size * v->len), data, v->size);
1084 static void bc_vec_pushByte(BcVec *v, char data)
1086 bc_vec_push(v, &data);
1089 static void bc_vec_pushZeroByte(BcVec *v)
1091 //bc_vec_pushByte(v, '\0');
1093 bc_vec_push(v, &const_int_0);
1096 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1099 bc_vec_push(v, data);
1104 if (v->len == v->cap) bc_vec_grow(v, 1);
1106 ptr = v->v + v->size * idx;
1108 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1109 memmove(ptr, data, v->size);
1113 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1116 bc_vec_expand(v, len + 1);
1117 memcpy(v->v, str, len);
1120 bc_vec_pushZeroByte(v);
1123 static void bc_vec_concat(BcVec *v, const char *str)
1127 if (v->len == 0) bc_vec_pushZeroByte(v);
1129 len = v->len + strlen(str);
1131 if (v->cap < len) bc_vec_grow(v, len - v->len);
1137 static void *bc_vec_item(const BcVec *v, size_t idx)
1139 return v->v + v->size * idx;
1142 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1144 return v->v + v->size * (v->len - idx - 1);
1147 static void bc_vec_free(void *vec)
1149 BcVec *v = (BcVec *) vec;
1154 static size_t bc_map_find(const BcVec *v, const void *ptr)
1156 size_t low = 0, high = v->len;
1158 while (low < high) {
1160 size_t mid = (low + high) / 2;
1161 BcId *id = bc_vec_item(v, mid);
1162 int result = bc_id_cmp(ptr, id);
1166 else if (result < 0)
1175 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1177 size_t n = *i = bc_map_find(v, ptr);
1180 bc_vec_push(v, ptr);
1181 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1182 return 0; // "was not inserted"
1184 bc_vec_pushAt(v, ptr, n);
1185 return 1; // "was inserted"
1188 static size_t bc_map_index(const BcVec *v, const void *ptr)
1190 size_t i = bc_map_find(v, ptr);
1191 if (i >= v->len) return BC_VEC_INVALID_IDX;
1192 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1195 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1203 bc_vec_pop_all(vec);
1206 #if ENABLE_FEATURE_BC_SIGNALS
1207 if (bb_got_signal) { // ^C was pressed
1209 bb_got_signal = 0; // resets G_interrupt to zero
1211 ? "\ninterrupt (type \"quit\" to exit)\n"
1212 : "\ninterrupt (type \"q\" to exit)\n"
1216 if (G.ttyin && !G_posix)
1217 fputs(prompt, stderr);
1219 #if ENABLE_FEATURE_BC_SIGNALS
1225 #if ENABLE_FEATURE_BC_SIGNALS
1226 // Both conditions appear simultaneously, check both just in case
1227 if (errno == EINTR || bb_got_signal) {
1234 quit(); // this emits error message
1236 // Note: EOF does not append '\n', therefore:
1237 // printf 'print 123\n' | bc - works
1238 // printf 'print 123' | bc - fails (syntax error)
1242 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1245 // Bad chars on this line, ignore entire line
1246 bc_error_fmt("illegal character 0x%02x", i);
1249 bc_vec_pushByte(vec, (char)i);
1250 } while (i != '\n');
1251 } while (bad_chars);
1253 bc_vec_pushZeroByte(vec);
1255 return BC_STATUS_SUCCESS;
1258 static char* bc_read_file(const char *path)
1261 size_t size = ((size_t) -1);
1264 buf = xmalloc_open_read_close(path, &size);
1266 for (i = 0; i < size; ++i) {
1268 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1280 static void bc_args(int argc, char **argv)
1286 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1287 opts = getopt32long(argv, "xwvsqli",
1288 "extended-register\0" No_argument "x"
1289 "warn\0" No_argument "w"
1290 "version\0" No_argument "v"
1291 "standard\0" No_argument "s"
1292 "quiet\0" No_argument "q"
1293 "mathlib\0" No_argument "l"
1294 "interactive\0" No_argument "i"
1297 opts = getopt32(argv, "xwvsqli");
1299 if (getenv("POSIXLY_CORRECT"))
1300 option_mask32 |= BC_FLAG_S;
1302 if (opts & BC_FLAG_V) bc_vm_info();
1303 // should not be necessary, getopt32() handles this??
1304 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1306 for (i = optind; i < argc; ++i)
1307 bc_vec_push(&G.files, argv + i);
1310 static void bc_num_setToZero(BcNum *n, size_t scale)
1317 static void bc_num_zero(BcNum *n)
1319 bc_num_setToZero(n, 0);
1322 static void bc_num_one(BcNum *n)
1324 bc_num_setToZero(n, 0);
1329 static void bc_num_ten(BcNum *n)
1331 bc_num_setToZero(n, 0);
1337 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1341 for (i = 0; i < len; ++i) {
1342 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1349 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1353 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1354 return BC_NUM_NEG(i + 1, c < 0);
1357 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1359 size_t i, min, a_int, b_int, diff;
1360 BcDig *max_num, *min_num;
1361 bool a_max, neg = false;
1364 if (a == b) return 0;
1365 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1366 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1376 a_int = BC_NUM_INT(a);
1377 b_int = BC_NUM_INT(b);
1379 a_max = (a->rdx > b->rdx);
1381 if (a_int != 0) return (ssize_t) a_int;
1385 diff = a->rdx - b->rdx;
1386 max_num = a->num + diff;
1391 diff = b->rdx - a->rdx;
1392 max_num = b->num + diff;
1396 cmp = bc_num_compare(max_num, min_num, b_int + min);
1397 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1399 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1400 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1406 static void bc_num_truncate(BcNum *n, size_t places)
1408 if (places == 0) return;
1414 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1418 static void bc_num_extend(BcNum *n, size_t places)
1420 size_t len = n->len + places;
1424 if (n->cap < len) bc_num_expand(n, len);
1426 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1427 memset(n->num, 0, sizeof(BcDig) * places);
1434 static void bc_num_clean(BcNum *n)
1436 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1439 else if (n->len < n->rdx)
1443 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1446 bc_num_extend(n, scale - n->rdx);
1448 bc_num_truncate(n, n->rdx - scale);
1451 if (n->len != 0) n->neg = !neg1 != !neg2;
1454 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1459 b->len = n->len - idx;
1461 a->rdx = b->rdx = 0;
1463 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1464 memcpy(a->num, n->num, idx * sizeof(BcDig));
1475 static BcStatus bc_num_shift(BcNum *n, size_t places)
1477 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1478 if (places + n->len > BC_MAX_NUM)
1479 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1481 if (n->rdx >= places)
1484 bc_num_extend(n, places - n->rdx);
1490 return BC_STATUS_SUCCESS;
1493 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1502 return bc_num_div(&one, a, b, scale);
1505 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1507 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1508 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1511 // Because this function doesn't need to use scale (per the bc spec),
1512 // I am hijacking it to say whether it's doing an add or a subtract.
1516 if (sub && c->len) c->neg = !c->neg;
1517 return BC_STATUS_SUCCESS;
1519 else if (b->len == 0) {
1521 return BC_STATUS_SUCCESS;
1525 c->rdx = BC_MAX(a->rdx, b->rdx);
1526 min_rdx = BC_MIN(a->rdx, b->rdx);
1529 if (a->rdx > b->rdx) {
1530 diff = a->rdx - b->rdx;
1532 ptr_a = a->num + diff;
1536 diff = b->rdx - a->rdx;
1539 ptr_b = b->num + diff;
1542 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1545 a_int = BC_NUM_INT(a);
1546 b_int = BC_NUM_INT(b);
1548 if (a_int > b_int) {
1559 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1560 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1562 ptr_c[i] = (BcDig)(in % 10);
1565 for (; i < max + min_rdx; ++i, ++c->len) {
1566 in = ((int) ptr[i]) + carry;
1568 ptr_c[i] = (BcDig)(in % 10);
1571 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1573 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1576 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1579 BcNum *minuend, *subtrahend;
1581 bool aneg, bneg, neg;
1583 // Because this function doesn't need to use scale (per the bc spec),
1584 // I am hijacking it to say whether it's doing an add or a subtract.
1588 if (sub && c->len) c->neg = !c->neg;
1589 return BC_STATUS_SUCCESS;
1591 else if (b->len == 0) {
1593 return BC_STATUS_SUCCESS;
1598 a->neg = b->neg = false;
1600 cmp = bc_num_cmp(a, b);
1606 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1607 return BC_STATUS_SUCCESS;
1616 if (sub) neg = !neg;
1621 bc_num_copy(c, minuend);
1624 if (c->rdx < subtrahend->rdx) {
1625 bc_num_extend(c, subtrahend->rdx - c->rdx);
1629 start = c->rdx - subtrahend->rdx;
1631 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1635 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1638 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1642 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1643 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1646 if (a->len == 0 || b->len == 0) {
1648 return BC_STATUS_SUCCESS;
1650 aone = BC_NUM_ONE(a);
1651 if (aone || BC_NUM_ONE(b)) {
1652 bc_num_copy(c, aone ? b : a);
1653 return BC_STATUS_SUCCESS;
1656 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1657 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1662 bc_num_expand(c, a->len + b->len + 1);
1664 memset(c->num, 0, sizeof(BcDig) * c->cap);
1667 for (i = 0; i < b->len; ++i) {
1670 for (j = 0; j < a->len; ++j) {
1671 unsigned in = c->num[i + j];
1672 in += ((unsigned) a->num[j]) * ((unsigned) b->num[i]) + carry;
1673 // note: compilers prefer _unsigned_ div/const
1675 c->num[i + j] = (BcDig)(in % 10);
1678 c->num[i + j] += (BcDig) carry;
1679 len = BC_MAX(len, i + j + !!carry);
1682 // a*a <- without check below, this will not be interruptible
1683 if (G_interrupt) return BC_STATUS_FAILURE;
1688 return BC_STATUS_SUCCESS;
1691 bc_num_init(&l1, max);
1692 bc_num_init(&h1, max);
1693 bc_num_init(&l2, max);
1694 bc_num_init(&h2, max);
1695 bc_num_init(&m1, max);
1696 bc_num_init(&m2, max);
1697 bc_num_init(&z0, max);
1698 bc_num_init(&z1, max);
1699 bc_num_init(&z2, max);
1700 bc_num_init(&temp, max + max);
1702 bc_num_split(a, max2, &l1, &h1);
1703 bc_num_split(b, max2, &l2, &h2);
1705 s = bc_num_add(&h1, &l1, &m1, 0);
1707 s = bc_num_add(&h2, &l2, &m2, 0);
1710 s = bc_num_k(&h1, &h2, &z0);
1712 s = bc_num_k(&m1, &m2, &z1);
1714 s = bc_num_k(&l1, &l2, &z2);
1717 s = bc_num_sub(&z1, &z0, &temp, 0);
1719 s = bc_num_sub(&temp, &z2, &z1, 0);
1722 s = bc_num_shift(&z0, max2 * 2);
1724 s = bc_num_shift(&z1, max2);
1726 s = bc_num_add(&z0, &z1, &temp, 0);
1728 s = bc_num_add(&temp, &z2, c, 0);
1744 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1748 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1750 scale = BC_MAX(scale, a->rdx);
1751 scale = BC_MAX(scale, b->rdx);
1752 scale = BC_MIN(a->rdx + b->rdx, scale);
1753 maxrdx = BC_MAX(maxrdx, scale);
1755 bc_num_init(&cpa, a->len);
1756 bc_num_init(&cpb, b->len);
1758 bc_num_copy(&cpa, a);
1759 bc_num_copy(&cpb, b);
1760 cpa.neg = cpb.neg = false;
1762 s = bc_num_shift(&cpa, maxrdx);
1764 s = bc_num_shift(&cpb, maxrdx);
1766 s = bc_num_k(&cpa, &cpb, c);
1770 bc_num_expand(c, c->len + maxrdx);
1772 if (c->len < maxrdx) {
1773 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1778 bc_num_retireMul(c, scale, a->neg, b->neg);
1786 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1788 BcStatus s = BC_STATUS_SUCCESS;
1795 return bc_error("divide by zero");
1796 else if (a->len == 0) {
1797 bc_num_setToZero(c, scale);
1798 return BC_STATUS_SUCCESS;
1800 else if (BC_NUM_ONE(b)) {
1802 bc_num_retireMul(c, scale, a->neg, b->neg);
1803 return BC_STATUS_SUCCESS;
1806 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1807 bc_num_copy(&cp, a);
1811 bc_num_expand(&cp, len + 2);
1812 bc_num_extend(&cp, len - cp.len);
1815 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1817 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1819 if (b->rdx == b->len) {
1820 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1824 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1826 // We want an extra zero in front to make things simpler.
1827 cp.num[cp.len++] = 0;
1830 bc_num_expand(c, cp.len);
1833 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1838 for (i = end - 1; !s && i < end; --i) {
1840 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1841 bc_num_subArrays(n, p, len);
1845 bc_num_retireMul(c, scale, a->neg, b->neg);
1848 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1851 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1852 BcNum *restrict d, size_t scale, size_t ts)
1859 return bc_error("divide by zero");
1862 bc_num_setToZero(d, ts);
1863 return BC_STATUS_SUCCESS;
1866 bc_num_init(&temp, d->cap);
1867 bc_num_d(a, b, c, scale);
1869 if (scale != 0) scale = ts;
1871 s = bc_num_m(c, b, &temp, scale);
1873 s = bc_num_sub(a, &temp, d, scale);
1876 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1879 bc_num_retireMul(d, ts, a->neg, b->neg);
1887 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1891 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1893 bc_num_init(&c1, len);
1894 s = bc_num_r(a, b, &c1, c, scale, ts);
1900 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1902 BcStatus s = BC_STATUS_SUCCESS;
1905 size_t i, powrdx, resrdx;
1908 if (b->rdx) return bc_error("non integer number");
1912 return BC_STATUS_SUCCESS;
1914 else if (a->len == 0) {
1915 bc_num_setToZero(c, scale);
1916 return BC_STATUS_SUCCESS;
1918 else if (BC_NUM_ONE(b)) {
1922 s = bc_num_inv(a, c, scale);
1929 s = bc_num_ulong(b, &pow);
1932 bc_num_init(©, a->len);
1933 bc_num_copy(©, a);
1935 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1939 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1941 s = bc_num_mul(©, ©, ©, powrdx);
1943 // Not needed: bc_num_mul() has a check for ^C:
1944 //if (G_interrupt) {
1945 // s = BC_STATUS_FAILURE;
1950 bc_num_copy(c, ©);
1952 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1955 s = bc_num_mul(©, ©, ©, powrdx);
1960 s = bc_num_mul(c, ©, c, resrdx);
1963 // Not needed: bc_num_mul() has a check for ^C:
1964 //if (G_interrupt) {
1965 // s = BC_STATUS_FAILURE;
1971 s = bc_num_inv(c, c, scale);
1975 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1977 // We can't use bc_num_clean() here.
1978 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1979 if (zero) bc_num_setToZero(c, scale);
1986 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1987 BcNumBinaryOp op, size_t req)
1990 BcNum num2, *ptr_a, *ptr_b;
1995 memcpy(ptr_a, c, sizeof(BcNum));
2004 memcpy(ptr_b, c, sizeof(BcNum));
2012 bc_num_init(c, req);
2014 bc_num_expand(c, req);
2016 s = op(ptr_a, ptr_b, c, scale);
2018 if (init) bc_num_free(&num2);
2023 static bool bc_num_strValid(const char *val, size_t base)
2026 bool small, radix = false;
2027 size_t i, len = strlen(val);
2029 if (!len) return true;
2032 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2034 for (i = 0; i < len; ++i) {
2040 if (radix) return false;
2046 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2053 static void bc_num_parseDecimal(BcNum *n, const char *val)
2059 for (i = 0; val[i] == '0'; ++i);
2066 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2067 bc_num_expand(n, len);
2070 ptr = strchr(val, '.');
2074 n->rdx = (size_t)((val + len) - (ptr + 1));
2077 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2078 n->num[n->len] = val[i] - '0';
2082 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2085 BcNum temp, mult, result;
2089 size_t i, digits, len = strlen(val);
2093 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2096 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2097 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2099 for (i = 0; i < len; ++i) {
2102 if (c == '.') break;
2104 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2106 s = bc_num_mul(n, base, &mult, 0);
2107 if (s) goto int_err;
2108 bc_num_ulong2num(&temp, v);
2109 s = bc_num_add(&mult, &temp, n, 0);
2110 if (s) goto int_err;
2115 if (c == 0) goto int_err;
2118 bc_num_init(&result, base->len);
2119 bc_num_zero(&result);
2122 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2127 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2129 s = bc_num_mul(&result, base, &result, 0);
2131 bc_num_ulong2num(&temp, v);
2132 s = bc_num_add(&result, &temp, &result, 0);
2134 s = bc_num_mul(&mult, base, &mult, 0);
2138 s = bc_num_div(&result, &mult, &result, digits);
2140 s = bc_num_add(n, &result, n, digits);
2144 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2150 bc_num_free(&result);
2156 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2158 if (*nchars == line_len - 1) {
2166 static void bc_num_printChar(size_t num, size_t width, bool radix,
2167 size_t *nchars, size_t line_len)
2169 (void) radix, (void) line_len;
2170 bb_putchar((char) num);
2171 *nchars = *nchars + width;
2175 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2176 size_t *nchars, size_t line_len)
2180 bc_num_printNewline(nchars, line_len);
2181 bb_putchar(radix ? '.' : ' ');
2184 bc_num_printNewline(nchars, line_len);
2185 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2188 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2190 bc_num_printNewline(nchars, line_len);
2193 bb_putchar(((char) dig) + '0');
2197 static void bc_num_printHex(size_t num, size_t width, bool radix,
2198 size_t *nchars, size_t line_len)
2201 bc_num_printNewline(nchars, line_len);
2206 bc_num_printNewline(nchars, line_len);
2207 bb_putchar(bb_hexdigits_upcase[num]);
2208 *nchars = *nchars + width;
2211 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2213 size_t i, rdx = n->rdx - 1;
2215 if (n->neg) bb_putchar('-');
2216 (*nchars) += n->neg;
2218 for (i = n->len - 1; i < n->len; --i)
2219 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2222 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2223 size_t *nchars, size_t len, BcNumDigitOp print)
2227 BcNum intp, fracp, digit, frac_len;
2228 unsigned long dig, *ptr;
2233 print(0, width, false, nchars, len);
2234 return BC_STATUS_SUCCESS;
2237 bc_vec_init(&stack, sizeof(long), NULL);
2238 bc_num_init(&intp, n->len);
2239 bc_num_init(&fracp, n->rdx);
2240 bc_num_init(&digit, width);
2241 bc_num_init(&frac_len, BC_NUM_INT(n));
2242 bc_num_copy(&intp, n);
2243 bc_num_one(&frac_len);
2245 bc_num_truncate(&intp, intp.rdx);
2246 s = bc_num_sub(n, &intp, &fracp, 0);
2249 while (intp.len != 0) {
2250 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2252 s = bc_num_ulong(&digit, &dig);
2254 bc_vec_push(&stack, &dig);
2257 for (i = 0; i < stack.len; ++i) {
2258 ptr = bc_vec_item_rev(&stack, i);
2259 print(*ptr, width, false, nchars, len);
2262 if (!n->rdx) goto err;
2264 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2265 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2267 s = bc_num_ulong(&fracp, &dig);
2269 bc_num_ulong2num(&intp, dig);
2270 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2272 print(dig, width, radix, nchars, len);
2273 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2278 bc_num_free(&frac_len);
2279 bc_num_free(&digit);
2280 bc_num_free(&fracp);
2282 bc_vec_free(&stack);
2286 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2287 size_t *nchars, size_t line_len)
2294 if (neg) bb_putchar('-');
2299 if (base_t <= BC_NUM_MAX_IBASE) {
2301 print = bc_num_printHex;
2304 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2305 print = bc_num_printDigits;
2308 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2315 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2317 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2321 static void bc_num_init(BcNum *n, size_t req)
2323 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2324 memset(n, 0, sizeof(BcNum));
2325 n->num = xmalloc(req);
2329 static void bc_num_expand(BcNum *n, size_t req)
2331 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2333 n->num = xrealloc(n->num, req);
2338 static void bc_num_free(void *num)
2340 free(((BcNum *) num)->num);
2343 static void bc_num_copy(BcNum *d, BcNum *s)
2346 bc_num_expand(d, s->cap);
2350 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2354 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2357 if (!bc_num_strValid(val, base_t))
2358 return bc_error("bad number string");
2361 bc_num_parseDecimal(n, val);
2363 bc_num_parseBase(n, val, base);
2365 return BC_STATUS_SUCCESS;
2368 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2369 size_t *nchars, size_t line_len)
2371 BcStatus s = BC_STATUS_SUCCESS;
2373 bc_num_printNewline(nchars, line_len);
2379 else if (base_t == 10)
2380 bc_num_printDecimal(n, nchars, line_len);
2382 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2392 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2397 if (n->neg) return bc_error("negative number");
2399 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2401 unsigned long prev = *result, powprev = pow;
2403 *result += ((unsigned long) n->num[i]) * pow;
2406 if (*result < prev || pow < powprev)
2407 return bc_error("overflow");
2410 return BC_STATUS_SUCCESS;
2413 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2421 if (val == 0) return;
2423 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2424 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2427 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2429 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2431 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2434 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2436 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2438 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2441 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2443 size_t req = BC_NUM_MREQ(a, b, scale);
2444 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2447 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2449 size_t req = BC_NUM_MREQ(a, b, scale);
2450 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2453 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2455 size_t req = BC_NUM_MREQ(a, b, scale);
2456 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2459 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2461 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2464 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2467 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2468 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2469 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2471 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2472 bc_num_expand(b, req);
2475 bc_num_setToZero(b, scale);
2476 return BC_STATUS_SUCCESS;
2479 return bc_error("negative number");
2480 else if (BC_NUM_ONE(a)) {
2482 bc_num_extend(b, scale);
2483 return BC_STATUS_SUCCESS;
2486 scale = BC_MAX(scale, a->rdx) + 1;
2487 len = a->len + scale;
2489 bc_num_init(&num1, len);
2490 bc_num_init(&num2, len);
2491 bc_num_init(&half, BC_NUM_DEF_SIZE);
2497 bc_num_init(&f, len);
2498 bc_num_init(&fprime, len);
2504 pow = BC_NUM_INT(a);
2513 pow -= 2 - (pow & 1);
2515 bc_num_extend(x0, pow);
2517 // Make sure to move the radix back.
2521 x0->rdx = digs = digs1 = 0;
2523 len = BC_NUM_INT(x0) + resrdx - 1;
2525 while (cmp != 0 || digs < len) {
2527 s = bc_num_div(a, x0, &f, resrdx);
2529 s = bc_num_add(x0, &f, &fprime, resrdx);
2531 s = bc_num_mul(&fprime, &half, x1, resrdx);
2534 cmp = bc_num_cmp(x1, x0);
2535 digs = x1->len - (unsigned long long) llabs(cmp);
2537 if (cmp == cmp2 && digs == digs1)
2542 resrdx += times > 4;
2555 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2558 bc_num_free(&fprime);
2566 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2572 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2575 memcpy(&num2, c, sizeof(BcNum));
2577 bc_num_init(c, len);
2582 bc_num_expand(c, len);
2585 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2587 if (init) bc_num_free(&num2);
2593 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2596 BcNum base, exp, two, temp;
2599 return bc_error("divide by zero");
2600 if (a->rdx || b->rdx || c->rdx)
2601 return bc_error("non integer number");
2603 return bc_error("negative number");
2605 bc_num_expand(d, c->len);
2606 bc_num_init(&base, c->len);
2607 bc_num_init(&exp, b->len);
2608 bc_num_init(&two, BC_NUM_DEF_SIZE);
2609 bc_num_init(&temp, b->len);
2615 s = bc_num_rem(a, c, &base, 0);
2617 bc_num_copy(&exp, b);
2619 while (exp.len != 0) {
2621 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2624 if (BC_NUM_ONE(&temp)) {
2625 s = bc_num_mul(d, &base, &temp, 0);
2627 s = bc_num_rem(&temp, c, d, 0);
2631 s = bc_num_mul(&base, &base, &temp, 0);
2633 s = bc_num_rem(&temp, c, &base, 0);
2646 static int bc_id_cmp(const void *e1, const void *e2)
2648 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2651 static void bc_id_free(void *id)
2653 free(((BcId *) id)->name);
2656 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2661 for (i = 0; i < f->autos.len; ++i) {
2662 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2663 return bc_error("function parameter or auto var has the same name as another");
2669 bc_vec_push(&f->autos, &a);
2671 return BC_STATUS_SUCCESS;
2674 static void bc_func_init(BcFunc *f)
2676 bc_char_vec_init(&f->code);
2677 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2678 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2682 static void bc_func_free(void *func)
2684 BcFunc *f = (BcFunc *) func;
2685 bc_vec_free(&f->code);
2686 bc_vec_free(&f->autos);
2687 bc_vec_free(&f->labels);
2690 static void bc_array_init(BcVec *a, bool nums)
2693 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2695 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2696 bc_array_expand(a, 1);
2699 static void bc_array_copy(BcVec *d, const BcVec *s)
2704 bc_vec_expand(d, s->cap);
2707 for (i = 0; i < s->len; ++i) {
2708 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2709 bc_num_init(dnum, snum->len);
2710 bc_num_copy(dnum, snum);
2714 static void bc_array_expand(BcVec *a, size_t len)
2718 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2719 while (len > a->len) {
2720 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2721 bc_vec_push(a, &data.n);
2725 while (len > a->len) {
2726 bc_array_init(&data.v, true);
2727 bc_vec_push(a, &data.v);
2732 static void bc_string_free(void *string)
2734 free(*((char **) string));
2738 static void bc_result_copy(BcResult *d, BcResult *src)
2744 case BC_RESULT_TEMP:
2745 case BC_RESULT_IBASE:
2746 case BC_RESULT_SCALE:
2747 case BC_RESULT_OBASE:
2749 bc_num_init(&d->d.n, src->d.n.len);
2750 bc_num_copy(&d->d.n, &src->d.n);
2755 case BC_RESULT_ARRAY:
2756 case BC_RESULT_ARRAY_ELEM:
2758 d->d.id.name = xstrdup(src->d.id.name);
2762 case BC_RESULT_CONSTANT:
2763 case BC_RESULT_LAST:
2767 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2774 static void bc_result_free(void *result)
2776 BcResult *r = (BcResult *) result;
2780 case BC_RESULT_TEMP:
2781 case BC_RESULT_IBASE:
2782 case BC_RESULT_SCALE:
2783 case BC_RESULT_OBASE:
2785 bc_num_free(&r->d.n);
2790 case BC_RESULT_ARRAY:
2791 case BC_RESULT_ARRAY_ELEM:
2805 static void bc_lex_lineComment(BcLex *l)
2807 l->t.t = BC_LEX_WHITESPACE;
2808 while (l->i < l->len && l->buf[l->i++] != '\n');
2812 static void bc_lex_whitespace(BcLex *l)
2815 l->t.t = BC_LEX_WHITESPACE;
2816 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2819 static BcStatus bc_lex_number(BcLex *l, char start)
2821 const char *buf = l->buf + l->i;
2822 size_t len, hits = 0, bslashes = 0, i = 0, j;
2824 bool last_pt, pt = start == '.';
2827 l->t.t = BC_LEX_NUMBER;
2829 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2830 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2844 len = i + !last_pt - bslashes * 2;
2845 if (len > BC_MAX_NUM)
2846 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2848 bc_vec_pop_all(&l->t.v);
2849 bc_vec_expand(&l->t.v, len + 1);
2850 bc_vec_push(&l->t.v, &start);
2852 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2856 // If we have hit a backslash, skip it. We don't have
2857 // to check for a newline because it's guaranteed.
2858 if (hits < bslashes && c == '\\') {
2864 bc_vec_push(&l->t.v, &c);
2867 bc_vec_pushZeroByte(&l->t.v);
2870 return BC_STATUS_SUCCESS;
2873 static BcStatus bc_lex_name(BcLex *l)
2876 const char *buf = l->buf + l->i - 1;
2879 l->t.t = BC_LEX_NAME;
2881 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2883 if (i > BC_MAX_STRING)
2884 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2885 bc_vec_string(&l->t.v, i, buf);
2887 // Increment the index. We minus 1 because it has already been incremented.
2890 return BC_STATUS_SUCCESS;
2893 static void bc_lex_init(BcLex *l, BcLexNext next)
2896 bc_char_vec_init(&l->t.v);
2899 static void bc_lex_free(BcLex *l)
2901 bc_vec_free(&l->t.v);
2904 static void bc_lex_file(BcLex *l)
2906 G.err_line = l->line = 1;
2910 static BcStatus bc_lex_next(BcLex *l)
2915 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2917 l->line += l->newline;
2918 G.err_line = l->line;
2919 l->t.t = BC_LEX_EOF;
2921 l->newline = (l->i == l->len);
2922 if (l->newline) return BC_STATUS_SUCCESS;
2924 // Loop until failure or we don't have whitespace. This
2925 // is so the parser doesn't get inundated with whitespace.
2928 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2933 static BcStatus bc_lex_text(BcLex *l, const char *text)
2937 l->len = strlen(text);
2938 l->t.t = l->t.last = BC_LEX_INVALID;
2939 return bc_lex_next(l);
2943 static BcStatus bc_lex_identifier(BcLex *l)
2947 const char *buf = l->buf + l->i - 1;
2949 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2950 const char *keyword8 = bc_lex_kws[i].name8;
2952 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2954 if (j == 8) goto match;
2956 if (keyword8[j] != '\0')
2959 // buf starts with keyword bc_lex_kws[i]
2960 l->t.t = BC_LEX_KEY_1st_keyword + i;
2961 if (!((1 << i) & POSIX_KWORD_MASK)) {
2962 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
2966 // We minus 1 because the index has already been incremented.
2968 return BC_STATUS_SUCCESS;
2974 if (l->t.v.len > 2) {
2977 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
2979 unsigned len = strchrnul(buf, '\n') - buf;
2980 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
2986 static BcStatus bc_lex_string(BcLex *l)
2988 size_t len, nls = 0, i = l->i;
2991 l->t.t = BC_LEX_STR;
2993 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2997 return bc_error("string end could not be found");
3001 if (len > BC_MAX_STRING)
3002 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3003 bc_vec_string(&l->t.v, len, l->buf + l->i);
3007 G.err_line = l->line;
3009 return BC_STATUS_SUCCESS;
3012 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3014 if (l->buf[l->i] == '=') {
3022 static BcStatus bc_lex_comment(BcLex *l)
3025 const char *buf = l->buf;
3027 l->t.t = BC_LEX_WHITESPACE;
3040 return bc_error("comment end could not be found");
3048 G.err_line = l->line;
3050 return BC_STATUS_SUCCESS;
3053 static BcStatus bc_lex_token(BcLex *l)
3055 BcStatus s = BC_STATUS_SUCCESS;
3056 char c = l->buf[l->i++], c2;
3058 // This is the workhorse of the lexer.
3065 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3075 bc_lex_whitespace(l);
3081 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3083 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3084 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3093 s = bc_lex_string(l);
3099 s = bc_POSIX_does_not_allow("'#' script comments");
3102 bc_lex_lineComment(l);
3109 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3118 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3122 l->t.t = BC_LEX_OP_BOOL_AND;
3125 l->t.t = BC_LEX_INVALID;
3126 s = bc_error_bad_character('&');
3135 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3141 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3150 l->t.t = BC_LEX_OP_INC;
3153 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3159 l->t.t = BC_LEX_COMMA;
3168 l->t.t = BC_LEX_OP_DEC;
3171 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3177 if (isdigit(l->buf[l->i]))
3178 s = bc_lex_number(l, c);
3180 l->t.t = BC_LEX_KEY_LAST;
3181 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
3190 s = bc_lex_comment(l);
3192 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3213 s = bc_lex_number(l, c);
3219 l->t.t = BC_LEX_SCOLON;
3225 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3231 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3237 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3244 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3250 if (l->buf[l->i] == '\n') {
3251 l->t.t = BC_LEX_WHITESPACE;
3255 s = bc_error_bad_character(c);
3261 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3292 s = bc_lex_identifier(l);
3299 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3308 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3312 l->t.t = BC_LEX_OP_BOOL_OR;
3315 l->t.t = BC_LEX_INVALID;
3316 s = bc_error_bad_character(c);
3324 l->t.t = BC_LEX_INVALID;
3325 s = bc_error_bad_character(c);
3335 static BcStatus dc_lex_register(BcLex *l)
3337 BcStatus s = BC_STATUS_SUCCESS;
3339 if (isspace(l->buf[l->i - 1])) {
3340 bc_lex_whitespace(l);
3343 s = bc_error("extended register");
3348 bc_vec_pop_all(&l->t.v);
3349 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3350 bc_vec_pushZeroByte(&l->t.v);
3351 l->t.t = BC_LEX_NAME;
3357 static BcStatus dc_lex_string(BcLex *l)
3359 size_t depth = 1, nls = 0, i = l->i;
3362 l->t.t = BC_LEX_STR;
3363 bc_vec_pop_all(&l->t.v);
3365 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3367 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3368 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3371 if (depth) bc_vec_push(&l->t.v, &c);
3376 return bc_error("string end could not be found");
3379 bc_vec_pushZeroByte(&l->t.v);
3380 if (i - l->i > BC_MAX_STRING)
3381 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3385 G.err_line = l->line;
3387 return BC_STATUS_SUCCESS;
3390 static BcStatus dc_lex_token(BcLex *l)
3392 BcStatus s = BC_STATUS_SUCCESS;
3393 char c = l->buf[l->i++], c2;
3396 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3397 if (l->t.last == dc_lex_regs[i])
3398 return dc_lex_register(l);
3401 if (c >= '%' && c <= '~' &&
3402 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3407 // This is the workhorse of the lexer.
3412 l->t.t = BC_LEX_EOF;
3423 l->newline = (c == '\n');
3424 bc_lex_whitespace(l);
3433 l->t.t = BC_LEX_OP_REL_NE;
3435 l->t.t = BC_LEX_OP_REL_LE;
3437 l->t.t = BC_LEX_OP_REL_GE;
3439 return bc_error_bad_character(c);
3447 bc_lex_lineComment(l);
3453 if (isdigit(l->buf[l->i]))
3454 s = bc_lex_number(l, c);
3456 s = bc_error_bad_character(c);
3477 s = bc_lex_number(l, c);
3483 s = dc_lex_string(l);
3489 l->t.t = BC_LEX_INVALID;
3490 s = bc_error_bad_character(c);
3499 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3501 bc_program_addFunc(name, idx);
3502 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3505 static void bc_parse_pushName(BcParse *p, char *name)
3507 size_t i = 0, len = strlen(name);
3509 for (; i < len; ++i) bc_parse_push(p, name[i]);
3510 bc_parse_push(p, BC_PARSE_STREND);
3515 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3517 unsigned char amt, i, nums[sizeof(size_t)];
3519 for (amt = 0; idx; ++amt) {
3520 nums[amt] = (char) idx;
3521 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3524 bc_parse_push(p, amt);
3525 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3528 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3530 char *num = xstrdup(p->l.t.v.v);
3531 size_t idx = G.prog.consts.len;
3533 bc_vec_push(&G.prog.consts, &num);
3535 bc_parse_push(p, BC_INST_NUM);
3536 bc_parse_pushIndex(p, idx);
3539 (*prev) = BC_INST_NUM;
3542 static BcStatus bc_parse_text(BcParse *p, const char *text)
3546 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3548 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3549 p->l.t.t = BC_LEX_INVALID;
3552 if (!BC_PARSE_CAN_EXEC(p))
3553 return bc_error("file is not executable");
3556 return bc_lex_text(&p->l, text);
3559 // Called when bc/dc_parse_parse() detects a failure,
3560 // resets parsing structures.
3561 static void bc_parse_reset(BcParse *p)
3563 if (p->fidx != BC_PROG_MAIN) {
3564 p->func->nparams = 0;
3565 bc_vec_pop_all(&p->func->code);
3566 bc_vec_pop_all(&p->func->autos);
3567 bc_vec_pop_all(&p->func->labels);
3569 bc_parse_updateFunc(p, BC_PROG_MAIN);
3573 p->l.t.t = BC_LEX_EOF;
3574 p->auto_part = (p->nbraces = 0);
3576 bc_vec_npop(&p->flags, p->flags.len - 1);
3577 bc_vec_pop_all(&p->exits);
3578 bc_vec_pop_all(&p->conds);
3579 bc_vec_pop_all(&p->ops);
3584 static void bc_parse_free(BcParse *p)
3586 bc_vec_free(&p->flags);
3587 bc_vec_free(&p->exits);
3588 bc_vec_free(&p->conds);
3589 bc_vec_free(&p->ops);
3593 static void bc_parse_create(BcParse *p, size_t func,
3594 BcParseParse parse, BcLexNext next)
3596 memset(p, 0, sizeof(BcParse));
3598 bc_lex_init(&p->l, next);
3599 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3600 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3601 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3602 bc_vec_pushZeroByte(&p->flags);
3603 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3606 // p->auto_part = p->nbraces = 0; - already is
3607 bc_parse_updateFunc(p, func);
3611 static BcStatus bc_parse_else(BcParse *p);
3612 static BcStatus bc_parse_stmt(BcParse *p);
3614 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3615 size_t *nexprs, bool next)
3617 BcStatus s = BC_STATUS_SUCCESS;
3619 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3620 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3622 while (p->ops.len > start) {
3624 t = BC_PARSE_TOP_OP(p);
3625 if (t == BC_LEX_LPAREN) break;
3627 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3628 if (l >= r && (l != r || !left)) break;
3630 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3631 bc_vec_pop(&p->ops);
3632 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3635 bc_vec_push(&p->ops, &type);
3636 if (next) s = bc_lex_next(&p->l);
3641 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3645 if (p->ops.len <= ops_bgn)
3646 return bc_error_bad_expression();
3647 top = BC_PARSE_TOP_OP(p);
3649 while (top != BC_LEX_LPAREN) {
3651 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3653 bc_vec_pop(&p->ops);
3654 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3656 if (p->ops.len <= ops_bgn)
3657 return bc_error_bad_expression();
3658 top = BC_PARSE_TOP_OP(p);
3661 bc_vec_pop(&p->ops);
3663 return bc_lex_next(&p->l);
3666 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3672 s = bc_lex_next(&p->l);
3675 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3677 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3678 s = bc_parse_expr(p, flags, bc_parse_next_param);
3681 comma = p->l.t.t == BC_LEX_COMMA;
3683 s = bc_lex_next(&p->l);
3688 if (comma) return bc_error_bad_token();
3689 bc_parse_push(p, BC_INST_CALL);
3690 bc_parse_pushIndex(p, nparams);
3692 return BC_STATUS_SUCCESS;
3695 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3698 BcId entry, *entry_ptr;
3703 s = bc_parse_params(p, flags);
3706 if (p->l.t.t != BC_LEX_RPAREN) {
3707 s = bc_error_bad_token();
3711 idx = bc_map_index(&G.prog.fn_map, &entry);
3713 if (idx == BC_VEC_INVALID_IDX) {
3714 name = xstrdup(entry.name);
3715 bc_parse_addFunc(p, name, &idx);
3716 idx = bc_map_index(&G.prog.fn_map, &entry);
3722 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3723 bc_parse_pushIndex(p, entry_ptr->idx);
3725 return bc_lex_next(&p->l);
3732 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3737 name = xstrdup(p->l.t.v.v);
3738 s = bc_lex_next(&p->l);
3741 if (p->l.t.t == BC_LEX_LBRACKET) {
3743 s = bc_lex_next(&p->l);
3746 if (p->l.t.t == BC_LEX_RBRACKET) {
3748 if (!(flags & BC_PARSE_ARRAY)) {
3749 s = bc_error_bad_expression();
3753 *type = BC_INST_ARRAY;
3757 *type = BC_INST_ARRAY_ELEM;
3759 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3760 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3764 s = bc_lex_next(&p->l);
3766 bc_parse_push(p, *type);
3767 bc_parse_pushName(p, name);
3769 else if (p->l.t.t == BC_LEX_LPAREN) {
3771 if (flags & BC_PARSE_NOCALL) {
3772 s = bc_error_bad_token();
3776 *type = BC_INST_CALL;
3777 s = bc_parse_call(p, name, flags);
3780 *type = BC_INST_VAR;
3781 bc_parse_push(p, BC_INST_VAR);
3782 bc_parse_pushName(p, name);
3792 static BcStatus bc_parse_read(BcParse *p)
3796 s = bc_lex_next(&p->l);
3798 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3800 s = bc_lex_next(&p->l);
3802 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3804 bc_parse_push(p, BC_INST_READ);
3806 return bc_lex_next(&p->l);
3809 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3814 s = bc_lex_next(&p->l);
3816 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3818 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3820 s = bc_lex_next(&p->l);
3823 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3826 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3828 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3829 bc_parse_push(p, *prev);
3831 return bc_lex_next(&p->l);
3834 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3838 s = bc_lex_next(&p->l);
3841 if (p->l.t.t != BC_LEX_LPAREN) {
3842 *type = BC_INST_SCALE;
3843 bc_parse_push(p, BC_INST_SCALE);
3844 return BC_STATUS_SUCCESS;
3847 *type = BC_INST_SCALE_FUNC;
3848 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3850 s = bc_lex_next(&p->l);
3853 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3855 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3856 bc_parse_push(p, BC_INST_SCALE_FUNC);
3858 return bc_lex_next(&p->l);
3861 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3862 size_t *nexprs, uint8_t flags)
3867 BcInst etype = *prev;
3869 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3870 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3871 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3873 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3874 bc_parse_push(p, inst);
3875 s = bc_lex_next(&p->l);
3879 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3882 s = bc_lex_next(&p->l);
3886 // Because we parse the next part of the expression
3887 // right here, we need to increment this.
3888 *nexprs = *nexprs + 1;
3894 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3898 case BC_LEX_KEY_IBASE:
3899 case BC_LEX_KEY_LAST:
3900 case BC_LEX_KEY_OBASE:
3902 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3903 s = bc_lex_next(&p->l);
3907 case BC_LEX_KEY_SCALE:
3909 s = bc_lex_next(&p->l);
3911 if (p->l.t.t == BC_LEX_LPAREN)
3912 s = bc_error_bad_token();
3914 bc_parse_push(p, BC_INST_SCALE);
3920 s = bc_error_bad_token();
3925 if (!s) bc_parse_push(p, inst);
3931 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3932 bool rparen, size_t *nexprs)
3936 BcInst etype = *prev;
3938 s = bc_lex_next(&p->l);
3941 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3942 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3945 *prev = BC_PARSE_TOKEN_INST(type);
3947 // We can just push onto the op stack because this is the largest
3948 // precedence operator that gets pushed. Inc/dec does not.
3949 if (type != BC_LEX_OP_MINUS)
3950 bc_vec_push(&p->ops, &type);
3952 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3957 static BcStatus bc_parse_string(BcParse *p, char inst)
3959 char *str = xstrdup(p->l.t.v.v);
3961 bc_parse_push(p, BC_INST_STR);
3962 bc_parse_pushIndex(p, G.prog.strs.len);
3963 bc_vec_push(&G.prog.strs, &str);
3964 bc_parse_push(p, inst);
3966 return bc_lex_next(&p->l);
3969 static BcStatus bc_parse_print(BcParse *p)
3975 s = bc_lex_next(&p->l);
3980 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3981 return bc_error("bad print statement");
3983 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3985 if (type == BC_LEX_STR)
3986 s = bc_parse_string(p, BC_INST_PRINT_POP);
3988 s = bc_parse_expr(p, 0, bc_parse_next_print);
3990 bc_parse_push(p, BC_INST_PRINT_POP);
3995 comma = p->l.t.t == BC_LEX_COMMA;
3996 if (comma) s = bc_lex_next(&p->l);
4001 if (comma) return bc_error_bad_token();
4003 return bc_lex_next(&p->l);
4006 static BcStatus bc_parse_return(BcParse *p)
4012 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
4014 s = bc_lex_next(&p->l);
4018 paren = t == BC_LEX_LPAREN;
4020 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4021 bc_parse_push(p, BC_INST_RET0);
4024 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4025 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4028 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4029 bc_parse_push(p, BC_INST_RET0);
4030 s = bc_lex_next(&p->l);
4034 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4035 s = bc_posix_error("POSIX requires parentheses around return expressions");
4039 bc_parse_push(p, BC_INST_RET);
4045 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4047 BcStatus s = BC_STATUS_SUCCESS;
4049 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4050 return bc_error_bad_token();
4054 if (p->l.t.t == BC_LEX_RBRACE) {
4055 if (!p->nbraces) return bc_error_bad_token();
4057 s = bc_lex_next(&p->l);
4061 return bc_error_bad_token();
4064 if (BC_PARSE_IF(p)) {
4068 while (p->l.t.t == BC_LEX_NLINE) {
4069 s = bc_lex_next(&p->l);
4073 bc_vec_pop(&p->flags);
4075 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4076 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4078 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4080 else if (BC_PARSE_ELSE(p)) {
4085 bc_vec_pop(&p->flags);
4087 ip = bc_vec_top(&p->exits);
4088 label = bc_vec_item(&p->func->labels, ip->idx);
4089 *label = p->func->code.len;
4091 bc_vec_pop(&p->exits);
4093 else if (BC_PARSE_FUNC_INNER(p)) {
4094 bc_parse_push(p, BC_INST_RET0);
4095 bc_parse_updateFunc(p, BC_PROG_MAIN);
4096 bc_vec_pop(&p->flags);
4100 BcInstPtr *ip = bc_vec_top(&p->exits);
4101 size_t *label = bc_vec_top(&p->conds);
4103 bc_parse_push(p, BC_INST_JUMP);
4104 bc_parse_pushIndex(p, *label);
4106 label = bc_vec_item(&p->func->labels, ip->idx);
4107 *label = p->func->code.len;
4109 bc_vec_pop(&p->flags);
4110 bc_vec_pop(&p->exits);
4111 bc_vec_pop(&p->conds);
4117 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4119 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4120 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4121 flags |= BC_PARSE_FLAG_BODY;
4122 bc_vec_push(&p->flags, &flags);
4125 static void bc_parse_noElse(BcParse *p)
4129 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4131 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4133 ip = bc_vec_top(&p->exits);
4134 label = bc_vec_item(&p->func->labels, ip->idx);
4135 *label = p->func->code.len;
4137 bc_vec_pop(&p->exits);
4140 static BcStatus bc_parse_if(BcParse *p)
4145 s = bc_lex_next(&p->l);
4147 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4149 s = bc_lex_next(&p->l);
4151 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4153 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4155 s = bc_lex_next(&p->l);
4157 bc_parse_push(p, BC_INST_JUMP_ZERO);
4159 ip.idx = p->func->labels.len;
4160 ip.func = ip.len = 0;
4162 bc_parse_pushIndex(p, ip.idx);
4163 bc_vec_push(&p->exits, &ip);
4164 bc_vec_push(&p->func->labels, &ip.idx);
4165 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4167 return BC_STATUS_SUCCESS;
4170 static BcStatus bc_parse_else(BcParse *p)
4174 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4176 ip.idx = p->func->labels.len;
4177 ip.func = ip.len = 0;
4179 bc_parse_push(p, BC_INST_JUMP);
4180 bc_parse_pushIndex(p, ip.idx);
4184 bc_vec_push(&p->exits, &ip);
4185 bc_vec_push(&p->func->labels, &ip.idx);
4186 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4188 return bc_lex_next(&p->l);
4191 static BcStatus bc_parse_while(BcParse *p)
4196 s = bc_lex_next(&p->l);
4198 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4199 s = bc_lex_next(&p->l);
4202 ip.idx = p->func->labels.len;
4204 bc_vec_push(&p->func->labels, &p->func->code.len);
4205 bc_vec_push(&p->conds, &ip.idx);
4207 ip.idx = p->func->labels.len;
4211 bc_vec_push(&p->exits, &ip);
4212 bc_vec_push(&p->func->labels, &ip.idx);
4214 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4216 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4217 s = bc_lex_next(&p->l);
4220 bc_parse_push(p, BC_INST_JUMP_ZERO);
4221 bc_parse_pushIndex(p, ip.idx);
4222 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4224 return BC_STATUS_SUCCESS;
4227 static BcStatus bc_parse_for(BcParse *p)
4231 size_t cond_idx, exit_idx, body_idx, update_idx;
4233 s = bc_lex_next(&p->l);
4235 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4236 s = bc_lex_next(&p->l);
4239 if (p->l.t.t != BC_LEX_SCOLON)
4240 s = bc_parse_expr(p, 0, bc_parse_next_for);
4242 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4245 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4246 s = bc_lex_next(&p->l);
4249 cond_idx = p->func->labels.len;
4250 update_idx = cond_idx + 1;
4251 body_idx = update_idx + 1;
4252 exit_idx = body_idx + 1;
4254 bc_vec_push(&p->func->labels, &p->func->code.len);
4256 if (p->l.t.t != BC_LEX_SCOLON)
4257 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4259 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4262 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4264 s = bc_lex_next(&p->l);
4267 bc_parse_push(p, BC_INST_JUMP_ZERO);
4268 bc_parse_pushIndex(p, exit_idx);
4269 bc_parse_push(p, BC_INST_JUMP);
4270 bc_parse_pushIndex(p, body_idx);
4272 ip.idx = p->func->labels.len;
4274 bc_vec_push(&p->conds, &update_idx);
4275 bc_vec_push(&p->func->labels, &p->func->code.len);
4277 if (p->l.t.t != BC_LEX_RPAREN)
4278 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4280 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4284 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4285 bc_parse_push(p, BC_INST_JUMP);
4286 bc_parse_pushIndex(p, cond_idx);
4287 bc_vec_push(&p->func->labels, &p->func->code.len);
4293 bc_vec_push(&p->exits, &ip);
4294 bc_vec_push(&p->func->labels, &ip.idx);
4296 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4298 return BC_STATUS_SUCCESS;
4301 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4307 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4309 if (type == BC_LEX_KEY_BREAK) {
4311 if (p->exits.len == 0) return bc_error_bad_token();
4313 i = p->exits.len - 1;
4314 ip = bc_vec_item(&p->exits, i);
4316 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4317 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4322 i = *((size_t *) bc_vec_top(&p->conds));
4324 bc_parse_push(p, BC_INST_JUMP);
4325 bc_parse_pushIndex(p, i);
4327 s = bc_lex_next(&p->l);
4330 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4331 return bc_error_bad_token();
4333 return bc_lex_next(&p->l);
4336 static BcStatus bc_parse_func(BcParse *p)
4339 bool var, comma = false;
4343 s = bc_lex_next(&p->l);
4345 if (p->l.t.t != BC_LEX_NAME)
4346 return bc_error("bad function definition");
4348 name = xstrdup(p->l.t.v.v);
4349 bc_parse_addFunc(p, name, &p->fidx);
4351 s = bc_lex_next(&p->l);
4353 if (p->l.t.t != BC_LEX_LPAREN)
4354 return bc_error("bad function definition");
4355 s = bc_lex_next(&p->l);
4358 while (p->l.t.t != BC_LEX_RPAREN) {
4360 if (p->l.t.t != BC_LEX_NAME)
4361 return bc_error("bad function definition");
4365 name = xstrdup(p->l.t.v.v);
4366 s = bc_lex_next(&p->l);
4369 var = p->l.t.t != BC_LEX_LBRACKET;
4373 s = bc_lex_next(&p->l);
4376 if (p->l.t.t != BC_LEX_RBRACKET) {
4377 s = bc_error("bad function definition");
4381 s = bc_lex_next(&p->l);
4385 comma = p->l.t.t == BC_LEX_COMMA;
4387 s = bc_lex_next(&p->l);
4391 s = bc_func_insert(p->func, name, var);
4395 if (comma) return bc_error("bad function definition");
4397 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4398 bc_parse_startBody(p, flags);
4400 s = bc_lex_next(&p->l);
4403 if (p->l.t.t != BC_LEX_LBRACE)
4404 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4413 static BcStatus bc_parse_auto(BcParse *p)
4416 bool comma, var, one;
4419 if (!p->auto_part) return bc_error_bad_token();
4420 s = bc_lex_next(&p->l);
4423 p->auto_part = comma = false;
4424 one = p->l.t.t == BC_LEX_NAME;
4426 while (p->l.t.t == BC_LEX_NAME) {
4428 name = xstrdup(p->l.t.v.v);
4429 s = bc_lex_next(&p->l);
4432 var = p->l.t.t != BC_LEX_LBRACKET;
4435 s = bc_lex_next(&p->l);
4438 if (p->l.t.t != BC_LEX_RBRACKET) {
4439 s = bc_error("bad function definition");
4443 s = bc_lex_next(&p->l);
4447 comma = p->l.t.t == BC_LEX_COMMA;
4449 s = bc_lex_next(&p->l);
4453 s = bc_func_insert(p->func, name, var);
4457 if (comma) return bc_error("bad function definition");
4458 if (!one) return bc_error("no auto variable found");
4460 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4461 return bc_error_bad_token();
4463 return bc_lex_next(&p->l);
4470 static BcStatus bc_parse_body(BcParse *p, bool brace)
4472 BcStatus s = BC_STATUS_SUCCESS;
4473 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4475 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4477 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4479 if (!brace) return bc_error_bad_token();
4480 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4482 if (!p->auto_part) {
4483 s = bc_parse_auto(p);
4487 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4490 s = bc_parse_stmt(p);
4491 if (!s && !brace) s = bc_parse_endBody(p, false);
4497 static BcStatus bc_parse_stmt(BcParse *p)
4499 BcStatus s = BC_STATUS_SUCCESS;
4505 return bc_lex_next(&p->l);
4508 case BC_LEX_KEY_ELSE:
4510 p->auto_part = false;
4516 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4519 s = bc_lex_next(&p->l);
4522 return bc_parse_body(p, true);
4525 case BC_LEX_KEY_AUTO:
4527 return bc_parse_auto(p);
4532 p->auto_part = false;
4534 if (BC_PARSE_IF_END(p)) {
4536 return BC_STATUS_SUCCESS;
4538 else if (BC_PARSE_BODY(p))
4539 return bc_parse_body(p, false);
4549 case BC_LEX_OP_MINUS:
4550 case BC_LEX_OP_BOOL_NOT:
4554 case BC_LEX_KEY_IBASE:
4555 case BC_LEX_KEY_LAST:
4556 case BC_LEX_KEY_LENGTH:
4557 case BC_LEX_KEY_OBASE:
4558 case BC_LEX_KEY_READ:
4559 case BC_LEX_KEY_SCALE:
4560 case BC_LEX_KEY_SQRT:
4562 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4566 case BC_LEX_KEY_ELSE:
4568 s = bc_parse_else(p);
4574 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4580 s = bc_parse_endBody(p, true);
4586 s = bc_parse_string(p, BC_INST_PRINT_STR);
4590 case BC_LEX_KEY_BREAK:
4591 case BC_LEX_KEY_CONTINUE:
4593 s = bc_parse_loopExit(p, p->l.t.t);
4597 case BC_LEX_KEY_FOR:
4599 s = bc_parse_for(p);
4603 case BC_LEX_KEY_HALT:
4605 bc_parse_push(p, BC_INST_HALT);
4606 s = bc_lex_next(&p->l);
4616 case BC_LEX_KEY_LIMITS:
4618 // "limits" is a compile-time command,
4619 // the output is produced at _parse time_.
4620 s = bc_lex_next(&p->l);
4622 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4623 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4624 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4625 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4626 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4627 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4628 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4629 printf("Number of vars = %lu\n", BC_MAX_VARS);
4633 case BC_LEX_KEY_PRINT:
4635 s = bc_parse_print(p);
4639 case BC_LEX_KEY_QUIT:
4641 // "quit" is a compile-time command. For example,
4642 // "if (0 == 1) quit" terminates when parsing the statement,
4643 // not when it is executed
4647 case BC_LEX_KEY_RETURN:
4649 s = bc_parse_return(p);
4653 case BC_LEX_KEY_WHILE:
4655 s = bc_parse_while(p);
4661 s = bc_error_bad_token();
4669 static BcStatus bc_parse_parse(BcParse *p)
4673 if (p->l.t.t == BC_LEX_EOF)
4674 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4675 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4676 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4677 s = bc_parse_func(p);
4680 s = bc_parse_stmt(p);
4682 if (s || G_interrupt) {
4684 s = BC_STATUS_FAILURE;
4690 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4692 BcStatus s = BC_STATUS_SUCCESS;
4693 BcInst prev = BC_INST_PRINT;
4694 BcLexType top, t = p->l.t.t;
4695 size_t nexprs = 0, ops_bgn = p->ops.len;
4696 uint32_t i, nparens, nrelops;
4697 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4699 paren_first = p->l.t.t == BC_LEX_LPAREN;
4700 nparens = nrelops = 0;
4701 paren_expr = rprn = done = get_token = assign = false;
4704 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4710 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4711 rprn = get_token = bin_last = false;
4715 case BC_LEX_OP_MINUS:
4717 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4718 rprn = get_token = false;
4719 bin_last = prev == BC_INST_MINUS;
4723 case BC_LEX_OP_ASSIGN_POWER:
4724 case BC_LEX_OP_ASSIGN_MULTIPLY:
4725 case BC_LEX_OP_ASSIGN_DIVIDE:
4726 case BC_LEX_OP_ASSIGN_MODULUS:
4727 case BC_LEX_OP_ASSIGN_PLUS:
4728 case BC_LEX_OP_ASSIGN_MINUS:
4729 case BC_LEX_OP_ASSIGN:
4731 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4732 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4733 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4735 s = bc_error("bad assignment:"
4736 " left side must be scale,"
4737 " ibase, obase, last, var,"
4744 case BC_LEX_OP_POWER:
4745 case BC_LEX_OP_MULTIPLY:
4746 case BC_LEX_OP_DIVIDE:
4747 case BC_LEX_OP_MODULUS:
4748 case BC_LEX_OP_PLUS:
4749 case BC_LEX_OP_REL_EQ:
4750 case BC_LEX_OP_REL_LE:
4751 case BC_LEX_OP_REL_GE:
4752 case BC_LEX_OP_REL_NE:
4753 case BC_LEX_OP_REL_LT:
4754 case BC_LEX_OP_REL_GT:
4755 case BC_LEX_OP_BOOL_NOT:
4756 case BC_LEX_OP_BOOL_OR:
4757 case BC_LEX_OP_BOOL_AND:
4759 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4760 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4762 return bc_error_bad_expression();
4765 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4766 prev = BC_PARSE_TOKEN_INST(t);
4767 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4768 rprn = get_token = false;
4769 bin_last = t != BC_LEX_OP_BOOL_NOT;
4776 if (BC_PARSE_LEAF(prev, rprn))
4777 return bc_error_bad_expression();
4779 paren_expr = rprn = bin_last = false;
4781 bc_vec_push(&p->ops, &t);
4788 if (bin_last || prev == BC_INST_BOOL_NOT)
4789 return bc_error_bad_expression();
4792 s = BC_STATUS_SUCCESS;
4797 else if (!paren_expr)
4798 return BC_STATUS_PARSE_EMPTY_EXP;
4801 paren_expr = rprn = true;
4802 get_token = bin_last = false;
4804 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4811 if (BC_PARSE_LEAF(prev, rprn))
4812 return bc_error_bad_expression();
4814 rprn = get_token = bin_last = false;
4815 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4823 if (BC_PARSE_LEAF(prev, rprn))
4824 return bc_error_bad_expression();
4825 bc_parse_number(p, &prev, &nexprs);
4826 paren_expr = get_token = true;
4827 rprn = bin_last = false;
4832 case BC_LEX_KEY_IBASE:
4833 case BC_LEX_KEY_LAST:
4834 case BC_LEX_KEY_OBASE:
4836 if (BC_PARSE_LEAF(prev, rprn))
4837 return bc_error_bad_expression();
4838 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4839 bc_parse_push(p, (char) prev);
4841 paren_expr = get_token = true;
4842 rprn = bin_last = false;
4848 case BC_LEX_KEY_LENGTH:
4849 case BC_LEX_KEY_SQRT:
4851 if (BC_PARSE_LEAF(prev, rprn))
4852 return bc_error_bad_expression();
4853 s = bc_parse_builtin(p, t, flags, &prev);
4855 rprn = get_token = bin_last = false;
4861 case BC_LEX_KEY_READ:
4863 if (BC_PARSE_LEAF(prev, rprn))
4864 return bc_error_bad_expression();
4865 else if (flags & BC_PARSE_NOREAD)
4866 s = bc_error_nested_read_call();
4868 s = bc_parse_read(p);
4871 rprn = get_token = bin_last = false;
4873 prev = BC_INST_READ;
4878 case BC_LEX_KEY_SCALE:
4880 if (BC_PARSE_LEAF(prev, rprn))
4881 return bc_error_bad_expression();
4882 s = bc_parse_scale(p, &prev, flags);
4884 rprn = get_token = bin_last = false;
4886 prev = BC_INST_SCALE;
4893 s = bc_error_bad_token();
4898 if (!s && get_token) s = bc_lex_next(&p->l);
4902 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4904 while (p->ops.len > ops_bgn) {
4906 top = BC_PARSE_TOP_OP(p);
4907 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4909 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4910 return bc_error_bad_expression();
4912 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4914 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4915 bc_vec_pop(&p->ops);
4918 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4919 return bc_error_bad_expression();
4921 for (i = 0; i < next.len; ++i)
4922 if (t == next.tokens[i])
4924 return bc_error_bad_expression();
4927 if (!(flags & BC_PARSE_REL) && nrelops) {
4928 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4931 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4932 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4936 if (flags & BC_PARSE_PRINT) {
4937 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4938 bc_parse_push(p, BC_INST_POP);
4944 static void bc_parse_init(BcParse *p, size_t func)
4946 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4949 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4951 return bc_parse_expr(p, flags, bc_parse_next_read);
4956 static BcStatus dc_parse_register(BcParse *p)
4961 s = bc_lex_next(&p->l);
4963 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4965 name = xstrdup(p->l.t.v.v);
4966 bc_parse_pushName(p, name);
4971 static BcStatus dc_parse_string(BcParse *p)
4973 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4974 size_t idx, len = G.prog.strs.len;
4976 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4979 str = xstrdup(p->l.t.v.v);
4980 bc_parse_push(p, BC_INST_STR);
4981 bc_parse_pushIndex(p, len);
4982 bc_vec_push(&G.prog.strs, &str);
4983 bc_parse_addFunc(p, name, &idx);
4985 return bc_lex_next(&p->l);
4988 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4992 bc_parse_push(p, inst);
4994 s = dc_parse_register(p);
4999 bc_parse_push(p, BC_INST_SWAP);
5000 bc_parse_push(p, BC_INST_ASSIGN);
5001 bc_parse_push(p, BC_INST_POP);
5004 return bc_lex_next(&p->l);
5007 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5011 bc_parse_push(p, inst);
5012 bc_parse_push(p, BC_INST_EXEC_COND);
5014 s = dc_parse_register(p);
5017 s = bc_lex_next(&p->l);
5020 if (p->l.t.t == BC_LEX_ELSE) {
5021 s = dc_parse_register(p);
5023 s = bc_lex_next(&p->l);
5026 bc_parse_push(p, BC_PARSE_STREND);
5031 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5033 BcStatus s = BC_STATUS_SUCCESS;
5036 bool assign, get_token = false;
5040 case BC_LEX_OP_REL_EQ:
5041 case BC_LEX_OP_REL_LE:
5042 case BC_LEX_OP_REL_GE:
5043 case BC_LEX_OP_REL_NE:
5044 case BC_LEX_OP_REL_LT:
5045 case BC_LEX_OP_REL_GT:
5047 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5054 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5060 s = dc_parse_string(p);
5067 if (t == BC_LEX_NEG) {
5068 s = bc_lex_next(&p->l);
5070 if (p->l.t.t != BC_LEX_NUMBER)
5071 return bc_error_bad_token();
5074 bc_parse_number(p, &prev, &p->nbraces);
5076 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5082 case BC_LEX_KEY_READ:
5084 if (flags & BC_PARSE_NOREAD)
5085 s = bc_error_nested_read_call();
5087 bc_parse_push(p, BC_INST_READ);
5092 case BC_LEX_OP_ASSIGN:
5093 case BC_LEX_STORE_PUSH:
5095 assign = t == BC_LEX_OP_ASSIGN;
5096 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5097 s = dc_parse_mem(p, inst, true, assign);
5102 case BC_LEX_LOAD_POP:
5104 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5105 s = dc_parse_mem(p, inst, true, false);
5109 case BC_LEX_STORE_IBASE:
5110 case BC_LEX_STORE_SCALE:
5111 case BC_LEX_STORE_OBASE:
5113 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5114 s = dc_parse_mem(p, inst, false, true);
5120 s = bc_error_bad_token();
5126 if (!s && get_token) s = bc_lex_next(&p->l);
5131 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5133 BcStatus s = BC_STATUS_SUCCESS;
5137 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5139 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5141 inst = dc_parse_insts[t];
5143 if (inst != BC_INST_INVALID) {
5144 bc_parse_push(p, inst);
5145 s = bc_lex_next(&p->l);
5148 s = dc_parse_token(p, t, flags);
5151 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5152 bc_parse_push(p, BC_INST_POP_EXEC);
5157 static BcStatus dc_parse_parse(BcParse *p)
5161 if (p->l.t.t == BC_LEX_EOF)
5162 s = bc_error("end of file");
5164 s = dc_parse_expr(p, 0);
5166 if (s || G_interrupt) {
5168 s = BC_STATUS_FAILURE;
5174 static void dc_parse_init(BcParse *p, size_t func)
5176 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5180 static void common_parse_init(BcParse *p, size_t func)
5183 bc_parse_init(p, func);
5185 dc_parse_init(p, func);
5189 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5192 return bc_parse_expression(p, flags);
5194 return dc_parse_expr(p, flags);
5198 static BcVec* bc_program_search(char *id, bool var)
5206 v = var ? &G.prog.vars : &G.prog.arrs;
5207 map = var ? &G.prog.var_map : &G.prog.arr_map;
5211 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5214 bc_array_init(&data.v, var);
5215 bc_vec_push(v, &data.v);
5218 ptr = bc_vec_item(map, i);
5219 if (new) ptr->name = xstrdup(e.name);
5220 return bc_vec_item(v, ptr->idx);
5223 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5225 BcStatus s = BC_STATUS_SUCCESS;
5230 case BC_RESULT_TEMP:
5231 case BC_RESULT_IBASE:
5232 case BC_RESULT_SCALE:
5233 case BC_RESULT_OBASE:
5239 case BC_RESULT_CONSTANT:
5241 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5242 size_t base_t, len = strlen(*str);
5245 bc_num_init(&r->d.n, len);
5247 hex = hex && len == 1;
5248 base = hex ? &G.prog.hexb : &G.prog.ib;
5249 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5250 s = bc_num_parse(&r->d.n, *str, base, base_t);
5253 bc_num_free(&r->d.n);
5258 r->t = BC_RESULT_TEMP;
5264 case BC_RESULT_ARRAY:
5265 case BC_RESULT_ARRAY_ELEM:
5269 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5271 if (r->t == BC_RESULT_ARRAY_ELEM) {
5273 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5274 *num = bc_vec_item(v, r->d.id.idx);
5277 *num = bc_vec_top(v);
5282 case BC_RESULT_LAST:
5284 *num = &G.prog.last;
5298 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5299 BcResult **r, BcNum **rn, bool assign)
5303 BcResultType lt, rt;
5305 if (!BC_PROG_STACK(&G.prog.results, 2))
5306 return bc_error_stack_has_too_few_elements();
5308 *r = bc_vec_item_rev(&G.prog.results, 0);
5309 *l = bc_vec_item_rev(&G.prog.results, 1);
5313 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5315 s = bc_program_num(*l, ln, false);
5317 s = bc_program_num(*r, rn, hex);
5320 // We run this again under these conditions in case any vector has been
5321 // reallocated out from under the BcNums or arrays we had.
5322 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5323 s = bc_program_num(*l, ln, false);
5327 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5328 return bc_error_variable_is_wrong_type();
5329 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5330 return bc_error_variable_is_wrong_type();
5335 static void bc_program_binOpRetire(BcResult *r)
5337 r->t = BC_RESULT_TEMP;
5338 bc_vec_pop(&G.prog.results);
5339 bc_vec_pop(&G.prog.results);
5340 bc_vec_push(&G.prog.results, r);
5343 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5347 if (!BC_PROG_STACK(&G.prog.results, 1))
5348 return bc_error_stack_has_too_few_elements();
5349 *r = bc_vec_top(&G.prog.results);
5351 s = bc_program_num(*r, n, false);
5354 if (!BC_PROG_NUM((*r), (*n)))
5355 return bc_error_variable_is_wrong_type();
5360 static void bc_program_retire(BcResult *r, BcResultType t)
5363 bc_vec_pop(&G.prog.results);
5364 bc_vec_push(&G.prog.results, r);
5367 static BcStatus bc_program_op(char inst)
5370 BcResult *opd1, *opd2, res;
5371 BcNum *n1, *n2 = NULL;
5373 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5375 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5377 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5379 bc_program_binOpRetire(&res);
5384 bc_num_free(&res.d.n);
5388 static BcStatus bc_program_read(void)
5390 const char *sv_file;
5396 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5398 for (i = 0; i < G.prog.stack.len; ++i) {
5399 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5400 if (ip_ptr->func == BC_PROG_READ)
5401 return bc_error_nested_read_call();
5404 bc_vec_pop_all(&f->code);
5405 bc_char_vec_init(&buf);
5407 sv_file = G.prog.file;
5410 s = bc_read_line(&buf, "read> ");
5413 common_parse_init(&parse, BC_PROG_READ);
5414 bc_lex_file(&parse.l);
5416 s = bc_parse_text(&parse, buf.v);
5417 if (s) goto exec_err;
5418 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5419 if (s) goto exec_err;
5421 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5422 s = bc_error("bad read() expression");
5426 ip.func = BC_PROG_READ;
5428 ip.len = G.prog.results.len;
5430 // Update this pointer, just in case.
5431 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5433 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5434 bc_vec_push(&G.prog.stack, &ip);
5437 G.prog.file = sv_file;
5438 bc_parse_free(&parse);
5444 static size_t bc_program_index(char *code, size_t *bgn)
5446 char amt = code[(*bgn)++], i = 0;
5449 for (; i < amt; ++i, ++(*bgn))
5450 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5455 static char *bc_program_name(char *code, size_t *bgn)
5458 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5460 s = xmalloc(ptr - str + 1);
5463 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5471 static void bc_program_printString(const char *str, size_t *nchars)
5473 size_t i, len = strlen(str);
5482 for (i = 0; i < len; ++i, ++(*nchars)) {
5486 if (c != '\\' || i == len - 1)
5546 // Just print the backslash and following character.
5557 static BcStatus bc_program_print(char inst, size_t idx)
5559 BcStatus s = BC_STATUS_SUCCESS;
5564 bool pop = inst != BC_INST_PRINT;
5566 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5567 return bc_error_stack_has_too_few_elements();
5569 r = bc_vec_item_rev(&G.prog.results, idx);
5570 s = bc_program_num(r, &num, false);
5573 if (BC_PROG_NUM(r, num)) {
5574 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5575 if (!s) bc_num_copy(&G.prog.last, num);
5579 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5580 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5582 if (inst == BC_INST_PRINT_STR) {
5583 for (i = 0, len = strlen(str); i < len; ++i) {
5586 if (c == '\n') G.prog.nchars = SIZE_MAX;
5591 bc_program_printString(str, &G.prog.nchars);
5592 if (inst == BC_INST_PRINT) bb_putchar('\n');
5596 if (!s && pop) bc_vec_pop(&G.prog.results);
5601 static BcStatus bc_program_negate(void)
5607 s = bc_program_prep(&ptr, &num);
5610 bc_num_init(&res.d.n, num->len);
5611 bc_num_copy(&res.d.n, num);
5612 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5614 bc_program_retire(&res, BC_RESULT_TEMP);
5619 static BcStatus bc_program_logical(char inst)
5622 BcResult *opd1, *opd2, res;
5627 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5629 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5631 if (inst == BC_INST_BOOL_AND)
5632 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5633 else if (inst == BC_INST_BOOL_OR)
5634 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5637 cmp = bc_num_cmp(n1, n2);
5641 case BC_INST_REL_EQ:
5647 case BC_INST_REL_LE:
5653 case BC_INST_REL_GE:
5659 case BC_INST_REL_NE:
5665 case BC_INST_REL_LT:
5671 case BC_INST_REL_GT:
5679 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5681 bc_program_binOpRetire(&res);
5687 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5693 memset(&n2, 0, sizeof(BcNum));
5694 n2.rdx = res.d.id.idx = r->d.id.idx;
5695 res.t = BC_RESULT_STR;
5698 if (!BC_PROG_STACK(&G.prog.results, 2))
5699 return bc_error_stack_has_too_few_elements();
5701 bc_vec_pop(&G.prog.results);
5704 bc_vec_pop(&G.prog.results);
5706 bc_vec_push(&G.prog.results, &res);
5707 bc_vec_push(v, &n2);
5709 return BC_STATUS_SUCCESS;
5713 static BcStatus bc_program_copyToVar(char *name, bool var)
5720 if (!BC_PROG_STACK(&G.prog.results, 1))
5721 return bc_error_stack_has_too_few_elements();
5723 ptr = bc_vec_top(&G.prog.results);
5724 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5725 return bc_error_variable_is_wrong_type();
5726 v = bc_program_search(name, var);
5729 if (ptr->t == BC_RESULT_STR && !var)
5730 return bc_error_variable_is_wrong_type();
5731 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5734 s = bc_program_num(ptr, &n, false);
5737 // Do this once more to make sure that pointers were not invalidated.
5738 v = bc_program_search(name, var);
5741 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5742 bc_num_copy(&r.d.n, n);
5745 bc_array_init(&r.d.v, true);
5746 bc_array_copy(&r.d.v, (BcVec *) n);
5749 bc_vec_push(v, &r.d);
5750 bc_vec_pop(&G.prog.results);
5755 static BcStatus bc_program_assign(char inst)
5758 BcResult *left, *right, res;
5759 BcNum *l = NULL, *r = NULL;
5760 unsigned long val, max;
5761 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5763 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5766 ib = left->t == BC_RESULT_IBASE;
5767 sc = left->t == BC_RESULT_SCALE;
5771 if (right->t == BC_RESULT_STR) {
5775 if (left->t != BC_RESULT_VAR)
5776 return bc_error_variable_is_wrong_type();
5777 v = bc_program_search(left->d.id.name, true);
5779 return bc_program_assignStr(right, v, false);
5783 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5784 return bc_error("bad assignment:"
5785 " left side must be scale,"
5786 " ibase, obase, last, var,"
5791 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5792 return bc_error("divide by zero");
5797 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5804 if (ib || sc || left->t == BC_RESULT_OBASE) {
5805 static const char *const msg[] = {
5806 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5807 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5808 "?1", //BC_RESULT_LAST
5809 "?2", //BC_RESULT_CONSTANT
5810 "?3", //BC_RESULT_ONE
5811 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5815 s = bc_num_ulong(l, &val);
5818 s = left->t - BC_RESULT_IBASE;
5821 ptr = &G.prog.scale;
5824 if (val < BC_NUM_MIN_BASE)
5825 return bc_error(msg[s]);
5826 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5827 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5831 return bc_error(msg[s]);
5833 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5835 *ptr = (size_t) val;
5836 s = BC_STATUS_SUCCESS;
5839 bc_num_init(&res.d.n, l->len);
5840 bc_num_copy(&res.d.n, l);
5841 bc_program_binOpRetire(&res);
5847 #define bc_program_pushVar(code, bgn, pop, copy) \
5848 bc_program_pushVar(code, bgn)
5849 // for bc, 'pop' and 'copy' are always false
5851 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5852 bool pop, bool copy)
5854 BcStatus s = BC_STATUS_SUCCESS;
5856 char *name = bc_program_name(code, bgn);
5858 r.t = BC_RESULT_VAR;
5863 BcVec *v = bc_program_search(name, true);
5864 BcNum *num = bc_vec_top(v);
5868 if (!BC_PROG_STACK(v, 2 - copy)) {
5870 return bc_error_stack_has_too_few_elements();
5876 if (!BC_PROG_STR(num)) {
5878 r.t = BC_RESULT_TEMP;
5880 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5881 bc_num_copy(&r.d.n, num);
5884 r.t = BC_RESULT_STR;
5885 r.d.id.idx = num->rdx;
5888 if (!copy) bc_vec_pop(v);
5893 bc_vec_push(&G.prog.results, &r);
5898 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5901 BcStatus s = BC_STATUS_SUCCESS;
5905 r.d.id.name = bc_program_name(code, bgn);
5907 if (inst == BC_INST_ARRAY) {
5908 r.t = BC_RESULT_ARRAY;
5909 bc_vec_push(&G.prog.results, &r);
5916 s = bc_program_prep(&operand, &num);
5918 s = bc_num_ulong(num, &temp);
5921 if (temp > BC_MAX_DIM) {
5922 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5926 r.d.id.idx = (size_t) temp;
5927 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5931 if (s) free(r.d.id.name);
5936 static BcStatus bc_program_incdec(char inst)
5939 BcResult *ptr, res, copy;
5943 s = bc_program_prep(&ptr, &num);
5946 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5947 copy.t = BC_RESULT_TEMP;
5948 bc_num_init(©.d.n, num->len);
5949 bc_num_copy(©.d.n, num);
5952 res.t = BC_RESULT_ONE;
5953 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5954 BC_INST_ASSIGN_PLUS :
5955 BC_INST_ASSIGN_MINUS;
5957 bc_vec_push(&G.prog.results, &res);
5958 bc_program_assign(inst);
5960 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5961 bc_vec_pop(&G.prog.results);
5962 bc_vec_push(&G.prog.results, ©);
5968 static BcStatus bc_program_call(char *code, size_t *idx)
5970 BcStatus s = BC_STATUS_SUCCESS;
5972 size_t i, nparams = bc_program_index(code, idx);
5979 ip.func = bc_program_index(code, idx);
5980 func = bc_vec_item(&G.prog.fns, ip.func);
5982 if (func->code.len == 0) {
5983 return bc_error("undefined function");
5985 if (nparams != func->nparams) {
5986 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5988 ip.len = G.prog.results.len - nparams;
5990 for (i = 0; i < nparams; ++i) {
5992 a = bc_vec_item(&func->autos, nparams - 1 - i);
5993 arg = bc_vec_top(&G.prog.results);
5995 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5996 return bc_error_variable_is_wrong_type();
5998 s = bc_program_copyToVar(a->name, a->idx);
6002 for (; i < func->autos.len; ++i) {
6005 a = bc_vec_item(&func->autos, i);
6006 v = bc_program_search(a->name, a->idx);
6009 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6010 bc_vec_push(v, ¶m.n);
6013 bc_array_init(¶m.v, true);
6014 bc_vec_push(v, ¶m.v);
6018 bc_vec_push(&G.prog.stack, &ip);
6020 return BC_STATUS_SUCCESS;
6023 static BcStatus bc_program_return(char inst)
6029 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6031 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6032 return bc_error_stack_has_too_few_elements();
6034 f = bc_vec_item(&G.prog.fns, ip->func);
6035 res.t = BC_RESULT_TEMP;
6037 if (inst == BC_INST_RET) {
6040 BcResult *operand = bc_vec_top(&G.prog.results);
6042 s = bc_program_num(operand, &num, false);
6044 bc_num_init(&res.d.n, num->len);
6045 bc_num_copy(&res.d.n, num);
6048 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6049 bc_num_zero(&res.d.n);
6052 // We need to pop arguments as well, so this takes that into account.
6053 for (i = 0; i < f->autos.len; ++i) {
6056 BcId *a = bc_vec_item(&f->autos, i);
6058 v = bc_program_search(a->name, a->idx);
6062 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6063 bc_vec_push(&G.prog.results, &res);
6064 bc_vec_pop(&G.prog.stack);
6066 return BC_STATUS_SUCCESS;
6070 static unsigned long bc_program_scale(BcNum *n)
6072 return (unsigned long) n->rdx;
6075 static unsigned long bc_program_len(BcNum *n)
6077 unsigned long len = n->len;
6080 if (n->rdx != n->len) return len;
6081 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6086 static BcStatus bc_program_builtin(char inst)
6092 bool len = inst == BC_INST_LENGTH;
6094 if (!BC_PROG_STACK(&G.prog.results, 1))
6095 return bc_error_stack_has_too_few_elements();
6096 opnd = bc_vec_top(&G.prog.results);
6098 s = bc_program_num(opnd, &num, false);
6102 if (!BC_PROG_NUM(opnd, num) && !len)
6103 return bc_error_variable_is_wrong_type();
6106 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6108 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6110 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6111 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6115 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6118 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6120 str = bc_vec_item(&G.prog.strs, idx);
6121 bc_num_ulong2num(&res.d.n, strlen(*str));
6125 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6126 bc_num_ulong2num(&res.d.n, f(num));
6129 bc_program_retire(&res, BC_RESULT_TEMP);
6135 static BcStatus bc_program_divmod(void)
6138 BcResult *opd1, *opd2, res, res2;
6139 BcNum *n1, *n2 = NULL;
6141 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6144 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6145 bc_num_init(&res2.d.n, n2->len);
6147 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6150 bc_program_binOpRetire(&res2);
6151 res.t = BC_RESULT_TEMP;
6152 bc_vec_push(&G.prog.results, &res);
6157 bc_num_free(&res2.d.n);
6158 bc_num_free(&res.d.n);
6162 static BcStatus bc_program_modexp(void)
6165 BcResult *r1, *r2, *r3, res;
6166 BcNum *n1, *n2, *n3;
6168 if (!BC_PROG_STACK(&G.prog.results, 3))
6169 return bc_error_stack_has_too_few_elements();
6170 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6173 r1 = bc_vec_item_rev(&G.prog.results, 2);
6174 s = bc_program_num(r1, &n1, false);
6176 if (!BC_PROG_NUM(r1, n1))
6177 return bc_error_variable_is_wrong_type();
6179 // Make sure that the values have their pointers updated, if necessary.
6180 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6182 if (r1->t == r2->t) {
6183 s = bc_program_num(r2, &n2, false);
6187 if (r1->t == r3->t) {
6188 s = bc_program_num(r3, &n3, false);
6193 bc_num_init(&res.d.n, n3->len);
6194 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6197 bc_vec_pop(&G.prog.results);
6198 bc_program_binOpRetire(&res);
6203 bc_num_free(&res.d.n);
6207 static void bc_program_stackLen(void)
6210 size_t len = G.prog.results.len;
6212 res.t = BC_RESULT_TEMP;
6214 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6215 bc_num_ulong2num(&res.d.n, len);
6216 bc_vec_push(&G.prog.results, &res);
6219 static BcStatus bc_program_asciify(void)
6223 BcNum *num = NULL, n;
6224 char *str, *str2, c;
6225 size_t len = G.prog.strs.len, idx;
6228 if (!BC_PROG_STACK(&G.prog.results, 1))
6229 return bc_error_stack_has_too_few_elements();
6230 r = bc_vec_top(&G.prog.results);
6232 s = bc_program_num(r, &num, false);
6235 if (BC_PROG_NUM(r, num)) {
6237 bc_num_init(&n, BC_NUM_DEF_SIZE);
6238 bc_num_copy(&n, num);
6239 bc_num_truncate(&n, n.rdx);
6241 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6242 if (s) goto num_err;
6243 s = bc_num_ulong(&n, &val);
6244 if (s) goto num_err;
6251 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6252 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6260 str2 = xstrdup(str);
6261 bc_program_addFunc(str2, &idx);
6263 if (idx != len + BC_PROG_REQ_FUNCS) {
6265 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6266 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6275 bc_vec_push(&G.prog.strs, &str);
6277 res.t = BC_RESULT_STR;
6279 bc_vec_pop(&G.prog.results);
6280 bc_vec_push(&G.prog.results, &res);
6282 return BC_STATUS_SUCCESS;
6289 static BcStatus bc_program_printStream(void)
6297 if (!BC_PROG_STACK(&G.prog.results, 1))
6298 return bc_error_stack_has_too_few_elements();
6299 r = bc_vec_top(&G.prog.results);
6301 s = bc_program_num(r, &n, false);
6304 if (BC_PROG_NUM(r, n))
6305 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6307 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6308 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6315 static BcStatus bc_program_nquit(void)
6322 s = bc_program_prep(&opnd, &num);
6324 s = bc_num_ulong(num, &val);
6327 bc_vec_pop(&G.prog.results);
6329 if (G.prog.stack.len < val)
6330 return bc_error_stack_has_too_few_elements();
6331 if (G.prog.stack.len == val)
6334 bc_vec_npop(&G.prog.stack, val);
6339 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6342 BcStatus s = BC_STATUS_SUCCESS;
6352 if (!BC_PROG_STACK(&G.prog.results, 1))
6353 return bc_error_stack_has_too_few_elements();
6355 r = bc_vec_top(&G.prog.results);
6359 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6361 if (code[*bgn] == BC_PARSE_STREND)
6364 else_name = bc_program_name(code, bgn);
6366 exec = r->d.n.len != 0;
6370 else if (else_name != NULL) {
6377 v = bc_program_search(name, true);
6384 if (!exec) goto exit;
6385 if (!BC_PROG_STR(n)) {
6386 s = bc_error_variable_is_wrong_type();
6394 if (r->t == BC_RESULT_STR)
6396 else if (r->t == BC_RESULT_VAR) {
6397 s = bc_program_num(r, &n, false);
6398 if (s || !BC_PROG_STR(n)) goto exit;
6405 fidx = sidx + BC_PROG_REQ_FUNCS;
6407 str = bc_vec_item(&G.prog.strs, sidx);
6408 f = bc_vec_item(&G.prog.fns, fidx);
6410 if (f->code.len == 0) {
6411 common_parse_init(&prs, fidx);
6412 s = bc_parse_text(&prs, *str);
6414 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6417 if (prs.l.t.t != BC_LEX_EOF) {
6418 s = bc_error_bad_expression();
6422 bc_parse_free(&prs);
6426 ip.len = G.prog.results.len;
6429 bc_vec_pop(&G.prog.results);
6430 bc_vec_push(&G.prog.stack, &ip);
6432 return BC_STATUS_SUCCESS;
6435 bc_parse_free(&prs);
6436 f = bc_vec_item(&G.prog.fns, fidx);
6437 bc_vec_pop_all(&f->code);
6439 bc_vec_pop(&G.prog.results);
6444 static void bc_program_pushGlobal(char inst)
6449 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6450 if (inst == BC_INST_IBASE)
6451 val = (unsigned long) G.prog.ib_t;
6452 else if (inst == BC_INST_SCALE)
6453 val = (unsigned long) G.prog.scale;
6455 val = (unsigned long) G.prog.ob_t;
6457 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6458 bc_num_ulong2num(&res.d.n, val);
6459 bc_vec_push(&G.prog.results, &res);
6462 static void bc_program_addFunc(char *name, size_t *idx)
6464 BcId entry, *entry_ptr;
6469 entry.idx = G.prog.fns.len;
6471 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6472 if (!inserted) free(name);
6474 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6475 *idx = entry_ptr->idx;
6479 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6481 // We need to reset these, so the function can be repopulated.
6483 bc_vec_pop_all(&func->autos);
6484 bc_vec_pop_all(&func->code);
6485 bc_vec_pop_all(&func->labels);
6489 bc_vec_push(&G.prog.fns, &f);
6493 // Called when parsing or execution detects a failure,
6494 // resets execution structures.
6495 static void bc_program_reset(void)
6500 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6501 bc_vec_pop_all(&G.prog.results);
6503 f = bc_vec_item(&G.prog.fns, 0);
6504 ip = bc_vec_top(&G.prog.stack);
6505 ip->idx = f->code.len;
6507 // If !tty, no need to check for ^C: we don't have ^C handler,
6508 // we would be killed by a signal and won't reach this place
6511 static BcStatus bc_program_exec(void)
6513 BcStatus s = BC_STATUS_SUCCESS;
6517 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6518 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6519 char *code = func->code.v;
6522 while (!s && ip->idx < func->code.len) {
6524 char inst = code[(ip->idx)++];
6529 case BC_INST_JUMP_ZERO:
6531 s = bc_program_prep(&ptr, &num);
6533 cond = !bc_num_cmp(num, &G.prog.zero);
6534 bc_vec_pop(&G.prog.results);
6540 idx = bc_program_index(code, &ip->idx);
6541 addr = bc_vec_item(&func->labels, idx);
6542 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6548 s = bc_program_call(code, &ip->idx);
6552 case BC_INST_INC_PRE:
6553 case BC_INST_DEC_PRE:
6554 case BC_INST_INC_POST:
6555 case BC_INST_DEC_POST:
6557 s = bc_program_incdec(inst);
6570 s = bc_program_return(inst);
6574 case BC_INST_BOOL_OR:
6575 case BC_INST_BOOL_AND:
6577 case BC_INST_REL_EQ:
6578 case BC_INST_REL_LE:
6579 case BC_INST_REL_GE:
6580 case BC_INST_REL_NE:
6581 case BC_INST_REL_LT:
6582 case BC_INST_REL_GT:
6584 s = bc_program_logical(inst);
6590 s = bc_program_read();
6596 s = bc_program_pushVar(code, &ip->idx, false, false);
6600 case BC_INST_ARRAY_ELEM:
6603 s = bc_program_pushArray(code, &ip->idx, inst);
6609 r.t = BC_RESULT_LAST;
6610 bc_vec_push(&G.prog.results, &r);
6618 bc_program_pushGlobal(inst);
6622 case BC_INST_SCALE_FUNC:
6623 case BC_INST_LENGTH:
6626 s = bc_program_builtin(inst);
6632 r.t = BC_RESULT_CONSTANT;
6633 r.d.id.idx = bc_program_index(code, &ip->idx);
6634 bc_vec_push(&G.prog.results, &r);
6640 if (!BC_PROG_STACK(&G.prog.results, 1))
6641 s = bc_error_stack_has_too_few_elements();
6643 bc_vec_pop(&G.prog.results);
6647 case BC_INST_POP_EXEC:
6649 bc_vec_pop(&G.prog.stack);
6654 case BC_INST_PRINT_POP:
6655 case BC_INST_PRINT_STR:
6657 s = bc_program_print(inst, 0);
6663 r.t = BC_RESULT_STR;
6664 r.d.id.idx = bc_program_index(code, &ip->idx);
6665 bc_vec_push(&G.prog.results, &r);
6670 case BC_INST_MULTIPLY:
6671 case BC_INST_DIVIDE:
6672 case BC_INST_MODULUS:
6676 s = bc_program_op(inst);
6680 case BC_INST_BOOL_NOT:
6682 s = bc_program_prep(&ptr, &num);
6685 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6686 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6687 bc_program_retire(&r, BC_RESULT_TEMP);
6694 s = bc_program_negate();
6699 case BC_INST_ASSIGN_POWER:
6700 case BC_INST_ASSIGN_MULTIPLY:
6701 case BC_INST_ASSIGN_DIVIDE:
6702 case BC_INST_ASSIGN_MODULUS:
6703 case BC_INST_ASSIGN_PLUS:
6704 case BC_INST_ASSIGN_MINUS:
6706 case BC_INST_ASSIGN:
6708 s = bc_program_assign(inst);
6712 case BC_INST_MODEXP:
6714 s = bc_program_modexp();
6718 case BC_INST_DIVMOD:
6720 s = bc_program_divmod();
6724 case BC_INST_EXECUTE:
6725 case BC_INST_EXEC_COND:
6727 cond = inst == BC_INST_EXEC_COND;
6728 s = bc_program_execStr(code, &ip->idx, cond);
6732 case BC_INST_PRINT_STACK:
6734 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6735 s = bc_program_print(BC_INST_PRINT, idx);
6739 case BC_INST_CLEAR_STACK:
6741 bc_vec_pop_all(&G.prog.results);
6745 case BC_INST_STACK_LEN:
6747 bc_program_stackLen();
6751 case BC_INST_DUPLICATE:
6753 if (!BC_PROG_STACK(&G.prog.results, 1))
6754 return bc_error_stack_has_too_few_elements();
6755 ptr = bc_vec_top(&G.prog.results);
6756 bc_result_copy(&r, ptr);
6757 bc_vec_push(&G.prog.results, &r);
6765 if (!BC_PROG_STACK(&G.prog.results, 2))
6766 return bc_error_stack_has_too_few_elements();
6768 ptr = bc_vec_item_rev(&G.prog.results, 0);
6769 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6770 memcpy(&r, ptr, sizeof(BcResult));
6771 memcpy(ptr, ptr2, sizeof(BcResult));
6772 memcpy(ptr2, &r, sizeof(BcResult));
6777 case BC_INST_ASCIIFY:
6779 s = bc_program_asciify();
6783 case BC_INST_PRINT_STREAM:
6785 s = bc_program_printStream();
6790 case BC_INST_PUSH_VAR:
6792 bool copy = inst == BC_INST_LOAD;
6793 s = bc_program_pushVar(code, &ip->idx, true, copy);
6797 case BC_INST_PUSH_TO_VAR:
6799 char *name = bc_program_name(code, &ip->idx);
6800 s = bc_program_copyToVar(name, true);
6807 if (G.prog.stack.len <= 2)
6809 bc_vec_npop(&G.prog.stack, 2);
6815 s = bc_program_nquit();
6821 if (s || G_interrupt) {
6826 // If the stack has changed, pointers may be invalid.
6827 ip = bc_vec_top(&G.prog.stack);
6828 func = bc_vec_item(&G.prog.fns, ip->func);
6829 code = func->code.v;
6835 static void bc_vm_info(void)
6837 printf("%s "BB_VER"\n"
6838 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6839 "Report bugs at: https://github.com/gavinhoward/bc\n"
6840 "This is free software with ABSOLUTELY NO WARRANTY\n"
6845 static void bc_vm_envArgs(void)
6847 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6850 char *env_args = getenv(bc_args_env_name), *buf;
6852 if (!env_args) return;
6854 G.env_args = xstrdup(env_args);
6857 bc_vec_init(&v, sizeof(char *), NULL);
6858 bc_vec_push(&v, &bc_args_env_name);
6861 if (!isspace(*buf)) {
6862 bc_vec_push(&v, &buf);
6863 while (*buf != 0 && !isspace(*buf)) ++buf;
6864 if (*buf != 0) (*(buf++)) = '\0';
6870 bc_args((int) v.len, (char **) v.v);
6876 static size_t bc_vm_envLen(const char *var)
6878 char *lenv = getenv(var);
6879 size_t i, len = BC_NUM_PRINT_WIDTH;
6882 if (!lenv) return len;
6886 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6888 len = (size_t) atoi(lenv) - 1;
6889 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6892 len = BC_NUM_PRINT_WIDTH;
6897 static BcStatus bc_vm_process(const char *text)
6899 BcStatus s = bc_parse_text(&G.prs, text);
6903 while (G.prs.l.t.t != BC_LEX_EOF) {
6904 s = G.prs.parse(&G.prs);
6908 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6909 s = bc_program_exec();
6918 static BcStatus bc_vm_file(const char *file)
6920 const char *sv_file;
6926 data = bc_read_file(file);
6927 if (!data) return bc_error_fmt("file '%s' is not text", file);
6929 sv_file = G.prog.file;
6931 bc_lex_file(&G.prs.l);
6932 s = bc_vm_process(data);
6935 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6936 ip = bc_vec_item(&G.prog.stack, 0);
6938 if (main_func->code.len < ip->idx)
6939 s = bc_error_fmt("file '%s' is not executable", file);
6942 G.prog.file = sv_file;
6947 static BcStatus bc_vm_stdin(void)
6951 size_t len, i, str = 0;
6952 bool comment = false;
6955 bc_lex_file(&G.prs.l);
6957 bc_char_vec_init(&buffer);
6958 bc_char_vec_init(&buf);
6959 bc_vec_pushZeroByte(&buffer);
6961 // This loop is complex because the vm tries not to send any lines that end
6962 // with a backslash to the parser. The reason for that is because the parser
6963 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6964 // case, and for strings and comments, the parser will expect more stuff.
6965 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6967 char *string = buf.v;
6972 if (str && buf.v[0] == G.send)
6974 else if (buf.v[0] == G.sbgn)
6977 else if (len > 1 || comment) {
6979 for (i = 0; i < len; ++i) {
6981 bool notend = len > i + 1;
6984 if (i - 1 > len || string[i - 1] != '\\') {
6985 if (G.sbgn == G.send)
6987 else if (c == G.send)
6989 else if (c == G.sbgn)
6993 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6997 else if (c == '*' && notend && comment && string[i + 1] == '/')
7001 if (str || comment || string[len - 2] == '\\') {
7002 bc_vec_concat(&buffer, buf.v);
7007 bc_vec_concat(&buffer, buf.v);
7008 s = bc_vm_process(buffer.v);
7011 fputs("ready for more input\n", stderr);
7014 bc_vec_pop_all(&buffer);
7018 s = bc_error("string end could not be found");
7021 s = bc_error("comment end could not be found");
7025 bc_vec_free(&buffer);
7030 static const char bc_lib[] = {
7033 "\n" "auto b,s,n,r,d,i,p,f,v"
7042 "\n" "scale=scale(x)+1"
7052 "\n" "for(i=2;v!=0;++i){"
7058 "\n" "while((d--)!=0)r*=r"
7061 "\n" "if(n!=0)return(1/r)"
7065 "\n" "auto b,s,r,p,a,q,i,v"
7069 "\n" "r=(1-10^scale)/1"
7080 "\n" "while(x<=0.5){"
7084 "\n" "r=a=(x-1)/(x+1)"
7087 "\n" "for(i=3;v!=0;i+=2){"
7098 "\n" "auto b,s,r,n,a,q,i"
7102 "\n" "scale=1.1*s+2"
7111 "\n" "if(q%2!=0)x=-x"
7115 "\n" "for(i=3;a!=0;i+=2){"
7116 "\n" "a*=q/(i*(i-1))"
7121 "\n" "if(n!=0)return(-r/1)"
7130 "\n" "x=s(2*a(1)+x)"
7136 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7145 "\n" "if(scale<65){"
7146 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7150 "\n" "if(scale<65){"
7151 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7162 "\n" "x=(x-.2)/(1+.2*x)"
7167 "\n" "for(i=3;t!=0;i+=2){"
7174 "\n" "return((m*a+r)/n)"
7176 "\n" "define j(n,x){"
7177 "\n" "auto b,s,o,a,i,v,f"
7185 "\n" "if(n%2==1)o=1"
7188 "\n" "for(i=2;i<=n;++i)a*=i"
7190 "\n" "a=(x^n)/2^n/a"
7193 "\n" "scale=scale+length(a)-scale(a)"
7194 "\n" "for(i=1;v!=0;++i){"
7195 "\n" "v=v*f/i/(n+i)"
7201 "\n" "return(a*r/1)"
7206 static BcStatus bc_vm_exec(void)
7208 BcStatus s = BC_STATUS_SUCCESS;
7212 if (option_mask32 & BC_FLAG_L) {
7214 // We know that internal library is not buggy,
7215 // thus error checking is normally disabled.
7216 # define DEBUG_LIB 0
7217 bc_lex_file(&G.prs.l);
7218 s = bc_parse_text(&G.prs, bc_lib);
7219 if (DEBUG_LIB && s) return s;
7221 while (G.prs.l.t.t != BC_LEX_EOF) {
7222 s = G.prs.parse(&G.prs);
7223 if (DEBUG_LIB && s) return s;
7225 s = bc_program_exec();
7226 if (DEBUG_LIB && s) return s;
7230 for (i = 0; !s && i < G.files.len; ++i)
7231 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7234 fputs("ready for more input\n", stderr);
7237 if (IS_BC || !G.files.len)
7239 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7240 s = bc_vm_process("");
7245 #if ENABLE_FEATURE_CLEAN_UP
7246 static void bc_program_free()
7248 bc_num_free(&G.prog.ib);
7249 bc_num_free(&G.prog.ob);
7250 bc_num_free(&G.prog.hexb);
7252 bc_num_free(&G.prog.strmb);
7254 bc_vec_free(&G.prog.fns);
7255 bc_vec_free(&G.prog.fn_map);
7256 bc_vec_free(&G.prog.vars);
7257 bc_vec_free(&G.prog.var_map);
7258 bc_vec_free(&G.prog.arrs);
7259 bc_vec_free(&G.prog.arr_map);
7260 bc_vec_free(&G.prog.strs);
7261 bc_vec_free(&G.prog.consts);
7262 bc_vec_free(&G.prog.results);
7263 bc_vec_free(&G.prog.stack);
7264 bc_num_free(&G.prog.last);
7265 bc_num_free(&G.prog.zero);
7266 bc_num_free(&G.prog.one);
7269 static void bc_vm_free(void)
7271 bc_vec_free(&G.files);
7273 bc_parse_free(&G.prs);
7278 static void bc_program_init(size_t line_len)
7283 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7284 memset(&ip, 0, sizeof(BcInstPtr));
7286 /* G.prog.nchars = G.prog.scale = 0; - already is */
7287 G.prog.len = line_len;
7289 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7290 bc_num_ten(&G.prog.ib);
7293 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7294 bc_num_ten(&G.prog.ob);
7297 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7298 bc_num_ten(&G.prog.hexb);
7299 G.prog.hexb.num[0] = 6;
7302 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7303 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7306 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7307 bc_num_zero(&G.prog.last);
7309 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7310 bc_num_zero(&G.prog.zero);
7312 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7313 bc_num_one(&G.prog.one);
7315 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7316 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7318 bc_program_addFunc(xstrdup("(main)"), &idx);
7319 bc_program_addFunc(xstrdup("(read)"), &idx);
7321 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7322 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7324 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7325 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7327 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7328 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7329 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7330 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7331 bc_vec_push(&G.prog.stack, &ip);
7334 static void bc_vm_init(const char *env_len)
7336 size_t len = bc_vm_envLen(env_len);
7338 bc_vec_init(&G.files, sizeof(char *), NULL);
7344 bc_program_init(len);
7346 bc_parse_init(&G.prs, BC_PROG_MAIN);
7348 dc_parse_init(&G.prs, BC_PROG_MAIN);
7352 static BcStatus bc_vm_run(int argc, char *argv[],
7353 const char *env_len)
7357 bc_vm_init(env_len);
7358 bc_args(argc, argv);
7360 G.ttyin = isatty(0);
7363 #if ENABLE_FEATURE_BC_SIGNALS
7364 // With SA_RESTART, most system calls will restart
7365 // (IOW: they won't fail with EINTR).
7366 // In particular, this means ^C won't cause
7367 // stdout to get into "error state" if SIGINT hits
7368 // within write() syscall.
7369 // The downside is that ^C while line input is taken
7370 // will only be handled after [Enter] since read()
7371 // from stdin is not interrupted by ^C either,
7372 // it restarts, thus fgetc() does not return on ^C.
7373 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7375 // Without SA_RESTART, this exhibits a bug:
7376 // "while (1) print 1" and try ^C-ing it.
7377 // Intermittently, instead of returning to input line,
7378 // you'll get "output error: Interrupted system call"
7380 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7382 if (!(option_mask32 & BC_FLAG_Q))
7387 #if ENABLE_FEATURE_CLEAN_UP
7394 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7395 int bc_main(int argc, char **argv)
7398 G.sbgn = G.send = '"';
7400 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7405 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7406 int dc_main(int argc, char **argv)
7412 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");